diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallComboBox.java b/src/net/java/sip/communicator/impl/gui/main/call/CallComboBox.java new file mode 100644 index 000000000..d0bb1c47f --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallComboBox.java @@ -0,0 +1,276 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.call; + +import java.awt.*; +import java.awt.event.*; +import java.beans.*; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.swing.AbstractListModel; +import javax.swing.ComboBoxEditor; +import javax.swing.MutableComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JTextField; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import net.java.sip.communicator.impl.gui.main.contactlist.*; +import net.java.sip.communicator.service.contactlist.*; + +/** + * The CallComboBox is a history editable combo box that is positioned + * above call and hangup buttons and is used when writing a number or a contact + * name in order to be called. + * + * @author Yana Stamcheva + */ +public class CallComboBox + extends JComboBox + implements ActionListener, + FocusListener +{ + + private ArrayList historyList = new ArrayList(); + + private CallManager callManager; + + public CallComboBox(CallManager callManager) { + + this.callManager = callManager; + + historyList.add("gigi@ekyga.net"); + historyList.add("sc3@voipgw.u-strasbg.fr"); + + setModel(new FilterableComboBoxModel(historyList)); + setEditor(new CallComboEditor()); + setEditable(true); + setFocusable(true); + + this.addActionListener(this); + this.getEditor().getEditorComponent().addFocusListener(this); + } + + /** + * Checks if this combo box editor field is empty. This will be the case if + * the user hasn't selected an item from the combobox and hasn't written + * anything the field. + * + * @return TRUE if the combobox editor field is empty, otherwise FALSE + */ + public boolean isComboFieldEmpty() + { + String item = ((CallComboEditor)this.getEditor()).getItem().toString(); + + if(item.length() > 0) + return false; + else + return true; + } + + /** + * Handles events triggered by user selection. Enables the call button + * when user selects something the combo box. + */ + public void actionPerformed(ActionEvent e) + { + if(!isComboFieldEmpty()) { + + callManager.setCallMetaContact(false); + callManager.getCallButton().setEnabled(true); + } + } + + public void focusGained(FocusEvent e) + { + this.callManager.setCallMetaContact(false); + + ContactList clist = this.callManager.getMainFrame() + .getContactListPanel().getContactList(); + clist.removeSelectionInterval( + clist.getSelectedIndex(), clist.getSelectedIndex()); + } + + public void focusLost(FocusEvent e) + {} + + public class FilterableComboBoxModel extends AbstractListModel + implements MutableComboBoxModel { + + private List items; + private Filter filter; + private List filteredItems; + private Object selectedItem; + + public FilterableComboBoxModel(List items) { + + this.items = new ArrayList(items); + filteredItems = new ArrayList(items.size()); + updateFilteredItems(); + } + + public void addElement( Object obj ) { + + items.add(obj); + updateFilteredItems(); + } + + public void removeElement( Object obj ) { + + items.remove(obj); + updateFilteredItems(); + } + + public void removeElementAt(int index) { + + items.remove(index); + updateFilteredItems(); + } + + public void insertElementAt( Object obj, int index ) {} + + public void setFilter(Filter filter) { + + this.filter = filter; + updateFilteredItems(); + } + + protected void updateFilteredItems() { + + fireIntervalRemoved(this, 0, filteredItems.size()); + filteredItems.clear(); + + if (filter == null) + filteredItems.addAll(items); + else { + for (Iterator iterator = items.iterator(); iterator.hasNext();) { + + Object item = iterator.next(); + + if (filter.accept(item)) + filteredItems.add(item); + } + } + fireIntervalAdded(this, 0, filteredItems.size()); + } + + public int getSize() { + return filteredItems.size(); + } + + public Object getElementAt(int index) { + return filteredItems.get(index); + } + + public Object getSelectedItem() { + return selectedItem; + } + + public void setSelectedItem(Object val) { + + if ((selectedItem == null) && (val == null)) + return; + + if ((selectedItem != null) && selectedItem.equals(val)) + return; + + if ((val != null) && val.equals(selectedItem)) + return; + + selectedItem = val; + fireContentsChanged(this, -1, -1); + } + } + + public static interface Filter { + public boolean accept(Object obj); + } + + class StartsWithFilter implements Filter { + + private String prefix; + public StartsWithFilter(String prefix) { this.prefix = prefix; } + public boolean accept(Object o) { return o.toString().startsWith(prefix); } + } + + public class CallComboEditor + implements ComboBoxEditor, DocumentListener + { + private JTextField text; + private volatile boolean filtering = false; + private volatile boolean setting = false; + + public CallComboEditor() { + + text = new JTextField(15); + text.getDocument().addDocumentListener(this); + } + + public Component getEditorComponent() { return text; } + + public void setItem(Object item) { + + if(filtering) + return; + + setting = true; + String newText = (item == null) ? "" : item.toString(); + text.setText(newText); + setting = false; + } + + public Object getItem() { + return text.getText(); + } + + public void selectAll() { text.selectAll(); } + + public void addActionListener(ActionListener l) { + text.addActionListener(l); + } + + public void removeActionListener(ActionListener l) { + text.removeActionListener(l); + } + + public void insertUpdate(DocumentEvent e) { handleChange(); } + public void removeUpdate(DocumentEvent e) { handleChange(); } + public void changedUpdate(DocumentEvent e) { } + + protected void handleChange() { + if (setting) + return; + + filtering = true; + + Filter filter = null; + if (text.getText().length() > 0) { + filter = new StartsWithFilter(text.getText()); + + callManager.setCallMetaContact(false); + + callManager.getCallButton().setEnabled(true); + } + else { + Object o = callManager.getMainFrame().getContactListPanel() + .getContactList().getSelectedValue(); + + if(o == null || !(o instanceof MetaContact)) + callManager.getCallButton().setEnabled(false); + } + + ((FilterableComboBoxModel) getModel()).setFilter(filter); + // A bit nasty but it seems to get the popup validated properly + setPopupVisible(false); + setPopupVisible(true); + filtering = false; + } + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java b/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java index 7c5f34d63..4e6d460fd 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java @@ -12,28 +12,35 @@ import java.util.*; import javax.swing.*; +import javax.swing.Timer; +import javax.swing.event.*; import net.java.sip.communicator.impl.gui.customcontrols.*; +import net.java.sip.communicator.impl.gui.i18n.*; import net.java.sip.communicator.impl.gui.main.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.protocol.*; -import java.text.*; - +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; /** - * The CallPanel is the panel that contains the "Call" and "Hangup" - * buttons, as well as the field, where user could enter the phone number or - * the contact name of the person, to which he would like to call. + * The CallManager 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 + implements ActionListener, + CallListener, + ListSelectionListener, + ChangeListener { + private Logger logger = Logger.getLogger(CallManager.class.getName()); - private JComboBox phoneNumberCombo = new JComboBox(); + private CallComboBox phoneNumberCombo; private JPanel comboPanel = new JPanel(new BorderLayout()); @@ -64,9 +71,11 @@ public class CallManager private Hashtable activeCalls = new Hashtable(); private boolean isShown; + + private boolean isCallMetaContact; /** - * Creates an instance of CallPanel. + * Creates an instance of CallManager. * @param mainFrame The main application window. */ public CallManager(MainFrame mainFrame) @@ -75,6 +84,8 @@ public CallManager(MainFrame mainFrame) this.mainFrame = mainFrame; + phoneNumberCombo = new CallComboBox(this); + this.buttonsPanel .setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); @@ -89,7 +100,7 @@ public CallManager(MainFrame mainFrame) private void init() { this.phoneNumberCombo.setEditable(true); - + this.comboPanel.add(phoneNumberCombo, BorderLayout.CENTER); // this.add(comboPanel, BorderLayout.NORTH); @@ -105,41 +116,60 @@ private void init() this.buttonsPanel.add(callButton); this.buttonsPanel.add(hangupButton); + + this.callButton.setEnabled(false); + + this.hangupButton.setEnabled(false); this.add(minimizeButtonPanel, BorderLayout.SOUTH); } - /** - * 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 getPhoneNumberCombo() - { - return phoneNumberCombo; - } - + /** * Handles the ActionEvent generated when user presses one of the * buttons in this panel. */ - public void actionPerformed(ActionEvent e) + public void actionPerformed(ActionEvent evt) { - JButton button = (JButton) e.getSource(); + JButton button = (JButton) evt.getSource(); String buttonName = button.getName(); - if (buttonName.equalsIgnoreCase("call")) { + if (buttonName.equals("call")) { OperationSetBasicTelephony telephony; - - Object o = mainFrame.getContactListPanel() - .getContactList().getSelectedValue(); - - if(o != null && o instanceof MetaContact) { + + Object o = mainFrame.getContactListPanel().getContactList() + .getSelectedValue(); + + //call button is pressed over an already open call panel + if(mainFrame.getSelectedCallPanel() != null + && mainFrame.getSelectedCallPanel().getCallType() + == CallPanel.INCOMING_CALL + && mainFrame.getSelectedCallPanel().getCall().getCallState() + == CallState.CALL_INITIALIZATION) { + + CallPanel callPanel = mainFrame.getSelectedCallPanel(); + + Call call = callPanel.getCall(); + + ProtocolProviderService pps + = call.getProtocolProvider(); + + Iterator participants = call.getCallParticipants(); + + while(participants.hasNext()) { + CallParticipant participant + = (CallParticipant)participants.next(); + answerCall(pps, participant); + } + } + //call button is pressed when a meta contact is selected + else if(isCallMetaContact && o != null && o instanceof MetaContact) { + MetaContact metaContact = (MetaContact)o; - Contact contact - = getTelephonyContact(metaContact); - + Contact contact = getTelephonyContact(metaContact); + if(contact != null) { telephony = mainFrame.getTelephony(contact.getProtocolProvider()); @@ -149,24 +179,30 @@ public void actionPerformed(ActionEvent e) createdCall = telephony.createCall(contact); CallPanel callPanel = new CallPanel( - createdCall, CallPanel.OUTGOING_CALL); + this, createdCall, CallPanel.OUTGOING_CALL); + mainFrame.addCallPanel(callPanel); activeCalls.put(createdCall, callPanel); } - catch (OperationFailedException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); + catch (OperationFailedException e) { + logger.error("The call could not be created: " + e); } } else { - //Message to user which says "This contact could not be called!" + JOptionPane.showMessageDialog(this.mainFrame, + Messages.getString("contactNotSupportingTelephony"), + Messages.getString("warning"), + JOptionPane.WARNING_MESSAGE); } } - else if(phoneNumberCombo.getSelectedItem() != null) { + //if no contact is selected checks if the user has chosen or has + //writen something in the phone combo box + else if(!phoneNumberCombo.isComboFieldEmpty()) { + ProtocolProviderService pps = getDefaultTelephonyProvider(); - + if(pps != null) { telephony = mainFrame.getTelephony(pps); @@ -176,27 +212,50 @@ else if(phoneNumberCombo.getSelectedItem() != null) { phoneNumberCombo.getSelectedItem().toString()); CallPanel callPanel = new CallPanel( - createdCall, CallPanel.OUTGOING_CALL); + this, createdCall, CallPanel.OUTGOING_CALL); + mainFrame.addCallPanel(callPanel); activeCalls.put(createdCall, callPanel); } - catch (OperationFailedException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); + catch (OperationFailedException e) { + logger.error("The call could not be created: " + e); } - catch (ParseException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); + catch (ParseException e) { + logger.error("The call could not be created: " + e); } } } - else { - //Message to user which says "You must select a contact to call or enter a phone number" - } } else if (buttonName.equalsIgnoreCase("hangup")) { - + CallPanel selectedCallPanel = this.mainFrame.getSelectedCallPanel(); + + if(selectedCallPanel != null) { + Call call = selectedCallPanel.getCall(); + + ProtocolProviderService pps + = call.getProtocolProvider(); + + OperationSetBasicTelephony telephony + = mainFrame.getTelephony(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); + } + } + + activeCalls.remove(call); + mainFrame.removeCallPanel(selectedCallPanel); + updateButtonsStateAccordingToSelectedPanel(); + } } else if (buttonName.equalsIgnoreCase("minimize")) { @@ -225,34 +284,6 @@ else if (buttonName.equalsIgnoreCase("restore")) { } } - /** - * Returns TRUE if this panel is visible, FALSE otherwise. - * @return TRUE if this panel is visible, FALSE otherwise - */ - public boolean isShown() - { - return this.isShown; - } - - /** - * When TRUE shows this panel, when FALSE hides it. - * @param isShown - */ - public void setShown(boolean isShown) - { - this.isShown = isShown; - - if(isShown) { - this.add(comboPanel, BorderLayout.NORTH); - this.add(buttonsPanel, BorderLayout.CENTER); - - this.minimizeButtonPanel.add(minimizeButton); - } - else { - this.minimizeButtonPanel.add(restoreButton); - } - } - /** * For the given MetaContact returns the protocol contact that supports * a basic telephony operation. @@ -263,19 +294,15 @@ public void setShown(boolean isShown) private Contact getTelephonyContact( MetaContact metaContact) { - String telephonySet - = OperationSetBasicTelephony.class.getName(); - Iterator i = metaContact.getContacts(); while(i.hasNext()) { Contact contact = (Contact)i.next(); - if(contact.getProtocolProvider() - .getSupportedOperationSets() - .containsKey(telephonySet)) { - + OperationSetBasicTelephony telephony + = mainFrame.getTelephony(contact.getProtocolProvider()); + + if(telephony != null) return contact; - } } return null; } @@ -294,7 +321,7 @@ private ProtocolProviderService getDefaultTelephonyProvider() { while(i.hasNext()) { ProtocolProviderService pps = (ProtocolProviderService) i.next(); - + if(pps.getSupportedOperationSets() .containsKey(telephonySet)) { return pps; @@ -302,4 +329,212 @@ private ProtocolProviderService getDefaultTelephonyProvider() { } return null; } + + /** + * 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, CallPanel.INCOMING_CALL); + + mainFrame.addCallPanel(callPanel); + + this.callButton.setEnabled(true); + this.hangupButton.setEnabled(true); + + SoundLoader.playInLoop(Constants.getDefaultIncomingCallAudio(), 2000); + + activeCalls.put(sourceCall, callPanel); + } + + /** + * 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) + { + SoundLoader.getSound(SoundLoader.BUSY).stop(); + SoundLoader.stop(Constants.getDefaultIncomingCallAudio()); + + Call sourceCall = event.getSourceCall(); + + if(activeCalls.get(sourceCall) != null) { + CallPanel callPanel = (CallPanel)activeCalls.get(sourceCall); + this.removeCallPanel(callPanel); + } + } + + public void outgoingCallCreated(CallEvent event) + {} + + /** + * Removes the given call panel tab. + * @param callPanel the CallPanel to remove + */ + public void removeCallPanel(CallPanel callPanel) + { + Timer timer = new Timer(5000, new RemoveCallPanelListener(callPanel)); + + timer.setRepeats(false); + timer.start(); + } + + + /** + * 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) + { + activeCalls.remove(callPanel.getCall()); + mainFrame.removeCallPanel(callPanel); + updateButtonsStateAccordingToSelectedPanel(); + } + } + + /** + * 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); + callButton.setEnabled(true); + } + 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(); + } + + private void updateButtonsStateAccordingToSelectedPanel() + { + if(mainFrame.getSelectedCallPanel() != null) { + 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 getPhoneNumberCombo() + { + return phoneNumberCombo; + } + + /** + * Returns TRUE if this panel is visible, FALSE otherwise. + * @return TRUE if this panel is visible, FALSE otherwise + */ + public boolean isShown() + { + return this.isShown; + } + + /** + * When TRUE shows this panel, when FALSE hides it. + * @param isShown + */ + public void setShown(boolean isShown) + { + this.isShown = isShown; + + if(isShown) { + this.add(comboPanel, BorderLayout.NORTH); + this.add(buttonsPanel, BorderLayout.CENTER); + + this.minimizeButtonPanel.add(minimizeButton); + } + else { + this.minimizeButtonPanel.add(restoreButton); + } + } + + /** + * Answers the given callParticipant. + * @param pps the protocol provider to use + * @param callParticipant the call participant to answer to + */ + public void answerCall(ProtocolProviderService pps, + CallParticipant callParticipant) + { + OperationSetBasicTelephony telephony = mainFrame.getTelephony(pps); + + try { + telephony.answerCallParticipant(callParticipant); + } + catch (OperationFailedException e) { + logger.error("Could not answer to : " + callParticipant + + " caused by the following exception: " + e); + } + } + + public boolean isCallMetaContact() + { + return isCallMetaContact; + } + + public void setCallMetaContact(boolean isCallMetaContact) + { + this.isCallMetaContact = isCallMetaContact; + } + } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java index 66e85516d..643490706 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java @@ -6,43 +6,283 @@ */ package net.java.sip.communicator.impl.gui.main.call; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + import javax.swing.*; +import javax.swing.Timer; +import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +/** + * The CallPanel is the panel containing call information. It's created + * and added to the main tabbed pane when user makes or receives calls. It + * shows information about call participants, call duration, etc. + * + * @author Yana Stamcheva + */ public class CallPanel - extends JPanel + extends JScrollPane + implements CallChangeListener, + CallParticipantListener { public static final String INCOMING_CALL = "IncomingCall"; public static final String OUTGOING_CALL = "OutgoingCall"; + private JPanel mainPanel = new JPanel(); + + private Hashtable participantsPanels = new Hashtable(); + + private CallManager callManager; + + private String title; + private Call call; - public CallPanel(Call call, String callType) + private String callType; + + /** + * Creates an instance of CallPanel for the given call and call type. + * @param call the call + * @param callType INCOMING_CALL and OUTGOING_CALL + */ + public CallPanel(CallManager callManager, Call call, String callType) { this.call = call; - if(callType.equals(INCOMING_CALL)) { - this.processIncomingCall(); - } - else { - this.processOutgoingCall(); - } + this.callType = callType; + + this.callManager = callManager; + this.call.addCallChangeListener(this); + + this.mainPanel.setBorder( + BorderFactory.createEmptyBorder(20, 10, 20, 10)); + + int participantsCount = call.getCallParticipantsCount(); + + if(participantsCount > 0) { + CallParticipant participant + = ((CallParticipant)call.getCallParticipants().next()); + + if(participant.getDisplayName() != null) + this.title = participant.getDisplayName(); + else + this.title = participant.getAddress(); + + if(participantsCount < 2) { + this.mainPanel.setLayout(new BorderLayout()); + } + else { + int rows = participantsCount/2 + participantsCount%2; + this.mainPanel.setLayout(new GridLayout(rows, 2)); + } + } + + this.getViewport().add(mainPanel); + + this.init(); } - private void processIncomingCall() - { + /** + * Initializes all panels which will contain participants information. + */ + public void init() + { + Iterator i = call.getCallParticipants(); + + while(i.hasNext()) { + CallParticipant participant = (CallParticipant)i.next(); + this.addCallParticipant(participant); + } } - private void processOutgoingCall() + /** + * Cteates and adds a panel for a call participant. + * + * @param participant the call participant + */ + private void addCallParticipant(CallParticipant participant) { + if(participantsPanels.get(participant) != null) + return; + + CallParticipantPanel participantPanel + = new CallParticipantPanel(participant); + this.mainPanel.add(participantPanel); + this.participantsPanels.put(participant, participantPanel); + + participant.addCallParticipantListener(this); } + /** + * Returns the title of this call panel. The title is now the name of the + * first participant in the list of the call participants. Should be + * improved in the future. + * + * @return the title of this call panel + */ public String getTitle() { - return null; + return title; + } + + /** + * Implements the CallChangeListener.callParticipantAdded method. + * When a new participant is added to our call add it to the call panel. + */ + public void callParticipantAdded(CallParticipantEvent evt) + { + if(evt.getSourceCall() == call) { + this.addCallParticipant(evt.getSourceCallParticipant()); + this.revalidate(); + this.repaint(); + } + } + + /** + * Implements the CallChangeListener.callParticipantRemoved method. + * When a call participant is removed from our call remove it from the + * call panel. + */ + public void callParticipantRemoved(CallParticipantEvent evt) + { + if(evt.getSourceCall() == call) { + CallParticipant participant = evt.getSourceCallParticipant(); + + CallParticipantPanel participantPanel + = (CallParticipantPanel)participantsPanels.get(participant); + + if(participantPanel != null) { + + CallParticipantState state = participant.getState(); + + participantPanel.setState(state.getStateString()); + + participantPanel.stopCallTimer(); + + this.participantsPanels.remove(participant); + + if(participantsPanels.size() == 0) + this.callManager.removeCallPanel(this); + else { + Timer timer = new Timer(5000, + new RemoveParticipantPanelListener(participantPanel)); + + timer.setRepeats(false); + timer.start(); + } + + this.revalidate(); + this.repaint(); + } + } + } + + public void callStateChanged(CallChangeEvent evt) + { + } + + /** + * Implements the CallParicipantChangeListener.participantStateChanged + * method. + */ + public void participantStateChanged(CallParticipantChangeEvent evt) + { + CallParticipant sourceParticipant = evt.getSourceCallParticipant(); + + if(sourceParticipant.getCall() != call) + return; + + CallParticipantPanel participantPanel + = (CallParticipantPanel)participantsPanels.get(sourceParticipant); + + participantPanel.setState( + sourceParticipant.getState().getStateString()); + + if(evt.getNewValue() == CallParticipantState.ALERTING_REMOTE_SIDE) { + SoundLoader.playInLoop( + Constants.getDefaultOutgoingCallAudio(), 3000); + } + else if(evt.getNewValue() == CallParticipantState.BUSY) { + SoundLoader.stop(Constants.getDefaultOutgoingCallAudio()); + SoundLoader.getSound(SoundLoader.BUSY).loop(); + } + else if(evt.getNewValue() == CallParticipantState.CONNECTED) { + //start the timer that takes care of refreshing the time label + participantPanel.startCallTimer(); + } + else if(evt.getNewValue() == CallParticipantState.CONNECTING) { + } + else if(evt.getNewValue() == CallParticipantState.DISCONNECTED) { + //The call participant should be already removed from the call + //see callParticipantRemoved + } + else if(evt.getNewValue() == CallParticipantState.FAILED) { + //The call participant should be already removed from the call + //see callParticipantRemoved + } + else if(evt.getNewValue() == CallParticipantState.INCOMING_CALL) { + } + else if(evt.getNewValue() == CallParticipantState.INITIATING_CALL) { + } + else if(evt.getNewValue() == CallParticipantState.ON_HOLD) { + } + else if(evt.getNewValue() == CallParticipantState.UNKNOWN) { + } + } + + public void participantDisplayNameChanged(CallParticipantChangeEvent evt) + { + } + + public void participantAddressChanged(CallParticipantChangeEvent evt) + { } + + public void participantImageChanged(CallParticipantChangeEvent evt) + { + } + + /** + * Returns the call for this call panel. + * @return the call for this call panel + */ + public Call getCall() + { + return call; + } + + /** + * Removes the given CallParticipant panel from this CallPanel. + */ + private class RemoveParticipantPanelListener implements ActionListener + { + private JPanel participantPanel; + public RemoveParticipantPanelListener(JPanel participantPanel) + { + this.participantPanel = participantPanel; + } + + public void actionPerformed(ActionEvent e) + { + mainPanel.remove(participantPanel); + } + } + + /** + * Returns this call type : INCOMING_CALL or OUTGOING_CALL + * @return Returns this call type : INCOMING_CALL or OUTGOING_CALL + */ + public String getCallType() + { + return callType; + } + + } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallParticipantPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/CallParticipantPanel.java new file mode 100644 index 000000000..38bd14abd --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallParticipantPanel.java @@ -0,0 +1,137 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.call; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; + +import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.protocol.*; + +/** + * The CallParticipantPanel is the panel containing data for a call + * participant in a given call. It contains information like call participant + * name, photo, call duration, etc. + * + * @author Yana Stamcheva + */ +public class CallParticipantPanel extends JPanel +{ + JPanel contactPanel = new JPanel(new BorderLayout()); + + JPanel namePanel = new JPanel(new GridLayout(0, 1)); + + JLabel nameLabel = new JLabel("", JLabel.CENTER); + + JLabel timeLabel = new JLabel("00:00:00", JLabel.CENTER); + + JLabel photoLabel = new JLabel(new ImageIcon( + ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO))); + + Timer timer = new Timer(1000, new CallTimerListener()); + + JLabel stateLabel; + + /** + * Creates a CallParticipantPanel for the given call participant. + * + * @param participant the call participant + */ + public CallParticipantPanel(CallParticipant participant) + { + super(new BorderLayout()); + + stateLabel = new JLabel(participant.getState().getStateString(), + JLabel.CENTER); + + timer.setRepeats(true); + + if(participant.getDisplayName() != null) + nameLabel.setText(participant.getDisplayName()); + else + nameLabel.setText(participant.getAddress()); + + namePanel.add(nameLabel); + namePanel.add(stateLabel); + namePanel.add(timeLabel); + + contactPanel.add(photoLabel, BorderLayout.CENTER); + contactPanel.add(namePanel, BorderLayout.SOUTH); + + this.add(contactPanel, BorderLayout.NORTH); + this.setPreferredSize(new Dimension(100, 200)); + } + + /** + * Sets the state of the contained call participant. + * @param state the state of the contained call participant + */ + public void setState(String state) + { + this.stateLabel.setText(state); + } + + /** + * Starts the timer that counts call duration. + */ + public void startCallTimer() + { + timer.start(); + } + + /** + * Stops the timer that counts call duration. + */ + public void stopCallTimer() + { + timer.stop(); + } + + /** + * Each second refreshes the time label to show to the user the exact + * duration of the call. + */ + private class CallTimerListener implements ActionListener + { + private int timer = 0; + + public void actionPerformed(ActionEvent e) + { + timer ++; + int s = timer%60; + int m = (timer - s)/60; + int h = m/60; + + timeLabel.setText(processTime(h) + + ":" + processTime(m) + + ":" + processTime(s)); + } + } + + /** + * Adds a 0 in the beginning of one digit numbers. + * + * @param time The time parameter could be hours, minutes or seconds. + * @return The formatted minutes string. + */ + private String processTime(int time) + { + String timeString = new Integer(time).toString(); + + String resultString = ""; + if (timeString.length() < 2) + resultString = resultString.concat("0").concat(timeString); + else + resultString = timeString; + + return resultString; + } + + +} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallReceivePanel.java b/src/net/java/sip/communicator/impl/gui/main/call/CallReceivePanel.java deleted file mode 100644 index 8b8d5d002..000000000 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallReceivePanel.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -package net.java.sip.communicator.impl.gui.main.call; - -import java.awt.*; -import javax.swing.*; - -import net.java.sip.communicator.impl.gui.customcontrols.*; -import net.java.sip.communicator.impl.gui.main.*; -import net.java.sip.communicator.impl.gui.utils.*; - -/** - * - * @author Yana Stamcheva - */ -public class CallReceivePanel extends JDialog { - - private Image callButtonBG = ImageLoader - .getImage(ImageLoader.CALL_BUTTON_BG); - - private Image callButtonRolloverBG = ImageLoader - .getImage(ImageLoader.CALL_ROLLOVER_BUTTON_BG); - - private Image hangupButtonBG = ImageLoader - .getImage(ImageLoader.HANGUP_BUTTON_BG); - - private Image hangupButtonRolloverBG = ImageLoader - .getImage(ImageLoader.HANGUP_ROLLOVER_BUTTON_BG); - - private JLabel personPhoto = new JLabel(new ImageIcon(ImageLoader - .getImage(ImageLoader.DEFAULT_USER_PHOTO))); - - private JLabel personName = new JLabel("John Smith"); - - private JLabel birthDate = new JLabel("11/11/1900"); - - private JLabel emptyLabel = new JLabel(" "); - - private JLabel personInfo = new JLabel("additional info"); - - private SIPCommButton callButton; - - private SIPCommButton hangupButton; - - private JPanel userInfoPanel = new JPanel(); - - private JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, - 15, 5)); - - public CallReceivePanel(MainFrame parent) { - - super(parent); - - this.setSize(300, 200); - - this.getContentPane().setLayout(new BorderLayout()); - - callButton = new SIPCommButton(callButtonBG, callButtonRolloverBG); - - hangupButton = new SIPCommButton( - hangupButtonBG, hangupButtonRolloverBG); - - this.init(); - } - - public void init() { - this.personName.setFont(new Font("Sans Serif", Font.BOLD, 12)); - - // this.buttonsPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, - // 0, Color.GRAY)); - this.buttonsPanel.add(callButton); - this.buttonsPanel.add(hangupButton); - - this.userInfoPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, - 0)); - this.userInfoPanel.setLayout(new BoxLayout(userInfoPanel, - BoxLayout.Y_AXIS)); - - this.userInfoPanel.add(personName); - this.userInfoPanel.add(birthDate); - this.userInfoPanel.add(emptyLabel); - this.userInfoPanel.add(personInfo); - - this.getContentPane().add(personPhoto, BorderLayout.WEST); - this.getContentPane().add(userInfoPanel, BorderLayout.CENTER); - this.getContentPane().add(buttonsPanel, BorderLayout.SOUTH); - } -}