diff --git a/src/net/java/sip/communicator/impl/contactlist/MetaContactImpl.java b/src/net/java/sip/communicator/impl/contactlist/MetaContactImpl.java index cbead6e9a..6f490a7c6 100644 --- a/src/net/java/sip/communicator/impl/contactlist/MetaContactImpl.java +++ b/src/net/java/sip/communicator/impl/contactlist/MetaContactImpl.java @@ -272,6 +272,72 @@ public Contact getDefaultContact() return defaultContact; } + /** + * Returns a default contact for a specific operation (call, + * file transfert, IM ...) + * + * @param operationSet the operation for which the default contact is needed + * @return the default contact for the specified operation. + */ + public Contact getDefaultContact(Class operationSet) + { + Contact defaultOpSetContact = null; + try + { + // if the current default contact supports the requested information + // we use it + if (getDefaultContact().getProtocolProvider() + .getOperationSet(Class.forName(operationSet.getName())) + != null) + { + defaultOpSetContact = getDefaultContact(); + } + else + { + for (int i = 0; i < this.protoContacts.size(); i++) + { + PresenceStatus currentStatus = null; + Contact protoContact = (Contact)this.protoContacts.get(i); + + // we filter to care only about contact which support + // the needed opset. + if (protoContact.getProtocolProvider() + .getOperationSet( + Class.forName(operationSet.getName())) != null) + { + PresenceStatus contactStatus + = protoContact.getPresenceStatus(); + + if (currentStatus != null) + { + if (currentStatus.getStatus() + < contactStatus.getStatus()) + { + currentStatus = contactStatus; + defaultOpSetContact = protoContact; + } + } + else + { + currentStatus = contactStatus; + defaultOpSetContact = protoContact; + } + } + } + } + } + catch (ClassNotFoundException ex) + { + logger.info("cannot find a default " + operationSet.getName() + + " contact for " + + this, ex); + } + finally + { + return defaultOpSetContact; + } + } + /** * Returns a String identifier (the actual contents is left to * implementations) that uniquely represents this MetaContact in 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 0bd384efa..1ad468d48 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 @@ -443,18 +443,9 @@ public void updateCallAccountStatus(ProtocolProviderService pps) */ private Contact getTelephonyContact(MetaContact metaContact) { - Iterator i = metaContact.getContacts(); - while (i.hasNext()) - { - Contact contact = (Contact) i.next(); - - OperationSetBasicTelephony telephony = mainFrame - .getTelephonyOpSet(contact.getProtocolProvider()); + return metaContact.getDefaultContact( + OperationSetBasicTelephony.class); - if (telephony != null) - return contact; - } - return null; } /** @@ -757,6 +748,19 @@ public void createCall(String contact) new CreateCallThread(contact, callPanel).start(); } + /** + * Call the specified contact. + * @param contact the contact to call. + */ + public void createCall(Contact contact) + { + CallPanel callPanel = new CallPanel(this, contact); + + mainFrame.addCallPanel(callPanel); + + new CreateCallThread(contact, callPanel).start(); + } + /** * Creates a call to the given list of contacts. * @@ -784,6 +788,8 @@ private class CreateCallThread String stringContact; OperationSetBasicTelephony telephony; + + Contact contact; public CreateCallThread(String contact, CallPanel callPanel) { @@ -803,6 +809,15 @@ public CreateCallThread(Vector contacts, CallPanel callPanel) telephony = mainFrame.getTelephonyOpSet(selectedCallProvider); } + public CreateCallThread(Contact contact, CallPanel callPanel) + { + this.contact = contact; + this.callPanel = callPanel; + + if (selectedCallProvider != null) + telephony = mainFrame.getTelephonyOpSet(selectedCallProvider); + } + public void run() { if (telephony == null) @@ -810,7 +825,44 @@ public void run() Call createdCall = null; - if (contacts != null) + if (contact != null) + { + try + { + createdCall = telephony.createCall(contact); + } + catch (OperationFailedException e) + { + logger.error("The call could not be created: " + e); + + // well, what if we try with the contact own telephony + // if it's different + OperationSetBasicTelephony tel + = (OperationSetBasicTelephony) contact.getProtocolProvider() + .getOperationSet(OperationSetBasicTelephony.class); + + if (tel != telephony) + logger.info("perpahps it would be better to use " + + "the contact own telephony " + tel); + + 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 if (contacts != null) { Contact contact = (Contact) contacts.get(0); 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 e4ae2fb37..557a591b1 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 @@ -70,7 +70,23 @@ public CallPanel(CallManager callManager, Call call, String callType) this.getViewport().add(mainPanel); } - + + public CallPanel(CallManager callManager, Contact contact) + { + this.callManager = callManager; + + this.mainPanel.setBorder( + BorderFactory.createEmptyBorder(20, 10, 20, 10)); + + this.title = contact.getDisplayName(); + + this.mainPanel.setLayout(new BorderLayout()); + + this.addCallParticipant(contact.getDisplayName(), callType); + + this.getViewport().add(mainPanel); + } + /** * Creates an instance of CallPanel for the given call and call type. * @param callManager the CallManager that manages this panel diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatContactPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatContactPanel.java index 684bf30ff..2b3f7e63a 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatContactPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatContactPanel.java @@ -16,8 +16,10 @@ import net.java.sip.communicator.impl.gui.customcontrols.*; import net.java.sip.communicator.impl.gui.i18n.*; import net.java.sip.communicator.impl.gui.lookandfeel.*; +import net.java.sip.communicator.impl.gui.main.call.*; import net.java.sip.communicator.impl.gui.main.chat.conference.*; import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.protocol.*; /** @@ -126,8 +128,31 @@ public ChatContactPanel(ChatPanel chatPanel, ChatContact contact) this.add(mainPanel, BorderLayout.CENTER); // Disabled all unused buttons. - this.callButton.setEnabled(false); - this.sendFileButton.setEnabled(false); + + ProtocolProviderService pps = chatContact.getProtocolProvider(); + + if (chatContact.getSourceContact() instanceof Contact) + { + Contact c = (Contact) chatContact.getSourceContact(); + MetaContact m = chatPanel.getChatWindow().getMainFrame() + .getContactList().findMetaContactByContact(c); + + if (m.getDefaultContact(OperationSetBasicTelephony.class) + == null) + this.callButton.setEnabled(false); + + if (m.getDefaultContact(OperationSetFileTransfer.class) + == null) + this.sendFileButton.setEnabled(false); + } + else + { + if (pps.getOperationSet(OperationSetBasicTelephony.class) == null) + this.callButton.setEnabled(false); + + if (pps.getOperationSet(OperationSetFileTransfer.class) == null) + this.sendFileButton.setEnabled(false); + } //Load the contact photo. new Thread() @@ -151,9 +176,6 @@ public void run() } }.start(); - ProtocolProviderService pps - = chatContact.getProtocolProvider(); - Object contactInfoOpSet = pps.getOperationSet(OperationSetWebContactInfo.class); @@ -215,9 +237,33 @@ public void actionPerformed(ActionEvent evt) { JButton button = (JButton) evt.getSource(); + // first, see if the contact with which we chat supports telephony + // and call that one. If he don't, we look for the default + // telephony contact in its enclosing metacontact if(button.getName().equals("call")) { - //TODO: Implement the call functionality. + CallManager cm = + chatPanel.getChatWindow().getMainFrame().getCallManager(); + Object o = chatContact.getSourceContact(); + + OperationSetBasicTelephony opSetBT + = (OperationSetBasicTelephony) chatContact.getProtocolProvider() + .getOperationSet(OperationSetBasicTelephony.class); + + if (opSetBT != null) + { + if (o instanceof Contact) + cm.createCall((Contact)chatContact.getSourceContact()); + else // hope an appropriate telephony will be used. + cm.createCall(((ChatRoomMember) o).getContactAddress()); + } + else if (o instanceof Contact) + { + MetaContact m = chatPanel.getChatWindow().getMainFrame() + .getContactList().findMetaContactByContact((Contact)o); + cm.createCall( + m.getDefaultContact(OperationSetBasicTelephony.class)); + } } else if(button.getName().equals("info")) { diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatSendPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatSendPanel.java index 269582405..e4de8d37d 100755 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatSendPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatSendPanel.java @@ -99,16 +99,31 @@ public void setStatusMessage(String statusMessage) { int stringWidth = GuiUtils.getStringWidth(statusLabel, statusMessage); - while (stringWidth > statusPanel.getWidth() - 10) { - if (statusMessage.endsWith("...")) { - statusMessage = statusMessage.substring(0, - statusMessage.indexOf("...") - 1).concat("..."); - } - else { - statusMessage = statusMessage.substring(0, - statusMessage.length() - 3).concat("..."); + int dot3 = GuiUtils.getStringWidth(statusLabel, "... "); + + // first, we avoid to loop if it is useless. + if (dot3 >= statusPanel.getWidth()) + { + if (stringWidth > dot3) + statusMessage = "..."; + } + else + { + while ((stringWidth > (statusPanel.getWidth() - dot3)) + && (statusMessage != "...")) + { + if (statusMessage.endsWith("...")) + { + statusMessage = statusMessage.substring(0, + statusMessage.indexOf("...") - 1).concat("..."); + } + else + { + statusMessage = statusMessage.substring(0, + statusMessage.length() - 3).concat("..."); + } + stringWidth = GuiUtils.getStringWidth(statusLabel, statusMessage); } - stringWidth = GuiUtils.getStringWidth(statusLabel, statusMessage); } statusLabel.setText(statusMessage); } diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactList.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactList.java index 7e62fdfe4..44a5835c0 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactList.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactList.java @@ -639,8 +639,9 @@ else if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) contactRightButtonMenu.setInvoker(this); - contactRightButtonMenu.setLocation(selectedCellPoint.x, - selectedCellPoint.y + renderer.getHeight()); + Point p = new Point(e.getPoint()); + SwingUtilities.convertPointToScreen(p, this); + contactRightButtonMenu.setLocation(p); contactRightButtonMenu.setVisible(true); } diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactRightButtonMenu.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactRightButtonMenu.java index fd6ac10a8..d83ec7afb 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactRightButtonMenu.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactRightButtonMenu.java @@ -57,7 +57,10 @@ public class ContactRightButtonMenu private I18NString removeContactString = Messages.getI18NString("removeContact"); - + + private I18NString callString + = Messages.getI18NString("call"); + private I18NString sendMessageString = Messages.getI18NString("sendMessage"); @@ -85,6 +88,10 @@ public class ContactRightButtonMenu private SIPCommMenu removeContactMenu = new SIPCommMenu(removeContactString.getText()); + private JMenuItem callItem = new JMenuItem( + callString.getText(), + new ImageIcon(ImageLoader.getImage(ImageLoader.CALL_16x16_ICON))); + private JMenuItem sendMessageItem = new JMenuItem( sendMessageString.getText(), new ImageIcon(ImageLoader.getImage(ImageLoader.SEND_MESSAGE_16x16_ICON))); @@ -284,6 +291,7 @@ private void init() { } this.add(sendMessageItem); + this.add(callItem); this.add(sendFileItem); this.addSeparator(); @@ -308,6 +316,7 @@ private void init() { this.initPluginComponents(); this.sendMessageItem.setName("sendMessage"); + this.callItem.setName("call"); this.sendFileItem.setName("sendFile"); this.moveToMenu.setName("moveToGroup"); this.addSubcontactMenu.setName("addSubcontact"); @@ -316,13 +325,22 @@ private void init() { this.userInfoMenu.setName("userInfo"); this.sendMessageItem.addActionListener(this); + this.callItem.addActionListener(this); this.sendFileItem.addActionListener(this); this.renameContactItem.addActionListener(this); this.viewHistoryItem.addActionListener(this); this.userInfoMenu.addActionListener(this); // Disable all menu items that do nothing. - this.sendFileItem.setEnabled(false); + if (contactItem.getDefaultContact(OperationSetFileTransfer.class) + == null) + this.sendFileItem.setEnabled(false); + if (contactItem.getDefaultContact(OperationSetBasicTelephony.class) + == null) + this.callItem.setEnabled(false); + if (contactItem.getDefaultContact(OperationSetBasicInstantMessaging.class) + == null) + this.sendMessageItem.setEnabled(false); } private void initPluginComponents() @@ -350,6 +368,7 @@ private void initPluginComponents() private void initMnemonics() { this.sendMessageItem.setMnemonic(sendMessageString.getMnemonic()); + this.callItem.setMnemonic(sendMessageString.getMnemonic()); this.sendFileItem.setMnemonic(sendFileString.getMnemonic()); this.moveToMenu.setMnemonic(moveToString.getMnemonic()); this.addSubcontactMenu.setMnemonic(addSubcontactString.getMnemonic()); @@ -369,6 +388,7 @@ public void actionPerformed(ActionEvent e){ JMenuItem menuItem = (JMenuItem) e.getSource(); String itemName = menuItem.getName(); String itemText = menuItem.getText(); + Contact cont = null; if (itemName.startsWith(addSubcontactPrefix)) { @@ -396,6 +416,19 @@ else if (itemName.equalsIgnoreCase("sendMessage")) SwingUtilities.invokeLater(clistPanel.new RunMessageWindow( contactItem)); } + else if (itemName.equalsIgnoreCase("call")) + { + cont = contactItem.getDefaultContact( + OperationSetBasicTelephony.class); + if (cont != null) + { + Vector v = new Vector(); + v.add(cont); + mainFrame.getCallManager().createCall(v); + // wow, it's really tricky, I wonder there isn't a simple method + // CallManager#createCall(Contact contact); + } + } else if (itemName.equalsIgnoreCase("sendFile")) { // disabled diff --git a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java index 21c5a617a..ccd413bb3 100644 --- a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java +++ b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java @@ -768,6 +768,13 @@ public class ImageLoader { public static final ImageID SEND_MESSAGE_16x16_ICON = new ImageID("SEND_MESSAGE_16x16_ICON"); + /** + * Call 16x16 image. + * //TODO : change to an appropriate logo + */ + public static final ImageLoader.ImageID CALL_16x16_ICON + = new ImageID("SIP_COMMUNICATOR_LOGO"); + /** * Delete 16x16 image. */ @@ -933,6 +940,7 @@ public class ImageLoader { public static final ImageID SMILEY12 = new ImageID("SMILEY12"); + /** * Load default smilies pack. * diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java index 7a55758f6..3ab551539 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java @@ -107,12 +107,9 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt) { if ((evt.getNewState() == RegistrationState.REGISTERED)) { - // NOTE: a null stun server is provided here _intentionally_ - // it may cause some exceptions, it's temporary - logger.warn("warning: we will use a null stun server ***"); transportManager = new ICETransportManager( protocolProvider.getConnection(), - null, 3478); + "stun.iptel.org", 3478); jingleManager = new JingleManager( protocolProvider.getConnection(), @@ -598,11 +595,7 @@ public void beforeChange(JingleNegotiator.State oldState , JingleNegotiator.State newState) throws JingleNegotiator.JingleException { - if (newState instanceof IncomingJingleSession.Accepting) - {} - else if (newState instanceof IncomingJingleSession.Pending) - {} - else if (newState instanceof IncomingJingleSession.Active) + if (newState instanceof IncomingJingleSession.Active) { JingleSession session = (JingleSession) newState.getNegotiator(); @@ -650,22 +643,6 @@ else if (newState instanceof OutgoingJingleSession.Active) } callParticipant.setState(CallParticipantState.CONNECTED); } -// else if (newState instanceof MediaNegotiator.Inviting) -// {} -// else if (newState instanceof MediaNegotiator.Pending) -// {} -// else if (newState instanceof MediaNegotiator.Accepting) -// {} -// else if (newState instanceof MediaNegotiator.Active) -// {} -// else if (newState instanceof TransportNegotiator.Inviting) -// {} -// else if (newState instanceof TransportNegotiator.Pending) -// {} -// else if (newState instanceof TransportNegotiator.Accepting) -// {} -// else if (newState instanceof TransportNegotiator.Active) -// {} if ((newState == null) && (oldState != null)) { //hanging diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java index 52d854c94..d05cd313d 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java @@ -266,6 +266,11 @@ public ChatRoom findRoom(String roomName) //make sure we are connected and multichat is supported. assertSupportedAndConnected(); +// return (ChatRoom)chatRoomCache.get(roomName); + +// XXX is the following behaviour correct ? in the test if finding +// an unexisting room return anything other than null, the test fails. + //first check whether we have already initialized the room. ChatRoom room = (ChatRoom)chatRoomCache.get(roomName); diff --git a/src/net/java/sip/communicator/service/contactlist/MetaContact.java b/src/net/java/sip/communicator/service/contactlist/MetaContact.java index 8330f6f44..09a23272e 100644 --- a/src/net/java/sip/communicator/service/contactlist/MetaContact.java +++ b/src/net/java/sip/communicator/service/contactlist/MetaContact.java @@ -30,6 +30,15 @@ public interface MetaContact extends Comparable */ public Contact getDefaultContact(); + /** + * Returns the default protocol specific Contact to use with this + * MetaContact for a precise operation (IM, call, ...). + * + * @param operationSet the operation for which the default contact is needed + * @return the default contact for the specified operation. + */ + public Contact getDefaultContact(Class operationSet); + /** * Returns a java.util.Iterator with all protocol specific * Contacts encapsulated by this MetaContact.