/** * Main method. Begins the GUI, and the rest of the program. * * @param args the command line arguments */ public static void main(String args[]) { // playSound(); try { for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.getLogger(mainForm.class.getName()).log(Level.SEVERE, null, ex); } // </editor-fold> /* Create and display the form */ EventQueue.invokeLater( new Runnable() { @Override public void run() { new mainForm().setVisible(true); } }); }
public void actionPerformed(ActionEvent ae) { if (ae.getActionCommand() == "timer") { if (counter >= imagePaths.length) { timer.stop(); counter = 0; PlayStopButton.setText("Play"); } else { try { // if the array contains URLs if (imagePaths[counter].contains("http://")) { scrollPane.setToolTipText(imagePaths[counter]); imageIcon = new ImageIcon((new URL(imagePaths[counter++]))); scrollPane.setViewportView(new JLabel(imageIcon)); } // if the array contains local images else { image.setIcon(new ImageIcon(imagePaths[counter])); image.setToolTipText(imagePaths[counter++]); } } catch (MalformedURLException ex) { Logger.getLogger(Slideshow.class.getName()).log(Level.SEVERE, null, ex); image = new JLabel("?" + imagePaths); } } } }
private void initLogger() { log = Logger.getLogger(this.getClass().getName()); log.setUseParentHandlers(false); log.setLevel(Level.ALL); try { new File(LOG_FILENAME).getParentFile().mkdirs(); StreamHandler handle = new StreamHandler(new FileOutputStream(LOG_FILENAME), new SimpleFormatter()) { @Override public boolean isLoggable(LogRecord record) { return true; // record.getLevel() == ENLevels.ERROR; } @Override public void publish(LogRecord record) { super.publish(record); } }; log.addHandler(handle); } catch (IOException e) { } }
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(); }
@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 BooleanToggleButtonManager(Preferences prNode, String prefName, boolean def) { // Chop of classname and last package component for logger. String p = getClass().getName(); int idx = p.lastIndexOf('.'); p = p.substring(0, idx); idx = p.lastIndexOf('.'); p = p.substring(0, idx); log = Logger.getLogger(p + "." + prefName.replace('/', '.')); this.def = def; pr = prNode; pref = prefName; }
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; } }
/** * Indicates that the security is time-outed, is not supported by the other end. * * @param evt Details about the event that caused this message. */ @Override public void securityTimeout(CallPeerSecurityTimeoutEvent evt) { timer.cancel(); // fail peer, call if (evt.getSource() instanceof AbstractCallPeer) { try { CallPeer peer = (CallPeer) evt.getSource(); OperationSetBasicTelephony<?> telephony = peer.getProtocolProvider().getOperationSet(OperationSetBasicTelephony.class); telephony.hangupCallPeer( peer, OperationSetBasicTelephony.HANGUP_REASON_ENCRYPTION_REQUIRED, "Encryption Required!"); } catch (OperationFailedException ex) { Logger.getLogger(getClass()).error("Failed to hangup peer", ex); } } }
/** @author james.bloom */ public class MainUI extends JFrame { /** */ private static final long serialVersionUID = -2404746632782793567L; private static Logger dLog = Logger.getLogger(MainUI.class); private JDesktopPane theDesktop = new JDesktopPane(); private JMenuBar menubar = new JMenuBar(); public MainUI() { super("Neato Burrito"); dLog.trace("In MainUI: " + MainUI.class.getCanonicalName()); this.setBounds(0, 0, 500, 500); Container container = getContentPane(); container.add(theDesktop); setJMenuBar(menubar); JMenu fileMenu = new JMenu("File"); JMenuItem exitItem = new JMenuItem("Exit"); exitItem.setMnemonic('X'); exitItem.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); fileMenu.add(exitItem); menubar.add(fileMenu); StatusUI statUI = new StatusUI(); statUI.setVisible(true); theDesktop.add(statUI); setDefaultCloseOperation(EXIT_ON_CLOSE); pack(); setVisible(true); } }
public static Logger initLogger() { Logger initlogger = Logger.getLogger(settings.getMainClass()); initlogger.setLevel(settings.getLogLevel()); boolean addconsole = false; if (settings.getLogToFile()) { try { Handler handler = new FileHandler(settings.getLogFile(), true); handler.setFormatter(new SimpleFormatter()); initlogger.addHandler(handler); } catch (Exception e) { Logger().warning("Could not set logfile " + settings.getLogFile() + ": " + e.getMessage()); addconsole = true; } } addconsole = settings.getLogToConsole() || addconsole; if (addconsole) { initlogger.addHandler(new ConsoleHandler()); } // restore original log state logger.setLevel(templevel); templevel = null; return initlogger; }
/** * The <tt>FileTransferConversationComponent</tt> is the parent of all file conversation components * - for incoming, outgoing and history file transfers. * * @author Yana Stamcheva * @author Adam Netocny */ public abstract class FileTransferConversationComponent extends ChatConversationComponent implements ActionListener, FileTransferProgressListener, Skinnable { /** The logger for this class. */ private final Logger logger = Logger.getLogger(FileTransferConversationComponent.class); /** Image default width. */ protected static final int IMAGE_WIDTH = 64; /** Image default height. */ protected static final int IMAGE_HEIGHT = 64; /** The image label. */ protected final FileImageLabel imageLabel; /** The title label. */ protected final JLabel titleLabel = new JLabel(); /** The file label. */ protected final JLabel fileLabel = new JLabel(); /** The error area. */ private final JTextArea errorArea = new JTextArea(); /** The error icon label. */ private final JLabel errorIconLabel = new JLabel(new ImageIcon(ImageLoader.getImage(ImageLoader.EXCLAMATION_MARK))); /** The cancel button. */ protected final ChatConversationButton cancelButton = new ChatConversationButton(); /** The retry button. */ protected final ChatConversationButton retryButton = new ChatConversationButton(); /** The accept button. */ protected final ChatConversationButton acceptButton = new ChatConversationButton(); /** The reject button. */ protected final ChatConversationButton rejectButton = new ChatConversationButton(); /** The open file button. */ protected final ChatConversationButton openFileButton = new ChatConversationButton(); /** The open folder button. */ protected final ChatConversationButton openFolderButton = new ChatConversationButton(); /** The progress bar. */ protected final JProgressBar progressBar = new JProgressBar(); /** The progress properties panel. */ private final TransparentPanel progressPropertiesPanel = new TransparentPanel(new FlowLayout(FlowLayout.RIGHT)); /** The progress speed label. */ private final JLabel progressSpeedLabel = new JLabel(); /** The estimated time label. */ private final JLabel estimatedTimeLabel = new JLabel(); /** The download file. */ private File downloadFile; /** The file transfer. */ private FileTransfer fileTransfer; /** The speed calculated delay. */ private static final int SPEED_CALCULATE_DELAY = 5000; /** The transferred file size. */ private long transferredFileSize = 0; /** The time of the last calculated transfer speed. */ private long lastSpeedTimestamp = 0; /** The last estimated time for the transfer. */ private long lastEstimatedTimeTimestamp = 0; /** The number of bytes last transferred. */ private long lastTransferredBytes = 0; /** The last calculated progress speed. */ private long lastProgressSpeed; /** The last estimated time. */ private long lastEstimatedTime; /** Creates a file conversation component. */ public FileTransferConversationComponent() { imageLabel = new FileImageLabel(); constraints.gridx = 0; constraints.gridy = 0; constraints.gridwidth = 1; constraints.gridheight = 4; constraints.anchor = GridBagConstraints.NORTHWEST; constraints.insets = new Insets(5, 5, 5, 5); add(imageLabel, constraints); imageLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.DEFAULT_FILE_ICON))); constraints.gridx = 1; constraints.gridy = 0; constraints.gridwidth = 3; constraints.gridheight = 1; constraints.fill = GridBagConstraints.HORIZONTAL; constraints.weightx = 1.0; constraints.anchor = GridBagConstraints.NORTHWEST; constraints.insets = new Insets(5, 5, 5, 5); add(titleLabel, constraints); titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 11f)); constraints.gridx = 1; constraints.gridy = 1; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 5, 5, 5); add(fileLabel, constraints); constraints.gridx = 1; constraints.gridy = 2; constraints.gridwidth = 1; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 5, 0, 5); constraints.fill = GridBagConstraints.NONE; add(errorIconLabel, constraints); errorIconLabel.setVisible(false); constraints.gridx = 2; constraints.gridy = 2; constraints.gridwidth = 2; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 5, 0, 5); constraints.fill = GridBagConstraints.HORIZONTAL; add(errorArea, constraints); errorArea.setForeground(new Color(resources.getColor("service.gui.ERROR_FOREGROUND"))); setTextAreaStyle(errorArea); errorArea.setVisible(false); constraints.gridx = 1; constraints.gridy = 3; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.weightx = 0.0; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 5, 0, 5); add(retryButton, constraints); retryButton.setText(GuiActivator.getResources().getI18NString("service.gui.RETRY")); retryButton.setVisible(false); constraints.gridx = 1; constraints.gridy = 3; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.weightx = 0.0; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 5, 0, 5); add(cancelButton, constraints); cancelButton.setText(GuiActivator.getResources().getI18NString("service.gui.CANCEL")); cancelButton.addActionListener(this); cancelButton.setVisible(false); constraints.gridx = 2; constraints.gridy = 3; constraints.gridwidth = GridBagConstraints.RELATIVE; constraints.gridheight = 1; constraints.weightx = 0.0; constraints.fill = GridBagConstraints.NONE; constraints.anchor = GridBagConstraints.EAST; constraints.insets = new Insets(0, 5, 0, 5); constraints.gridx = 3; constraints.gridy = 3; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.weightx = 0.0; constraints.fill = GridBagConstraints.NONE; constraints.anchor = GridBagConstraints.LINE_END; constraints.insets = new Insets(0, 5, 0, 5); add(progressPropertiesPanel, constraints); estimatedTimeLabel.setFont(estimatedTimeLabel.getFont().deriveFont(11f)); estimatedTimeLabel.setVisible(false); progressSpeedLabel.setFont(progressSpeedLabel.getFont().deriveFont(11f)); progressSpeedLabel.setVisible(false); progressPropertiesPanel.add(progressSpeedLabel); progressPropertiesPanel.add(estimatedTimeLabel); constraints.gridx = 1; constraints.gridy = 3; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.weightx = 0.0; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 5, 0, 5); constraints.fill = GridBagConstraints.NONE; add(acceptButton, constraints); acceptButton.setText(GuiActivator.getResources().getI18NString("service.gui.ACCEPT")); acceptButton.setVisible(false); constraints.gridx = 2; constraints.gridy = 3; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.weightx = 0.0; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 5, 0, 5); constraints.fill = GridBagConstraints.NONE; add(rejectButton, constraints); rejectButton.setText(GuiActivator.getResources().getI18NString("service.gui.REJECT")); rejectButton.setVisible(false); constraints.gridx = 1; constraints.gridy = 3; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.weightx = 0.0; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 5, 0, 5); constraints.fill = GridBagConstraints.NONE; add(openFileButton, constraints); openFileButton.setText(GuiActivator.getResources().getI18NString("service.gui.OPEN")); openFileButton.setVisible(false); openFileButton.addActionListener(this); constraints.gridx = 2; constraints.gridy = 3; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.weightx = 0.0; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 5, 0, 5); constraints.fill = GridBagConstraints.NONE; add(openFolderButton, constraints); openFolderButton.setText(GuiActivator.getResources().getI18NString("service.gui.OPEN_FOLDER")); openFolderButton.setVisible(false); openFolderButton.addActionListener(this); constraints.gridx = 1; constraints.gridy = 2; constraints.gridwidth = 3; constraints.gridheight = 1; constraints.weightx = 1.0; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 5, 0, 5); constraints.ipadx = 150; constraints.fill = GridBagConstraints.HORIZONTAL; add(progressBar, constraints); progressBar.setVisible(false); progressBar.setStringPainted(true); } /** * Sets a custom style for the given text area. * * @param textArea the text area to style */ private void setTextAreaStyle(JTextArea textArea) { textArea.setOpaque(false); textArea.setLineWrap(true); textArea.setWrapStyleWord(true); } /** * Shows the given error message in the error area of this component. * * @param message the message to show */ protected void showErrorMessage(String message) { errorArea.setText(message); errorIconLabel.setVisible(true); errorArea.setVisible(true); } /** * Sets the download file. * * @param file the file that has been downloaded or sent */ protected void setCompletedDownloadFile(File file) { this.downloadFile = file; imageLabel.setFile(downloadFile); imageLabel.setToolTipText(resources.getI18NString("service.gui.OPEN_FILE_FROM_IMAGE")); imageLabel.addMouseListener( new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() > 1) { openFile(downloadFile); } } }); } /** * Sets the file transfer. * * @param fileTransfer the file transfer * @param transferredFileSize the size of the transferred file */ protected void setFileTransfer(FileTransfer fileTransfer, long transferredFileSize) { this.fileTransfer = fileTransfer; this.transferredFileSize = transferredFileSize; fileTransfer.addProgressListener(this); } /** * Handles buttons action events. * * @param evt the <tt>ActionEvent</tt> that notified us */ public void actionPerformed(ActionEvent evt) { JButton sourceButton = (JButton) evt.getSource(); if (sourceButton.equals(openFileButton)) { this.openFile(downloadFile); } else if (sourceButton.equals(openFolderButton)) { try { File downloadDir = GuiActivator.getFileAccessService().getDefaultDownloadDirectory(); GuiActivator.getDesktopService().open(downloadDir); } catch (IllegalArgumentException e) { if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e); this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_DOES_NOT_EXIST")); } catch (NullPointerException e) { if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e); this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_DOES_NOT_EXIST")); } catch (UnsupportedOperationException e) { if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e); this.showErrorMessage(resources.getI18NString("service.gui.FILE_OPEN_NOT_SUPPORTED")); } catch (SecurityException e) { if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e); this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_OPEN_NO_PERMISSION")); } catch (IOException e) { if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e); this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_OPEN_NO_APPLICATION")); } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Unable to open file.", e); this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_OPEN_FAILED")); } } else if (sourceButton.equals(cancelButton)) { if (fileTransfer != null) fileTransfer.cancel(); } } /** * Updates progress bar progress line every time a progress event has been received. * * @param event the <tt>FileTransferProgressEvent</tt> that notified us */ public void progressChanged(FileTransferProgressEvent event) { progressBar.setValue((int) event.getProgress()); long transferredBytes = event.getFileTransfer().getTransferedBytes(); long progressTimestamp = event.getTimestamp(); ByteFormat format = new ByteFormat(); String bytesString = format.format(transferredBytes); if ((progressTimestamp - lastSpeedTimestamp) >= SPEED_CALCULATE_DELAY) { lastProgressSpeed = Math.round(calculateProgressSpeed(transferredBytes)); this.lastSpeedTimestamp = progressTimestamp; this.lastTransferredBytes = transferredBytes; } if ((progressTimestamp - lastEstimatedTimeTimestamp) >= SPEED_CALCULATE_DELAY && lastProgressSpeed > 0) { lastEstimatedTime = Math.round( calculateEstimatedTransferTime( lastProgressSpeed, transferredFileSize - transferredBytes)); lastEstimatedTimeTimestamp = progressTimestamp; } progressBar.setString(getProgressLabel(bytesString)); if (lastProgressSpeed > 0) { progressSpeedLabel.setText( resources.getI18NString("service.gui.SPEED") + format.format(lastProgressSpeed) + "/sec"); progressSpeedLabel.setVisible(true); } if (lastEstimatedTime > 0) { estimatedTimeLabel.setText( resources.getI18NString("service.gui.ESTIMATED_TIME") + GuiUtils.formatSeconds(lastEstimatedTime * 1000)); estimatedTimeLabel.setVisible(true); } } /** * Returns the string, showing information for the given file. * * @param file the file * @return the name of the given file */ protected String getFileLabel(File file) { String fileName = file.getName(); long fileSize = file.length(); ByteFormat format = new ByteFormat(); String text = format.format(fileSize); return fileName + " (" + text + ")"; } /** * Returns the string, showing information for the given file. * * @param fileName the name of the file * @param fileSize the size of the file * @return the name of the given file */ protected String getFileLabel(String fileName, long fileSize) { ByteFormat format = new ByteFormat(); String text = format.format(fileSize); return fileName + " (" + text + ")"; } /** Hides all progress related components. */ protected void hideProgressRelatedComponents() { progressBar.setVisible(false); progressSpeedLabel.setVisible(false); estimatedTimeLabel.setVisible(false); } /** * Returns the label to show on the progress bar. * * @param bytesString the bytes that have been transfered * @return the label to show on the progress bar */ protected abstract String getProgressLabel(String bytesString); /** * Returns the speed of the transfer. * * @param transferredBytes the number of bytes that have been transferred * @return the speed of the transfer */ private double calculateProgressSpeed(long transferredBytes) { // Bytes per second = bytes / SPEED_CALCULATE_DELAY miliseconds * 1000. return (transferredBytes - lastTransferredBytes) / SPEED_CALCULATE_DELAY * 1000; } /** * Returns the estimated transfer time left. * * @param speed the speed of the transfer * @param bytesLeft the size of the file * @return the estimated transfer time left */ private double calculateEstimatedTransferTime(double speed, long bytesLeft) { return bytesLeft / speed; } /** Reload images and colors. */ public void loadSkin() { errorIconLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.EXCLAMATION_MARK))); if (downloadFile != null) imageLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.DEFAULT_FILE_ICON))); errorArea.setForeground(new Color(resources.getColor("service.gui.ERROR_FOREGROUND"))); } }
/** * The <tt>OneToOneCallPeerPanel</tt> is the panel containing data for a call peer in a given call. * It contains information like call peer name, photo, call duration, etc. * * @author Yana Stamcheva * @author Lyubomir Marinov * @author Sebastien Vincent * @author Adam Netocny */ public class OneToOneCallPeerPanel extends TransparentPanel implements SwingCallPeerRenderer, PropertyChangeListener, Skinnable { /** * The <tt>Logger</tt> used by the <tt>OneToOneCallPeerPanel</tt> class and its instances for * logging output. */ private static final Logger logger = Logger.getLogger(OneToOneCallPeerPanel.class); /** Serial version UID. */ private static final long serialVersionUID = 0L; /** The <tt>CallPeer</tt>, which is rendered in this panel. */ private final CallPeer callPeer; /** The <tt>Call</tt>, which is rendered in this panel. */ private final Call call; /** * The <tt>CallPeerAdapter</tt> which implements common <tt>CallPeer</tt>-related listeners on * behalf of this instance. */ private final CallPeerAdapter callPeerAdapter; /** The renderer of the call. */ private final SwingCallRenderer callRenderer; /** The component showing the status of the underlying call peer. */ private final JLabel callStatusLabel = new JLabel(); /** The center component. */ private final VideoContainer center; /** * The AWT <tt>Component</tt> which implements a button which allows closing/hiding the visual * <tt>Component</tt> which depicts the video streaming from the local peer/user to the remote * peer(s). */ private Component closeLocalVisualComponentButton; /** * A listener to desktop sharing granted/revoked events and to mouse and keyboard interaction with * the remote video displaying the remote desktop. */ private final DesktopSharingMouseAndKeyboardListener desktopSharingMouseAndKeyboardListener; /** * The indicator which determines whether {@link #dispose()} has already been invoked on this * instance. If <tt>true</tt>, this instance is considered non-functional and is to be left to the * garbage collector. */ private boolean disposed = false; /** The DTMF label. */ private final JLabel dtmfLabel = new JLabel(); /** The component responsible for displaying an error message. */ private JTextComponent errorMessageComponent; /** The label showing whether the call is on or off hold. */ private final JLabel holdStatusLabel = new JLabel(); /** Sound local level label. */ private InputVolumeControlButton localLevel; /** * The <tt>Component</tt> which {@link #updateViewFromModelInEventDispatchThread()} last added to * {@link #center} as the visual <tt>Component</tt> displaying the video streaming from the local * peer/user to the remote peer(s). * * <p><b>Warning</b>: It is not to be used for any other purposes because it may not represent the * current state of the model of this view. */ private Component localVideo; /** The label showing whether the voice has been set to mute. */ private final JLabel muteStatusLabel = new JLabel(); /** The <tt>Icon</tt> which represents the avatar of the associated call peer. */ private ImageIcon peerImage; /** The name of the peer. */ private String peerName; /** The label containing the user photo. */ private final JLabel photoLabel; /** Sound remote level label. */ private Component remoteLevel; /** * The <tt>Component</tt> which {@link #updateViewFromModelInEventDispatchThread()} last added to * {@link #center} as the visual <tt>Component</tt> displaying the video streaming from the remote * peer(s) to the local peer/user. * * <p><b>Warning</b>: It is not to be used for any other purposes because it may not represent the * current state of the model of this view. */ private Component remoteVideo; /** Current id for security image. */ private ImageID securityImageID = ImageLoader.SECURE_BUTTON_OFF; /** The panel containing security related components. */ private SecurityPanel<?> securityPanel; /** The security status of the peer */ private final SecurityStatusLabel securityStatusLabel = new SecurityStatusLabel(); /** The status bar component. */ private final Component statusBar; /** The facility which aids this instance in the dealing with the video-related information. */ private final UIVideoHandler2 uiVideoHandler; /** * The <tt>Observer</tt> which listens to changes in the video-related information detected and * reported by {@link #uiVideoHandler}. */ private final Observer uiVideoHandlerObserver = new Observer() { public void update(Observable o, Object arg) { updateViewFromModel(); } }; /** * The <tt>Runnable</tt> which is scheduled by {@link #updateViewFromModel()} for execution in the * AWT event dispatching thread in order to invoke {@link * #updateViewFromModelInEventDispatchThread()}. */ private final Runnable updateViewFromModelInEventDispatchThread = new Runnable() { public void run() { /* * We receive events/notifications from various threads and we * respond to them in the AWT event dispatching thread. It is * possible to first schedule an event to be brought to the AWT * event dispatching thread, then to have #dispose() invoked on * this instance and, finally, to receive the scheduled event in * the AWT event dispatching thread. In such a case, this * disposed instance should not respond to the event. */ if (!disposed) updateViewFromModelInEventDispatchThread(); } }; /** * Creates a <tt>CallPeerPanel</tt> for the given call peer. * * @param callRenderer the renderer of the call * @param callPeer the <tt>CallPeer</tt> represented in this panel * @param uiVideoHandler the facility which is to aid the new instance in the dealing with the * video-related information */ public OneToOneCallPeerPanel( SwingCallRenderer callRenderer, CallPeer callPeer, UIVideoHandler2 uiVideoHandler) { this.callRenderer = callRenderer; this.callPeer = callPeer; // we need to obtain call as soon as possible // cause if it fails too quickly we may fail to show it this.call = callPeer.getCall(); this.uiVideoHandler = uiVideoHandler; peerName = CallManager.getPeerDisplayName(callPeer); securityPanel = SecurityPanel.create(this, callPeer, null); photoLabel = new JLabel(getPhotoLabelIcon()); center = createCenter(); statusBar = createStatusBar(); setPeerImage(CallManager.getPeerImage(callPeer)); /* Lay out the main Components of the UI. */ setLayout(new GridBagLayout()); GridBagConstraints cnstrnts = new GridBagConstraints(); if (center != null) { cnstrnts.fill = GridBagConstraints.BOTH; cnstrnts.gridx = 0; cnstrnts.gridy = 1; cnstrnts.weightx = 1; cnstrnts.weighty = 1; add(center, cnstrnts); } if (statusBar != null) { cnstrnts.fill = GridBagConstraints.NONE; cnstrnts.gridx = 0; cnstrnts.gridy = 3; cnstrnts.weightx = 0; cnstrnts.weighty = 0; cnstrnts.insets = new Insets(5, 0, 0, 0); add(statusBar, cnstrnts); } createSoundLevelIndicators(); initSecuritySettings(); /* * Add the listeners which will be notified about changes in the model * and which will update this view. */ callPeerAdapter = new CallPeerAdapter(callPeer, this); uiVideoHandler.addObserver(uiVideoHandlerObserver); /* * This view adapts to whether it is displayed in full-screen or * windowed mode. */ if (callRenderer instanceof Component) { ((Component) callRenderer).addPropertyChangeListener(CallContainer.PROP_FULL_SCREEN, this); } OperationSetDesktopSharingClient desktopSharingClient = callPeer.getProtocolProvider().getOperationSet(OperationSetDesktopSharingClient.class); if (desktopSharingClient != null) { desktopSharingMouseAndKeyboardListener = new DesktopSharingMouseAndKeyboardListener(callPeer, desktopSharingClient); } else desktopSharingMouseAndKeyboardListener = null; updateViewFromModel(); } /** * Creates the <tt>Component</tt> hierarchy of the central area of this <tt>CallPeerPanel</tt> * which displays the photo of the <tt>CallPeer</tt> or the video if any. */ private VideoContainer createCenter() { photoLabel.setPreferredSize(new Dimension(90, 90)); return createVideoContainer(photoLabel); } /** Creates sound level related components. */ private void createSoundLevelIndicators() { TransparentPanel localLevelPanel = new TransparentPanel(new BorderLayout(5, 0)); TransparentPanel remoteLevelPanel = new TransparentPanel(new BorderLayout(5, 0)); localLevel = new InputVolumeControlButton( call, ImageLoader.MICROPHONE, ImageLoader.MUTE_BUTTON, false, false); remoteLevel = new OutputVolumeControlButton(call.getConference(), ImageLoader.HEADPHONE, false, false) .getComponent(); final SoundLevelIndicator localLevelIndicator = new SoundLevelIndicator(SoundLevelChangeEvent.MIN_LEVEL, SoundLevelChangeEvent.MAX_LEVEL); final SoundLevelIndicator remoteLevelIndicator = new SoundLevelIndicator(SoundLevelChangeEvent.MIN_LEVEL, SoundLevelChangeEvent.MAX_LEVEL); localLevelPanel.add(localLevel, BorderLayout.WEST); localLevelPanel.add(localLevelIndicator, BorderLayout.CENTER); remoteLevelPanel.add(remoteLevel, BorderLayout.WEST); remoteLevelPanel.add(remoteLevelIndicator, BorderLayout.CENTER); GridBagConstraints constraints = new GridBagConstraints(); constraints.fill = GridBagConstraints.NONE; constraints.gridx = 0; constraints.gridy = 5; constraints.weightx = 0; constraints.weighty = 0; constraints.insets = new Insets(10, 0, 0, 0); add(localLevelPanel, constraints); constraints.fill = GridBagConstraints.NONE; constraints.gridx = 0; constraints.gridy = 6; constraints.weightx = 0; constraints.weighty = 0; constraints.insets = new Insets(5, 0, 10, 0); add(remoteLevelPanel, constraints); if (!GuiActivator.getConfigurationService() .getBoolean( "net.java.sip.communicator.impl.gui.main.call." + "DISABLE_SOUND_LEVEL_INDICATORS", false)) { callPeer.addStreamSoundLevelListener( new SoundLevelListener() { public void soundLevelChanged(Object source, int level) { remoteLevelIndicator.updateSoundLevel(level); } }); /* * By the time the UI gets to be initialized, the callPeer may have * been removed from its Call. As far as the UI is concerned, the * callPeer will never have a Call again and there will be no audio * levels to display anyway so there is no point in throwing a * NullPointerException here. */ if (call != null) { call.addLocalUserSoundLevelListener( new SoundLevelListener() { public void soundLevelChanged(Object source, int level) { localLevelIndicator.updateSoundLevel(level); } }); } } } /** * Creates the <tt>Component</tt> hierarchy of the area of status-related information such as * <tt>CallPeer</tt> display name, call duration, security status. * * @return the root of the <tt>Component</tt> hierarchy of the area of status-related information * such as <tt>CallPeer</tt> display name, call duration, security status */ private Component createStatusBar() { // stateLabel callStatusLabel.setForeground(Color.WHITE); dtmfLabel.setForeground(Color.WHITE); callStatusLabel.setText(callPeer.getState().getLocalizedStateString()); PeerStatusPanel statusPanel = new PeerStatusPanel(new GridBagLayout()); GridBagConstraints constraints = new GridBagConstraints(); constraints.gridx = 0; constraints.gridy = 0; statusPanel.add(securityStatusLabel, constraints); initSecurityStatusLabel(); constraints.gridx++; statusPanel.add(holdStatusLabel, constraints); constraints.gridx++; statusPanel.add(muteStatusLabel, constraints); constraints.gridx++; callStatusLabel.setBorder(BorderFactory.createEmptyBorder(2, 3, 2, 12)); statusPanel.add(callStatusLabel, constraints); constraints.gridx++; constraints.weightx = 1f; statusPanel.add(dtmfLabel, constraints); return statusPanel; } /** * Creates a new AWT <tt>Container</tt> which can display a single <tt>Component</tt> at a time * (supposedly, one which represents video) and, in the absence of such a <tt>Component</tt>, * displays a predefined default <tt>Component</tt> (in accord with the previous supposition, one * which is the default when there is no video). The returned <tt>Container</tt> will track the * <tt>Components</tt>s added to and removed from it in order to make sure that * <tt>noVideoContainer</tt> is displayed as described. * * @param noVideoComponent the predefined default <tt>Component</tt> to be displayed in the * returned <tt>Container</tt> when there is no other <tt>Component</tt> in it * @return a new <tt>Container</tt> which can display a single <tt>Component</tt> at a time and, * in the absence of such a <tt>Component</tt>, displays <tt>noVideoComponent</tt> */ private VideoContainer createVideoContainer(Component noVideoComponent) { Container oldParent = noVideoComponent.getParent(); if (oldParent != null) oldParent.remove(noVideoComponent); return new VideoContainer(noVideoComponent, false); } /** * Releases the resources acquired by this instance which require explicit disposal (e.g. any * listeners added to the depicted <tt>CallPeer</tt>. Invoked by <tt>OneToOneCallPanel</tt> when * it determines that this <tt>OneToOneCallPeerPanel</tt> is no longer necessary. */ public void dispose() { disposed = true; callPeerAdapter.dispose(); uiVideoHandler.deleteObserver(uiVideoHandlerObserver); if (callRenderer instanceof Component) { ((Component) callRenderer).removePropertyChangeListener(CallContainer.PROP_FULL_SCREEN, this); } } /** * Returns the parent <tt>CallPanel</tt> containing this renderer. * * @return the parent <tt>CallPanel</tt> containing this renderer */ public CallPanel getCallPanel() { return callRenderer.getCallContainer(); } /** * Returns the parent call renderer. * * @return the parent call renderer */ public CallRenderer getCallRenderer() { return callRenderer; } /** * Returns the component associated with this renderer. * * @return the component associated with this renderer */ public Component getComponent() { return this; } /** * Returns the name of the peer, contained in this panel. * * @return the name of the peer, contained in this panel */ public String getPeerName() { return peerName; } /** * Gets the <tt>Icon</tt> to be displayed in {@link #photoLabel}. * * @return the <tt>Icon</tt> to be displayed in {@link #photoLabel} */ private ImageIcon getPhotoLabelIcon() { return (peerImage == null) ? new ImageIcon(ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO)) : peerImage; } /** Initializes the security settings for this call peer. */ private void initSecuritySettings() { CallPeerSecurityStatusEvent securityEvent = callPeer.getCurrentSecuritySettings(); if (securityEvent instanceof CallPeerSecurityOnEvent) securityOn((CallPeerSecurityOnEvent) securityEvent); } /** Initializes the security status label, shown in the call status bar. */ private void initSecurityStatusLabel() { securityStatusLabel.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5)); securityStatusLabel.addMouseListener( new MouseAdapter() { /** Invoked when a mouse button has been pressed on a component. */ @Override public void mousePressed(MouseEvent e) { // Only show the security details if the security is on. SrtpControl ctrl = securityPanel.getSecurityControl(); if (ctrl instanceof ZrtpControl && ctrl.getSecureCommunicationStatus()) { setSecurityPanelVisible( !callRenderer .getCallContainer() .getCallWindow() .getFrame() .getGlassPane() .isVisible()); } } }); } /** * Determines whether the visual <tt>Component</tt> depicting the video streaming from the local * peer/user to the remote peer(s) is currently visible. * * @return <tt>true</tt> if the visual <tt>Component</tt> depicting the video streaming from the * local peer/user to the remote peer(s) is currently visible; otherwise, <tt>false</tt> */ public boolean isLocalVideoVisible() { return uiVideoHandler.isLocalVideoVisible(); } /** Reloads all icons. */ public void loadSkin() { if (localLevel != null) localLevel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.MICROPHONE))); if (remoteLevel != null && remoteLevel instanceof Skinnable) ((Skinnable) remoteLevel).loadSkin(); if (muteStatusLabel.getIcon() != null) muteStatusLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.MUTE_STATUS_ICON))); if (holdStatusLabel.getIcon() != null) holdStatusLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.HOLD_STATUS_ICON))); securityStatusLabel.setIcon(new ImageIcon(ImageLoader.getImage(securityImageID))); if (peerImage == null) { photoLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO))); } } /** * Prints the given DTMG character through this <tt>CallPeerRenderer</tt>. * * @param dtmfChar the DTMF char to print */ public void printDTMFTone(char dtmfChar) { dtmfLabel.setText(dtmfLabel.getText() + dtmfChar); if (dtmfLabel.getBorder() == null) dtmfLabel.setBorder(BorderFactory.createEmptyBorder(2, 1, 2, 5)); } /** * Notifies this instance about a change in the value of a property of a source which of interest * to this instance. For example, <tt>OneToOneCallPeerPanel</tt> updates its user * interface-related properties upon changes in the value of the {@link * CallContainer#PROP_FULL_SCREEN} property of its associated {@link #callRenderer}. * * @param ev a <tt>PropertyChangeEvent</tt> which identifies the source, the name of the property * and the old and new values */ public void propertyChange(PropertyChangeEvent ev) { if (CallContainer.PROP_FULL_SCREEN.equals(ev.getPropertyName())) updateViewFromModel(); } /** * Re-dispatches glass pane mouse events only in case they occur on the security panel. * * @param glassPane the glass pane * @param e the mouse event in question */ private void redispatchMouseEvent(Component glassPane, MouseEvent e) { Point glassPanePoint = e.getPoint(); Point securityPanelPoint = SwingUtilities.convertPoint(glassPane, glassPanePoint, securityPanel); Component component; Point componentPoint; if (securityPanelPoint.y > 0) { component = securityPanel; componentPoint = securityPanelPoint; } else { Container contentPane = callRenderer.getCallContainer().getCallWindow().getFrame().getContentPane(); Point containerPoint = SwingUtilities.convertPoint(glassPane, glassPanePoint, contentPane); component = SwingUtilities.getDeepestComponentAt(contentPane, containerPoint.x, containerPoint.y); componentPoint = SwingUtilities.convertPoint(contentPane, glassPanePoint, component); } if (component != null) component.dispatchEvent( new MouseEvent( component, e.getID(), e.getWhen(), e.getModifiers(), componentPoint.x, componentPoint.y, e.getClickCount(), e.isPopupTrigger())); e.consume(); } /** * The handler for the security event received. The security event for starting establish a secure * connection. * * @param evt the security started event received */ public void securityNegotiationStarted(CallPeerSecurityNegotiationStartedEvent evt) { if (Boolean.parseBoolean( GuiActivator.getResources().getSettingsString("impl.gui.PARANOIA_UI"))) { SrtpControl srtpControl = null; if (callPeer instanceof MediaAwareCallPeer) srtpControl = evt.getSecurityController(); securityPanel = new ParanoiaTimerSecurityPanel<SrtpControl>(srtpControl); setSecurityPanelVisible(true); } } /** * Indicates that the security has gone off. * * @param evt the <tt>CallPeerSecurityOffEvent</tt> that notified us */ public void securityOff(final CallPeerSecurityOffEvent evt) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater( new Runnable() { public void run() { securityOff(evt); } }); return; } if (evt.getSessionType() == CallPeerSecurityOffEvent.AUDIO_SESSION) { securityStatusLabel.setText(""); securityStatusLabel.setSecurityOff(); if (securityStatusLabel.getBorder() == null) securityStatusLabel.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 3)); } securityPanel.securityOff(evt); } /** * Indicates that the security is turned on. * * <p>Sets the secured status icon to the status panel and initializes/updates the corresponding * security details. * * @param evt Details about the event that caused this message. */ public void securityOn(final CallPeerSecurityOnEvent evt) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater( new Runnable() { public void run() { securityOn(evt); } }); return; } // If the securityOn is called without a specific event, we'll just set // the security label status to on. if (evt == null) { securityStatusLabel.setSecurityOn(); return; } SrtpControl srtpControl = evt.getSecurityController(); if (!srtpControl.requiresSecureSignalingTransport() || callPeer.getProtocolProvider().isSignalingTransportSecure()) { if (srtpControl instanceof ZrtpControl) { securityStatusLabel.setText("zrtp"); if (!((ZrtpControl) srtpControl).isSecurityVerified()) securityStatusLabel.setSecurityPending(); else securityStatusLabel.setSecurityOn(); } else securityStatusLabel.setSecurityOn(); } // if we have some other panel, using other control if (!srtpControl.getClass().isInstance(securityPanel.getSecurityControl()) || (securityPanel instanceof ParanoiaTimerSecurityPanel)) { setSecurityPanelVisible(false); securityPanel = SecurityPanel.create(this, callPeer, srtpControl); if (srtpControl instanceof ZrtpControl) ((ZrtpSecurityPanel) securityPanel).setSecurityStatusLabel(securityStatusLabel); } securityPanel.securityOn(evt); boolean isSecurityLowPriority = Boolean.parseBoolean( GuiActivator.getResources() .getSettingsString("impl.gui.I_DONT_CARE_THAT_MUCH_ABOUT_SECURITY")); // Display ZRTP panel in case SAS was not verified or a AOR mismtach // was detected during creation of ZrtpSecurityPanel. // Don't show panel if user does not care about security at all. if (srtpControl instanceof ZrtpControl && !isSecurityLowPriority && (!((ZrtpControl) srtpControl).isSecurityVerified() || ((ZrtpSecurityPanel) securityPanel).isZidAorMismatch())) { setSecurityPanelVisible(true); } this.revalidate(); } /** Indicates that the security status is pending confirmation. */ public void securityPending() { securityStatusLabel.setSecurityPending(); } /** * Indicates that the security is timeouted, is not supported by the other end. * * @param evt Details about the event that caused this message. */ public void securityTimeout(final CallPeerSecurityTimeoutEvent evt) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater( new Runnable() { public void run() { securityTimeout(evt); } }); return; } if (securityPanel != null) securityPanel.securityTimeout(evt); } /** * Sets the reason of a call failure if one occurs. The renderer should display this reason to the * user. * * @param reason the reason to display */ public void setErrorReason(final String reason) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater( new Runnable() { public void run() { setErrorReason(reason); } }); return; } if (errorMessageComponent == null) { errorMessageComponent = new JTextPane(); JTextPane textPane = (JTextPane) errorMessageComponent; textPane.setEditable(false); textPane.setOpaque(false); StyledDocument doc = textPane.getStyledDocument(); MutableAttributeSet standard = new SimpleAttributeSet(); StyleConstants.setAlignment(standard, StyleConstants.ALIGN_CENTER); StyleConstants.setFontFamily(standard, textPane.getFont().getFamily()); StyleConstants.setFontSize(standard, 12); doc.setParagraphAttributes(0, 0, standard, true); GridBagConstraints constraints = new GridBagConstraints(); constraints.fill = GridBagConstraints.HORIZONTAL; constraints.gridx = 0; constraints.gridy = 4; constraints.weightx = 1; constraints.weighty = 0; constraints.insets = new Insets(5, 0, 0, 0); add(errorMessageComponent, constraints); this.revalidate(); } errorMessageComponent.setText(reason); if (isVisible()) errorMessageComponent.repaint(); } /** * Shows/hides the visual <tt>Component</tt> depicting the video streaming from the local * peer/user to the remote peer(s). * * @param visible <tt>true</tt> to show the visual <tt>Component</tt> depicting the video * streaming from the local peer/user to the remote peer(s); <tt>false</tt>, otherwise */ public void setLocalVideoVisible(boolean visible) { uiVideoHandler.setLocalVideoVisible(visible); } /** * Sets the mute status icon to the status panel. * * @param isMute indicates if the call with this peer is muted */ public void setMute(final boolean isMute) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater( new Runnable() { public void run() { setMute(isMute); } }); return; } if (isMute) { muteStatusLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.MUTE_STATUS_ICON))); muteStatusLabel.setBorder(BorderFactory.createEmptyBorder(2, 3, 2, 3)); } else { muteStatusLabel.setIcon(null); muteStatusLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); } // Update input volume control button state to reflect the current // mute status. if (localLevel.isSelected() != isMute) localLevel.setSelected(isMute); this.revalidate(); this.repaint(); } /** * Sets the "on hold" property value. * * @param isOnHold indicates if the call with this peer is put on hold */ public void setOnHold(final boolean isOnHold) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater( new Runnable() { public void run() { setOnHold(isOnHold); } }); return; } if (isOnHold) { holdStatusLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.HOLD_STATUS_ICON))); holdStatusLabel.setBorder(BorderFactory.createEmptyBorder(2, 3, 2, 3)); } else { holdStatusLabel.setIcon(null); holdStatusLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); } this.revalidate(); this.repaint(); } /** * Set the image of the peer * * @param image new image */ public void setPeerImage(byte[] image) { // If the image is still null we try to obtain it from one of the // available contact sources. if (image == null || image.length <= 0) { GuiActivator.getContactList().setSourceContactImage(peerName, photoLabel, 100, 100); } else { peerImage = ImageUtils.getScaledRoundedIcon(image, 100, 100); if (peerImage == null) peerImage = getPhotoLabelIcon(); if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater( new Runnable() { public void run() { photoLabel.setIcon(peerImage); photoLabel.repaint(); } }); } else { photoLabel.setIcon(peerImage); photoLabel.repaint(); } } } /** * Sets the name of the peer. * * @param name the name of the peer */ public void setPeerName(final String name) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater( new Runnable() { public void run() { setPeerName(name); } }); return; } peerName = name; ((OneToOneCallPanel) callRenderer).setPeerName(name); } /** * Sets the state of the contained call peer by specifying the state name. * * @param oldState the previous state of the peer * @param newState the new state of the peer * @param stateString the state of the contained call peer */ public void setPeerState( final CallPeerState oldState, final CallPeerState newState, final String stateString) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater( new Runnable() { public void run() { setPeerState(oldState, newState, stateString); } }); return; } this.callStatusLabel.setText(stateString); if (newState == CallPeerState.CONNECTED && !CallPeerState.isOnHold(oldState) && !securityStatusLabel.isSecurityStatusSet()) { securityStatusLabel.setSecurityOff(); } } /** * Shows/hides the security panel. * * @param isVisible <tt>true</tt> to show the security panel, <tt>false</tt> to hide it */ public void setSecurityPanelVisible(final boolean isVisible) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater( new Runnable() { public void run() { setSecurityPanelVisible(isVisible); } }); return; } final JFrame callFrame = callRenderer.getCallContainer().getCallWindow().getFrame(); final JPanel glassPane = (JPanel) callFrame.getGlassPane(); if (!isVisible) { // Need to hide the security panel explicitly in order to keep the // fade effect. securityPanel.setVisible(false); glassPane.setVisible(false); glassPane.removeAll(); } else { glassPane.setLayout(null); glassPane.addMouseListener( new MouseListener() { public void mouseClicked(MouseEvent e) { redispatchMouseEvent(glassPane, e); } public void mouseEntered(MouseEvent e) { redispatchMouseEvent(glassPane, e); } public void mouseExited(MouseEvent e) { redispatchMouseEvent(glassPane, e); } public void mousePressed(MouseEvent e) { redispatchMouseEvent(glassPane, e); } public void mouseReleased(MouseEvent e) { redispatchMouseEvent(glassPane, e); } }); Point securityLabelPoint = securityStatusLabel.getLocation(); Point newPoint = SwingUtilities.convertPoint( securityStatusLabel.getParent(), securityLabelPoint.x, securityLabelPoint.y, callFrame); securityPanel.setBeginPoint(new Point((int) newPoint.getX() + 15, 0)); securityPanel.setBounds(0, (int) newPoint.getY() - 5, this.getWidth(), 130); glassPane.add(securityPanel); // Need to show the security panel explicitly in order to keep the // fade effect. securityPanel.setVisible(true); glassPane.setVisible(true); glassPane.addComponentListener( new ComponentAdapter() { /** Invoked when the component's size changes. */ @Override public void componentResized(ComponentEvent e) { if (glassPane.isVisible()) { glassPane.setVisible(false); callFrame.removeComponentListener(this); } } }); } } /** * Updates this view i.e. <tt>OneToOneCallPeerPanel</tt> so that it depicts the current state of * its model i.e. <tt>callPeer</tt>. */ private void updateViewFromModel() { /* * We receive events/notifications from various threads and we respond * to them in the AWT event dispatching thread. It is possible to first * schedule an event to be brought to the AWT event dispatching thread, * then to have #dispose() invoked on this instance and, finally, to * receive the scheduled event in the AWT event dispatching thread. In * such a case, this disposed instance should not respond to the event * because it may, for example, steal a visual Components depicting * video (which cannot belong to more than one parent at a time) from * another non-disposed OneToOneCallPeerPanel. */ if (!disposed) { if (SwingUtilities.isEventDispatchThread()) updateViewFromModelInEventDispatchThread(); else { SwingUtilities.invokeLater(updateViewFromModelInEventDispatchThread); } } } /** * Updates this view i.e. <tt>OneToOneCallPeerPanel</tt> so that it depicts the current state of * its model i.e. <tt>callPeer</tt>. The update is performed in the AWT event dispatching thread. */ private void updateViewFromModelInEventDispatchThread() { /* * We receive events/notifications from various threads and we respond * to them in the AWT event dispatching thread. It is possible to first * schedule an event to be brought to the AWT event dispatching thread, * then to have #dispose() invoked on this instance and, finally, to * receive the scheduled event in the AWT event dispatching thread. In * such a case, this disposed instance should not respond to the event * because it may, for example, steal a visual Components depicting * video (which cannot belong to more than one parent at a time) from * another non-disposed OneToOneCallPeerPanel. */ if (disposed) return; /* * Update the display of visual <tt>Component</tt>s depicting video * streaming between the local peer/user and the remote peer(s). */ OperationSetVideoTelephony videoTelephony = callPeer.getProtocolProvider().getOperationSet(OperationSetVideoTelephony.class); Component remoteVideo = null; Component localVideo = null; if (videoTelephony != null) { List<Component> remoteVideos = videoTelephony.getVisualComponents(callPeer); if ((remoteVideos != null) && !remoteVideos.isEmpty()) { /* * TODO OneToOneCallPeerPanel displays a one-to-one conversation * between the local peer/user and a specific remote peer. If * the remote peer is the focus of a telephony conference of its * own, it may be sending multiple videos to the local peer. * Switching to a user interface which displays multiple videos * is the responsibility of whoever decided that this * OneToOneCallPeerPanel is to be used to depict the current * state of the CallConference associated with the CallPeer * depicted by this instance. If that switching decides that * this instance is to continue being the user interface, then * we should probably pick up the remote video which is * generated by the remote peer and not one of its * ConferenceMembers. */ remoteVideo = remoteVideos.get(0); } if (uiVideoHandler.isLocalVideoVisible()) { try { localVideo = videoTelephony.getLocalVisualComponent(callPeer); } catch (OperationFailedException ofe) { /* * Well, we cannot do much about the exception. We'll just * not display the local video. */ logger.warn("Failed to retrieve local video to be displayed.", ofe); } } /* * Determine whether there is actually a change in the local and * remote videos which requires an update. */ boolean localVideoChanged = ((localVideo != this.localVideo) || ((localVideo != null) && !UIVideoHandler2.isAncestor(center, localVideo))); boolean remoteVideoChanged = ((remoteVideo != this.remoteVideo) || ((remoteVideo != null) && !UIVideoHandler2.isAncestor(center, remoteVideo))); // If the remote video has changed, maybe the CallPanel can display // the LO/SD/HD button. if (remoteVideoChanged) { // Updates video component which may listen the mouse and key // events. if (desktopSharingMouseAndKeyboardListener != null) { desktopSharingMouseAndKeyboardListener.setVideoComponent(remoteVideo); } CallPanel callPanel = callRenderer.getCallContainer(); // The remote video has been added, then tries to display the // LO/SD/HD button. if (remoteVideo != null) { callPanel.addRemoteVideoSpecificComponents(callPeer); } // The remote video has been removed, then hide the LO/SD/HD // button if it is currently displayed. else { callPanel.removeRemoteVideoSpecificComponents(); } } if (localVideoChanged || remoteVideoChanged) { /* * VideoContainer and JAWTRenderer cannot handle random * additions of Components. Removing the localVideo when the * user has requests its hiding though, should work without * removing all Components from the VideoCotainer and adding * them again. */ if (localVideoChanged && !remoteVideoChanged && (localVideo == null)) { if (this.localVideo != null) { center.remove(this.localVideo); this.localVideo = null; if (closeLocalVisualComponentButton != null) center.remove(closeLocalVisualComponentButton); } } else { center.removeAll(); this.localVideo = null; this.remoteVideo = null; /* * AWT does not make a guarantee about the Z order even * within an operating system i.e. the order of adding the * Components to their Container does not mean that they * will be determinedly painted in that or reverse order. * Anyway, there appears to be an expectation among the * developers less acquainted with AWT that AWT paints the * Components of a Container in an order that is the reverse * of the order of their adding. In order to satisfy that * expectation and thus give at least some idea to the * developers reading the code bellow, do add the Components * according to that expectation. */ if (localVideo != null) { if (closeLocalVisualComponentButton == null) { closeLocalVisualComponentButton = new CloseLocalVisualComponentButton(uiVideoHandler); } center.add(closeLocalVisualComponentButton, VideoLayout.CLOSE_LOCAL_BUTTON, -1); center.add(localVideo, VideoLayout.LOCAL, -1); this.localVideo = localVideo; } if (remoteVideo != null) { center.add(remoteVideo, VideoLayout.CENTER_REMOTE, -1); this.remoteVideo = remoteVideo; } } } } } /** The <tt>TransparentPanel</tt> that will display the peer status. */ private static class PeerStatusPanel extends TransparentPanel { /** * Silence the serial warning. Though there isn't a plan to serialize the instances of the * class, there're no fields so the default serialization routine will work. */ private static final long serialVersionUID = 0L; /** * Constructs a new <tt>PeerStatusPanel</tt>. * * @param layout the <tt>LayoutManager</tt> to use */ public PeerStatusPanel(LayoutManager layout) { super(layout); } /** @{inheritDoc} */ @Override public void paintComponent(Graphics g) { super.paintComponent(g); g = g.create(); try { AntialiasingManager.activateAntialiasing(g); g.setColor(Color.DARK_GRAY); g.fillRoundRect(0, 0, this.getWidth(), this.getHeight(), 10, 10); } finally { g.dispose(); } } } }
/** * The <tt>NewStatusMessageDialog</tt> is the dialog containing the form for changing the status * message for a protocol provider. * * @author Yana Stamcheva * @author Adam Netocny */ public class NewStatusMessageDialog extends SIPCommDialog implements ActionListener, Skinnable { /** The Object used for logging. */ private final Logger logger = Logger.getLogger(NewStatusMessageDialog.class); /** The field, containing the status message. */ private final JTextField messageTextField = new JTextField(); /** The button, used to cancel this dialog. */ private final JButton cancelButton = new JButton(GuiActivator.getResources().getI18NString("service.gui.CANCEL")); /** The presence operation set through which we change the status message. */ private final OperationSetPresence presenceOpSet; /** Message panel. */ private JPanel messagePanel; /** * Creates an instance of <tt>NewStatusMessageDialog</tt>. * * @param protocolProvider the <tt>ProtocolProviderService</tt>. */ public NewStatusMessageDialog(ProtocolProviderService protocolProvider) { presenceOpSet = (OperationSetPersistentPresence) protocolProvider.getOperationSet(OperationSetPresence.class); this.init(); pack(); } /** Initializes the <tt>NewStatusMessageDialog</tt> by adding the buttons, fields, etc. */ private void init() { JLabel messageLabel = new JLabel(GuiActivator.getResources().getI18NString("service.gui.NEW_STATUS_MESSAGE")); JPanel dataPanel = new TransparentPanel(new BorderLayout(5, 5)); JTextArea infoArea = new JTextArea(GuiActivator.getResources().getI18NString("service.gui.STATUS_MESSAGE_INFO")); JLabel infoTitleLabel = new JLabel(GuiActivator.getResources().getI18NString("service.gui.NEW_STATUS_MESSAGE")); JPanel labelsPanel = new TransparentPanel(new GridLayout(0, 1)); JButton okButton = new JButton(GuiActivator.getResources().getI18NString("service.gui.OK")); JPanel buttonsPanel = new TransparentPanel(new FlowLayout(FlowLayout.RIGHT)); this.setTitle(GuiActivator.getResources().getI18NString("service.gui.NEW_STATUS_MESSAGE")); this.getRootPane().setDefaultButton(okButton); this.setPreferredSize(new Dimension(500, 200)); infoArea.setEditable(false); infoArea.setLineWrap(true); infoArea.setWrapStyleWord(true); infoArea.setOpaque(false); dataPanel.add(messageLabel, BorderLayout.WEST); messageTextField.setText(presenceOpSet.getCurrentStatusMessage()); dataPanel.add(messageTextField, BorderLayout.CENTER); infoTitleLabel.setHorizontalAlignment(JLabel.CENTER); infoTitleLabel.setFont(infoTitleLabel.getFont().deriveFont(Font.BOLD, 18.0f)); labelsPanel.add(infoTitleLabel); labelsPanel.add(infoArea); labelsPanel.add(dataPanel); messagePanel = new TransparentPanel(new GridBagLayout()); GridBagConstraints messagePanelConstraints = new GridBagConstraints(); messagePanelConstraints.anchor = GridBagConstraints.NORTHWEST; messagePanelConstraints.fill = GridBagConstraints.NONE; messagePanelConstraints.gridx = 0; messagePanelConstraints.gridy = 0; messagePanelConstraints.insets = new Insets(5, 0, 5, 10); messagePanelConstraints.weightx = 0; messagePanelConstraints.weighty = 0; messagePanel.add( new ImageCanvas(ImageLoader.getImage(ImageLoader.RENAME_DIALOG_ICON)), messagePanelConstraints); messagePanelConstraints.anchor = GridBagConstraints.NORTH; messagePanelConstraints.fill = GridBagConstraints.HORIZONTAL; messagePanelConstraints.gridx = 1; messagePanelConstraints.insets = new Insets(0, 0, 0, 0); messagePanelConstraints.weightx = 1; messagePanel.add(labelsPanel, messagePanelConstraints); okButton.setName("ok"); cancelButton.setName("cancel"); okButton.setMnemonic(GuiActivator.getResources().getI18nMnemonic("service.gui.OK")); cancelButton.setMnemonic(GuiActivator.getResources().getI18nMnemonic("service.gui.CANCEL")); okButton.addActionListener(this); cancelButton.addActionListener(this); buttonsPanel.add(okButton); buttonsPanel.add(cancelButton); JPanel mainPanel = new TransparentPanel(new GridBagLayout()); mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 10, 0, 10)); GridBagConstraints mainPanelConstraints = new GridBagConstraints(); mainPanelConstraints.anchor = GridBagConstraints.NORTH; mainPanelConstraints.fill = GridBagConstraints.BOTH; mainPanelConstraints.gridx = 0; mainPanelConstraints.gridy = 0; mainPanelConstraints.weightx = 1; mainPanelConstraints.weighty = 1; mainPanel.add(messagePanel, mainPanelConstraints); mainPanelConstraints.anchor = GridBagConstraints.SOUTHEAST; mainPanelConstraints.fill = GridBagConstraints.NONE; mainPanelConstraints.gridy = 1; mainPanelConstraints.weightx = 0; mainPanelConstraints.weighty = 0; mainPanel.add(buttonsPanel, mainPanelConstraints); this.getContentPane().add(mainPanel); } /** * Handles the <tt>ActionEvent</tt>. In order to change the status message with the new one calls * the <tt>PublishStatusMessageThread</tt>. * * @param e the event that notified us of the action */ public void actionPerformed(ActionEvent e) { JButton button = (JButton) e.getSource(); String name = button.getName(); if (name.equals("ok")) { new PublishStatusMessageThread(messageTextField.getText()).start(); } this.dispose(); } /** Requests the focus in the text field contained in this dialog. */ public void requestFocusInField() { this.messageTextField.requestFocus(); } /** This class allow to use a thread to change the presence status message. */ private class PublishStatusMessageThread extends Thread { private String message; private PresenceStatus currentStatus; public PublishStatusMessageThread(String message) { this.message = message; this.currentStatus = presenceOpSet.getPresenceStatus(); } public void run() { try { presenceOpSet.publishPresenceStatus(currentStatus, message); } catch (IllegalArgumentException e1) { logger.error("Error - changing status", e1); } catch (IllegalStateException e1) { logger.error("Error - changing status", e1); } catch (OperationFailedException e1) { if (e1.getErrorCode() == OperationFailedException.GENERAL_ERROR) { logger.error("General error occured while " + "publishing presence status.", e1); } else if (e1.getErrorCode() == OperationFailedException.NETWORK_FAILURE) { logger.error("Network failure occured while " + "publishing presence status.", e1); } else if (e1.getErrorCode() == OperationFailedException.PROVIDER_NOT_REGISTERED) { logger.error("Protocol provider must be" + "registered in order to change status.", e1); } } } } /** * Artificially clicks the cancel button when this panel is escaped. * * @param isEscaped indicates if this dialog is closed by the Esc shortcut */ protected void close(boolean isEscaped) { if (isEscaped) cancelButton.doClick(); } /** Reloads icon. */ public void loadSkin() { if (messagePanel != null) { for (Component component : messagePanel.getComponents()) { if (component instanceof ImageCanvas) { ImageCanvas cmp = (ImageCanvas) component; cmp.setImage(ImageLoader.getImage(ImageLoader.RENAME_DIALOG_ICON)); } } } } }
/** * The <tt>GibberishAccountRegistrationWizard</tt> is an implementation of the * <tt>AccountRegistrationWizard</tt> for the Gibberish protocol. It allows the user to create and * configure a new Gibberish account. * * @author Emil Ivov */ public class GibberishAccountRegistrationWizard extends DesktopAccountRegistrationWizard { private final Logger logger = Logger.getLogger(GibberishAccountRegistrationWizard.class); /** The first page of the gibberish account registration wizard. */ private FirstWizardPage firstWizardPage; /** The object that we use to store details on an account that we will be creating. */ private GibberishAccountRegistration registration = new GibberishAccountRegistration(); private ProtocolProviderService protocolProvider; /** * Creates an instance of <tt>GibberishAccountRegistrationWizard</tt>. * * @param wizardContainer the wizard container, where this wizard is added */ public GibberishAccountRegistrationWizard(WizardContainer wizardContainer) { setWizardContainer(wizardContainer); wizardContainer.setFinishButtonText(Resources.getString("service.gui.SIGN_IN")); } /** * Implements the <code>AccountRegistrationWizard.getIcon</code> method. Returns the icon to be * used for this wizard. * * @return byte[] */ public byte[] getIcon() { return Resources.getImage(Resources.GIBBERISH_LOGO); } /** * Implements the <code>AccountRegistrationWizard.getPageImage</code> method. Returns the image * used to decorate the wizard page * * @return byte[] the image used to decorate the wizard page */ public byte[] getPageImage() { return Resources.getImage(Resources.PAGE_IMAGE); } /** * Implements the <code>AccountRegistrationWizard.getProtocolName</code> method. Returns the * protocol name for this wizard. * * @return String */ public String getProtocolName() { return Resources.getString("plugin.gibberishaccregwizz.PROTOCOL_NAME"); } /** * Implements the <code>AccountRegistrationWizard.getProtocolDescription * </code> method. Returns the description of the protocol for this wizard. * * @return String */ public String getProtocolDescription() { return Resources.getString("plugin.gibberishaccregwizz.PROTOCOL_DESCRIPTION"); } /** * Returns the set of pages contained in this wizard. * * @return Iterator */ public Iterator<WizardPage> getPages() { java.util.List<WizardPage> pages = new ArrayList<WizardPage>(); firstWizardPage = new FirstWizardPage(this); pages.add(firstWizardPage); return pages.iterator(); } /** * Returns the set of data that user has entered through this wizard. * * @return Iterator */ public Iterator<Map.Entry<String, String>> getSummary() { Map<String, String> summaryTable = new Hashtable<String, String>(); summaryTable.put("User ID", registration.getUserID()); return summaryTable.entrySet().iterator(); } /** * Defines the operations that will be executed when the user clicks on the wizard "Signin" * button. * * @return the created <tt>ProtocolProviderService</tt> corresponding to the new account * @throws OperationFailedException if the operation didn't succeed */ public ProtocolProviderService signin() throws OperationFailedException { firstWizardPage.commitPage(); return signin(registration.getUserID(), null); } /** * Defines the operations that will be executed when the user clicks on the wizard "Signin" * button. * * @param userName the user name to sign in with * @param password the password to sign in with * @return the created <tt>ProtocolProviderService</tt> corresponding to the new account * @throws OperationFailedException if the operation didn't succeed */ public ProtocolProviderService signin(String userName, String password) throws OperationFailedException { ProtocolProviderFactory factory = GibberishAccRegWizzActivator.getGibberishProtocolProviderFactory(); return this.installAccount(factory, userName); } /** * Creates an account for the given user and password. * * @param providerFactory the ProtocolProviderFactory which will create the account * @param user the user identifier * @return the <tt>ProtocolProviderService</tt> for the new account. */ public ProtocolProviderService installAccount( ProtocolProviderFactory providerFactory, String user) throws OperationFailedException { Hashtable<String, String> accountProperties = new Hashtable<String, String>(); accountProperties.put( ProtocolProviderFactory.ACCOUNT_ICON_PATH, "resources/images/protocol/gibberish/gibberish32x32.png"); if (registration.isRememberPassword()) { accountProperties.put(ProtocolProviderFactory.PASSWORD, registration.getPassword()); } if (isModification()) { providerFactory.uninstallAccount(protocolProvider.getAccountID()); this.protocolProvider = null; setModification(false); } try { AccountID accountID = providerFactory.installAccount(user, accountProperties); ServiceReference serRef = providerFactory.getProviderForAccount(accountID); protocolProvider = (ProtocolProviderService) GibberishAccRegWizzActivator.bundleContext.getService(serRef); } catch (IllegalStateException exc) { logger.warn(exc.getMessage()); throw new OperationFailedException( "Account already exists.", OperationFailedException.IDENTIFICATION_CONFLICT); } catch (Exception exc) { logger.warn(exc.getMessage()); throw new OperationFailedException( "Failed to add account", OperationFailedException.GENERAL_ERROR); } return protocolProvider; } /** * Fills the UserID and Password fields in this panel with the data comming from the given * protocolProvider. * * @param protocolProvider The <tt>ProtocolProviderService</tt> to load the data from. */ public void loadAccount(ProtocolProviderService protocolProvider) { setModification(true); this.protocolProvider = protocolProvider; this.registration = new GibberishAccountRegistration(); this.firstWizardPage.loadAccount(protocolProvider); } /** * Returns the registration object, which will store all the data through the wizard. * * @return the registration object, which will store all the data through the wizard */ public GibberishAccountRegistration getRegistration() { return registration; } /** * Returns the size of this wizard. * * @return the size of this wizard */ public Dimension getSize() { return new Dimension(600, 500); } /** * Returns the identifier of the page to show first in the wizard. * * @return the identifier of the page to show first in the wizard. */ public Object getFirstPageIdentifier() { return firstWizardPage.getIdentifier(); } /** * Returns the identifier of the page to show last in the wizard. * * @return the identifier of the page to show last in the wizard. */ public Object getLastPageIdentifier() { return firstWizardPage.getIdentifier(); } /** * Returns an example string, which should indicate to the user how the user name should look * like. * * @return an example string, which should indicate to the user how the user name should look * like. */ public String getUserNameExample() { return FirstWizardPage.USER_NAME_EXAMPLE; } /** * Indicates whether this wizard enables the simple "sign in" form shown when the user opens the * application for the first time. The simple "sign in" form allows user to configure her account * in one click, just specifying her username and password and leaving any other configuration as * by default. * * @return <code>true</code> if the simple "Sign in" form is enabled or <code>false</code> * otherwise. */ public boolean isSimpleFormEnabled() { return false; } /** * Returns a simple account registration form that would be the first form shown to the user. Only * if the user needs more settings she'll choose to open the advanced wizard, consisted by all * pages. * * @param isCreateAccount indicates if the simple form should be opened as a create account form * or as a login form * @return a simple account registration form */ public Object getSimpleForm(boolean isCreateAccount) { firstWizardPage = new FirstWizardPage(this); return firstWizardPage.getSimpleForm(); } }
/** * 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() {} }
/** * A meta-class to handle all logging and input-related console improvements. Portions are heavily * based on CraftBukkit. */ public final class ConsoleManager { private static final String CONSOLE_DATE = "HH:mm:ss"; private static final String FILE_DATE = "yyyy/MM/dd HH:mm:ss"; private static final Logger logger = Logger.getLogger(""); private final GlowServer server; private ConsoleReader reader; private ConsoleCommandSender sender; private ConsoleHandler consoleHandler; private JFrame jFrame = null; private JTerminal jTerminal = null; private JTextField jInput = null; private boolean running = true; private boolean jLine = false; public ConsoleManager(GlowServer server) { this.server = server; // install Ansi code handler, which makes colors work on Windows AnsiConsole.systemInstall(); for (Handler h : logger.getHandlers()) { logger.removeHandler(h); } // used until/unless gui is created consoleHandler = new FancyConsoleHandler(); // consoleHandler.setFormatter(new DateOutputFormatter(CONSOLE_DATE)); logger.addHandler(consoleHandler); // todo: why is this here? Runtime.getRuntime().addShutdownHook(new ServerShutdownThread()); // reader must be initialized before standard streams are changed try { reader = new ConsoleReader(); } catch (IOException ex) { logger.log(Level.SEVERE, "Exception initializing console reader", ex); } reader.addCompleter(new CommandCompleter()); // set system output streams System.setOut(new PrintStream(new LoggerOutputStream(Level.INFO), true)); System.setErr(new PrintStream(new LoggerOutputStream(Level.WARNING), true)); } public ConsoleCommandSender getSender() { return sender; } public void startGui() { JTerminalListener listener = new JTerminalListener(); jFrame = new JFrame("Glowstone"); jTerminal = new JTerminal(); jInput = new JTextField(80) { @Override public void setBorder(Border border) {} }; jInput.paint(null); jInput.setFont(new Font("Monospaced", Font.PLAIN, 12)); jInput.setBackground(Color.BLACK); jInput.setForeground(Color.WHITE); jInput.setMargin(new Insets(0, 0, 0, 0)); jInput.addKeyListener(listener); JLabel caret = new JLabel("> "); caret.setFont(new Font("Monospaced", Font.PLAIN, 12)); caret.setForeground(Color.WHITE); JPanel ipanel = new JPanel(); ipanel.add(caret, BorderLayout.WEST); ipanel.add(jInput, BorderLayout.EAST); ipanel.setBorder(BorderFactory.createEmptyBorder()); ipanel.setBackground(Color.BLACK); ipanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); ipanel.setSize(jTerminal.getWidth(), ipanel.getHeight()); jFrame.getContentPane().add(jTerminal, BorderLayout.NORTH); jFrame.getContentPane().add(ipanel, BorderLayout.SOUTH); jFrame.addWindowListener(listener); jFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); jFrame.setLocationRelativeTo(null); jFrame.pack(); jFrame.setVisible(true); sender = new ColoredCommandSender(); logger.removeHandler(consoleHandler); logger.addHandler( new StreamHandler(new TerminalOutputStream(), new DateOutputFormatter(CONSOLE_DATE))); } public void startConsole(boolean jLine) { this.jLine = jLine; sender = new ColoredCommandSender(); Thread thread = new ConsoleCommandThread(); thread.setName("ConsoleCommandThread"); thread.setDaemon(true); thread.start(); /*logger.removeHandler(consoleHandler); consoleHandler = new FancyConsoleHandler(); consoleHandler.setFormatter(new DateOutputFormatter(CONSOLE_DATE)); logger.addHandler(consoleHandler);*/ } public void startFile(String logfile) { File parent = new File(logfile).getParentFile(); if (!parent.isDirectory() && !parent.mkdirs()) { logger.warning("Could not create log folder: " + parent); } Handler fileHandler = new RotatingFileHandler(logfile); fileHandler.setFormatter(new DateOutputFormatter(FILE_DATE)); logger.addHandler(fileHandler); } public void stop() { running = false; for (Handler handler : logger.getHandlers()) { handler.flush(); handler.close(); } if (jFrame != null) { jFrame.dispose(); } } private String colorize(String string) { if (string.indexOf(ChatColor.COLOR_CHAR) < 0) { return string; // no colors in the message } else if ((!jLine || !reader.getTerminal().isAnsiSupported()) && jTerminal == null) { return ChatColor.stripColor(string); // color not supported } else { return string .replace(ChatColor.RED.toString(), "\033[1;31m") .replace(ChatColor.YELLOW.toString(), "\033[1;33m") .replace(ChatColor.GREEN.toString(), "\033[1;32m") .replace(ChatColor.AQUA.toString(), "\033[1;36m") .replace(ChatColor.BLUE.toString(), "\033[1;34m") .replace(ChatColor.LIGHT_PURPLE.toString(), "\033[1;35m") .replace(ChatColor.BLACK.toString(), "\033[0;0m") .replace(ChatColor.DARK_GRAY.toString(), "\033[1;30m") .replace(ChatColor.DARK_RED.toString(), "\033[0;31m") .replace(ChatColor.GOLD.toString(), "\033[0;33m") .replace(ChatColor.DARK_GREEN.toString(), "\033[0;32m") .replace(ChatColor.DARK_AQUA.toString(), "\033[0;36m") .replace(ChatColor.DARK_BLUE.toString(), "\033[0;34m") .replace(ChatColor.DARK_PURPLE.toString(), "\033[0;35m") .replace(ChatColor.GRAY.toString(), "\033[0;37m") .replace(ChatColor.WHITE.toString(), "\033[1;37m") + "\033[0m"; } } private class CommandCompleter implements Completer { public int complete(final String buffer, int cursor, List<CharSequence> candidates) { try { List<String> completions = server .getScheduler() .syncIfNeeded( new Callable<List<String>>() { public List<String> call() throws Exception { return server.getCommandMap().tabComplete(sender, buffer); } }); if (completions == null) { return cursor; // no completions } candidates.addAll(completions); // location to position the cursor at (before autofilling takes place) return buffer.lastIndexOf(' ') + 1; } catch (Throwable t) { logger.log(Level.WARNING, "Error while tab completing", t); return cursor; } } } private class ConsoleCommandThread extends Thread { @Override public void run() { String command = ""; while (running) { try { if (jLine) { command = reader.readLine(">", null); } else { command = reader.readLine(); } if (command == null || command.trim().length() == 0) continue; server.getScheduler().runTask(null, new CommandTask(command.trim())); } catch (CommandException ex) { logger.log(Level.WARNING, "Exception while executing command: " + command, ex); } catch (Exception ex) { logger.log(Level.SEVERE, "Error while reading commands", ex); } } } } private class ServerShutdownThread extends Thread { @Override public void run() { server.shutdown(); } } private class CommandTask implements Runnable { private final String command; public CommandTask(String command) { this.command = command; } public void run() { server.dispatchCommand(sender, EventFactory.onServerCommand(sender, command).getCommand()); } } private class ColoredCommandSender implements ConsoleCommandSender { private final PermissibleBase perm = new PermissibleBase(this); //////////////////////////////////////////////////////////////////////// // CommandSender public String getName() { return "CONSOLE"; } public void sendMessage(String text) { server.getLogger().info(text); } public void sendMessage(String[] strings) { for (String line : strings) { sendMessage(line); } } public GlowServer getServer() { return server; } public boolean isOp() { return true; } public void setOp(boolean value) { throw new UnsupportedOperationException("Cannot change operator status of server console"); } //////////////////////////////////////////////////////////////////////// // Permissible public boolean isPermissionSet(String name) { return perm.isPermissionSet(name); } public boolean isPermissionSet(Permission perm) { return this.perm.isPermissionSet(perm); } public boolean hasPermission(String name) { return perm.hasPermission(name); } public boolean hasPermission(Permission perm) { return this.perm.hasPermission(perm); } public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) { return perm.addAttachment(plugin, name, value); } public PermissionAttachment addAttachment(Plugin plugin) { return perm.addAttachment(plugin); } public PermissionAttachment addAttachment( Plugin plugin, String name, boolean value, int ticks) { return perm.addAttachment(plugin, name, value, ticks); } public PermissionAttachment addAttachment(Plugin plugin, int ticks) { return perm.addAttachment(plugin, ticks); } public void removeAttachment(PermissionAttachment attachment) { perm.removeAttachment(attachment); } public void recalculatePermissions() { perm.recalculatePermissions(); } public Set<PermissionAttachmentInfo> getEffectivePermissions() { return perm.getEffectivePermissions(); } //////////////////////////////////////////////////////////////////////// // Conversable @Override public boolean isConversing() { return false; } @Override public void acceptConversationInput(String input) {} @Override public boolean beginConversation(Conversation conversation) { return false; } @Override public void abandonConversation(Conversation conversation) {} @Override public void abandonConversation( Conversation conversation, ConversationAbandonedEvent details) {} @Override public void sendRawMessage(String message) {} } private static class LoggerOutputStream extends ByteArrayOutputStream { private final String separator = System.getProperty("line.separator"); private final Level level; public LoggerOutputStream(Level level) { super(); this.level = level; } @Override public synchronized void flush() throws IOException { super.flush(); String record = this.toString(); super.reset(); if (record.length() > 0 && !record.equals(separator)) { logger.logp(level, "LoggerOutputStream", "log" + level, record); } } } private class FancyConsoleHandler extends ConsoleHandler { public FancyConsoleHandler() { setFormatter(new DateOutputFormatter(CONSOLE_DATE)); setOutputStream(System.out); } @Override public synchronized void flush() { try { if (jLine) { reader.print(ConsoleReader.RESET_LINE + ""); reader.flush(); super.flush(); try { reader.drawLine(); } catch (Throwable ex) { reader.getCursorBuffer().clear(); } reader.flush(); } else { super.flush(); } } catch (IOException ex) { logger.log(Level.SEVERE, "I/O exception flushing console output", ex); } } } private static class RotatingFileHandler extends StreamHandler { private final SimpleDateFormat dateFormat; private final String template; private final boolean rotate; private String filename; public RotatingFileHandler(String template) { this.template = template; rotate = template.contains("%D"); dateFormat = new SimpleDateFormat("yyyy-MM-dd"); filename = calculateFilename(); updateOutput(); } private void updateOutput() { try { setOutputStream(new FileOutputStream(filename, true)); } catch (IOException ex) { logger.log(Level.SEVERE, "Unable to open " + filename + " for writing", ex); } } private String calculateFilename() { return template.replace("%D", dateFormat.format(new Date())); } @Override public synchronized void publish(LogRecord record) { if (!isLoggable(record)) { return; } super.publish(record); flush(); } @Override public synchronized void flush() { if (rotate) { String newFilename = calculateFilename(); if (!filename.equals(newFilename)) { filename = newFilename; logger.log(Level.INFO, "Log rotating to {0}...", filename); updateOutput(); } } super.flush(); } } private class DateOutputFormatter extends Formatter { private final SimpleDateFormat date; public DateOutputFormatter(String pattern) { this.date = new SimpleDateFormat(pattern); } @Override @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public String format(LogRecord record) { StringBuilder builder = new StringBuilder(); builder.append(date.format(record.getMillis())); builder.append(" ["); builder.append(record.getLevel().getLocalizedName().toUpperCase()); builder.append("] "); builder.append(colorize(formatMessage(record))); builder.append('\n'); if (record.getThrown() != null) { StringWriter writer = new StringWriter(); record.getThrown().printStackTrace(new PrintWriter(writer)); builder.append(writer.toString()); } return builder.toString(); } } private class JTerminalListener implements WindowListener, KeyListener { public void windowOpened(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} public void windowClosed(WindowEvent e) {} public void keyPressed(KeyEvent e) {} public void keyReleased(KeyEvent e) {} public void windowClosing(WindowEvent e) { server.shutdown(); } public void keyTyped(KeyEvent e) { if (e.getKeyChar() == '\n') { String command = jInput.getText().trim(); if (command.length() > 0) { server.getScheduler().scheduleSyncDelayedTask(null, new CommandTask(command)); } jInput.setText(""); } } } private class TerminalOutputStream extends ByteArrayOutputStream { private final String separator = System.getProperty("line.separator"); @Override public synchronized void flush() throws IOException { super.flush(); String record = this.toString(); super.reset(); if (record.length() > 0 && !record.equals(separator)) { jTerminal.print(record); jFrame.repaint(); } } } }
/** * 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); } } } } }
@SuppressWarnings("serial") public class HelpBrowserFrame extends JFrame { private static final Logger logger = Logger.getLogger(HelpBrowserFrame.class.getName()); boolean plugin; HelpBrowser browser; private void Init() throws Exception { // ------------------------------------------------------------------------ // Configure objects // ------------------------------------------------------------------------ this.setTitle("Frost - Help Browser"); this.setResizable(true); browser.setPreferredSize(new Dimension(780, 550)); this.getContentPane().add(browser); } @Override protected void processWindowEvent(final WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) { if (!plugin) { dispose(); System.exit(0); } else { saveWindowState(); setVisible(false); } } else { super.processWindowEvent(e); } } /** Shorthand for ziphelp usage */ public HelpBrowserFrame(final String langlocale, final String zipfile) { this(langlocale, "jar:file:" + zipfile + "!/", "index.html", true); } /** Complete for browser usage */ public HelpBrowserFrame( final String langlocale, final String zipfile, final String startpage, boolean plugin) { this.plugin = plugin; this.browser = new HelpBrowser(this, langlocale, zipfile, startpage); setIconImage(MiscToolkit.loadImageIcon("/data/toolbar/help-browser.png").getImage()); enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { Init(); if (!plugin) { // standalone - fix size this.setSize(new Dimension(780, 550)); } else { loadWindowState(); } } catch (final Throwable e) { logger.log(Level.SEVERE, "Exception thrown in constructor", e); } } public void showHelpPage(final String page) { browser.setHelpPage(page); } public void showHelpPage_htmlLink(final String page) { browser.setHelpPage(page); } public void showHelpPage_alias(final String page) { browser.setHelpPage(page); } private void saveWindowState() { final Rectangle bounds = getBounds(); boolean isMaximized = ((getExtendedState() & Frame.MAXIMIZED_BOTH) != 0); Core.frostSettings.setValue("helpBrowser.lastFrameMaximized", isMaximized); if (!isMaximized) { // Only save the current dimension if frame is not maximized Core.frostSettings.setValue("helpBrowser.lastFrameHeight", bounds.height); Core.frostSettings.setValue("helpBrowser.lastFrameWidth", bounds.width); Core.frostSettings.setValue("helpBrowser.lastFramePosX", bounds.x); Core.frostSettings.setValue("helpBrowser.lastFramePosY", bounds.y); } } private void loadWindowState() { // load size, location and state of window int lastHeight = Core.frostSettings.getIntValue("helpBrowser.lastFrameHeight"); int lastWidth = Core.frostSettings.getIntValue("helpBrowser.lastFrameWidth"); final int lastPosX = Core.frostSettings.getIntValue("helpBrowser.lastFramePosX"); final int lastPosY = Core.frostSettings.getIntValue("helpBrowser.lastFramePosY"); final boolean lastMaximized = Core.frostSettings.getBoolValue("helpBrowser.lastFrameMaximized"); if (lastHeight <= 0 || lastWidth <= 0) { // first call setSize(780, 550); setLocationRelativeTo(MainFrame.getInstance()); return; } final Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize(); if (lastWidth < 100) { lastWidth = 780; } if (lastHeight < 100) { lastHeight = 550; } if ((lastPosX + lastWidth) > scrSize.width) { setSize(780, 550); setLocationRelativeTo(MainFrame.getInstance()); return; } if ((lastPosY + lastHeight) > scrSize.height) { setSize(780, 550); setLocationRelativeTo(MainFrame.getInstance()); return; } setBounds(lastPosX, lastPosY, lastWidth, lastHeight); if (lastMaximized) { setExtendedState(getExtendedState() | Frame.MAXIMIZED_BOTH); } } }
/** * The dialog used as menu. * * @author Damian Minkov */ public class SelectAvatarMenu extends SIPCommPopupMenu implements ActionListener { /** Logger for this class. */ private static final Logger logger = Logger.getLogger(SelectAvatarMenu.class); /** Name of choose button. */ private static final String CHOSE_BUTTON_NAME = "chooseButton"; /** Name of remove button. */ private static final String REMOVE_BUTTON_NAME = "removeButton"; /** Name of clear button. */ private static final String CLEAR_BUTTON_NAME = "clearButton"; /** Images shown as history. */ private static final int MAX_STORED_IMAGES = 8; /** Ordered in columns. */ private static final int IMAGES_PER_COLUMN = 4; /** Thumbnail width. */ private static final int THUMB_WIDTH = 48; /** Thumbnail height. */ private static final int THUMB_HEIGHT = 48; /** Buttons corresponding to images. */ private SIPCommButton recentImagesButtons[] = new SIPCommButton[MAX_STORED_IMAGES]; /** Next free image index number. */ private int nextImageIndex = 0; /** The parent button using us. */ private FramedImageWithMenu avatarImage; /** * Creates the dialog. * * @param avatarImage the button that will trigger this menu. */ public SelectAvatarMenu(FramedImageWithMenu avatarImage) { this.avatarImage = avatarImage; init(); this.pack(); } /** Init visible components. */ private void init() { TransparentPanel panel = new TransparentPanel(new BorderLayout()); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); // Title label JLabel titleLabel = new JLabel(GuiActivator.getResources().getI18NString("service.gui.avatar.RECENT_ICONS")); titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD)); // fix for displaying text in menu // when using a dark OS theme (as default one in ubuntu) titleLabel.setForeground(new JMenuItem().getForeground()); panel.add(titleLabel, BorderLayout.NORTH); // Init recent images grid TransparentPanel recentImagesGrid = new TransparentPanel(); recentImagesGrid.setLayout(new GridLayout(0, IMAGES_PER_COLUMN)); Dimension thumbsize = new Dimension(THUMB_WIDTH, THUMB_HEIGHT); for (int i = 0; i < MAX_STORED_IMAGES; i++) { this.recentImagesButtons[i] = new SIPCommButton(null); this.recentImagesButtons[i].setBorder(BorderFactory.createEtchedBorder()); this.recentImagesButtons[i].setMaximumSize(thumbsize); this.recentImagesButtons[i].setMinimumSize(thumbsize); this.recentImagesButtons[i].setPreferredSize(thumbsize); this.recentImagesButtons[i].addActionListener(this); this.recentImagesButtons[i].setName("" + i); recentImagesGrid.add(this.recentImagesButtons[i]); } panel.add(recentImagesGrid, BorderLayout.CENTER); // Action buttons TransparentPanel buttonsPanel = new TransparentPanel(); buttonsPanel.setLayout(new GridLayout(0, 1)); // we use this menu item just to get its foreground color. Color linkColor = new JMenuItem().getForeground(); addActionButton( buttonsPanel, this, GuiActivator.getResources().getI18NString("service.gui.avatar.CHOOSE_ICON"), CHOSE_BUTTON_NAME, linkColor); addActionButton( buttonsPanel, this, GuiActivator.getResources().getI18NString("service.gui.avatar.REMOVE_ICON"), REMOVE_BUTTON_NAME, linkColor); addActionButton( buttonsPanel, this, GuiActivator.getResources().getI18NString("service.gui.avatar.CLEAR_RECENT"), CLEAR_BUTTON_NAME, linkColor); panel.add(buttonsPanel, BorderLayout.SOUTH); this.setLayout(new BorderLayout()); this.add(panel, BorderLayout.CENTER); } /** * Adds action buttons. * * @param buttonsPanel the panel to add to. * @param listener the listener for actions * @param text the text on the button. * @param name name of the button. * @param linkColor the color of the link. */ private static void addActionButton( TransparentPanel buttonsPanel, ActionListener listener, String text, String name, Color linkColor) { SIPCommLinkButton button = new SIPCommLinkButton(text); button.setName(name); button.addActionListener(listener); button.setOpaque(false); button.setLinkColor(linkColor); TransparentPanel panel = new TransparentPanel(new BorderLayout()); panel.add(button, BorderLayout.WEST); buttonsPanel.add(panel); } @Override public void setVisible(boolean b) { refreshRecentImages(); super.setVisible(b); } /** Refresh images with those stored locally. */ public void refreshRecentImages() { int i; for (i = 0; i < MAX_STORED_IMAGES; i++) { BufferedImage image = AvatarStackManager.loadImage(i); if (image == null) break; this.recentImagesButtons[i].setImage(createThumbnail(image)); this.recentImagesButtons[i].setEnabled(true); } if (i < MAX_STORED_IMAGES) { this.nextImageIndex = i; for (; i < MAX_STORED_IMAGES; i++) { this.recentImagesButtons[i].setImage(null); this.recentImagesButtons[i].setEnabled(false); } } else this.nextImageIndex = MAX_STORED_IMAGES; } /** * Create thumbnail for the image. * * @param image to scale. * @return the thumbnail image. */ private static BufferedImage createThumbnail(BufferedImage image) { int width = image.getWidth(); int height = image.getHeight(); // Image smaller than the thumbnail size if (width < THUMB_WIDTH && height < THUMB_HEIGHT) return image; Image i; if (width > height) i = image.getScaledInstance(THUMB_WIDTH, -1, Image.SCALE_SMOOTH); else i = image.getScaledInstance(-1, THUMB_HEIGHT, Image.SCALE_SMOOTH); return ImageUtils.getBufferedImage(i); } /** * Here is all the action. Stores the selected image into protocols and if needed update it ina * AccountStatusPanel. * * @param image the new image. */ private void setNewImage(final BufferedImage image) { // Use separate thread to be sure we don't block UI thread. new Thread() { public void run() { AccountManager accountManager = GuiActivator.getAccountManager(); for (AccountID accountID : accountManager.getStoredAccounts()) { if (accountManager.isAccountLoaded(accountID)) { ProtocolProviderService protocolProvider = GuiActivator.getRegisteredProviderForAccount(accountID); if (protocolProvider != null && protocolProvider.isRegistered()) { OperationSetAvatar opSetAvatar = protocolProvider.getOperationSet(OperationSetAvatar.class); if (opSetAvatar != null) { byte[] imageByte = null; // Sets new avatar if not null. Otherwise, the // opSetAvatar.setAvatar(null) will removes the // current one. if (image != null) { imageByte = ImageUtils.toByteArray(image); } try { opSetAvatar.setAvatar(imageByte); } catch (Throwable t) { logger.error("Error setting image", t); } } } } } } }.start(); } /** Clear stored images. */ private void clearRecentImages() { for (int i = 0; i < MAX_STORED_IMAGES; i++) { this.recentImagesButtons[i].setImage(null); this.recentImagesButtons[i].setEnabled(false); AvatarStackManager.deleteImage(i); } this.nextImageIndex = 0; } /** * Action performed on various action links(buttons). * * @param e the action. */ public void actionPerformed(ActionEvent e) { JButton src = (JButton) e.getSource(); if (src instanceof SIPCommButton) { // Load image int index = Integer.parseInt(src.getName()); BufferedImage image = AvatarStackManager.loadImage(index); // Set the new image setNewImage(image); } else if (src.getName().equals("chooseButton")) { // Open the image picker Image currentImage = this.avatarImage.getAvatar(); ImagePickerDialog dialog = new ImagePickerDialog(96, 96); byte[] bimage = dialog.showDialog(currentImage); if (bimage == null) return; // New image BufferedImage image = ImageUtils.getBufferedImage(new ImageIcon(bimage).getImage()); // Store image if (this.nextImageIndex == MAX_STORED_IMAGES) { // No more place to store images // Pop the first element (index 0) AvatarStackManager.popFirstImage(MAX_STORED_IMAGES); this.nextImageIndex = MAX_STORED_IMAGES - 1; } // Store the new image on hard drive AvatarStackManager.storeImage(image, this.nextImageIndex); // Inform protocols about the new image setNewImage(image); } else if (src.getName().equals("removeButton")) { // Removes the current photo. setNewImage(null); } else if (src.getName().equals("clearButton")) { clearRecentImages(); } setVisible(false); } }
/** * The <tt>StatusSubMenu</tt> provides a menu which allow to select the status for each of the * protocol providers registered when the menu appears * * @author Nicolas Chamouard */ public class StatusSubMenu extends JMenu { /** A reference of <tt>Systray</tt> */ private SystrayServiceJdicImpl parentSystray; /** Contains all accounts and corresponding menus. */ private Hashtable accountSelectors = new Hashtable(); private Logger logger = Logger.getLogger(StatusSubMenu.class); /** * Creates an instance of <tt>StatusSubMenu</tt>. * * @param tray a reference of the parent <tt>Systray</tt> */ public StatusSubMenu(SystrayServiceJdicImpl tray) { parentSystray = tray; this.setText(Resources.getString("setStatus")); this.setIcon(Resources.getImage("statusMenuIcon")); /* makes the menu look better */ this.setPreferredSize(new java.awt.Dimension(28, 24)); this.init(); } /** * Adds the account corresponding to the given protocol provider to this menu. * * @param protocolProvider the protocol provider corresponding to the account to add */ private void addAccount(ProtocolProviderService protocolProvider) { OperationSetPresence presence = (OperationSetPresence) protocolProvider.getOperationSet(OperationSetPresence.class); if (presence == null) { StatusSimpleSelector simpleSelector = new StatusSimpleSelector(parentSystray, protocolProvider); this.accountSelectors.put(protocolProvider.getAccountID(), simpleSelector); this.add(simpleSelector); } else { StatusSelector statusSelector = new StatusSelector(parentSystray, protocolProvider, presence); this.accountSelectors.put(protocolProvider.getAccountID(), statusSelector); this.add(statusSelector); presence.addProviderPresenceStatusListener(new SystrayProviderPresenceStatusListener()); } } /** * Removes the account corresponding to the given protocol provider from this menu. * * @param protocolProvider the protocol provider corresponding to the account to remove. */ private void removeAccount(ProtocolProviderService protocolProvider) { Component c = (Component) this.accountSelectors.get(protocolProvider.getAccountID()); this.remove(c); } /** * We fill the protocolProviderTable with all running protocol providers at the start of the * bundle. */ private void init() { SystrayActivator.bundleContext.addServiceListener(new ProtocolProviderServiceListener()); ServiceReference[] protocolProviderRefs = null; try { protocolProviderRefs = SystrayActivator.bundleContext.getServiceReferences( ProtocolProviderService.class.getName(), null); } catch (InvalidSyntaxException ex) { // this shouldn't happen since we're providing no parameter string // but let's log just in case. logger.error("Error while retrieving service refs", ex); return; } // in case we found any if (protocolProviderRefs != null) { for (int i = 0; i < protocolProviderRefs.length; i++) { ProtocolProviderService provider = (ProtocolProviderService) SystrayActivator.bundleContext.getService(protocolProviderRefs[i]); boolean isHidden = provider.getAccountID().getAccountProperties().get("HIDDEN_PROTOCOL") != null; if (!isHidden) this.addAccount(provider); } } } /** * Listens for <tt>ServiceEvent</tt>s indicating that a <tt>ProtocolProviderService</tt> has been * registered and completes the account status menu. */ private class ProtocolProviderServiceListener implements ServiceListener { /** * When a service is registered or unregistered, we update the provider tables and add/remove * listeners (if it supports BasicInstantMessenging implementation) * * @param event ServiceEvent */ public void serviceChanged(ServiceEvent event) { // if the event is caused by a bundle being stopped, we don't want to // know if (event.getServiceReference().getBundle().getState() == Bundle.STOPPING) { return; } Object service = SystrayActivator.bundleContext.getService(event.getServiceReference()); if (!(service instanceof ProtocolProviderService)) return; ProtocolProviderService provider = (ProtocolProviderService) service; if (event.getType() == ServiceEvent.REGISTERED) addAccount(provider); if (event.getType() == ServiceEvent.UNREGISTERING) removeAccount(provider); } } /** * Listens for all providerStatusChanged and providerStatusMessageChanged events in order to * refresh the account status panel, when a status is changed. */ private class SystrayProviderPresenceStatusListener implements ProviderPresenceStatusListener { /** Fired when an account has changed its status. We update the icon in the menu. */ public void providerStatusChanged(ProviderPresenceStatusChangeEvent evt) { ProtocolProviderService pps = evt.getProvider(); StatusSelector selectorBox = (StatusSelector) accountSelectors.get(pps.getAccountID()); if (selectorBox == null) return; selectorBox.updateStatus(evt.getNewStatus()); } public void providerStatusMessageChanged(PropertyChangeEvent evt) {} } }
/** warns events */ private void warn(String msg, Throwable t) { Logger.getLogger(getClass().getName()).log(Level.WARNING, msg, t); }
/** 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(); } } }
public class XBaseWindow implements XConstants, XUtilConstants { private static final Logger log = Logger.getLogger("sun.awt.X11.XBaseWindow"); private static final Logger insLog = Logger.getLogger("sun.awt.X11.insets.XBaseWindow"); private static final Logger eventLog = Logger.getLogger("sun.awt.X11.event.XBaseWindow"); private static final Logger focusLog = Logger.getLogger("sun.awt.X11.focus.XBaseWindow"); private static final Logger grabLog = Logger.getLogger("sun.awt.X11.grab.XBaseWindow"); public static final String PARENT_WINDOW = "parent window", // parent window, Long BOUNDS = "bounds", // bounds of the window, Rectangle OVERRIDE_REDIRECT = "overrideRedirect", // override_redirect setting, Boolean EVENT_MASK = "event mask", // event mask, Integer VALUE_MASK = "value mask", // value mask, Long BORDER_PIXEL = "border pixel", // border pixel value, Integer COLORMAP = "color map", // color map, Long DEPTH = "visual depth", // depth, Integer VISUAL_CLASS = "visual class", // visual class, Integer VISUAL = "visual", // visual, Long EMBEDDED = "embedded", // is embedded?, Boolean DELAYED = "delayed", // is creation delayed?, Boolean PARENT = "parent", // parent peer BACKGROUND_PIXMAP = "pixmap", // background pixmap VISIBLE = "visible", // whether it is visible by default SAVE_UNDER = "save under", // save content under this window BACKING_STORE = "backing store", // enables double buffering BIT_GRAVITY = "bit gravity"; // copy old content on geometry change private XCreateWindowParams delayedParams; Set<Long> children = new HashSet<Long>(); long window; boolean visible; boolean mapped; boolean embedded; Rectangle maxBounds; volatile XBaseWindow parentWindow; private boolean disposed; private long screen; private XSizeHints hints; private XWMHints wmHints; static final int MIN_SIZE = 1; static final int DEF_LOCATION = 1; private static XAtom wm_client_leader; static enum InitialiseState { INITIALISING, NOT_INITIALISED, INITIALISED, FAILED_INITIALISATION }; private InitialiseState initialising; int x; int y; int width; int height; void awtLock() { XToolkit.awtLock(); } void awtUnlock() { XToolkit.awtUnlock(); } void awtLockNotifyAll() { XToolkit.awtLockNotifyAll(); } void awtLockWait() throws InterruptedException { XToolkit.awtLockWait(); } // To prevent errors from overriding obsolete methods protected final void init(long parentWindow, Rectangle bounds) {} protected final void preInit() {} protected final void postInit() {} // internal lock for synchronizing state changes and paint calls, initialized in preInit. // the order with other locks: AWTLock -> stateLock static class StateLock extends Object {} protected StateLock state_lock; /** Called for delayed inits during construction */ void instantPreInit(XCreateWindowParams params) { state_lock = new StateLock(); initialising = InitialiseState.NOT_INITIALISED; } /** * Called before window creation, descendants should override to initialize the data, initialize * params. */ void preInit(XCreateWindowParams params) { state_lock = new StateLock(); initialising = InitialiseState.NOT_INITIALISED; embedded = Boolean.TRUE.equals(params.get(EMBEDDED)); visible = Boolean.TRUE.equals(params.get(VISIBLE)); Object parent = params.get(PARENT); if (parent instanceof XBaseWindow) { parentWindow = (XBaseWindow) parent; } else { Long parentWindowID = (Long) params.get(PARENT_WINDOW); if (parentWindowID != null) { parentWindow = XToolkit.windowToXWindow(parentWindowID); } } Long eventMask = (Long) params.get(EVENT_MASK); if (eventMask != null) { long mask = eventMask.longValue(); mask |= SubstructureNotifyMask; params.put(EVENT_MASK, mask); } screen = -1; } /** * Called after window creation, descendants should override to initialize Window with * class-specific values and perform post-initialization actions. */ void postInit(XCreateWindowParams params) { if (log.isLoggable(Level.FINE)) log.fine("WM name is " + getWMName()); updateWMName(); // Set WM_CLIENT_LEADER property initClientLeader(); } /** * Creates window using parameters <code>params</code> If params contain flag DELAYED doesn't do * anything. Note: Descendants can call this method to create the window at the time different to * instance construction. */ protected final void init(XCreateWindowParams params) { awtLock(); initialising = InitialiseState.INITIALISING; awtUnlock(); try { if (!Boolean.TRUE.equals(params.get(DELAYED))) { preInit(params); create(params); postInit(params); } else { instantPreInit(params); delayedParams = params; } awtLock(); initialising = InitialiseState.INITIALISED; awtLockNotifyAll(); awtUnlock(); } catch (RuntimeException re) { awtLock(); initialising = InitialiseState.FAILED_INITIALISATION; awtLockNotifyAll(); awtUnlock(); throw re; } catch (Throwable t) { log.log(Level.WARNING, "Exception during peer initialization", t); awtLock(); initialising = InitialiseState.FAILED_INITIALISATION; awtLockNotifyAll(); awtUnlock(); } } public boolean checkInitialised() { awtLock(); try { switch (initialising) { case INITIALISED: return true; case INITIALISING: try { while (initialising != InitialiseState.INITIALISED) { awtLockWait(); } } catch (InterruptedException ie) { return false; } return true; case NOT_INITIALISED: case FAILED_INITIALISATION: return false; default: return false; } } finally { awtUnlock(); } } /* * Creates an invisible InputOnly window without an associated Component. */ XBaseWindow() { this(new XCreateWindowParams()); } /** Creates normal child window */ XBaseWindow(long parentWindow, Rectangle bounds) { this( new XCreateWindowParams( new Object[] {BOUNDS, bounds, PARENT_WINDOW, Long.valueOf(parentWindow)})); } /** Creates top-level window */ XBaseWindow(Rectangle bounds) { this(new XCreateWindowParams(new Object[] {BOUNDS, bounds})); } public XBaseWindow(XCreateWindowParams params) { init(params); } /* This create is used by the XEmbeddedFramePeer since it has to create the window as a child of the netscape window. This netscape window is passed in as wid */ XBaseWindow(long parentWindow) { this( new XCreateWindowParams( new Object[] {PARENT_WINDOW, Long.valueOf(parentWindow), EMBEDDED, Boolean.TRUE})); } /** * Verifies that all required parameters are set. If not, sets them to default values. Verifies * values of critical parameters, adjust their values when needed. * * @throws IllegalArgumentException if params is null */ protected void checkParams(XCreateWindowParams params) { if (params == null) { throw new IllegalArgumentException("Window creation parameters are null"); } params.putIfNull(PARENT_WINDOW, Long.valueOf(XToolkit.getDefaultRootWindow())); params.putIfNull(BOUNDS, new Rectangle(DEF_LOCATION, DEF_LOCATION, MIN_SIZE, MIN_SIZE)); params.putIfNull(DEPTH, Integer.valueOf((int) XlibWrapper.CopyFromParent)); params.putIfNull(VISUAL, Long.valueOf(XlibWrapper.CopyFromParent)); params.putIfNull(VISUAL_CLASS, Integer.valueOf((int) XlibWrapper.InputOnly)); params.putIfNull(VALUE_MASK, Long.valueOf(XlibWrapper.CWEventMask)); Rectangle bounds = (Rectangle) params.get(BOUNDS); bounds.width = Math.max(MIN_SIZE, bounds.width); bounds.height = Math.max(MIN_SIZE, bounds.height); Long eventMaskObj = (Long) params.get(EVENT_MASK); long eventMask = eventMaskObj != null ? eventMaskObj.longValue() : 0; // We use our own synthetic grab see XAwtState.getGrabWindow() // (see X vol. 1, 8.3.3.2) eventMask |= PropertyChangeMask | OwnerGrabButtonMask; params.put(EVENT_MASK, Long.valueOf(eventMask)); } /** * Creates window with parameters specified by <code>params</code> * * @see #init */ private final void create(XCreateWindowParams params) { XToolkit.awtLock(); try { XSetWindowAttributes xattr = new XSetWindowAttributes(); try { checkParams(params); long value_mask = ((Long) params.get(VALUE_MASK)).longValue(); Long eventMask = (Long) params.get(EVENT_MASK); xattr.set_event_mask(eventMask.longValue()); value_mask |= XlibWrapper.CWEventMask; Long border_pixel = (Long) params.get(BORDER_PIXEL); if (border_pixel != null) { xattr.set_border_pixel(border_pixel.longValue()); value_mask |= XlibWrapper.CWBorderPixel; } Long colormap = (Long) params.get(COLORMAP); if (colormap != null) { xattr.set_colormap(colormap.longValue()); value_mask |= XlibWrapper.CWColormap; } Long background_pixmap = (Long) params.get(BACKGROUND_PIXMAP); if (background_pixmap != null) { xattr.set_background_pixmap(background_pixmap.longValue()); value_mask |= XlibWrapper.CWBackPixmap; } Long parentWindow = (Long) params.get(PARENT_WINDOW); Rectangle bounds = (Rectangle) params.get(BOUNDS); Integer depth = (Integer) params.get(DEPTH); Integer visual_class = (Integer) params.get(VISUAL_CLASS); Long visual = (Long) params.get(VISUAL); Boolean overrideRedirect = (Boolean) params.get(OVERRIDE_REDIRECT); if (overrideRedirect != null) { xattr.set_override_redirect(overrideRedirect.booleanValue()); value_mask |= XlibWrapper.CWOverrideRedirect; } Boolean saveUnder = (Boolean) params.get(SAVE_UNDER); if (saveUnder != null) { xattr.set_save_under(saveUnder.booleanValue()); value_mask |= XlibWrapper.CWSaveUnder; } Integer backingStore = (Integer) params.get(BACKING_STORE); if (backingStore != null) { xattr.set_backing_store(backingStore.intValue()); value_mask |= XlibWrapper.CWBackingStore; } Integer bitGravity = (Integer) params.get(BIT_GRAVITY); if (bitGravity != null) { xattr.set_bit_gravity(bitGravity.intValue()); value_mask |= XlibWrapper.CWBitGravity; } if (log.isLoggable(Level.FINE)) { log.fine("Creating window for " + this + " with the following attributes: \n" + params); } window = XlibWrapper.XCreateWindow( XToolkit.getDisplay(), parentWindow.longValue(), bounds.x, bounds.y, // location bounds.width, bounds.height, // size 0, // border depth.intValue(), // depth visual_class.intValue(), // class visual.longValue(), // visual value_mask, // value mask xattr.pData); // attributes if (window == 0) { throw new IllegalStateException( "Couldn't create window because of wrong parameters. Run with NOISY_AWT to see details"); } XToolkit.addToWinMap(window, this); } finally { xattr.dispose(); } } finally { XToolkit.awtUnlock(); } } public XCreateWindowParams getDelayedParams() { return delayedParams; } protected String getWMName() { return XToolkit.getCorrectXIDString(getClass().getName()); } protected void initClientLeader() { XToolkit.awtLock(); try { if (wm_client_leader == null) { wm_client_leader = XAtom.get("WM_CLIENT_LEADER"); } wm_client_leader.setWindowProperty(this, getXAWTRootWindow()); } finally { XToolkit.awtUnlock(); } } static XRootWindow getXAWTRootWindow() { return XRootWindow.getInstance(); } void destroy() { XToolkit.awtLock(); try { if (hints != null) { XlibWrapper.XFree(hints.pData); hints = null; } XToolkit.removeFromWinMap(getWindow(), this); XlibWrapper.XDestroyWindow(XToolkit.getDisplay(), getWindow()); if (XPropertyCache.isCachingSupported()) { XPropertyCache.clearCache(window); } window = -1; if (!isDisposed()) { setDisposed(true); } XAwtState .getGrabWindow(); // Magic - getGrabWindow clear state if grabbing window is disposed of. } finally { XToolkit.awtUnlock(); } } void flush() { XToolkit.awtLock(); try { XlibWrapper.XFlush(XToolkit.getDisplay()); } finally { XToolkit.awtUnlock(); } } /** Helper function to set W */ public final void setWMHints(XWMHints hints) { XToolkit.awtLock(); try { XlibWrapper.XSetWMHints(XToolkit.getDisplay(), getWindow(), hints.pData); } finally { XToolkit.awtUnlock(); } } public XWMHints getWMHints() { if (wmHints == null) { wmHints = new XWMHints(XlibWrapper.XAllocWMHints()); // XlibWrapper.XGetWMHints(XToolkit.getDisplay(), // getWindow(), // wmHints.pData); } return wmHints; } /* * Call this method under AWTLock. * The lock should be acquired untill all operations with XSizeHints are completed. */ public XSizeHints getHints() { if (hints == null) { long p_hints = XlibWrapper.XAllocSizeHints(); hints = new XSizeHints(p_hints); // XlibWrapper.XGetWMNormalHints(XToolkit.getDisplay(), getWindow(), p_hints, // XlibWrapper.larg1); // TODO: Shouldn't we listen for WM updates on this property? } return hints; } public void setSizeHints(long flags, int x, int y, int width, int height) { if (insLog.isLoggable(Level.FINER)) insLog.finer("Setting hints, flags " + XlibWrapper.hintsToString(flags)); XToolkit.awtLock(); try { XSizeHints hints = getHints(); // Note: if PPosition is not set in flags this means that // we want to reset PPosition in hints. This is necessary // for locationByPlatform functionality if ((flags & XlibWrapper.PPosition) != 0) { hints.set_x(x); hints.set_y(y); } if ((flags & XlibWrapper.PSize) != 0) { hints.set_width(width); hints.set_height(height); } else if ((hints.get_flags() & XlibWrapper.PSize) != 0) { flags |= XlibWrapper.PSize; } if ((flags & XlibWrapper.PMinSize) != 0) { hints.set_min_width(width); hints.set_min_height(height); } else if ((hints.get_flags() & XlibWrapper.PMinSize) != 0) { flags |= XlibWrapper.PMinSize; // Fix for 4320050: Minimum size for java.awt.Frame is not being enforced. // We don't need to reset minimum size if it's already set } if ((flags & XlibWrapper.PMaxSize) != 0) { if (maxBounds != null) { if (maxBounds.width != Integer.MAX_VALUE) { hints.set_max_width(maxBounds.width); } else { hints.set_max_width(XToolkit.getDefaultScreenWidth()); } if (maxBounds.height != Integer.MAX_VALUE) { hints.set_max_height(maxBounds.height); } else { hints.set_max_height(XToolkit.getDefaultScreenHeight()); } } else { hints.set_max_width(width); hints.set_max_height(height); } } else if ((hints.get_flags() & XlibWrapper.PMaxSize) != 0) { flags |= XlibWrapper.PMaxSize; if (maxBounds != null) { if (maxBounds.width != Integer.MAX_VALUE) { hints.set_max_width(maxBounds.width); } else { hints.set_max_width(XToolkit.getDefaultScreenWidth()); } if (maxBounds.height != Integer.MAX_VALUE) { hints.set_max_height(maxBounds.height); } else { hints.set_max_height(XToolkit.getDefaultScreenHeight()); } } else { // Leave intact } } flags |= XlibWrapper.PWinGravity; hints.set_flags(flags); hints.set_win_gravity((int) XlibWrapper.NorthWestGravity); if (insLog.isLoggable(Level.FINER)) insLog.finer( "Setting hints, resulted flags " + XlibWrapper.hintsToString(flags) + ", values " + hints); XlibWrapper.XSetWMNormalHints(XToolkit.getDisplay(), getWindow(), hints.pData); } finally { XToolkit.awtUnlock(); } } public boolean isMinSizeSet() { XSizeHints hints = getHints(); long flags = hints.get_flags(); return ((flags & XlibWrapper.PMinSize) == XlibWrapper.PMinSize); } /** * This lock object can be used to protect instance data from concurrent access by two threads. If * both state lock and AWT lock are taken, AWT Lock should be taken first. */ Object getStateLock() { return state_lock; } public long getWindow() { return window; } public long getContentWindow() { return window; } public XBaseWindow getContentXWindow() { return XToolkit.windowToXWindow(getContentWindow()); } public Rectangle getBounds() { return new Rectangle(x, y, width, height); } public Dimension getSize() { return new Dimension(width, height); } public void toFront() { XToolkit.awtLock(); try { XlibWrapper.XRaiseWindow(XToolkit.getDisplay(), getWindow()); } finally { XToolkit.awtUnlock(); } } public void xRequestFocus(long time) { XToolkit.awtLock(); try { if (focusLog.isLoggable(Level.FINER)) focusLog.finer("XSetInputFocus on " + Long.toHexString(getWindow()) + " with time " + time); XlibWrapper.XSetInputFocus2(XToolkit.getDisplay(), getWindow(), time); } finally { XToolkit.awtUnlock(); } } public void xRequestFocus() { XToolkit.awtLock(); try { if (focusLog.isLoggable(Level.FINER)) focusLog.finer("XSetInputFocus on " + Long.toHexString(getWindow())); XlibWrapper.XSetInputFocus(XToolkit.getDisplay(), getWindow()); } finally { XToolkit.awtUnlock(); } } public static long xGetInputFocus() { XToolkit.awtLock(); try { return XlibWrapper.XGetInputFocus(XToolkit.getDisplay()); } finally { XToolkit.awtUnlock(); } } public void xSetVisible(boolean visible) { if (log.isLoggable(Level.FINE)) log.fine("Setting visible on " + this + " to " + visible); XToolkit.awtLock(); try { this.visible = visible; if (visible) { XlibWrapper.XMapWindow(XToolkit.getDisplay(), getWindow()); } else { XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), getWindow()); } XlibWrapper.XFlush(XToolkit.getDisplay()); } finally { XToolkit.awtUnlock(); } } boolean isMapped() { return mapped; } void updateWMName() { String name = getWMName(); XToolkit.awtLock(); try { if (name == null) { name = " "; } XAtom nameAtom = XAtom.get(XAtom.XA_WM_NAME); nameAtom.setProperty(getWindow(), name); XAtom netNameAtom = XAtom.get("_NET_WM_NAME"); netNameAtom.setPropertyUTF8(getWindow(), name); } finally { XToolkit.awtUnlock(); } } void setWMClass(String[] cl) { if (cl.length != 2) { throw new IllegalArgumentException("WM_CLASS_NAME consists of exactly two strings"); } XToolkit.awtLock(); try { XAtom xa = XAtom.get(XAtom.XA_WM_CLASS); xa.setProperty8(getWindow(), cl[0] + '\0' + cl[1]); } finally { XToolkit.awtUnlock(); } } boolean isVisible() { return visible; } static long getScreenOfWindow(long window) { XToolkit.awtLock(); try { return XlibWrapper.getScreenOfWindow(XToolkit.getDisplay(), window); } finally { XToolkit.awtUnlock(); } } long getScreenNumber() { XToolkit.awtLock(); try { return XlibWrapper.XScreenNumberOfScreen(getScreen()); } finally { XToolkit.awtUnlock(); } } long getScreen() { if (screen == -1) { // Not initialized screen = getScreenOfWindow(window); } return screen; } public void xSetBounds(Rectangle bounds) { xSetBounds(bounds.x, bounds.y, bounds.width, bounds.height); } public void xSetBounds(int x, int y, int width, int height) { if (getWindow() == 0) { insLog.warning("Attempt to resize uncreated window"); throw new IllegalStateException("Attempt to resize uncreated window"); } insLog.fine( "Setting bounds on " + this + " to (" + x + ", " + y + "), " + width + "x" + height); if (width <= 0) { width = 1; } if (height <= 0) { height = 1; } XToolkit.awtLock(); try { XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getWindow(), x, y, width, height); } finally { XToolkit.awtUnlock(); } } /** * Translate coordinates from one window into another. Optimized for XAWT - uses cached data when * possible. Preferable over pure XTranslateCoordinates. * * @return coordinates relative to dst, or null if error happened */ static Point toOtherWindow(long src, long dst, int x, int y) { Point rpt = new Point(0, 0); // Check if both windows belong to XAWT - then no X calls are necessary XBaseWindow srcPeer = XToolkit.windowToXWindow(src); XBaseWindow dstPeer = XToolkit.windowToXWindow(dst); if (srcPeer != null && dstPeer != null) { // (x, y) is relative to src rpt.x = x + srcPeer.getAbsoluteX() - dstPeer.getAbsoluteX(); rpt.y = y + srcPeer.getAbsoluteY() - dstPeer.getAbsoluteY(); } else if (dstPeer != null && XlibUtil.isRoot(src, dstPeer.getScreenNumber())) { // from root into peer rpt.x = x - dstPeer.getAbsoluteX(); rpt.y = y - dstPeer.getAbsoluteY(); } else if (srcPeer != null && XlibUtil.isRoot(dst, srcPeer.getScreenNumber())) { // from peer into root rpt.x = x + srcPeer.getAbsoluteX(); rpt.y = y + srcPeer.getAbsoluteY(); } else { rpt = XlibUtil.translateCoordinates(src, dst, new Point(x, y)); } return rpt; } /* * Convert to global coordinates. */ Rectangle toGlobal(Rectangle rec) { Point p = toGlobal(rec.getLocation()); Rectangle newRec = new Rectangle(rec); if (p != null) { newRec.setLocation(p); } return newRec; } Point toGlobal(Point pt) { Point p = toGlobal(pt.x, pt.y); if (p != null) { return p; } else { return new Point(pt); } } Point toGlobal(int x, int y) { long root; XToolkit.awtLock(); try { root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()); } finally { XToolkit.awtUnlock(); } Point p = toOtherWindow(getContentWindow(), root, x, y); if (p != null) { return p; } else { return new Point(x, y); } } /* * Convert to local coordinates. */ Point toLocal(Point pt) { Point p = toLocal(pt.x, pt.y); if (p != null) { return p; } else { return new Point(pt); } } Point toLocal(int x, int y) { long root; XToolkit.awtLock(); try { root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()); } finally { XToolkit.awtUnlock(); } Point p = toOtherWindow(root, getContentWindow(), x, y); if (p != null) { return p; } else { return new Point(x, y); } } /** * We should always grab both keyboard and pointer to control event flow on popups. This also * simplifies synthetic grab implementation. The active grab overrides activated automatic grab. */ public boolean grabInput() { if (grabLog.isLoggable(Level.FINE)) { grabLog.log(Level.FINE, "Grab input on {0}", new Object[] {String.valueOf(this)}); } XToolkit.awtLock(); try { if (XAwtState.getGrabWindow() == this && XAwtState.isManualGrab()) { grabLog.fine(" Already Grabbed"); return true; } // 6273031: PIT. Choice drop down does not close once it is right clicked to show a popup menu // remember previous window having grab and if it's not null ungrab it. XBaseWindow prevGrabWindow = XAwtState.getGrabWindow(); final int eventMask = (int) (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonMotionMask); final int ownerEvents = 1; int ptrGrab = XlibWrapper.XGrabPointer( XToolkit.getDisplay(), getContentWindow(), ownerEvents, eventMask, GrabModeAsync, GrabModeAsync, None, (XWM.isMotif() ? XToolkit.arrowCursor : None), CurrentTime); // Check grab results to be consistent with X server grab if (ptrGrab != GrabSuccess) { XlibWrapper.XUngrabPointer(XToolkit.getDisplay(), CurrentTime); XAwtState.setGrabWindow(null); grabLog.fine(" Grab Failure - mouse"); return false; } int keyGrab = XlibWrapper.XGrabKeyboard( XToolkit.getDisplay(), getContentWindow(), ownerEvents, GrabModeAsync, GrabModeAsync, CurrentTime); if (keyGrab != GrabSuccess) { XlibWrapper.XUngrabPointer(XToolkit.getDisplay(), CurrentTime); XlibWrapper.XUngrabKeyboard(XToolkit.getDisplay(), CurrentTime); XAwtState.setGrabWindow(null); grabLog.fine(" Grab Failure - keyboard"); return false; } if (prevGrabWindow != null) { prevGrabWindow.ungrabInputImpl(); } XAwtState.setGrabWindow(this); grabLog.fine(" Grab - success"); return true; } finally { XToolkit.awtUnlock(); } } static void ungrabInput() { XToolkit.awtLock(); try { XBaseWindow grabWindow = XAwtState.getGrabWindow(); if (grabLog.isLoggable(Level.FINE)) { grabLog.log(Level.FINE, "UnGrab input on {0}", new Object[] {String.valueOf(grabWindow)}); } if (grabWindow != null) { grabWindow.ungrabInputImpl(); XlibWrapper.XUngrabPointer(XToolkit.getDisplay(), CurrentTime); XlibWrapper.XUngrabKeyboard(XToolkit.getDisplay(), CurrentTime); XAwtState.setGrabWindow(null); // we need to call XFlush() here to force ungrab // see 6384219 for details XlibWrapper.XFlush(XToolkit.getDisplay()); } } finally { XToolkit.awtUnlock(); } } // called from ungrabInput, used in popup windows to hide theirselfs in ungrabbing void ungrabInputImpl() {} static void checkSecurity() { if (XToolkit.isSecurityWarningEnabled() && XToolkit.isToolkitThread()) { StackTraceElement stack[] = (new Throwable()).getStackTrace(); log.warning(stack[1] + ": Security violation: calling user code on toolkit thread"); } } public Set<Long> getChildren() { synchronized (getStateLock()) { return new HashSet<Long>(children); } } // -------------- Event handling ---------------- public void handleMapNotifyEvent(XEvent xev) { mapped = true; } public void handleUnmapNotifyEvent(XEvent xev) { mapped = false; } public void handleReparentNotifyEvent(XEvent xev) { if (eventLog.isLoggable(Level.FINER)) { XReparentEvent msg = xev.get_xreparent(); eventLog.finer(msg.toString()); } } public void handlePropertyNotify(XEvent xev) { XPropertyEvent msg = xev.get_xproperty(); if (XPropertyCache.isCachingSupported()) { XPropertyCache.clearCache(window, XAtom.get(msg.get_atom())); } if (eventLog.isLoggable(Level.FINER)) { eventLog.log(Level.FINER, "{0}", new Object[] {String.valueOf(msg)}); } } public void handleDestroyNotify(XEvent xev) { XAnyEvent xany = xev.get_xany(); if (xany.get_window() == getWindow()) { XToolkit.removeFromWinMap(getWindow(), this); if (XPropertyCache.isCachingSupported()) { XPropertyCache.clearCache(getWindow()); } } if (xany.get_window() != getWindow()) { synchronized (getStateLock()) { children.remove(xany.get_window()); } } } public void handleCreateNotify(XEvent xev) { XAnyEvent xany = xev.get_xany(); if (xany.get_window() != getWindow()) { synchronized (getStateLock()) { children.add(xany.get_window()); } } } public void handleClientMessage(XEvent xev) { if (eventLog.isLoggable(Level.FINER)) { XClientMessageEvent msg = xev.get_xclient(); eventLog.finer(msg.toString()); } } public void handleVisibilityEvent(XEvent xev) {} public void handleKeyPress(XEvent xev) {} public void handleKeyRelease(XEvent xev) {} public void handleExposeEvent(XEvent xev) {} /** Activate automatic grab on first ButtonPress, deactivate on full mouse release */ public void handleButtonPressRelease(XEvent xev) { XButtonEvent xbe = xev.get_xbutton(); final int buttonState = xbe.get_state() & (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask); switch (xev.get_type()) { case ButtonPress: if (buttonState == 0) { XAwtState.setAutoGrabWindow(this); } break; case ButtonRelease: if (isFullRelease(buttonState, xbe.get_button())) { XAwtState.setAutoGrabWindow(null); } break; } } public void handleMotionNotify(XEvent xev) {} public void handleXCrossingEvent(XEvent xev) {} public void handleConfigureNotifyEvent(XEvent xev) { XConfigureEvent xe = xev.get_xconfigure(); if (insLog.isLoggable(Level.FINER)) { insLog.log(Level.FINER, "Configure, {0}", new Object[] {String.valueOf(xe)}); } x = xe.get_x(); y = xe.get_y(); width = xe.get_width(); height = xe.get_height(); } /** Checks ButtonRelease released all Mouse buttons */ static boolean isFullRelease(int buttonState, int button) { switch (button) { case Button1: return buttonState == Button1Mask; case Button2: return buttonState == Button2Mask; case Button3: return buttonState == Button3Mask; case Button4: return buttonState == Button4Mask; case Button5: return buttonState == Button5Mask; } return buttonState == 0; } static boolean isGrabbedEvent(XEvent ev, XBaseWindow target) { switch (ev.get_type()) { case ButtonPress: case ButtonRelease: case MotionNotify: case KeyPress: case KeyRelease: return true; case LeaveNotify: case EnterNotify: // We shouldn't dispatch this events to the grabbed components (see 6317481) // But this logic is important if the grabbed component is top-level (see realSync) return (target instanceof XWindowPeer); default: return false; } } /** * Dispatches event to the grab Window or event source window depending on whether the grab is * active and on the event type */ static void dispatchToWindow(XEvent ev) { XBaseWindow target = XAwtState.getGrabWindow(); if (target == null || !isGrabbedEvent(ev, target)) { target = XToolkit.windowToXWindow(ev.get_xany().get_window()); } if (target != null && target.checkInitialised()) { target.dispatchEvent(ev); } } public void dispatchEvent(XEvent xev) { if (eventLog.isLoggable(Level.FINEST)) eventLog.finest(xev.toString()); int type = xev.get_type(); if (isDisposed()) { return; } switch (type) { case VisibilityNotify: handleVisibilityEvent(xev); break; case ClientMessage: handleClientMessage(xev); break; case Expose: case GraphicsExpose: handleExposeEvent(xev); break; case ButtonPress: case ButtonRelease: handleButtonPressRelease(xev); break; case MotionNotify: handleMotionNotify(xev); break; case KeyPress: handleKeyPress(xev); break; case KeyRelease: handleKeyRelease(xev); break; case EnterNotify: case LeaveNotify: handleXCrossingEvent(xev); break; case ConfigureNotify: handleConfigureNotifyEvent(xev); break; case MapNotify: handleMapNotifyEvent(xev); break; case UnmapNotify: handleUnmapNotifyEvent(xev); break; case ReparentNotify: handleReparentNotifyEvent(xev); break; case PropertyNotify: handlePropertyNotify(xev); break; case DestroyNotify: handleDestroyNotify(xev); break; case CreateNotify: handleCreateNotify(xev); break; } } protected boolean isEventDisabled(XEvent e) { return false; } int getX() { return x; } int getY() { return y; } int getWidth() { return width; } int getHeight() { return height; } void setDisposed(boolean d) { disposed = d; } boolean isDisposed() { return disposed; } public int getAbsoluteX() { XBaseWindow pw = getParentWindow(); if (pw != null) { return pw.getAbsoluteX() + getX(); } else { // Overridden for top-levels as their (x,y) is Java (x, y), not native location return getX(); } } public int getAbsoluteY() { XBaseWindow pw = getParentWindow(); if (pw != null) { return pw.getAbsoluteY() + getY(); } else { return getY(); } } public XBaseWindow getParentWindow() { return parentWindow; } public XWindowPeer getToplevelXWindow() { XBaseWindow bw = this; while (bw != null && !(bw instanceof XWindowPeer)) { bw = bw.getParentWindow(); } return (XWindowPeer) bw; } public String toString() { return super.toString() + "(" + Long.toString(getWindow(), 16) + ")"; } /** Returns whether the given point is inside of the window. Coordinates are local. */ public boolean contains(int x, int y) { return x >= 0 && y >= 0 && x < getWidth() && y < getHeight(); } /** Returns whether the given point is inside of the window. Coordinates are global. */ public boolean containsGlobal(int x, int y) { return x >= getAbsoluteX() && y >= getAbsoluteY() && x < (getAbsoluteX() + getWidth()) && y < (getAbsoluteY() + getHeight()); } }
/** * Provides capabilities to a specific <code>JComponent</code> to contain <code>PluginComponent * </code>s, track when they are added and removed. * * @author Lyubomir Marinov */ public class PluginContainer implements PluginComponentListener { /** * The <tt>Logger</tt> used by the <tt>PluginContainer</tt> class and its instances for logging * output. */ private static final Logger logger = Logger.getLogger(PluginContainer.class); /** * The <code>JComponent</code> which contains the components of the <code>PluginComponent</code>s * managed by this instance. */ private final JComponent container; /** The container id of the <code>PluginComponent</code> managed by this instance. */ private final Container containerId; /** * The list of <code>PluginComponent</code> instances which have their components added to this * <code>PluginContainer</code>. */ private final java.util.List<PluginComponent> pluginComponents = new LinkedList<PluginComponent>(); /** * Initializes a new <code>PluginContainer</code> instance which is to provide capabilities to a * specific <code>JComponent</code> container with a specific <code>Container</code> id to contain * <code>PluginComponent</code> and track when they are added and removed. * * @param container the <code>JComponent</code> container the new instance is to provide its * capabilities to * @param containerId the <code>Container</code> id of the specified <code>container</code> */ public PluginContainer(JComponent container, Container containerId) { this.container = container; this.containerId = containerId; initPluginComponents(); } /** * Adds a specific <tt>Component</tt> to a specific <tt>JComponent</tt> container. Allows * extenders to apply custom logic to the exact placement of the specified <tt>Component</tt> in * the specified container. * * @param component the <tt>Component</tt> to be added to the specified <tt>JComponent</tt> * container * @param container the <tt>JComponent</tt> container to add the specified <tt>Component</tt> to * @param preferredIndex the index at which <tt>component</tt> is to be added to * <tt>container</tt> if possible or <tt>-1</tt> if there is no preference with respect to the * index in question */ protected void addComponentToContainer( Component component, JComponent container, int preferredIndex) { if ((0 <= preferredIndex) && (preferredIndex < getComponentCount(container))) container.add(component, preferredIndex); else container.add(component); } /** * Adds the component of a specific <tt>PluginComponent</tt> to the associated <tt>Container</tt>. * * @param c the <tt>PluginComponent</tt> which is to have its component added to the * <tt>Container</tt> associated with this <tt>PluginContainer</tt> */ private synchronized void addPluginComponent(PluginComponent c) { /* * Try to respect positionIndex of PluginComponent to some extent: * PluginComponents with positionIndex equal to 0 go at the beginning, * these with positionIndex equal to -1 follow them and then go these * with positionIndex greater than 0. */ int cIndex = c.getPositionIndex(); int index = -1; int i = 0; for (PluginComponent pluginComponent : pluginComponents) { if (pluginComponent.equals(c)) return; if (-1 == index) { int pluginComponentIndex = pluginComponent.getPositionIndex(); if ((0 == cIndex) || (-1 == cIndex)) { if ((0 != pluginComponentIndex) && (cIndex != pluginComponentIndex)) index = i; } else if (cIndex < pluginComponentIndex) index = i; } i++; } int pluginComponentCount = pluginComponents.size(); if (-1 == index) index = pluginComponents.size(); /* * The container may have added Components of its own apart from the * ones this PluginContainer has added to it. Since the common case for * the additional Components is to have them appear at the beginning, * adjust the index so it gets correct in the common case. */ int containerComponentCount = getComponentCount(container); addComponentToContainer( (Component) c.getComponent(), container, (containerComponentCount > pluginComponentCount) ? (index + (containerComponentCount - pluginComponentCount)) : index); pluginComponents.add(index, c); container.revalidate(); container.repaint(); } /** * Runs clean-up for associated resources which need explicit disposal (e.g. listeners keeping * this instance alive because they were added to the model which operationally outlives this * instance). */ public void dispose() { GuiActivator.getUIService().removePluginComponentListener(this); /* * Explicitly remove the components of the PluginComponent instances * because the latter are registered with OSGi and are thus global. */ synchronized (this) { for (PluginComponent pluginComponent : pluginComponents) container.remove((Component) pluginComponent.getComponent()); pluginComponents.clear(); } } /** * Gets the number of <tt>Component</tt>s in a specific <tt>JComponent</tt> container. For * example, returns the result of <tt>getMenuComponentCount()</tt> if <tt>container</tt> is an * instance of <tt>JMenu</tt>. * * @param container the <tt>JComponent</tt> container to get the number of <tt>Component</tt>s of * @return the number of <tt>Component</tt>s in the specified <tt>container</tt> */ protected int getComponentCount(JComponent container) { return (container instanceof JMenu) ? ((JMenu) container).getMenuComponentCount() : container.getComponentCount(); } /** * Gets the <tt>PluginComponent</tt>s of this <tt>PluginContainer</tt>. * * @return an <tt>Iterable</tt> over the <tt>PluginComponent</tt>s of this * <tt>PluginContainer</tt> */ public Iterable<PluginComponent> getPluginComponents() { return pluginComponents; } /** * Adds the <tt>Component</tt>s of the <tt>PluginComponent</tt>s registered in the OSGi * <tt>BundleContext</tt> in the associated <tt>Container</tt>. */ private void initPluginComponents() { // Look for PluginComponents registered in the OSGi BundleContext. ServiceReference[] serRefs = null; try { serRefs = GuiActivator.bundleContext.getServiceReferences( PluginComponent.class.getName(), "(" + Container.CONTAINER_ID + "=" + containerId.getID() + ")"); } catch (InvalidSyntaxException exc) { logger.error("Could not obtain plugin reference.", exc); } if (serRefs != null) { for (ServiceReference serRef : serRefs) { PluginComponent component = (PluginComponent) GuiActivator.bundleContext.getService(serRef); addPluginComponent(component); } } GuiActivator.getUIService().addPluginComponentListener(this); } /** * Implements {@link PluginComponentListener#pluginComponentAdded(PluginComponentEvent)}. * * @param event a <tt>PluginComponentEvent</tt> which specifies the <tt>PluginComponent</tt> which * has been added */ public void pluginComponentAdded(PluginComponentEvent event) { PluginComponent c = event.getPluginComponent(); if (c.getContainer().equals(containerId)) addPluginComponent(c); } /** * Implements {@link PluginComponentListener#pluginComponentRemoved(PluginComponentEvent)}. * * @param event a <tt>PluginComponentEvent</tt> which specifies the <tt>PluginComponent</tt> which * has been added */ public void pluginComponentRemoved(PluginComponentEvent event) { PluginComponent c = event.getPluginComponent(); if (c.getContainer().equals(containerId)) removePluginComponent(c); } /** * Removes the component of a specific <code>PluginComponent</code> from this <code> * PluginContainer</code>. * * @param c the <code>PluginComponent</code> which is to have its component removed from this * <code>PluginContainer</code> */ private synchronized void removePluginComponent(PluginComponent c) { container.remove((Component) c.getComponent()); pluginComponents.remove(c); } }
public class ShowPreviewDialog extends SIPCommDialog implements ActionListener, ChatLinkClickedListener { /** Serial version UID. */ private static final long serialVersionUID = 1L; /** * The <tt>Logger</tt> used by the <tt>ShowPreviewDialog</tt> class and its instances for logging * output. */ private static final Logger logger = Logger.getLogger(ShowPreviewDialog.class); ConfigurationService cfg = GuiActivator.getConfigurationService(); /** The Ok button. */ private final JButton okButton; /** The cancel button. */ private final JButton cancelButton; /** Checkbox that indicates whether or not to show this dialog next time. */ private final JCheckBox enableReplacementProposal; /** Checkbox that indicates whether or not to show previews automatically */ private final JCheckBox enableReplacement; /** The <tt>ChatConversationPanel</tt> that this dialog is associated with. */ private final ChatConversationPanel chatPanel; /** Mapping between messageID and the string representation of the chat message. */ private Map<String, String> msgIDToChatString = new ConcurrentHashMap<String, String>(); /** * Mapping between the pair (messageID, link position) and the actual link in the string * representation of the chat message. */ private Map<String, String> msgIDandPositionToLink = new ConcurrentHashMap<String, String>(); /** * Mapping between link and replacement for this link that is acquired from it's corresponding * <tt>ReplacementService</tt>. */ private Map<String, String> linkToReplacement = new ConcurrentHashMap<String, String>(); /** The id of the message that is currently associated with this dialog. */ private String currentMessageID = ""; /** The position of the link in the current message. */ private String currentLinkPosition = ""; /** * Creates an instance of <tt>ShowPreviewDialog</tt> * * @param chatPanel The <tt>ChatConversationPanel</tt> that is associated with this dialog. */ ShowPreviewDialog(final ChatConversationPanel chatPanel) { this.chatPanel = chatPanel; this.setTitle( GuiActivator.getResources().getI18NString("service.gui.SHOW_PREVIEW_DIALOG_TITLE")); okButton = new JButton(GuiActivator.getResources().getI18NString("service.gui.OK")); cancelButton = new JButton(GuiActivator.getResources().getI18NString("service.gui.CANCEL")); JPanel mainPanel = new TransparentPanel(); mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); // mainPanel.setPreferredSize(new Dimension(200, 150)); this.getContentPane().add(mainPanel); JTextPane descriptionMsg = new JTextPane(); descriptionMsg.setEditable(false); descriptionMsg.setOpaque(false); descriptionMsg.setText( GuiActivator.getResources().getI18NString("service.gui.SHOW_PREVIEW_WARNING_DESCRIPTION")); Icon warningIcon = null; try { warningIcon = new ImageIcon( ImageIO.read( GuiActivator.getResources().getImageURL("service.gui.icons.WARNING_ICON"))); } catch (IOException e) { logger.debug("failed to load the warning icon"); } JLabel warningSign = new JLabel(warningIcon); JPanel warningPanel = new TransparentPanel(); warningPanel.setLayout(new BoxLayout(warningPanel, BoxLayout.X_AXIS)); warningPanel.add(warningSign); warningPanel.add(Box.createHorizontalStrut(10)); warningPanel.add(descriptionMsg); enableReplacement = new JCheckBox( GuiActivator.getResources() .getI18NString("plugin.chatconfig.replacement.ENABLE_REPLACEMENT_STATUS")); enableReplacement.setOpaque(false); enableReplacement.setSelected(cfg.getBoolean(ReplacementProperty.REPLACEMENT_ENABLE, true)); enableReplacementProposal = new JCheckBox( GuiActivator.getResources() .getI18NString("plugin.chatconfig.replacement.ENABLE_REPLACEMENT_PROPOSAL")); enableReplacementProposal.setOpaque(false); JPanel checkBoxPanel = new TransparentPanel(); checkBoxPanel.setLayout(new BoxLayout(checkBoxPanel, BoxLayout.Y_AXIS)); checkBoxPanel.add(enableReplacement); checkBoxPanel.add(enableReplacementProposal); JPanel buttonsPanel = new TransparentPanel(new FlowLayout(FlowLayout.CENTER)); buttonsPanel.add(okButton); buttonsPanel.add(cancelButton); mainPanel.add(warningPanel); mainPanel.add(Box.createVerticalStrut(10)); mainPanel.add(checkBoxPanel); mainPanel.add(buttonsPanel); okButton.addActionListener(this); cancelButton.addActionListener(this); this.setPreferredSize(new Dimension(390, 230)); } @Override public void actionPerformed(ActionEvent arg0) { if (arg0.getSource().equals(okButton)) { cfg.setProperty(ReplacementProperty.REPLACEMENT_ENABLE, enableReplacement.isSelected()); cfg.setProperty( ReplacementProperty.REPLACEMENT_PROPOSAL, enableReplacementProposal.isSelected()); SwingWorker worker = new SwingWorker() { /** * Called on the event dispatching thread (not on the worker thread) after the <code> * construct</code> method has returned. */ @Override public void finished() { String newChatString = (String) get(); if (newChatString != null) { try { Element elem = chatPanel.document.getElement(currentMessageID); chatPanel.document.setOuterHTML(elem, newChatString); msgIDToChatString.put(currentMessageID, newChatString); } catch (BadLocationException ex) { logger.error("Could not replace chat message", ex); } catch (IOException ex) { logger.error("Could not replace chat message", ex); } } } @Override protected Object construct() throws Exception { String newChatString = msgIDToChatString.get(currentMessageID); try { String originalLink = msgIDandPositionToLink.get(currentMessageID + "#" + currentLinkPosition); String replacementLink = linkToReplacement.get(originalLink); String replacement; DirectImageReplacementService source = GuiActivator.getDirectImageReplacementSource(); if (originalLink.equals(replacementLink) && (!source.isDirectImage(originalLink) || source.getImageSize(originalLink) == -1)) { replacement = originalLink; } else { replacement = "<IMG HEIGHT=\"90\" WIDTH=\"120\" SRC=\"" + replacementLink + "\" BORDER=\"0\" ALT=\"" + originalLink + "\"></IMG>"; } String old = originalLink + "</A> <A href=\"jitsi://" + ShowPreviewDialog.this.getClass().getName() + "/SHOWPREVIEW?" + currentMessageID + "#" + currentLinkPosition + "\">" + GuiActivator.getResources().getI18NString("service.gui.SHOW_PREVIEW"); newChatString = newChatString.replace(old, replacement); } catch (Exception ex) { logger.error("Could not replace chat message", ex); } return newChatString; } }; worker.start(); this.setVisible(false); } else if (arg0.getSource().equals(cancelButton)) { this.setVisible(false); } } @Override public void chatLinkClicked(URI url) { String action = url.getPath(); if (action.equals("/SHOWPREVIEW")) { enableReplacement.setSelected(cfg.getBoolean(ReplacementProperty.REPLACEMENT_ENABLE, true)); enableReplacementProposal.setSelected( cfg.getBoolean(ReplacementProperty.REPLACEMENT_PROPOSAL, true)); currentMessageID = url.getQuery(); currentLinkPosition = url.getFragment(); this.setVisible(true); this.setLocationRelativeTo(chatPanel); } } /** * Returns mapping between messageID and the string representation of the chat message. * * @return mapping between messageID and chat string. */ Map<String, String> getMsgIDToChatString() { return msgIDToChatString; } /** * Returns mapping between the pair (messageID, link position) and the actual link in the string * representation of the chat message. * * @return mapping between (messageID, linkPosition) and link. */ Map<String, String> getMsgIDandPositionToLink() { return msgIDandPositionToLink; } /** * Returns mapping between link and replacement for this link that was acquired from it's * corresponding <tt>ReplacementService</tt>. * * @return mapping between link and it's corresponding replacement. */ Map<String, String> getLinkToReplacement() { return linkToReplacement; } }
/** * @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; } } }
/** * The stream used by JMF for our image streaming. * * @author Sebastien Vincent * @author Lyubomir Marinov * @author Damian Minkov */ public class ImageStream extends AbstractVideoPullBufferStream<DataSource> { /** * The <tt>Logger</tt> used by the <tt>ImageStream</tt> class and its instances for logging * output. */ private static final Logger logger = Logger.getLogger(ImageStream.class); /** * The pool of <tt>ByteBuffer</tt>s this instances is using to optimize the allocations and * deallocations of <tt>ByteBuffer</tt>s. */ private final ByteBufferPool byteBufferPool = new ByteBufferPool(); /** Desktop interaction (screen capture, key press, ...). */ private DesktopInteract desktopInteract = null; /** Index of display that we will capture from. */ private int displayIndex = -1; /** Sequence number. */ private long seqNo = 0; /** X origin. */ private int x = 0; /** Y origin. */ private int y = 0; /** * Initializes a new <tt>ImageStream</tt> instance which is to have a specific * <tt>FormatControl</tt> * * @param dataSource the <tt>DataSource</tt> which is creating the new instance so that it becomes * one of its <tt>streams</tt> * @param formatControl the <tt>FormatControl</tt> of the new instance which is to specify the * format in which it is to provide its media data */ ImageStream(DataSource dataSource, FormatControl formatControl) { super(dataSource, formatControl); } /** * Blocks and reads into a <tt>Buffer</tt> from this <tt>PullBufferStream</tt>. * * @param buffer the <tt>Buffer</tt> this <tt>PullBufferStream</tt> is to read into * @throws IOException if an I/O error occurs while this <tt>PullBufferStream</tt> reads into the * specified <tt>Buffer</tt> * @see AbstractVideoPullBufferStream#doRead(Buffer) */ @Override protected void doRead(Buffer buffer) throws IOException { /* * Determine the Format in which we're expected to output. We cannot * rely on the Format always being specified in the Buffer because it is * not its responsibility, the DataSource of this ImageStream knows the * output Format. */ Format format = buffer.getFormat(); if (format == null) { format = getFormat(); if (format != null) buffer.setFormat(format); } if (format instanceof AVFrameFormat) { Object o = buffer.getData(); AVFrame frame; if (o instanceof AVFrame) frame = (AVFrame) o; else { frame = new AVFrame(); buffer.setData(frame); } AVFrameFormat avFrameFormat = (AVFrameFormat) format; Dimension size = avFrameFormat.getSize(); ByteBuffer data = readScreenNative(size); if (data != null) { if (frame.avpicture_fill(data, avFrameFormat) < 0) { data.free(); throw new IOException("avpicture_fill"); } } else { /* * This can happen when we disconnect a monitor from computer * before or during grabbing. */ throw new IOException("Failed to grab screen."); } } else { byte[] bytes = (byte[]) buffer.getData(); Dimension size = ((VideoFormat) format).getSize(); bytes = readScreen(bytes, size); buffer.setData(bytes); buffer.setOffset(0); buffer.setLength(bytes.length); } buffer.setHeader(null); buffer.setTimeStamp(System.nanoTime()); buffer.setSequenceNumber(seqNo); buffer.setFlags(Buffer.FLAG_SYSTEM_TIME | Buffer.FLAG_LIVE_DATA); seqNo++; } /** * Read screen. * * @param output output buffer for screen bytes * @param dim dimension of the screen * @return raw bytes, it could be equal to output or not. Take care in the caller to check if * output is the returned value. */ public byte[] readScreen(byte[] output, Dimension dim) { VideoFormat format = (VideoFormat) getFormat(); Dimension formatSize = format.getSize(); int width = formatSize.width; int height = formatSize.height; BufferedImage scaledScreen = null; BufferedImage screen = null; byte data[] = null; int size = width * height * 4; // If output is not large enough, enlarge it. if ((output == null) || (output.length < size)) output = new byte[size]; /* get desktop screen via native grabber if available */ if (desktopInteract.captureScreen(displayIndex, x, y, dim.width, dim.height, output)) { return output; } System.out.println("failed to grab with native! " + output.length); /* OK native grabber failed or is not available, * try with AWT Robot and convert it to the right format * * Note that it is very memory consuming since memory are allocated * to capture screen (via Robot) and then for converting to raw bytes * Moreover support for multiple display has not yet been investigated * * Normally not of our supported platform (Windows (x86, x64), * Linux (x86, x86-64), Mac OS X (i386, x86-64, ppc) and * FreeBSD (x86, x86-64) should go here. */ screen = desktopInteract.captureScreen(); if (screen != null) { /* convert to ARGB BufferedImage */ scaledScreen = ImgStreamingUtils.getScaledImage(screen, width, height, BufferedImage.TYPE_INT_ARGB); /* get raw bytes */ data = ImgStreamingUtils.getImageBytes(scaledScreen, output); } screen = null; scaledScreen = null; return data; } /** * Read screen and store result in native buffer. * * @param dim dimension of the video * @return true if success, false otherwise */ private ByteBuffer readScreenNative(Dimension dim) { int size = dim.width * dim.height * 4 + FFmpeg.FF_INPUT_BUFFER_PADDING_SIZE; ByteBuffer data = byteBufferPool.getBuffer(size); data.setLength(size); /* get desktop screen via native grabber */ boolean b; try { b = desktopInteract.captureScreen( displayIndex, x, y, dim.width, dim.height, data.getPtr(), data.getLength()); } catch (Throwable t) { if (t instanceof ThreadDeath) { throw (ThreadDeath) t; } else { b = false; // logger.error("Failed to grab screen!", t); } } if (!b) { data.free(); data = null; } return data; } /** * Sets the index of the display to be used by this <tt>ImageStream</tt>. * * @param displayIndex the index of the display to be used by this <tt>ImageStream</tt> */ public void setDisplayIndex(int displayIndex) { this.displayIndex = displayIndex; } /** * Sets the origin to be captured by this <tt>ImageStream</tt>. * * @param x the x coordinate of the origin to be set on this instance * @param y the y coordinate of the origin to be set on this instance */ public void setOrigin(int x, int y) { this.x = x; this.y = y; } /** * Start desktop capture stream. * * @see AbstractPullBufferStream#start() */ @Override public void start() throws IOException { super.start(); if (desktopInteract == null) { try { desktopInteract = new DesktopInteractImpl(); } catch (Exception e) { logger.warn("Cannot create DesktopInteract object!"); } } } /** * Stop desktop capture stream. * * @see AbstractPullBufferStream#stop() */ @Override public void stop() throws IOException { try { if (logger.isInfoEnabled()) logger.info("Stop stream"); } finally { super.stop(); byteBufferPool.drain(); } } }
/** * The Dialog Class * * @author Frank Kunz The dialog class draws the basic dialog with a grid layout. The dialog * consists of three main parts. A settings panel, a table panel and three buttons. */ public final class UARTProtocolAnalysisDialog extends BaseToolDialog<UARTDataSet> implements ExportAware<UARTDataSet> { // INNER TYPES /** Provides a combobox renderer for {@link UARTParity} values. */ static final class UARTParityItemRenderer extends EnumItemRenderer<Parity> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final Parity aValue) { String text = super.getDisplayValue(aValue); if (Parity.EVEN.equals(aValue)) { text = "Even parity"; } else if (Parity.NONE.equals(aValue)) { text = "No parity"; } else if (Parity.ODD.equals(aValue)) { text = "Odd parity"; } return text; } } /** Provides a combobox renderer for {@link UARTStopBits} values. */ static final class UARTStopBitsItemRenderer extends EnumItemRenderer<StopBits> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final StopBits aValue) { String text = super.getDisplayValue(aValue); if (StopBits.ONE.equals(aValue)) { text = "1"; } else if (StopBits.ONE_HALF.equals(aValue)) { text = "1.5"; } else if (StopBits.TWO.equals(aValue)) { text = "2"; } return text; } } /** Provides a combobox renderer for {@link BitOrder} values. */ static final class UARTBitOrderItemRenderer extends EnumItemRenderer<BitOrder> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final BitOrder aValue) { String text = super.getDisplayValue(aValue); if (BitOrder.LSB_FIRST.equals(aValue)) { text = "LSB first"; } else if (BitOrder.MSB_FIRST.equals(aValue)) { text = "MSB first"; } return text; } } /** Provides a combobox renderer for {@link BitEncoding} values. */ static final class UARTBitEncodingItemRenderer extends EnumItemRenderer<BitEncoding> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final BitEncoding aValue) { String text = super.getDisplayValue(aValue); if (BitEncoding.HIGH_IS_MARK.equals(aValue)) { text = "High is mark (1)"; } else if (BitEncoding.HIGH_IS_SPACE.equals(aValue)) { text = "High is space (0)"; } return text; } } /** Provides a combobox renderer for {@link BitLevel} values. */ static final class UARTIdleLevelItemRenderer extends EnumItemRenderer<BitLevel> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final BitLevel aValue) { String text = super.getDisplayValue(aValue); if (BitLevel.HIGH.equals(aValue)) { text = "High (start = L, stop = H)"; } else if (BitLevel.LOW.equals(aValue)) { text = "Low (start = H, stop = L)"; } return text; } } // CONSTANTS private static final long serialVersionUID = 1L; private static final Logger LOG = Logger.getLogger(UARTProtocolAnalysisDialog.class.getName()); // VARIABLES private JComboBox rxd; private JComboBox txd; private JComboBox cts; private JComboBox rts; private JComboBox dtr; private JComboBox dsr; private JComboBox dcd; private JComboBox ri; private JComboBox parity; private JComboBox bits; private JComboBox stop; private JComboBox bitEncoding; private JComboBox bitOrder; private JComboBox idleLevel; private JCheckBox autoDetectBaudRate; private JComboBox baudrate; private JEditorPane outText; private RestorableAction runAnalysisAction; private Action closeAction; private Action exportAction; // CONSTRUCTORS /** * Creates a new UARTProtocolAnalysisDialog instance. * * @param aOwner the owner of this dialog; * @param aToolContext the tool context; * @param aContext the OSGi bundle context to use; * @param aTool the {@link UARTAnalyser} tool. */ public UARTProtocolAnalysisDialog( final Window aOwner, final ToolContext aToolContext, final BundleContext aContext, final UARTAnalyser aTool) { super(aOwner, aToolContext, aContext, aTool); initDialog(); setLocationRelativeTo(getOwner()); } // METHODS /** {@inheritDoc} */ @Override public void exportToFile( final File aOutputFile, final nl.lxtreme.ols.tool.base.ExportAware.ExportFormat aFormat) throws IOException { if (ExportFormat.HTML.equals(aFormat)) { storeToHtmlFile(aOutputFile, getLastResult()); } else if (ExportFormat.CSV.equals(aFormat)) { storeToCsvFile(aOutputFile, getLastResult()); } } /** {@inheritDoc} */ @Override public void readPreferences(final UserSettings aSettings) { // Issue #114: avoid setting illegal values... setComboBoxIndex(this.rxd, aSettings, "rxd"); setComboBoxIndex(this.txd, aSettings, "txd"); setComboBoxIndex(this.cts, aSettings, "cts"); setComboBoxIndex(this.rts, aSettings, "rts"); setComboBoxIndex(this.dtr, aSettings, "dtr"); setComboBoxIndex(this.dsr, aSettings, "dsr"); setComboBoxIndex(this.dcd, aSettings, "dcd"); setComboBoxIndex(this.ri, aSettings, "ri"); this.parity.setSelectedIndex(aSettings.getInt("parity", this.parity.getSelectedIndex())); this.bits.setSelectedIndex(aSettings.getInt("bits", this.bits.getSelectedIndex())); this.stop.setSelectedIndex(aSettings.getInt("stop", this.stop.getSelectedIndex())); this.idleLevel.setSelectedIndex( aSettings.getInt("idle-state", this.idleLevel.getSelectedIndex())); this.bitEncoding.setSelectedIndex( aSettings.getInt("bit-encoding", this.bitEncoding.getSelectedIndex())); this.bitOrder.setSelectedIndex(aSettings.getInt("bit-order", this.bitOrder.getSelectedIndex())); this.baudrate.setSelectedItem(Integer.valueOf(aSettings.getInt("baudrate", 9600))); this.autoDetectBaudRate.setSelected( aSettings.getBoolean("auto-baudrate", this.autoDetectBaudRate.isSelected())); } /** {@inheritDoc} */ @Override public void reset() { this.outText.setText(getEmptyHtmlPage()); this.outText.setEditable(false); this.runAnalysisAction.restore(); setControlsEnabled(true); this.exportAction.setEnabled(false); } /** @see nl.lxtreme.ols.api.Configurable#writePreferences(nl.lxtreme.ols.api.UserSettings) */ @Override public void writePreferences(final UserSettings aSettings) { aSettings.putInt("rxd", this.rxd.getSelectedIndex()); aSettings.putInt("txd", this.txd.getSelectedIndex()); aSettings.putInt("cts", this.cts.getSelectedIndex()); aSettings.putInt("rts", this.rts.getSelectedIndex()); aSettings.putInt("dtr", this.dtr.getSelectedIndex()); aSettings.putInt("dsr", this.dsr.getSelectedIndex()); aSettings.putInt("dcd", this.dcd.getSelectedIndex()); aSettings.putInt("ri", this.ri.getSelectedIndex()); aSettings.putInt("parity", this.parity.getSelectedIndex()); aSettings.putInt("bits", this.bits.getSelectedIndex()); aSettings.putInt("stop", this.stop.getSelectedIndex()); aSettings.putInt("idle-state", this.idleLevel.getSelectedIndex()); aSettings.putInt("bit-encoding", this.bitEncoding.getSelectedIndex()); aSettings.putInt("bit-order", this.bitOrder.getSelectedIndex()); aSettings.putInt("baudrate", ((Integer) this.baudrate.getSelectedItem()).intValue()); aSettings.putBoolean("auto-baudrate", this.autoDetectBaudRate.isSelected()); } /** {@inheritDoc} */ @Override protected void onToolEnded(final UARTDataSet aAnalysisResult) { try { final String htmlPage; if (aAnalysisResult != null) { htmlPage = toHtmlPage(null /* aFile */, aAnalysisResult); } else { htmlPage = getEmptyHtmlPage(); } this.outText.setText(htmlPage); this.outText.setEditable(false); this.runAnalysisAction.restore(); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { // Should not happen in this situation! throw new RuntimeException(exception); } } } /** {@inheritDoc} */ @Override protected void onToolStarted() { // NO-op } /** {@inheritDoc} */ @Override protected void prepareToolTask(final ToolTask<UARTDataSet> aToolTask) { final UARTAnalyserTask toolTask = (UARTAnalyserTask) aToolTask; // The value at index zero is "Unused", so extracting one of all items // causes all "unused" values to be equivalent to -1, which is interpreted // as not used... toolTask.setRxdIndex(this.rxd.getSelectedIndex() - 1); toolTask.setTxdIndex(this.txd.getSelectedIndex() - 1); toolTask.setCtsIndex(this.cts.getSelectedIndex() - 1); toolTask.setRtsIndex(this.rts.getSelectedIndex() - 1); toolTask.setDcdIndex(this.dcd.getSelectedIndex() - 1); toolTask.setRiIndex(this.ri.getSelectedIndex() - 1); toolTask.setDsrIndex(this.dsr.getSelectedIndex() - 1); toolTask.setDtrIndex(this.dtr.getSelectedIndex() - 1); // Handle the auto detect option for baudrates... if (this.autoDetectBaudRate.isSelected()) { toolTask.setBaudRate(UARTAnalyserTask.AUTO_DETECT_BAUDRATE); } else { toolTask.setBaudRate(((Integer) this.baudrate.getSelectedItem()).intValue()); } // Other properties... toolTask.setIdleLevel((BitLevel) this.idleLevel.getSelectedItem()); toolTask.setBitEncoding((BitEncoding) this.bitEncoding.getSelectedItem()); toolTask.setBitOrder((BitOrder) this.bitOrder.getSelectedItem()); toolTask.setParity((Parity) this.parity.getSelectedItem()); toolTask.setStopBits((StopBits) this.stop.getSelectedItem()); toolTask.setBitCount(NumberUtils.smartParseInt((String) this.bits.getSelectedItem(), 8)); } /** * set the controls of the dialog enabled/disabled * * @param aEnable status of the controls */ @Override protected void setControlsEnabled(final boolean aEnable) { this.rxd.setEnabled(aEnable); this.txd.setEnabled(aEnable); this.cts.setEnabled(aEnable); this.rts.setEnabled(aEnable); this.dtr.setEnabled(aEnable); this.dsr.setEnabled(aEnable); this.dcd.setEnabled(aEnable); this.ri.setEnabled(aEnable); this.parity.setEnabled(aEnable); this.bits.setEnabled(aEnable); this.stop.setEnabled(aEnable); this.idleLevel.setEnabled(aEnable); this.bitEncoding.setEnabled(aEnable); this.bitOrder.setEnabled(aEnable); this.closeAction.setEnabled(aEnable); this.exportAction.setEnabled(aEnable); } /** * Creates the HTML template for exports to HTML. * * @param aExporter the HTML exporter instance to use, cannot be <code>null</code>. * @return a HTML exporter filled with the template, never <code>null</code>. */ private HtmlExporter createHtmlTemplate(final HtmlExporter aExporter) { aExporter.addCssStyle("body { font-family: sans-serif; } "); aExporter.addCssStyle( "table { border-width: 1px; border-spacing: 0px; border-color: gray;" + " border-collapse: collapse; border-style: solid; margin-bottom: 15px; } "); aExporter.addCssStyle( "table th { border-width: 1px; padding: 2px; border-style: solid; border-color: gray;" + " background-color: #C0C0FF; text-align: left; font-weight: bold; font-family: sans-serif; } "); aExporter.addCssStyle( "table td { border-width: 1px; padding: 2px; border-style: solid; border-color: gray;" + " font-family: monospace; } "); aExporter.addCssStyle(".error { color: red; } "); aExporter.addCssStyle(".warning { color: orange; } "); aExporter.addCssStyle(".date { text-align: right; font-size: x-small; margin-bottom: 15px; } "); aExporter.addCssStyle(".w100 { width: 100%; } "); aExporter.addCssStyle(".w35 { width: 35%; } "); aExporter.addCssStyle(".w30 { width: 30%; } "); aExporter.addCssStyle(".w15 { width: 15%; } "); aExporter.addCssStyle(".w10 { width: 10%; } "); aExporter.addCssStyle(".w8 { width: 8%; } "); aExporter.addCssStyle(".w7 { width: 7%; } "); final Element body = aExporter.getBody(); body.addChild(H1).addContent("UART Analysis results"); body.addChild(HR); body.addChild(DIV).addAttribute("class", "date").addContent("Generated: ", "{date-now}"); Element table, tr, thead, tbody; table = body.addChild(TABLE).addAttribute("class", "w100"); tbody = table.addChild(TBODY); tr = tbody.addChild(TR); tr.addChild(TH).addAttribute("colspan", "2").addContent("Statistics"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Decoded bytes"); tr.addChild(TD).addContent("{decoded-bytes}"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Detected bus errors"); tr.addChild(TD).addContent("{detected-bus-errors}"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Baudrate"); tr.addChild(TD).addContent("{baudrate}"); table = body.addChild(TABLE).addAttribute("class", "w100"); thead = table.addChild(THEAD); tr = thead.addChild(TR); tr.addChild(TH).addAttribute("class", "w30").addAttribute("colspan", "2"); tr.addChild(TH).addAttribute("class", "w35").addAttribute("colspan", "4").addContent("RxD"); tr.addChild(TH).addAttribute("class", "w35").addAttribute("colspan", "4").addContent("TxD"); tr = thead.addChild(TR); tr.addChild(TH).addAttribute("class", "w15").addContent("Index"); tr.addChild(TH).addAttribute("class", "w15").addContent("Time"); tr.addChild(TH).addAttribute("class", "w10").addContent("Hex"); tr.addChild(TH).addAttribute("class", "w10").addContent("Bin"); tr.addChild(TH).addAttribute("class", "w8").addContent("Dec"); tr.addChild(TH).addAttribute("class", "w7").addContent("ASCII"); tr.addChild(TH).addAttribute("class", "w10").addContent("Hex"); tr.addChild(TH).addAttribute("class", "w10").addContent("Bin"); tr.addChild(TH).addAttribute("class", "w8").addContent("Dec"); tr.addChild(TH).addAttribute("class", "w7").addContent("ASCII"); tbody = table.addChild(TBODY); tbody.addContent("{decoded-data}"); return aExporter; } /** @return */ private JPanel createPreviewPane() { final JPanel panTable = new JPanel(new GridLayout(1, 1, 0, 0)); this.outText = new JEditorPane("text/html", getEmptyHtmlPage()); this.outText.setEditable(false); panTable.add(new JScrollPane(this.outText)); return panTable; } /** @return */ private JPanel createSettingsPane() { final int channelCount = getData().getChannels(); final Integer[] baudrates = new Integer[AsyncSerialDataDecoder.COMMON_BAUDRATES.length]; for (int i = 0; i < baudrates.length; i++) { baudrates[i] = Integer.valueOf(AsyncSerialDataDecoder.COMMON_BAUDRATES[i]); } final String[] bitarray = new String[10]; // allow symbol lengths between 5 and 14 bits... for (int i = 0; i < bitarray.length; i++) { bitarray[i] = String.format("%d", Integer.valueOf(i + 5)); } final JPanel settings = new JPanel(new SpringLayout()); SpringLayoutUtils.addSeparator(settings, "Settings"); settings.add(createRightAlignedLabel("RxD")); this.rxd = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.rxd); settings.add(createRightAlignedLabel("TxD")); this.txd = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.txd); settings.add(createRightAlignedLabel("CTS")); this.cts = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.cts); settings.add(createRightAlignedLabel("RTS")); this.rts = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.rts); settings.add(createRightAlignedLabel("DTR")); this.dtr = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.dtr); settings.add(createRightAlignedLabel("DSR")); this.dsr = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.dsr); settings.add(createRightAlignedLabel("DCD")); this.dcd = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.dcd); settings.add(createRightAlignedLabel("RI")); this.ri = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.ri); settings.add(createRightAlignedLabel("Baudrate")); this.autoDetectBaudRate = new JCheckBox("Auto detect"); settings.add(this.autoDetectBaudRate); settings.add(new JLabel("")); this.baudrate = new JComboBox(baudrates); // Issue #90: allow custom baudrates to be specified... this.baudrate.setEditable(true); this.baudrate.setSelectedIndex(0); settings.add(this.baudrate); this.autoDetectBaudRate.addItemListener( new ItemListener() { @Override public void itemStateChanged(final ItemEvent aEvent) { final JCheckBox cb = (JCheckBox) aEvent.getSource(); UARTProtocolAnalysisDialog.this.baudrate.setEnabled(!cb.isSelected()); } }); settings.add(createRightAlignedLabel("Parity")); this.parity = new JComboBox(Parity.values()); this.parity.setSelectedIndex(0); this.parity.setRenderer(new UARTParityItemRenderer()); settings.add(this.parity); settings.add(createRightAlignedLabel("Bits")); this.bits = new JComboBox(bitarray); this.bits.setSelectedIndex(3); settings.add(this.bits); settings.add(createRightAlignedLabel("Stopbits")); this.stop = new JComboBox(StopBits.values()); this.stop.setSelectedIndex(0); this.stop.setRenderer(new UARTStopBitsItemRenderer()); settings.add(this.stop); settings.add(createRightAlignedLabel("Idle level")); this.idleLevel = new JComboBox(BitLevel.values()); this.idleLevel.setSelectedIndex(0); this.idleLevel.setRenderer(new UARTIdleLevelItemRenderer()); settings.add(this.idleLevel); settings.add(createRightAlignedLabel("Bit encoding")); this.bitEncoding = new JComboBox(BitEncoding.values()); this.bitEncoding.setSelectedIndex(0); this.bitEncoding.setRenderer(new UARTBitEncodingItemRenderer()); settings.add(this.bitEncoding); settings.add(createRightAlignedLabel("Bit order")); this.bitOrder = new JComboBox(BitOrder.values()); this.bitOrder.setSelectedIndex(0); this.bitOrder.setRenderer(new UARTBitOrderItemRenderer()); settings.add(this.bitOrder); SpringLayoutUtils.makeEditorGrid(settings, 10, 4); return settings; } /** * generate a HTML page * * @param empty if this is true an empty output is generated * @return String with HTML data */ private String getEmptyHtmlPage() { final HtmlExporter exporter = createHtmlTemplate(ExportUtils.createHtmlExporter()); return exporter.toString( new MacroResolver() { @Override public Object resolve(final String aMacro, final Element aParent) { if ("date-now".equals(aMacro)) { final DateFormat df = DateFormat.getDateInstance(DateFormat.LONG); return df.format(new Date()); } else if ("decoded-bytes".equals(aMacro) || "detected-bus-errors".equals(aMacro) || "baudrate".equals(aMacro)) { return "-"; } else if ("decoded-data".equals(aMacro)) { return null; } return null; } }); } /** Initializes this dialog. */ private void initDialog() { setMinimumSize(new Dimension(640, 480)); final JComponent settingsPane = createSettingsPane(); final JComponent previewPane = createPreviewPane(); final JPanel contentPane = new JPanel(new GridBagLayout()); contentPane.add( settingsPane, new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(2, 0, 2, 0), 0, 0)); contentPane.add( previewPane, new GridBagConstraints( 1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(2, 0, 2, 0), 0, 0)); final JButton runAnalysisButton = ToolUtils.createRunAnalysisButton(this); this.runAnalysisAction = (RestorableAction) runAnalysisButton.getAction(); final JButton exportButton = ToolUtils.createExportButton(this); this.exportAction = exportButton.getAction(); this.exportAction.setEnabled(false); final JButton closeButton = ToolUtils.createCloseButton(); this.closeAction = closeButton.getAction(); final JComponent buttons = SwingComponentUtils.createButtonPane(runAnalysisButton, exportButton, closeButton); SwingComponentUtils.setupWindowContentPane(this, contentPane, buttons, runAnalysisButton); } /** * exports the data to a CSV file * * @param aFile File object */ private void storeToCsvFile(final File aFile, final UARTDataSet aDataSet) { try { final CsvExporter exporter = ExportUtils.createCsvExporter(aFile); exporter.setHeaders( "index", "start-time", "end-time", "event?", "event-type", "RxD event", "TxD event", "RxD data", "TxD data"); final List<UARTData> decodedData = aDataSet.getData(); for (int i = 0; i < decodedData.size(); i++) { final UARTData ds = decodedData.get(i); final String startTime = Unit.Time.format(aDataSet.getTime(ds.getStartSampleIndex())); final String endTime = Unit.Time.format(aDataSet.getTime(ds.getEndSampleIndex())); String eventType = null; String rxdEvent = null; String txdEvent = null; String rxdData = null; String txdData = null; switch (ds.getType()) { case UARTData.UART_TYPE_EVENT: eventType = ds.getEventName(); break; case UARTData.UART_TYPE_RXEVENT: rxdEvent = ds.getEventName(); break; case UARTData.UART_TYPE_TXEVENT: txdEvent = ds.getEventName(); break; case UARTData.UART_TYPE_RXDATA: rxdData = Integer.toString(ds.getData()); break; case UARTData.UART_TYPE_TXDATA: txdData = Integer.toString(ds.getData()); break; default: break; } exporter.addRow( Integer.valueOf(i), startTime, endTime, Boolean.valueOf(ds.isEvent()), eventType, rxdEvent, txdEvent, rxdData, txdData); } exporter.close(); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { LOG.log(Level.WARNING, "CSV export failed!", exception); } } } /** * stores the data to a HTML file * * @param aFile file object */ private void storeToHtmlFile(final File aFile, final UARTDataSet aDataSet) { try { toHtmlPage(aFile, aDataSet); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { LOG.log(Level.WARNING, "HTML export failed!", exception); } } } /** * generate a HTML page * * @param empty if this is true an empty output is generated * @return String with HTML data */ private String toHtmlPage(final File aFile, final UARTDataSet aDataSet) throws IOException { final int bitCount = Integer.parseInt((String) this.bits.getSelectedItem()); final int bitAdder = ((bitCount % 4) != 0) ? 1 : 0; final MacroResolver macroResolver = new MacroResolver() { @Override public Object resolve(final String aMacro, final Element aParent) { if ("date-now".equals(aMacro)) { final DateFormat df = DateFormat.getDateInstance(DateFormat.LONG); return df.format(new Date()); } else if ("decoded-bytes".equals(aMacro)) { return Integer.valueOf(aDataSet.getDecodedSymbols()); } else if ("detected-bus-errors".equals(aMacro)) { return Integer.valueOf(aDataSet.getDetectedErrors()); } else if ("baudrate".equals(aMacro)) { final String baudrate; if (aDataSet.getBaudRate() <= 0) { baudrate = "<span class='error'>Baudrate calculation failed!</span>"; } else { baudrate = String.format( "%d (exact: %d)", Integer.valueOf(aDataSet.getBaudRate()), Integer.valueOf(aDataSet.getBaudRateExact())); if (!aDataSet.isBitLengthUsable()) { return baudrate.concat( " <span class='warning'>The baudrate may be wrong, use a higher samplerate to avoid this!</span>"); } return baudrate; } } else if ("decoded-data".equals(aMacro)) { final List<UARTData> decodedData = aDataSet.getData(); Element tr; for (int i = 0; i < decodedData.size(); i++) { final UARTData ds = decodedData.get(i); if (ds.isEvent()) { String rxEventData = ""; String txEventData = ""; String bgColor; if (UARTData.UART_TYPE_EVENT == ds.getType()) { rxEventData = txEventData = ds.getEventName(); bgColor = "#e0e0e0"; } else if (UARTData.UART_TYPE_RXEVENT == ds.getType()) { rxEventData = ds.getEventName(); bgColor = "#c0ffc0"; } else if (UARTData.UART_TYPE_TXEVENT == ds.getType()) { txEventData = ds.getEventName(); bgColor = "#c0ffc0"; } else { // unknown event bgColor = "#ff8000"; } if (txEventData.endsWith("_ERR") || rxEventData.endsWith("_ERR")) { bgColor = "#ff8000"; } tr = aParent .addChild(TR) .addAttribute("style", "background-color: " + bgColor + ";"); tr.addChild(TD).addContent(String.valueOf(i)); tr.addChild(TD) .addContent(Unit.Time.format(aDataSet.getTime(ds.getStartSampleIndex()))); tr.addChild(TD).addContent(rxEventData); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD).addContent(txEventData); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD); } else { String rxDataHex = "", rxDataBin = "", rxDataDec = "", rxDataASCII = ""; String txDataHex = "", txDataBin = "", txDataDec = "", txDataASCII = ""; // Normal data... if (UARTData.UART_TYPE_RXDATA == ds.getType()) { final int rxData = ds.getData(); rxDataHex = integerToHexString(rxData, (bitCount / 4) + bitAdder); rxDataBin = integerToBinString(rxData, bitCount); rxDataDec = String.valueOf(rxData); rxDataASCII = toASCII((char) rxData); } else /* if ( UARTData.UART_TYPE_TXDATA == ds.getType() ) */ { final int txData = ds.getData(); txDataHex = integerToHexString(txData, (bitCount / 4) + bitAdder); txDataBin = integerToBinString(txData, bitCount); txDataDec = String.valueOf(txData); txDataASCII = toASCII(txData); } tr = aParent.addChild(TR); tr.addChild(TD).addContent(String.valueOf(i)); tr.addChild(TD) .addContent(Unit.Time.format(aDataSet.getTime(ds.getStartSampleIndex()))); tr.addChild(TD).addContent("0x", rxDataHex); tr.addChild(TD).addContent("0b", rxDataBin); tr.addChild(TD).addContent(rxDataDec); tr.addChild(TD).addContent(rxDataASCII); tr.addChild(TD).addContent("0x", txDataHex); tr.addChild(TD).addContent("0b", txDataBin); tr.addChild(TD).addContent(txDataDec); tr.addChild(TD).addContent(txDataASCII); } } } return null; } }; if (aFile == null) { final HtmlExporter exporter = createHtmlTemplate(ExportUtils.createHtmlExporter()); return exporter.toString(macroResolver); } else { final HtmlFileExporter exporter = (HtmlFileExporter) createHtmlTemplate(ExportUtils.createHtmlExporter(aFile)); exporter.write(macroResolver); exporter.close(); } return null; } }
/** * Dialog box to get configuration options for client application. This class provides a standard * dialog box which allows the user to select the location of the database (which may be a physical * file in local mode, or the address (and, optionally, the port) of the server. The user can, of * course, cancel, in which case the application should not start (this is at the applications * discretion though - the business logic could be changed later in the calling class to decide to * start the application anyway if there configuration info can be loaded from file).<br> */ public class DatabaseLocationDialog extends WindowAdapter implements ActionListener, Observer { /* * The strings for the title and buttons in the dialog box. While these * could be hard coded in the application, having them here makes it * easier to use internationalization options such as a ResourceBundle. */ private static final String TITLE = "Please enter database location"; private static final String CONNECT = "Connect"; private static final String EXIT = "Exit"; /* * Some values for possible port ranges so we can determine what sort of * port the user has specified. */ private static final int LOWEST_PORT = 0; private static final int HIGHEST_PORT = 65535; private static final int SYSTEM_PORT_BOUNDARY = 1024; private static final int IANA_PORT_BOUNDARY = 49151; /* * The bits and pieces that comprise our dialog box. They are all global so * we can disable them or enable them as the user enters valid information. */ private JOptionPane options = null; private JDialog dialog = null; private JButton connectButton = new JButton(CONNECT); private JButton exitButton = new JButton(EXIT); /* * The common panel that is used by both the client and the server for * specifying where the database is. */ private ConfigOptions configOptions = null; /* * Flags to show whether enough information has been provided for us to * start the application. */ private boolean validDb = false; private boolean validPort = false; private boolean validCnx = false; /* * Details specified in the configOptions pane detailing where the database * is. */ private String location = null; private String port = null; private ConnectionType networkType = null; /* * The Logger instance. All log messages from this class are routed through * this member. The Logger namespace is <code>sampleproject.gui</code>. */ private Logger log = Logger.getLogger("sampleproject.gui"); /** * Creates a dialog where the user can specify the location of the database,including the type of * network connection (if this is a networked client)and IP address and port number; or search and * select the database on a local drive if this is a standalone client. * * @param parent Defines the Component that is to be the parent of this dialog box. For * information on how this is used, see <code>JOptionPane</code> * @param connectionMode Specifies the type of connection (standalone or networked) * @see JOptionPane */ public DatabaseLocationDialog(Frame parent, ApplicationMode connectionMode) { configOptions = (new ConfigOptions(connectionMode)); configOptions.getObservable().addObserver(this); // load saved configuration SavedConfiguration config = SavedConfiguration.getSavedConfiguration(); // the port and connection type are irrelevant in standalone mode if (connectionMode == ApplicationMode.STANDALONE_CLIENT) { validPort = true; validCnx = true; networkType = ConnectionType.DIRECT; location = config.getParameter(SavedConfiguration.DATABASE_LOCATION); } else { // there may not be a network connectivity type defined and, if // not, we do not set a default - force the user to make a choice // the at least for the first time they run this. String tmp = config.getParameter(SavedConfiguration.NETWORK_TYPE); if (tmp != null) { try { networkType = ConnectionType.valueOf(tmp); configOptions.setNetworkConnection(networkType); validCnx = true; } catch (IllegalArgumentException e) { log.warning("Unknown connection type: " + networkType); } } // there is always at least a default port number, so we don't have // to validate this. port = config.getParameter(SavedConfiguration.SERVER_PORT); configOptions.setPortNumberText(port); validPort = true; location = config.getParameter(SavedConfiguration.SERVER_ADDRESS); } // there may not be a default database location, so we had better // validate before using the returned value. if (location != null) { configOptions.setLocationFieldText(location); validDb = true; } options = new JOptionPane(configOptions, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION); connectButton.setActionCommand(CONNECT); connectButton.addActionListener(this); boolean allValid = validDb && validPort && validCnx; connectButton.setEnabled(allValid); exitButton.setActionCommand(EXIT); exitButton.addActionListener(this); options.setOptions(new Object[] {connectButton, exitButton}); dialog = options.createDialog(parent, TITLE); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); dialog.addWindowListener(this); dialog.setVisible(true); } // Note: we can get away with not specifying the parameters in these // callback methods, as they are specified in the interfaces we are // implementing. /** * Callback event handler to process situations where the user has closed the window rather than * clicking one of the buttons. */ public void windowClosing(WindowEvent we) { processCommand(EXIT); } /** Callback event handler to process clicks on any of the buttons. */ public void actionPerformed(ActionEvent ae) { processCommand(ae.getActionCommand()); } /** * Common event handling code - can handle desirable actions (such as buttons being clicked) and * undesirable actions (the window being closed) all in a common location. * * @param command a String representing the action that occurred. */ private void processCommand(String command) { dialog.setVisible(false); if (CONNECT.equals(command)) { options.setValue(JOptionPane.OK_OPTION); } else { options.setValue(JOptionPane.CANCEL_OPTION); } } /** * Callback method to process modifications in the common ConfigOptions panel. ConfigOptions was * developed to be common to many applications (even though we only have three modes), so it does * not have any knowledge of how we are using it within this dialog box. So ConfigOptions just * sends updates to registered Observers whenever anything changes. We can receive those * notifications here, and decide whether we have enough information to enable the "Connect" * button of the dialog box. */ public void update(Observable o, Object arg) { // we are going to ignore the Observable object, since we are only // observing one object. All we are interested in is the argument. if (!(arg instanceof OptionUpdate)) { log.log( Level.WARNING, "DatabaseLocationDialog received update type: " + arg, new IllegalArgumentException()); return; } OptionUpdate optionUpdate = (OptionUpdate) arg; // load saved configuration SavedConfiguration config = SavedConfiguration.getSavedConfiguration(); switch (optionUpdate.getUpdateType()) { case DB_LOCATION_CHANGED: location = (String) optionUpdate.getPayload(); if (configOptions.getApplicationMode() == ApplicationMode.STANDALONE_CLIENT) { File f = new File(location); if (f.exists() && f.canRead() && f.canWrite()) { validDb = true; log.info("File chosen " + location); config.setParameter(SavedConfiguration.DATABASE_LOCATION, location); } else { log.warning("Invalid file " + location); } } else { try { if (location.matches("\\d+\\.\\d+\\.\\d+\\.\\d+")) { // location given matches 4 '.' separated numbers // regex could be improved by limiting each quad to // no more than 3 digits. String[] quads = location.split("\\."); byte[] address = new byte[quads.length]; for (int i = 0; i < quads.length; i++) { address[i] = new Integer(quads[i]).byteValue(); } InetAddress.getByAddress(address); } else { InetAddress.getAllByName(location); } log.info("Server specified " + location); validDb = true; config.setParameter(SavedConfiguration.SERVER_ADDRESS, location); } catch (UnknownHostException uhe) { log.warning("Unknown host: " + location); validDb = false; } } break; case PORT_CHANGED: port = (String) optionUpdate.getPayload(); int p = Integer.parseInt(port); if (p >= LOWEST_PORT && p < HIGHEST_PORT) { if (p < SYSTEM_PORT_BOUNDARY) { log.info("User chose System port " + port); } else if (p < IANA_PORT_BOUNDARY) { log.info("User chose IANA port " + port); } else { log.info("User chose dynamic port " + port); } validPort = true; config.setParameter(SavedConfiguration.SERVER_PORT, port); } else { validPort = false; } break; case NETWORK_CHOICE_MADE: networkType = (ConnectionType) optionUpdate.getPayload(); switch (networkType) { case SOCKET: log.info("Server connection via Sockets"); break; case RMI: log.info("Server connection via RMI"); break; default: log.info("Unknown connection type: " + networkType); break; } config.setParameter(SavedConfiguration.NETWORK_TYPE, "" + networkType); validCnx = true; break; default: log.warning("Unknown update: " + optionUpdate); break; } boolean allValid = validDb && validPort && validCnx; connectButton.setEnabled(allValid); } /** * Returns the location of the database, which may be either the path to the local database, or * the address of the network server hosting the database. * * @return the location of the database. */ public String getLocation() { return location; } /** * Returns the port number the network server should be listening on for client connections. * * @return the port number for connecting to the network server. */ public String getPort() { return port; } /** * Returns the type of network connection (Sockets, RMI ...) that should be used to connect to the * server. * * @return the network protocol used to connect to the server. */ public ConnectionType getNetworkType() { return networkType; } /** * Let the caller of this dialog know whether the user connected or cancelled. * * @return true if the user cancelled or closed the window. */ public boolean userCanceled() { if (options.getValue() instanceof Integer) { int status = ((Integer) options.getValue()).intValue(); return status != JOptionPane.OK_OPTION; } else { return false; } } }
/** * @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(); } }