diff options
Diffstat (limited to 'src/net/java/sip')
60 files changed, 3565 insertions, 1135 deletions
diff --git a/src/net/java/sip/communicator/impl/callhistory/CallHistoryContactSource.java b/src/net/java/sip/communicator/impl/callhistory/CallHistoryContactSource.java index cc6ede3..db504f9 100644 --- a/src/net/java/sip/communicator/impl/callhistory/CallHistoryContactSource.java +++ b/src/net/java/sip/communicator/impl/callhistory/CallHistoryContactSource.java @@ -274,13 +274,23 @@ public class CallHistoryContactSource } /** - * Returns the identifier of this contact source. Some of the common - * identifiers are defined here (For example the CALL_HISTORY identifier - * should be returned by all call history implementations of this interface) - * @return the identifier of this contact source + * Returns default type to indicate that this contact source can be queried + * by default filters. + * + * @return the type of this contact source */ - public String getIdentifier() + public int getType() { - return CALL_HISTORY; + return HISTORY_TYPE; + } + + /** + * Returns the index of the contact source in the result list. + * + * @return the index of the contact source in the result list + */ + public int getIndex() + { + return 0; } } diff --git a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsSourceService.java b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsSourceService.java index 7ce8ead..c946514 100644 --- a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsSourceService.java +++ b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsSourceService.java @@ -319,14 +319,13 @@ public class GoogleContactsSourceService } /** - * Returns the identifier of this contact source. Some of the common - * identifiers are defined here (For example the CALL_HISTORY identifier - * should be returned by all call history implementations of this interface) + * Returns SEARCH_TYPE to indicate that this contact source + * * @return the identifier of this contact source */ - public String getIdentifier() + public int getType() { - return "GoogleContacts"; + return SEARCH_TYPE; } /** @@ -416,4 +415,14 @@ public class GoogleContactsSourceService { this.phoneNumberprefix = phoneNumberprefix; } + + /** + * Returns the index of the contact source in the result list. + * + * @return the index of the contact source in the result list + */ + public int getIndex() + { + return -1; + } } diff --git a/src/net/java/sip/communicator/impl/gui/GuiActivator.java b/src/net/java/sip/communicator/impl/gui/GuiActivator.java index 026dd4a..1ec9479 100644 --- a/src/net/java/sip/communicator/impl/gui/GuiActivator.java +++ b/src/net/java/sip/communicator/impl/gui/GuiActivator.java @@ -313,7 +313,8 @@ public class GuiActivator implements BundleActivator * <tt>protocolName</tt> and supporting the given <tt>operationSetClass</tt> */ public static List<ProtocolProviderService> getRegisteredProviders( - String protocolName, Class<? extends OperationSet> operationSetClass) + String protocolName, + Class<? extends OperationSet> operationSetClass) { List<ProtocolProviderService> opSetProviders = new LinkedList<ProtocolProviderService>(); diff --git a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java index 58b2e3d..a0f2eb9 100644 --- a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java +++ b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java @@ -56,7 +56,8 @@ import com.explodingpixels.macwidgets.*; */ public class MainFrame extends SIPCommFrame - implements ExportedWindow, + implements ContactListContainer, + ExportedWindow, PluginComponentListener, Skinnable { @@ -96,7 +97,7 @@ public class MainFrame /** * The search field shown above the contact list. */ - private final SearchField searchField; + private SearchField searchField; /** * A mapping of <tt>ProtocolProviderService</tt>s and their indexes. @@ -165,6 +166,11 @@ public class MainFrame private CallListener uiCallListener; /** + * Contact list search key dispatcher; + */ + private final ContactListSearchKeyDispatcher clKeyDispatcher; + + /** * Creates an instance of <tt>MainFrame</tt>. */ public MainFrame() @@ -174,12 +180,12 @@ public class MainFrame this.setUndecorated(true); } - this.searchField = new SearchField(this); - this.contactListPanel = new ContactListPane(this); this.accountStatusPanel = new AccountStatusPanel(this); + this.searchField = new SearchField(this, TreeContactList.searchFilter); + menu = new MainMenu(this); /* @@ -233,7 +239,11 @@ public class MainFrame KeyboardFocusManager keyManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); - keyManager.addKeyEventDispatcher(new MainKeyDispatcher(keyManager)); + + clKeyDispatcher = new ContactListSearchKeyDispatcher( keyManager, + searchField, + this); + keyManager.addKeyEventDispatcher(clKeyDispatcher); this.init(); @@ -471,6 +481,9 @@ public class MainFrame public void setContactList(MetaContactListService contactList) { contactListPanel.initList(contactList); + + searchField.setContactList(GuiActivator.getContactList()); + clKeyDispatcher.setContactList(GuiActivator.getContactList()); } /** @@ -1826,144 +1839,11 @@ public class MainFrame } /** - * The <tt>MainKeyDispatcher</tt> is added to pre-listen KeyEvents before - * they're delivered to the current focus owner in order to introduce a - * specific behavior for the <tt>SearchField</tt> on top of the contact - * list. - */ - private class MainKeyDispatcher implements KeyEventDispatcher - { - private KeyboardFocusManager keyManager; - - /** - * Creates an instance of <tt>MainKeyDispatcher</tt>. - * @param keyManager the parent <tt>KeyboardFocusManager</tt> - */ - public MainKeyDispatcher(KeyboardFocusManager keyManager) - { - this.keyManager = keyManager; - } - - /** - * Dispatches the given <tt>KeyEvent</tt>. - * @param e the <tt>KeyEvent</tt> to dispatch - * @return <tt>true</tt> if the KeyboardFocusManager should take no - * further action with regard to the KeyEvent; <tt>false</tt> - * otherwise - */ - public boolean dispatchKeyEvent(KeyEvent e) - { - // If this window is not the focus window or if the event is not - // of type PRESSED we have nothing more to do here. - if (!isFocused() - || (e.getID() != KeyEvent.KEY_PRESSED - && e.getID() != KeyEvent.KEY_TYPED) - || (GuiActivator.getUIService() - .getSingleWindowContainer() != null) - && GuiActivator.getUIService() - .getSingleWindowContainer().containsFocus()) - return false; - - // Ctrl-Enter || Cmd-Enter typed when this window is the focused - // window. - // - // Tried to make this with key bindings first, but has a problem - // with enter key binding. When the popup menu containing call - // contacts was opened the default keyboard manager was prioritizing - // the window ENTER key, which will open a chat and we wanted that - // the enter starts a call with the selected contact from the menu. - // This is why we need to do it here and to check if the - // permanent focus owner is equal to the focus owner, which is not - // the case when a popup menu is opened. - if (e.getKeyCode() == KeyEvent.VK_ENTER - && (e.isControlDown() || e.isMetaDown())) - { - ctrlEnterKeyTyped(); - return false; - } - else if (e.getKeyCode() == KeyEvent.VK_ENTER - && keyManager.getFocusOwner() - .equals(keyManager.getPermanentFocusOwner())) - { - enterKeyTyped(); - return false; - } - - TreeContactList contactList - = getContactListPanel().getContactList(); - - // If the search field is the focus owner. - if (searchField.isFocusOwner() - && (e.getKeyCode() == KeyEvent.VK_UP - || e.getKeyCode() == KeyEvent.VK_DOWN - || e.getKeyCode() == KeyEvent.VK_PAGE_UP - || e.getKeyCode() == KeyEvent.VK_PAGE_DOWN)) - { - contactList.selectFirstContact(); - contactList.requestFocus(); - return false; - } - - // If the contact list is the focus owner. - if (contactList.isFocusOwner() - && e.getKeyCode() == KeyEvent.VK_ESCAPE) - { - // Removes all current selections. - contactList.removeSelectionRows(contactList.getSelectionRows()); - - if (searchField.getText() != null) - { - searchField.requestFocus(); - } - return false; - } - - Object selectedObject = contactList.getSelectedValue(); - - // No matter who is the focus owner. - if (e.getKeyChar() == KeyEvent.CHAR_UNDEFINED - || e.getKeyCode() == KeyEvent.VK_ENTER - || e.getKeyCode() == KeyEvent.VK_DELETE - || e.getKeyCode() == KeyEvent.VK_BACK_SPACE - || e.getKeyCode() == KeyEvent.VK_TAB - || e.getKeyCode() == KeyEvent.VK_SPACE - || (selectedObject != null - && selectedObject instanceof GroupNode - && (e.getKeyChar() == '+' - || e.getKeyChar() == '-'))) - { - return false; - } - - boolean singleWindowRule - = GuiActivator.getUIService().getSingleWindowContainer() == null - || contactList.isFocusOwner(); - - if (!searchField.isFocusOwner() - && keyManager.getFocusOwner() != null - && singleWindowRule - && keyManager.getFocusOwner() - .equals(keyManager.getPermanentFocusOwner())) - { - // Request the focus in the search field if a letter is typed. - searchField.requestFocusInWindow(); - - // We re-dispatch the event to search field. - keyManager.redispatchEvent(searchField, e); - - // We don't want to dispatch further this event. - return true; - } - return false; - } - } - - /** * Called when the ENTER key was typed when this window was the focused * window. Performs the appropriate actions depending on the current state * of the contact list. */ - private void enterKeyTyped() + public void enterKeyTyped() { if (unknownContactPanel != null && unknownContactPanel.isVisible()) { 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 dbd7e98..c7d2928 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 @@ -19,7 +19,9 @@ import net.java.sip.communicator.impl.gui.main.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.ServerStoredDetails.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.service.protocol.media.*; import net.java.sip.communicator.util.Logger; @@ -1333,6 +1335,95 @@ public class CallManager } /** + * Searches for additional phone numbers found in contact information + * @return additional phone numbers found in contact information; + */ + public static List<UIContactDetail> getAdditionalNumbers( + MetaContact metaContact) + { + List<UIContactDetail> telephonyContacts + = new ArrayList<UIContactDetail>(); + + Iterator<Contact> contacts = metaContact.getContacts(); + + while(contacts.hasNext()) + { + Contact contact = contacts.next(); + OperationSetServerStoredContactInfo infoOpSet = + contact.getProtocolProvider().getOperationSet( + OperationSetServerStoredContactInfo.class); + Iterator<GenericDetail> details; + ArrayList<String> phones = new ArrayList<String>(); + + if(infoOpSet != null) + { + details = infoOpSet.getAllDetailsForContact(contact); + + while(details.hasNext()) + { + GenericDetail d = details.next(); + if(d instanceof PhoneNumberDetail && + !(d instanceof PagerDetail) && + !(d instanceof FaxDetail)) + { + PhoneNumberDetail pnd = (PhoneNumberDetail)d; + if(pnd.getNumber() != null && + pnd.getNumber().length() > 0) + { + String localizedType = null; + + if(d instanceof WorkPhoneDetail) + { + localizedType = + GuiActivator.getResources(). + getI18NString( + "service.gui.WORK_PHONE"); + } + else if(d instanceof MobilePhoneDetail) + { + localizedType = + GuiActivator.getResources(). + getI18NString( + "service.gui.MOBILE_PHONE"); + } + else + { + localizedType = + GuiActivator.getResources(). + getI18NString( + "service.gui.PHONE"); + } + + phones.add(pnd.getNumber()); + + UIContactDetail cd = + new UIContactDetailImpl( + pnd.getNumber(), + pnd.getNumber() + + " (" + localizedType + ")", + null, + new ArrayList<String>(), + null, + null, + null, + pnd) + { + public PresenceStatus getPresenceStatus() + { + return null; + } + }; + telephonyContacts.add(cd); + } + } + } + } + } + + return telephonyContacts; + } + + /** * Adds a missed call notification. * * @param peerName the name of the peer diff --git a/src/net/java/sip/communicator/impl/gui/main/call/ReceivedCallDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/ReceivedCallDialog.java index 81807bc..071acd9 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/ReceivedCallDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/ReceivedCallDialog.java @@ -13,7 +13,6 @@ import java.util.*; import javax.swing.*; import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java index 2446722..9ead3b8 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java @@ -8,15 +8,15 @@ package net.java.sip.communicator.impl.gui.main.call; import java.awt.*;
import java.awt.event.*;
-import java.util.*;
import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*;
import net.java.sip.communicator.impl.gui.utils.*;
-import net.java.sip.communicator.service.contactlist.*;
+import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
/**
- * Represents a <code>Dialog</code> which allows specifying the target contact
+ * Represents a <tt>Dialog</tt> which allows specifying the target contact
* address of a transfer-call operation.
*
* @author Yana Stamcheva
@@ -25,6 +25,11 @@ public class TransferCallDialog extends OneChoiceInviteDialog
{
/**
+ * The peer to transfer.
+ */
+ private final CallPeer transferPeer;
+
+ /**
* Creates a <tt>TransferCallDialog</tt> by specifying the peer to transfer
* @param peer the peer to transfer
*/
@@ -33,6 +38,8 @@ public class TransferCallDialog super(GuiActivator.getResources()
.getI18NString("service.gui.TRANSFER_CALL_TITLE"));
+ this.transferPeer = peer;
+
this.initContactListData(peer.getProtocolProvider());
this.setInfoText(GuiActivator.getResources()
@@ -52,16 +59,11 @@ public class TransferCallDialog CallManager.transferCall(peer, transferString);
else
{
- MetaContact metaContact = getSelectedMetaContact();
+ UIContact uiContact = getSelectedContact();
- if (metaContact != null)
+ if (uiContact != null)
{
- Iterator<Contact> contactsIter = metaContact
- .getContactsForProvider(peer.getProtocolProvider());
-
- if (contactsIter.hasNext())
- CallManager.transferCall(peer,
- contactsIter.next().getAddress());
+ transferToContact(uiContact);
}
}
setVisible(false);
@@ -81,32 +83,34 @@ public class TransferCallDialog /**
* Initializes the left contact list with the contacts that could be added
* to the current chat session.
+ *
* @param protocolProvider the protocol provider from which to initialize
* the contact list data
*/
private void initContactListData(ProtocolProviderService protocolProvider)
{
- MetaContactListService metaContactListService
- = GuiActivator.getContactListService();
-
- Iterator<MetaContact> contactListIter = metaContactListService
- .findAllMetaContactsForProvider(protocolProvider);
+ contactList.addContactSource(
+ new ProtocolContactSourceServiceImpl(
+ protocolProvider, OperationSetBasicTelephony.class));
+ contactList.addContactSource(
+ new StringContactSourceServiceImpl(
+ protocolProvider, OperationSetBasicTelephony.class));
- while (contactListIter.hasNext())
- {
- MetaContact metaContact = contactListIter.next();
-
- this.addMetaContact(metaContact);
- }
+ contactList.applyDefaultFilter();
}
- /*
- * (non-Javadoc)
- *
- * @see
- * net.java.sip.communicator.impl.gui.customcontrols.SIPCommDialog#close
- * (boolean)
+ /**
+ * Transfer the transfer peer to the given <tt>UIContact</tt>.
+ *
+ * @param uiContact the contact to transfer to
*/
- @Override
- protected void close(boolean isEscaped) {}
+ private void transferToContact(UIContact uiContact)
+ {
+ UIContactDetail contactDetail = uiContact
+ .getDefaultContactDetail(
+ OperationSetBasicTelephony.class);
+
+ CallManager.transferCall( transferPeer,
+ contactDetail.getAddress());
+ }
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java index a4d9a1f..067fa87 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java @@ -15,8 +15,10 @@ import javax.swing.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.call.*; +import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.impl.gui.utils.*; -import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.swing.*; // disambiguation @@ -51,6 +53,16 @@ public class ConferenceInviteDialog private final Call call; /** + * The current provider contact source. + */ + private ContactSourceService currentProviderContactSource; + + /** + * The current string contact source. + */ + private ContactSourceService currentStringContactSource; + + /** * Creates <tt>ConferenceInviteDialog</tt> by specifying the call, to which * the contacts are invited. * @@ -128,8 +140,6 @@ public class ConferenceInviteDialog { lastSelectedAccount = accountSelectorBoxSelectedItem; - //removeAllSelectedContacts(); - initContactListData( (ProtocolProviderService) accountSelectorBox .getSelectedItem()); @@ -141,14 +151,16 @@ public class ConferenceInviteDialog { public void actionPerformed(ActionEvent e) { - if (getSelectedMetaContacts() != null - || getSelectedStrings() != null) + Collection<UIContact> selectedContacts + = destContactList.getContacts(null); + + if (selectedContacts != null && selectedContacts.size() > 0) { ProtocolProviderService selectedProvider = (ProtocolProviderService) accountSelectorBox .getSelectedItem(); - inviteContacts(); + inviteContacts(selectedContacts); // Store the last used account in order to pre-select it // next time. @@ -226,94 +238,73 @@ public class ConferenceInviteDialog */ private void initContactListData(ProtocolProviderService protocolProvider) { - // re-init list. - this.removeAllMetaContacts(); + this.setCurrentProvider(protocolProvider); - MetaContactListService metaContactListService - = GuiActivator.getContactListService(); + srcContactList.removeContactSource(currentProviderContactSource); + srcContactList.removeContactSource(currentStringContactSource); - Iterator<MetaContact> contactListIter = metaContactListService - .findAllMetaContactsForProvider(protocolProvider); + currentProviderContactSource + = new ProtocolContactSourceServiceImpl( + protocolProvider, + OperationSetBasicTelephony.class); + currentStringContactSource + = new StringContactSourceServiceImpl( + protocolProvider, + OperationSetBasicTelephony.class); - while (contactListIter.hasNext()) - { - MetaContact metaContact = contactListIter.next(); + srcContactList.addContactSource(currentProviderContactSource); + srcContactList.addContactSource(currentStringContactSource); - if (!containsContact(metaContact)) - { - if (metaContact.getDefaultContact( - OperationSetBasicTelephony.class) != null) - addMetaContact(metaContact); - } - } + srcContactList.applyDefaultFilter(); } /** * Invites the contacts to the chat conference. + * + * @param contacts the list of contacts to invite */ - private void inviteContacts() + private void inviteContacts(Collection<UIContact> contacts) { ProtocolProviderService selectedProvider = null; - Map<ProtocolProviderService, List<String>> selectedProviderCallees = - new HashMap<ProtocolProviderService, List<String>>(); + Map<ProtocolProviderService, List<String>> selectedProviderCallees + = new HashMap<ProtocolProviderService, List<String>>(); List<String> callees = null; - // Obtain selected contacts. - Enumeration<MetaContact> selectedContacts = getSelectedMetaContacts(); + Iterator<UIContact> contactsIter = contacts.iterator(); - if (selectedContacts != null) + while (contactsIter.hasNext()) { - while (selectedContacts.hasMoreElements()) - { - MetaContact metaContact - = selectedContacts.nextElement(); + UIContact uiContact = contactsIter.next(); - Iterator<Contact> contactsIter = metaContact.getContacts(); + Iterator<UIContactDetail> contactDetailsIter = uiContact + .getContactDetailsForOperationSet( + OperationSetBasicTelephony.class).iterator(); - // We invite the first protocol contact that corresponds to the - // invite provider. - if (contactsIter.hasNext()) - { - Contact inviteContact = contactsIter.next(); - selectedProvider = inviteContact.getProtocolProvider(); - - if(selectedProviderCallees.get(selectedProvider) != null) - { - callees = selectedProviderCallees.get(selectedProvider); - } - else - { - callees = new ArrayList<String>(); - } - - callees.add(inviteContact.getAddress()); - selectedProviderCallees.put(selectedProvider, callees); - } - } - } - - // Obtain selected strings. - Enumeration<ContactWithProvider> selectedContactWithProvider = - getSelectedContactsWithProvider(); - - if (selectedContactWithProvider != null) - { - while (selectedContactWithProvider.hasMoreElements()) + // We invite the first protocol contact that corresponds to the + // invite provider. + if (contactDetailsIter.hasNext()) { - ContactWithProvider c = - selectedContactWithProvider.nextElement(); - selectedProvider = c.getProvider(); + UIContactDetail inviteDetail = contactDetailsIter.next(); + selectedProvider = inviteDetail + .getPreferredProtocolProvider( + OperationSetBasicTelephony.class); - if(selectedProviderCallees.get(selectedProvider) != null) + if (selectedProvider == null) + selectedProvider + = (ProtocolProviderService) accountSelectorBox + .getSelectedItem(); + + if(selectedProvider != null + && selectedProviderCallees.get(selectedProvider) != null) { callees = selectedProviderCallees.get(selectedProvider); } else { - callees = new ArrayList<String>(); + callees = new ArrayList<String>(); } - callees.add(c.getAddress()); + callees.add(inviteDetail.getAddress()); selectedProviderCallees.put(selectedProvider, callees); } } @@ -321,7 +312,7 @@ public class ConferenceInviteDialog if(call != null) { Map.Entry<ProtocolProviderService, List<String>> entry; - if(selectedProviderCallees.size() == 1 + if (selectedProviderCallees.size() == 1 && (entry = selectedProviderCallees.entrySet().iterator().next()) != null && call.getProtocolProvider().equals(entry.getKey())) @@ -344,6 +335,7 @@ public class ConferenceInviteDialog // one provider, normal conf call Map.Entry<ProtocolProviderService, List<String>> entry = selectedProviderCallees.entrySet().iterator().next(); + CallManager.createConferenceCall( entry.getValue().toArray( new String[entry.getValue().size()]), @@ -356,131 +348,4 @@ public class ConferenceInviteDialog } } } - - /** - * Check if the given <tt>metaContact</tt> is already contained in the call. - * - * @param metaContact the <tt>Contact</tt> to check for - * @return <tt>true</tt> if the given <tt>metaContact</tt> is already - * contained in the call, otherwise - returns <tt>false</tt> - */ - private boolean containsContact(MetaContact metaContact) - { - // If the call is not yet created we just return false. - if (call == null) - return false; - - Iterator<? extends CallPeer> callPeers = call.getCallPeers(); - - while(callPeers.hasNext()) - { - CallPeer callPeer = callPeers.next(); - - if(metaContact.containsContact(callPeer.getContact())) - return true; - } - - return false; - } - - /** - * Moves a string from left to right. - */ - @Override - protected void moveStringFromLeftToRight() - { - String newContactText = newContactField.getText(); - - ContactWithProvider c = new ContactWithProvider( - newContactText, (ProtocolProviderService) accountSelectorBox - .getSelectedItem()); - if (newContactText != null && newContactText.length() > 0) - selectedContactListModel.addElement(c); - - newContactField.setText(""); - } - - /** - * Returns an enumeration of the list of selected Strings. - * @return an enumeration of the list of selected Strings - */ - public Enumeration<ContactWithProvider> getSelectedContactsWithProvider() - { - if (selectedContactListModel.getSize() == 0) - return null; - - Vector<ContactWithProvider> selectedStrings = - new Vector<ContactWithProvider>(); - Enumeration<?> selectedContacts = selectedContactListModel.elements(); - while(selectedContacts.hasMoreElements()) - { - Object contact = selectedContacts.nextElement(); - if (contact instanceof ContactWithProvider) - selectedStrings.add((ContactWithProvider)contact); - } - - return selectedStrings.elements(); - } - - /** - * Contact with the provider to call him. - * - * @author Sebastien Vincent - */ - private class ContactWithProvider - { - /** - * The provider. - */ - private final ProtocolProviderService provider; - - /** - * The contact. - */ - private final String contact; - - /** - * Constructor. - * - * @param contact the contact - * @param provider the provider - */ - public ContactWithProvider(String contact, - ProtocolProviderService provider) - { - this.contact = contact; - this.provider = provider; - } - - /** - * Returns the contact - * - * @return the contact - */ - public String getAddress() - { - return contact; - } - - /** - * Returns the provider. - * - * @return the provider - */ - public ProtocolProviderService getProvider() - { - return provider; - } - - /** - * Returns <tt>String</tt> representation. - * - * @return <tt>String</tt> representation - */ - @Override - public String toString() - { - return contact; - } - } } diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatInviteDialog.java b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatInviteDialog.java index c9813b3..ac5996d 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatInviteDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatInviteDialog.java @@ -11,9 +11,9 @@ import java.util.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.chat.*; -import net.java.sip.communicator.impl.gui.main.contactlist.*; +import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.impl.gui.utils.*; -import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; /** @@ -70,20 +70,12 @@ public class ChatInviteDialog { this.inviteChatTransport = chatPanel.findInviteChatTransport(); - MetaContactListService metaContactListService - = GuiActivator.getContactListService(); + srcContactList.addContactSource( + new ProtocolContactSourceServiceImpl( + inviteChatTransport.getProtocolProvider(), + OperationSetMultiUserChat.class)); - Iterator<MetaContact> contactListIter = metaContactListService - .findAllMetaContactsForProvider( - inviteChatTransport.getProtocolProvider()); - - while (contactListIter.hasNext()) - { - MetaContact metaContact = contactListIter.next(); - - if(TreeContactList.presenceFilter.isMatching(metaContact)) - this.addMetaContact(metaContact); - } + srcContactList.applyDefaultFilter(); } /** @@ -91,44 +83,33 @@ public class ChatInviteDialog */ private void inviteContacts() { - java.util.List<String> selectedContactAddresses = - new ArrayList<String>(); + Collection<String> selectedContactAddresses = new ArrayList<String>(); // Obtain selected contacts. - Enumeration<MetaContact> selectedContacts = getSelectedMetaContacts(); + Iterator<UIContact> selectedContacts + = destContactList.getContacts(null).iterator(); if (selectedContacts != null) { - while (selectedContacts.hasMoreElements()) + while (selectedContacts.hasNext()) { - MetaContact metaContact - = selectedContacts.nextElement(); + UIContact uiContact = selectedContacts.next(); - Iterator<Contact> contactsIter = metaContact - .getContactsForProvider( - inviteChatTransport.getProtocolProvider()); + Iterator<UIContactDetail> contactsIter + = uiContact.getContactDetailsForOperationSet( + OperationSetMultiUserChat.class).iterator(); // We invite the first protocol contact that corresponds to the // invite provider. if (contactsIter.hasNext()) { - Contact inviteContact = contactsIter.next(); + UIContactDetail inviteDetail = contactsIter.next(); - selectedContactAddresses.add(inviteContact.getAddress()); + selectedContactAddresses.add(inviteDetail.getAddress()); } } } - // Obtain selected strings. - Enumeration<String> selectedStrings = getSelectedStrings(); - if (selectedStrings != null) - { - while (selectedStrings.hasMoreElements()) - { - selectedContactAddresses.add(selectedStrings.nextElement()); - } - } - // Invite all selected. if (selectedContactAddresses.size() > 0) { diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/CallHistoryFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/CallHistoryFilter.java index b688c21..82d93e4 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/CallHistoryFilter.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/CallHistoryFilter.java @@ -37,20 +37,17 @@ public class CallHistoryFilter addMatching(notificationSource); Collection<UIContactSource> contactSources - = GuiActivator.getContactList().getContactSources(); + = GuiActivator.getContactList() + .getContactSources(ContactSourceService.HISTORY_TYPE); // Then add Call history contact source. for (UIContactSource contactSource : contactSources) { - ContactSourceService sourceService - = contactSource.getContactSourceService(); - - if (!sourceService.getIdentifier() - .equals(ContactSourceService.CALL_HISTORY)) - continue; - // We're in a case of call history contact source. - ContactQuery query = sourceService.queryContactSource("", 50); + ContactQuery query + = contactSource.getContactSourceService() + .queryContactSource("", 50); + filterQuery.addContactQuery(query); // Add first available results. @@ -80,8 +77,8 @@ public class CallHistoryFilter { SourceContact sourceContact = (SourceContact) descriptor; - if (sourceContact.getContactSource().getIdentifier() - .equals(ContactSourceService.CALL_HISTORY)) + if (sourceContact.getContactSource().getType() + == ContactSourceService.HISTORY_TYPE) return true; } else if (uiContact instanceof NotificationContact) diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListSearchKeyDispatcher.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListSearchKeyDispatcher.java new file mode 100644 index 0000000..4ec8228 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListSearchKeyDispatcher.java @@ -0,0 +1,177 @@ +/* + * Jitsi, 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.contactlist; + +import java.awt.*; +import java.awt.event.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.service.gui.*; + +/** + * The <tt>MainKeyDispatcher</tt> is added to pre-listen KeyEvents before + * they're delivered to the current focus owner in order to introduce a + * specific behavior for the <tt>SearchField</tt> on top of the contact + * list. + * + * @author Yana Stamcheva + */ +public class ContactListSearchKeyDispatcher + implements KeyEventDispatcher +{ + /** + * The keyboard focus manager. + */ + private KeyboardFocusManager keyManager; + + /** + * The contact list on which this key dispatcher works. + */ + private ContactList contactList; + + /** + * The search field of this key dispatcher. + */ + private final SearchField searchField; + + /** + * The container of the contact list. + */ + private final ContactListContainer contactListContainer; + + /** + * Creates an instance of <tt>MainKeyDispatcher</tt>. + * @param keyManager the parent <tt>KeyboardFocusManager</tt> + */ + public ContactListSearchKeyDispatcher( KeyboardFocusManager keyManager, + SearchField searchField, + ContactListContainer container) + { + this.keyManager = keyManager; + this.searchField = searchField; + this.contactListContainer = container; + } + + /** + * Sets the contact list. + * + * @param contactList the contact list to set + */ + public void setContactList(ContactList contactList) + { + this.contactList = contactList; + } + + /** + * Dispatches the given <tt>KeyEvent</tt>. + * @param e the <tt>KeyEvent</tt> to dispatch + * @return <tt>true</tt> if the KeyboardFocusManager should take no + * further action with regard to the KeyEvent; <tt>false</tt> + * otherwise + */ + public boolean dispatchKeyEvent(KeyEvent e) + { + // If this window is not the focus window or if the event is not + // of type PRESSED we have nothing more to do here. + if (!contactListContainer.isFocused() + || (e.getID() != KeyEvent.KEY_PRESSED + && e.getID() != KeyEvent.KEY_TYPED) + || (GuiActivator.getUIService() + .getSingleWindowContainer() != null) + && GuiActivator.getUIService() + .getSingleWindowContainer().containsFocus()) + return false; + + // Ctrl-Enter || Cmd-Enter typed when this window is the focused + // window. + // + // Tried to make this with key bindings first, but has a problem + // with enter key binding. When the popup menu containing call + // contacts was opened the default keyboard manager was prioritizing + // the window ENTER key, which will open a chat and we wanted that + // the enter starts a call with the selected contact from the menu. + // This is why we need to do it here and to check if the + // permanent focus owner is equal to the focus owner, which is not + // the case when a popup menu is opened. + if (e.getKeyCode() == KeyEvent.VK_ENTER + && (e.isControlDown() || e.isMetaDown())) + { + contactListContainer.ctrlEnterKeyTyped(); + return false; + } + else if (e.getKeyCode() == KeyEvent.VK_ENTER + && keyManager.getFocusOwner() + .equals(keyManager.getPermanentFocusOwner())) + { + contactListContainer.enterKeyTyped(); + return false; + } + + // If the search field is the focus owner. + if (searchField.isFocusOwner() + && (e.getKeyCode() == KeyEvent.VK_UP + || e.getKeyCode() == KeyEvent.VK_DOWN + || e.getKeyCode() == KeyEvent.VK_PAGE_UP + || e.getKeyCode() == KeyEvent.VK_PAGE_DOWN)) + { + contactList.selectFirstContact(); + contactList.getComponent().requestFocus(); + return false; + } + + // If the contact list is the focus owner. + if (contactList.getComponent().isFocusOwner() + && e.getKeyCode() == KeyEvent.VK_ESCAPE) + { + // Removes all current selections. + contactList.removeSelection(); + + if (searchField.getText() != null) + { + searchField.requestFocus(); + } + return false; + } + + UIGroup selectedGroup = contactList.getSelectedGroup(); + + // No matter who is the focus owner. + if (e.getKeyChar() == KeyEvent.CHAR_UNDEFINED + || e.getKeyCode() == KeyEvent.VK_ENTER + || e.getKeyCode() == KeyEvent.VK_DELETE + || e.getKeyCode() == KeyEvent.VK_BACK_SPACE + || e.getKeyCode() == KeyEvent.VK_TAB + || e.getKeyCode() == KeyEvent.VK_SPACE + || (selectedGroup != null + && (e.getKeyChar() == '+' + || e.getKeyChar() == '-'))) + { + return false; + } + + boolean singleWindowRule + = GuiActivator.getUIService().getSingleWindowContainer() == null + || contactList.getComponent().isFocusOwner(); + + if (!searchField.isFocusOwner() + && keyManager.getFocusOwner() != null + && singleWindowRule + && keyManager.getFocusOwner() + .equals(keyManager.getPermanentFocusOwner())) + { + // Request the focus in the search field if a letter is typed. + searchField.requestFocusInWindow(); + + // We re-dispatch the event to search field. + keyManager.redispatchEvent(searchField, e); + + // We don't want to dispatch further this event. + return true; + } + return false; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java index 951cc1c..b6a5f75 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java @@ -26,10 +26,8 @@ import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.ServerStoredDetails.FaxDetail; import net.java.sip.communicator.service.protocol.ServerStoredDetails.GenericDetail; -import net.java.sip.communicator.service.protocol.ServerStoredDetails.MobilePhoneDetail; import net.java.sip.communicator.service.protocol.ServerStoredDetails.PagerDetail; import net.java.sip.communicator.service.protocol.ServerStoredDetails.PhoneNumberDetail; -import net.java.sip.communicator.service.protocol.ServerStoredDetails.WorkPhoneDetail; import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.skin.*; import net.java.sip.communicator.util.swing.*; @@ -203,7 +201,7 @@ public class ContactListTreeCellRenderer /** * The parent tree. */ - private TreeContactList tree; + private TreeContactList treeContactList; /** * A list of the custom action buttons. @@ -342,7 +340,7 @@ public class ContactListTreeCellRenderer boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { - this.tree = (TreeContactList)tree; + this.treeContactList = (TreeContactList) tree; this.row = row; this.isSelected = selected; this.treeNode = (TreeNode) value; @@ -406,11 +404,12 @@ public class ContactListTreeCellRenderer // contains a status message. this.initDisplayDetails(contact.getDisplayDetails()); - this.initButtonsPanel(contact); + if (this.treeContactList.isContactButtonsVisible()) + this.initButtonsPanel(contact); int avatarWidth, avatarHeight; - if (isSelected) + if (isSelected && treeContactList.isContactButtonsVisible()) { avatarWidth = EXTENDED_AVATAR_WIDTH; avatarHeight = EXTENDED_AVATAR_HEIGHT; @@ -574,7 +573,7 @@ public class ContactListTreeCellRenderer */ public int getIconWidth() { - return tree.getWidth() + 10; + return treeContactList.getWidth() + 10; } /** @@ -597,7 +596,7 @@ public class ContactListTreeCellRenderer preferredSize.height = preferredHeight; else if (contact instanceof ShowMoreContact) preferredSize.height = 18; - else if (isSelected) + else if (isSelected && treeContactList.isContactButtonsVisible()) preferredSize.height = 70; else preferredSize.height = 30; @@ -943,7 +942,7 @@ public class ContactListTreeCellRenderer addLabels(gridX); } - this.setBounds(0, 0, tree.getWidth(), getPreferredSize().height); + this.setBounds(0, 0, treeContactList.getWidth(), getPreferredSize().height); } /** @@ -1078,12 +1077,21 @@ public class ContactListTreeCellRenderer */ private void call(TreeNode treeNode) { + if (!(treeNode instanceof ContactNode)) + return; + + UIContactImpl contactDescriptor + = ((ContactNode) treeNode).getContactDescriptor(); + List<UIContactDetail> telephonyContacts - = ((ContactNode) treeNode).getContactDescriptor() - .getContactDetailsForOperationSet( + = contactDescriptor.getContactDetailsForOperationSet( OperationSetBasicTelephony.class); - telephonyContacts.addAll(getAdditionalNumbers()); + if(contactDescriptor.getDescriptor() instanceof MetaContact) + { + telephonyContacts.addAll(CallManager.getAdditionalNumbers( + (MetaContact) contactDescriptor.getDescriptor())); + } ChooseCallAccountPopupMenu chooseAccountDialog = null; @@ -1122,13 +1130,13 @@ public class ContactListTreeCellRenderer } else if (providersCount > 1) chooseAccountDialog = new ChooseCallAccountPopupMenu( - tree, detail.getAddress(), providers); + treeContactList, detail.getAddress(), providers); } } else if (telephonyContacts.size() > 1) { chooseAccountDialog - = new ChooseCallAccountPopupMenu(tree, telephonyContacts); + = new ChooseCallAccountPopupMenu(treeContactList, telephonyContacts); } // If the choose dialog is created we're going to show it. @@ -1137,10 +1145,10 @@ public class ContactListTreeCellRenderer Point location = new Point(callButton.getX(), callButton.getY() + callButton.getHeight()); - SwingUtilities.convertPointToScreen(location, tree); + SwingUtilities.convertPointToScreen(location, treeContactList); location.y = location.y - + tree.getPathBounds(tree.getSelectionPath()).y; + + treeContactList.getPathBounds(treeContactList.getSelectionPath()).y; chooseAccountDialog.showPopupMenu(location.x + 8, location.y - 8); } @@ -1152,13 +1160,19 @@ public class ContactListTreeCellRenderer */ private void callVideo(TreeNode treeNode) { + UIContactImpl contactDescriptor + = ((ContactNode) treeNode).getContactDescriptor(); + List<UIContactDetail> videoContacts - = ((ContactNode) treeNode).getContactDescriptor() - .getContactDetailsForOperationSet( + = contactDescriptor.getContactDetailsForOperationSet( OperationSetVideoTelephony.class); - if(ConfigurationManager.isRouteVideoAndDesktopUsingPhoneNumberEnabled()) - videoContacts.addAll(getAdditionalNumbers()); + if(ConfigurationManager.isRouteVideoAndDesktopUsingPhoneNumberEnabled() + && contactDescriptor.getDescriptor() instanceof MetaContact) + { + videoContacts.addAll(CallManager.getAdditionalNumbers( + (MetaContact) contactDescriptor.getDescriptor())); + } ChooseCallAccountPopupMenu chooseAccountDialog = null; @@ -1228,14 +1242,14 @@ public class ContactListTreeCellRenderer } else if (providersCount > 1) chooseAccountDialog = new ChooseCallAccountPopupMenu( - tree, detail.getAddress(), providers, + treeContactList, detail.getAddress(), providers, OperationSetVideoTelephony.class); } } else if (videoContacts.size() > 1) { chooseAccountDialog - = new ChooseCallAccountPopupMenu(tree, videoContacts, + = new ChooseCallAccountPopupMenu(treeContactList, videoContacts, OperationSetVideoTelephony.class); } @@ -1245,10 +1259,10 @@ public class ContactListTreeCellRenderer Point location = new Point(callVideoButton.getX(), callVideoButton.getY() + callVideoButton.getHeight()); - SwingUtilities.convertPointToScreen(location, tree); + SwingUtilities.convertPointToScreen(location, treeContactList); location.y = location.y - + tree.getPathBounds(tree.getSelectionPath()).y; + + treeContactList.getPathBounds(treeContactList.getSelectionPath()).y; chooseAccountDialog.showPopupMenu(location.x + 8, location.y - 8); } @@ -1262,13 +1276,19 @@ public class ContactListTreeCellRenderer */ private void shareDesktop(TreeNode treeNode) { + UIContactImpl contactDescriptor + = ((ContactNode) treeNode).getContactDescriptor(); + List<UIContactDetail> desktopContacts - = ((ContactNode) treeNode).getContactDescriptor() - .getContactDetailsForOperationSet( + = contactDescriptor.getContactDetailsForOperationSet( OperationSetDesktopSharingServer.class); - if(ConfigurationManager.isRouteVideoAndDesktopUsingPhoneNumberEnabled()) - desktopContacts.addAll(getAdditionalNumbers()); + if(ConfigurationManager.isRouteVideoAndDesktopUsingPhoneNumberEnabled() + && contactDescriptor.getDescriptor() instanceof MetaContact) + { + desktopContacts.addAll(CallManager.getAdditionalNumbers( + (MetaContact) contactDescriptor.getDescriptor())); + } ChooseCallAccountPopupMenu chooseAccountDialog = null; @@ -1338,14 +1358,14 @@ public class ContactListTreeCellRenderer } else if (providersCount > 1) chooseAccountDialog = new ChooseCallAccountPopupMenu( - tree, detail.getAddress(), providers, + treeContactList, detail.getAddress(), providers, OperationSetDesktopSharingServer.class); } } else if (desktopContacts.size() > 1) { chooseAccountDialog - = new ChooseCallAccountPopupMenu(tree, desktopContacts, + = new ChooseCallAccountPopupMenu(treeContactList, desktopContacts, OperationSetDesktopSharingServer.class); } @@ -1355,112 +1375,16 @@ public class ContactListTreeCellRenderer Point location = new Point(desktopSharingButton.getX(), desktopSharingButton.getY() + desktopSharingButton.getHeight()); - SwingUtilities.convertPointToScreen(location, tree); + SwingUtilities.convertPointToScreen(location, treeContactList); location.y = location.y - + tree.getPathBounds(tree.getSelectionPath()).y; + + treeContactList.getPathBounds(treeContactList.getSelectionPath()).y; chooseAccountDialog.showPopupMenu(location.x + 8, location.y - 8); } } /** - * Searches for additional phone numbers found in contact information - * @return additional phone numbers found in contact information; - */ - private List<UIContactDetail> getAdditionalNumbers() - { - List<UIContactDetail> telephonyContacts - = new ArrayList<UIContactDetail>(); - - // Adds additional phone numbers found in contact information - ContactNode n = (ContactNode)treeNode; - MetaContact metaContact = null; - - if(n.getContactDescriptor().getDescriptor() instanceof MetaContact) - { - metaContact = (MetaContact)n.getContactDescriptor().getDescriptor(); - Iterator<Contact> contacts = metaContact.getContacts(); - - while(contacts.hasNext()) - { - Contact contact = contacts.next(); - OperationSetServerStoredContactInfo infoOpSet = - contact.getProtocolProvider().getOperationSet( - OperationSetServerStoredContactInfo.class); - Iterator<GenericDetail> details; - ArrayList<String> phones = new ArrayList<String>(); - - if(infoOpSet != null) - { - details = infoOpSet.getAllDetailsForContact(contact); - - while(details.hasNext()) - { - GenericDetail d = details.next(); - if(d instanceof PhoneNumberDetail && - !(d instanceof PagerDetail) && - !(d instanceof FaxDetail)) - { - PhoneNumberDetail pnd = (PhoneNumberDetail)d; - if(pnd.getNumber() != null && - pnd.getNumber().length() > 0) - { - String localizedType = null; - - if(d instanceof WorkPhoneDetail) - { - localizedType = - GuiActivator.getResources(). - getI18NString( - "service.gui.WORK_PHONE"); - } - else if(d instanceof MobilePhoneDetail) - { - localizedType = - GuiActivator.getResources(). - getI18NString( - "service.gui.MOBILE_PHONE"); - } - else - { - localizedType = - GuiActivator.getResources(). - getI18NString( - "service.gui.PHONE"); - } - - phones.add(pnd.getNumber()); - - UIContactDetail cd = - new UIContactDetailImpl( - pnd.getNumber(), - pnd.getNumber() + - " (" + localizedType + ")", - null, - new ArrayList<String>(), - null, - null, - null, - pnd) - { - public PresenceStatus getPresenceStatus() - { - return null; - } - }; - telephonyContacts.add(cd); - } - } - } - } - } - } - - return telephonyContacts; - } - - /** * Shares the user desktop with the contact contained in the given * <tt>treeNode</tt>. * @@ -1506,15 +1430,15 @@ public class ContactListTreeCellRenderer popupMenu.insert(new Separator(), 1); popupMenu.setFocusable(true); - popupMenu.setInvoker(tree); + popupMenu.setInvoker(treeContactList); Point location = new Point(addContactButton.getX(), addContactButton.getY() + addContactButton.getHeight()); - SwingUtilities.convertPointToScreen(location, tree); + SwingUtilities.convertPointToScreen(location, treeContactList); location.y = location.y - + tree.getPathBounds(tree.getSelectionPath()).y; + + treeContactList.getPathBounds(treeContactList.getSelectionPath()).y; popupMenu.setLocation(location.x + 8, location.y - 8); popupMenu.setVisible(true); @@ -1694,7 +1618,7 @@ public class ContactListTreeCellRenderer { callButton.setEnabled(true); - tree.refreshContact(uiContact); + treeContactList.refreshContact(uiContact); } }); diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/GenericUIContactImpl.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/GenericUIContactImpl.java new file mode 100644 index 0000000..74ea61a --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/GenericUIContactImpl.java @@ -0,0 +1,417 @@ +/* + * Jitsi, 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.contactlist; + +import java.awt.*; +import java.util.*; +import java.util.List; + +import javax.swing.*; + +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.protocol.*; + +import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.swing.*; + +/** + * A generic full implementation of the <tt>UIContact</tt> interface. + * + * @author Yana Stamcheva + */ +public class GenericUIContactImpl + extends UIContactImpl +{ + /** + * The descriptor of the contact. + */ + private final Object descriptor; + + /** + * The parent group. + */ + private UIGroup parentGroup; + + /** + * The display name of this contact. + */ + private final String displayName; + + /** + * The display details of this contact. + */ + private String displayDetails; + + /** + * The index of the contact in its original source. + */ + private int sourceIndex; + + /** + * The list of string that correspond to this contact matches. + */ + private List<String> searchStrings; + + /** + * A map of this contact details. + */ + private Map<Class<? extends OperationSet>, List<UIContactDetail>> + contactDetails; + + private Collection<SIPCommButton> customActionButtons; + + /** + * The corresponding <tt>ContactNode</tt> in the contact list component. + */ + private ContactNode contactNode; + + /** + * The status icon of this contact. + */ + private ImageIcon statusIcon; + + /** + * The avatar icon of this contact. + */ + private ImageIcon avatarIcon; + + /** + * Creates an instance of <tt>GenericUIContactImpl</tt>. + * + * @param descriptor the descriptor of the contact + * @param parentGroup the parent group + * @param displayName the display name of the contact + */ + public GenericUIContactImpl(Object descriptor, + UIGroup parentGroup, + String displayName) + { + this.descriptor = descriptor; + this.parentGroup = parentGroup; + this.displayName = displayName; + } + + /** + * Returns the descriptor of this contact. + * + * @return the descriptor of this contact + */ + @Override + public Object getDescriptor() + { + return descriptor; + } + + /** + * Returns the display name of this contact. + * + * @return the display name of this contact + */ + @Override + public String getDisplayName() + { + return displayName; + } + + /** + * Returns the display details of this contact. These would be shown + * whenever the contact is selected. + * + * @return the display details of this contact + */ + @Override + public String getDisplayDetails() + { + return displayDetails; + } + + /** + * Sets the display details of this contact. These would be shown + * whenever the contact is selected. + * + * @param the display details of this contact + */ + public void setDisplayDetails(String displayDetails) + { + this.displayDetails = displayDetails; + } + + /** + * Returns the index of this contact in its source. + * + * @return the source index + */ + @Override + public int getSourceIndex() + { + return sourceIndex; + } + + /** + * Sets the index of this contact. + * + * @param the source index + */ + public void setSourceIndex(int index) + { + this.sourceIndex = index; + } + + /** + * Creates a tool tip for this contact. If such tooltip is + * provided it would be shown on mouse over over this <tt>UIContact</tt>. + * + * @return the tool tip for this contact descriptor + */ + @Override + public ExtendedTooltip getToolTip() + { + return null; + } + + /** + * Returns the right button menu component. + * + * @return the right button menu component + */ + @Override + public Component getRightButtonMenu() + { + return null; + } + + /** + * Returns the parent group. + * + * @return the parent group + */ + @Override + public UIGroup getParentGroup() + { + return parentGroup; + } + + /** + * Sets the parent group. + * + * @param parentGroup the parent group + */ + @Override + public void setParentGroup(UIGroup parentGroup) + { + this.parentGroup = parentGroup; + } + + /** + * Returns an <tt>Iterator</tt> over a list of the search strings of this + * contact. + * + * @return an <tt>Iterator</tt> over a list of the search strings of this + * contact + */ + @Override + public Iterator<String> getSearchStrings() + { + return searchStrings.iterator(); + } + + /** + * Sets the list of the search strings of this contact. + * + * @param strings the list of search strings of this contact + */ + public void setSearchStrings(List<String> strings) + { + this.searchStrings = strings; + } + + /** + * Returns the default <tt>ContactDetail</tt> to use for any operations + * depending to the given <tt>OperationSet</tt> class. + * + * @param opSetClass the <tt>OperationSet</tt> class we're interested in + * @return the default <tt>ContactDetail</tt> to use for any operations + * depending to the given <tt>OperationSet</tt> class + */ + @Override + public UIContactDetail getDefaultContactDetail( + Class<? extends OperationSet> opSetClass) + { + List<UIContactDetail> opSetDetails = contactDetails.get(opSetClass); + + if (opSetDetails != null && opSetDetails.size() > 0) + return opSetDetails.get(0); + + return null; + } + + /** + * Returns a list of all <tt>UIContactDetail</tt>s corresponding to the + * given <tt>OperationSet</tt> class. + * + * @param opSetClass the <tt>OperationSet</tt> class we're looking for + * @return a list of all <tt>UIContactDetail</tt>s corresponding to the + * given <tt>OperationSet</tt> class + */ + @Override + public List<UIContactDetail> getContactDetailsForOperationSet( + Class<? extends OperationSet> opSetClass) + { + return contactDetails.get(opSetClass); + } + + /** + * Returns a list of all <tt>UIContactDetail</tt>s within this + * <tt>UIContact</tt>. + * + * @return a list of all <tt>UIContactDetail</tt>s within this + * <tt>UIContact</tt> + */ + @Override + public List<UIContactDetail> getContactDetails() + { + List<UIContactDetail> details = new ArrayList<UIContactDetail>(); + + Iterator<List<UIContactDetail>> listsIter + = contactDetails.values().iterator(); + + while (listsIter.hasNext()) + { + details.addAll(listsIter.next()); + } + + return details; + } + + /** + * Returns all custom action buttons for this notification contact. + * + * @return a list of all custom action buttons for this notification contact + */ + @Override + public Collection<SIPCommButton> getContactCustomActionButtons() + { + return customActionButtons; + } + + /** + * Sets all custom action buttons for this notification contact. + * + * @param buttonsList a list of all custom action buttons for this + * notification contact + */ + public void setContactCustomActionButtons( + Collection<SIPCommButton> buttonsList) + { + this.customActionButtons = buttonsList; + } + + /** + * Adds the given <tt>detailsList</tt> for the given <tt>opSetClass</tt>. + * + * @param opSetClass the class of the OperationSet + * @param detailsList the list of contact details supported for the given + * operation set + */ + public void addContactDetails( Class<? extends OperationSet> opSetClass, + List<UIContactDetail> detailsList) + { + if (contactDetails == null) + contactDetails = new HashMap< Class<? extends OperationSet>, + List<UIContactDetail>>(); + + contactDetails.put(opSetClass, detailsList); + } + + /** + * Sets the contact details map. + * + * @param contactDetailsMap the map of contact details and corresponding + * supported operation set + */ + public void setContactDetails( Map <Class<? extends OperationSet>, + List<UIContactDetail>> contactDetailsMap) + { + contactDetails = contactDetailsMap; + } + + /** + * Returns the corresponding <tt>ContactNode</tt> from the contact list + * component. + * @return the corresponding <tt>ContactNode</tt> + */ + public ContactNode getContactNode() + { + return contactNode; + } + + /** + * Sets the corresponding <tt>ContactNode</tt>. + * @param contactNode the corresponding <tt>ContactNode</tt> + */ + public void setContactNode(ContactNode contactNode) + { + this.contactNode = contactNode; + } + + /** + * Returns the general status icon of the given UIContact. + * + * @return PresenceStatus the most "available" status from all + * sub-contact statuses. + */ + @Override + public ImageIcon getStatusIcon() + { + return statusIcon; + } + + /** + * Sets the general status icon of this contact. + * + * @return PresenceStatus The most "available" status from all + * sub-contact statuses. + */ + public void setStatusIcon(ImageIcon statusIcon) + { + this.statusIcon = statusIcon; + } + + /** + * Gets the avatar of a specific <tt>UIContact</tt> in the form of an + * <tt>ImageIcon</tt> value. + * + * @param isSelected indicates if the contact is selected + * @param width the desired icon width + * @param height the desired icon height + * @return an <tt>ImageIcon</tt> which represents the avatar of the + * specified <tt>MetaContact</tt> + */ + @Override + public ImageIcon getAvatar(boolean isSelected, int width, int height) + { + if (avatarIcon != null + && (avatarIcon.getIconWidth() > width + || avatarIcon.getIconHeight() > height)) + { + avatarIcon = ImageUtils.getScaledRoundedIcon( + avatarIcon.getImage(), width, height); + } + return avatarIcon; + } + + /** + * Sets the avatar of this <tt>UIContact</tt> in the form of an + * <tt>ImageIcon</tt> value. + * + * @param avatarIcon the avatar icon of this contact + */ + public void setAvatar(ImageIcon avatarIcon) + { + this.avatarIcon = avatarIcon; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/GroupNode.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/GroupNode.java index 2d053ae..0f01bcd 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/GroupNode.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/GroupNode.java @@ -241,6 +241,20 @@ public class GroupNode } /** + * Returns a collection of all direct children of this <tt>GroupNode</tt>. + * + * @return a collection of all direct children of this <tt>GroupNode</tt> + */ + @SuppressWarnings("unchecked") + public Collection<ContactNode> getContacts() + { + if (children != null) + return Collections.unmodifiableCollection(children); + + return null; + } + + /** * Returns the <tt>UIGroup</tt> corresponding to this <tt>GroupNode</tt>. * @return the <tt>UIGroup</tt> corresponding to this <tt>GroupNode</tt> */ diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/InviteUIContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/InviteUIContact.java new file mode 100644 index 0000000..909393c --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/InviteUIContact.java @@ -0,0 +1,154 @@ +/* + * Jitsi, 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.contactlist; + +import java.util.*; + +import javax.swing.*; + +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.protocol.*; + +/** + * The <tt>InviteUIContact</tt> is an <tt>UIContact</tt> used in invite dialogs + * to represent the selected contacts the invite operation. + * + * @author Yana Stamcheva + */ +public class InviteUIContact + extends GenericUIContactImpl +{ + /** + * The source <tt>UIContact</tt> from which this contact is created. This + * contact can be seen as a copy of the source contact. + */ + private final UIContact sourceUIContact; + + /** + * The backup protocol provider to be used for contact operations, if no + * other protocol provider has been specified. + */ + private final ProtocolProviderService backupProvider; + + /** + * Creates an instance of <tt>InviteUIContact</tt>. + * + * @param uiContact the source <tt>UIContact</tt>. + * @param protocolProvider the backup protocol provider to use if no other + * protocol provider has been specified in the source ui contact + */ + public InviteUIContact( UIContact uiContact, + ProtocolProviderService protocolProvider) + { + super(uiContact.getDescriptor(), null, uiContact.getDisplayName()); + + setDisplayDetails(uiContact.getDisplayDetails()); + + sourceUIContact = uiContact; + backupProvider = protocolProvider; + } + + /** + * Returns a list of <tt>UIContactDetail</tt>s supporting the given + * <tt>OperationSet</tt> class. + * @param opSetClass the <tt>OperationSet</tt> class we're interested in + * @return a list of <tt>UIContactDetail</tt>s supporting the given + * <tt>OperationSet</tt> class + */ + public List<UIContactDetail> getContactDetailsForOperationSet( + Class<? extends OperationSet> opSetClass) + { + List<UIContactDetail> contactDetails + = sourceUIContact.getContactDetailsForOperationSet(opSetClass); + + if (contactDetails == null) + return null; + + if (backupProvider == null) + return contactDetails; + + Iterator<UIContactDetail> contactDetailsIter + = contactDetails.iterator(); + + while (contactDetailsIter.hasNext()) + { + UIContactDetail contactDetail = contactDetailsIter.next(); + + if (contactDetail + .getPreferredProtocolProvider(opSetClass) == null) + { + contactDetail.addPreferredProtocolProvider( opSetClass, + backupProvider); + } + + if (contactDetail + .getPreferredProtocol(opSetClass) == null) + { + contactDetail.addPreferredProtocol( + opSetClass, + backupProvider.getProtocolName()); + } + } + + return contactDetails; + } + + /** + * Returns a list of all contained <tt>UIContactDetail</tt>s. + * + * @return a list of all contained <tt>UIContactDetail</tt>s + */ + public List<UIContactDetail> getContactDetails() + { + return sourceUIContact.getContactDetails(); + } + + /** + * Returns the default <tt>ContactDetail</tt> to use for any operations + * depending to the given <tt>OperationSet</tt> class. + * + * @param opSetClass the <tt>OperationSet</tt> class we're interested in + * @return the default <tt>ContactDetail</tt> to use for any operations + * depending to the given <tt>OperationSet</tt> class + */ + public UIContactDetail getDefaultContactDetail( + Class<? extends OperationSet> opSetClass) + { + return sourceUIContact.getDefaultContactDetail(opSetClass); + } + + /** + * Returns the avatar of this <tt>UIContact</tt>. + * + * @param isSelected indicates if the avatar is selected + * @param width avatar preferred width + * @param height avatar preferred height + */ + @Override + public ImageIcon getAvatar(boolean isSelected, int width, int height) + { + if (sourceUIContact instanceof UIContactImpl) + return ((UIContactImpl) sourceUIContact) + .getAvatar(isSelected, width, height); + + return null; + } + + /** + * Returns the status icon of this contact. + * + * @return an <tt>ImageIcon</tt> representing the status of this contact + */ + @Override + public ImageIcon getStatusIcon() + { + if (sourceUIContact instanceof UIContactImpl) + return ((UIContactImpl) sourceUIContact).getStatusIcon(); + + return null; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java index 3bf255e..133f82b 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java @@ -13,6 +13,7 @@ import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.gui.event.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; @@ -49,6 +50,7 @@ public class PresenceFilter /** * Applies this filter. This filter is applied over the * <tt>MetaContactListService</tt>. + * * @param filterQuery the query which keeps track of the filtering results */ public void applyFilter(FilterQuery filterQuery) @@ -76,6 +78,7 @@ public class PresenceFilter /** * Indicates if the given <tt>uiContact</tt> is matching this filter. + * * @param uiContact the <tt>UIContact</tt> to check * @return <tt>true</tt> if the given <tt>uiContact</tt> is matching * this filter, otherwise returns <tt>false</tt> @@ -91,6 +94,7 @@ public class PresenceFilter /** * Indicates if the given <tt>uiGroup</tt> is matching this filter. + * * @param uiGroup the <tt>UIGroup</tt> to check * @return <tt>true</tt> if the given <tt>uiGroup</tt> is matching * this filter, otherwise returns <tt>false</tt> @@ -106,6 +110,7 @@ public class PresenceFilter /** * Sets the show offline property. + * * @param isShowOffline indicates if offline contacts are shown */ public void setShowOffline(boolean isShowOffline) @@ -118,6 +123,7 @@ public class PresenceFilter /** * Returns <tt>true</tt> if offline contacts are shown, otherwise returns * <tt>false</tt>. + * * @return <tt>true</tt> if offline contacts are shown, otherwise returns * <tt>false</tt> */ @@ -129,6 +135,7 @@ public class PresenceFilter /** * Returns <tt>true</tt> if offline contacts are shown or if the given * <tt>MetaContact</tt> is online, otherwise returns false. + * * @param metaContact the <tt>MetaContact</tt> to check * @return <tt>true</tt> if the given <tt>MetaContact</tt> is matching this * filter @@ -141,6 +148,7 @@ public class PresenceFilter /** * Returns <tt>true</tt> if offline contacts are shown or if the given * <tt>MetaContactGroup</tt> contains online contacts. + * * @param metaGroup the <tt>MetaContactGroup</tt> to check * @return <tt>true</tt> if the given <tt>MetaContactGroup</tt> is matching * this filter @@ -176,6 +184,7 @@ public class PresenceFilter /** * Adds all contacts contained in the given <tt>MetaContactGroup</tt> * matching the current filter and not contained in the contact list. + * * @param metaGroup the <tt>MetaContactGroup</tt>, which matching contacts * to add * @param query the <tt>MetaContactQuery</tt> that notifies interested diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchField.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchField.java index c97ad48..9e08ec7 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchField.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchField.java @@ -53,15 +53,30 @@ public class SearchField private final MainFrame mainFrame; /** + * The contact list on which we apply the filter. + */ + private ContactList contactList; + + /** + * The filter to apply on search. + */ + private final ContactListSearchFilter searchFilter; + + /** * Creates the <tt>SearchField</tt>. + * * @param frame the main application window + * @param contactList the contact list, which we're searching + * @param searchFilter the filter to apply on search */ - public SearchField(MainFrame frame) + public SearchField( MainFrame frame, + ContactListSearchFilter searchFilter) { super(GuiActivator.getResources() .getI18NString("service.gui.ENTER_NAME_OR_NUMBER")); this.mainFrame = frame; + this.searchFilter = searchFilter; if(getUI() instanceof SearchFieldUI) ((SearchFieldUI)getUI()).setDeleteButtonEnabled(true); @@ -82,7 +97,8 @@ public class SearchField { setText(""); - SearchField.this.mainFrame.requestFocusInCenterPanel(); + if (SearchField.this.mainFrame != null) + SearchField.this.mainFrame.requestFocusInCenterPanel(); } }); @@ -128,17 +144,15 @@ public class SearchField boolean isDefaultFilter = false; + searchFilter.setFilterString(filterString.trim()); + if (filterString != null && filterString.length() > 0) { - TreeContactList.searchFilter - .setFilterString(filterString.trim()); - - filterQuery = GuiActivator.getContactList() - .applyFilter(TreeContactList.searchFilter); + filterQuery = contactList.applyFilter(searchFilter); } else { - filterQuery = GuiActivator.getContactList().applyDefaultFilter(); + filterQuery = contactList.applyDefaultFilter(); isDefaultFilter = true; } @@ -156,13 +170,16 @@ public class SearchField filterQuery.setQueryListener(this); } else + { // If the query is null or is canceled, we would simply check the // contact list content. - enableUnknownContactView(GuiActivator.getContactList().isEmpty()); + closeFilterQuery(filterQuery, !contactList.isEmpty()); + } } /** * Sets the unknown contact view to the main contact list window. + * * @param isEnabled indicates if the unknown contact view should be enabled * or disabled. */ @@ -172,14 +189,26 @@ public class SearchField { public void run() { - mainFrame.enableUnknownContactView(isEnabled); + if (mainFrame != null) + mainFrame.enableUnknownContactView(isEnabled); } }); } /** + * Sets the contact list, in which the search is performed. + * + * @param contactList the contact list in which the search is performed + */ + public void setContactList(ContactList contactList) + { + this.contactList = contactList; + } + + /** * Indicates that the given <tt>query</tt> has finished with failure, i.e. * no results for the filter were found. + * * @param query the <tt>FilterQuery</tt>, where this listener is registered */ public void filterQueryFailed(FilterQuery query) @@ -194,17 +223,12 @@ public class SearchField /** * Indicates that the given <tt>query</tt> has finished with success, i.e. * the filter has returned results. + * * @param query the <tt>FilterQuery</tt>, where this listener is registered */ public void filterQuerySucceeded(FilterQuery query) { - // If the unknown contact view was previously enabled, but we - // have found matching contacts we enter the normal view. - enableUnknownContactView(false); - - GuiActivator.getContactList().selectFirstContact(); - - query.setQueryListener(null); + closeFilterQuery(query, !contactList.isEmpty()); } /** @@ -227,4 +251,16 @@ public class SearchField { return uiClassID; } + + private void closeFilterQuery(FilterQuery query, boolean hasResults) + { + // If the unknown contact view was previously enabled, but we + // have found matching contacts we enter the normal view. + enableUnknownContactView(!hasResults); + + if (hasResults) + contactList.selectFirstContact(); + + query.setQueryListener(null); + } } diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java index 202ae0c..2287618 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java @@ -13,6 +13,7 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.service.contactsource.*; import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.gui.event.*; /** * The <tt>SearchFilter</tt> is a <tt>ContactListFilter</tt> that filters the @@ -21,27 +22,17 @@ import net.java.sip.communicator.service.gui.*; * @author Yana Stamcheva */ public class SearchFilter - implements ContactListFilter + implements ContactListSearchFilter { /** - * The default contact source search type. - */ - public static final int DEFAULT_SOURCE = 0; - - /** - * The history contact source search type. - */ - public static final int HISTORY_SOURCE = 1; - - /** * The string, which we're searching. */ - private String filterString; + protected String filterString; /** * The pattern to filter. */ - private Pattern filterPattern; + protected Pattern filterPattern; /** * The <tt>MetaContactListSource</tt> to search in. @@ -49,22 +40,25 @@ public class SearchFilter private final MetaContactListSource mclSource; /** - * The list of external contact sources to search in. + * The source contact list. */ - private Collection<UIContactSource> contactSources; + protected ContactList sourceContactList; /** - * The type of the search source. One of the above defined DEFAUT_SOURCE or - * HISTORY_SOURCE. + * Creates an instance of <tt>SearchFilter</tt>. */ - private int searchSourceType = DEFAULT_SOURCE; + public SearchFilter(MetaContactListSource contactListSource) + { + this.mclSource = contactListSource; + } /** * Creates an instance of <tt>SearchFilter</tt>. */ - public SearchFilter(MetaContactListSource contactListSource) + public SearchFilter(ContactList sourceContactList) { - this.mclSource = contactListSource; + this.mclSource = null; + this.sourceContactList = sourceContactList; } /** @@ -73,25 +67,34 @@ public class SearchFilter */ public void applyFilter(FilterQuery filterQuery) { - // If the filter has a default contact source, we apply it first. - if (searchSourceType == DEFAULT_SOURCE) + if (sourceContactList == null) + sourceContactList = GuiActivator.getContactList(); + + Iterator<UIContactSource> filterSources + = sourceContactList.getContactSources().iterator(); + + if (sourceContactList.getDefaultFilter() + .equals(TreeContactList.presenceFilter)) { MetaContactQuery defaultQuery = mclSource.queryMetaContactSource(filterPattern); - defaultQuery.addContactQueryListener(GuiActivator.getContactList()); + defaultQuery.addContactQueryListener(sourceContactList); // First add the MetaContactListSource filterQuery.addContactQuery(defaultQuery); } + else if (sourceContactList.getDefaultFilter() + .equals(TreeContactList.historyFilter)) + { + filterSources = sourceContactList.getContactSources( + ContactSourceService.HISTORY_TYPE).iterator(); + } // If we have stopped filtering in the mean time we return here. if (filterQuery.isCanceled()) return; - Iterator<UIContactSource> filterSources - = getContactSources().iterator(); - // Then we apply the filter on all its contact sources. while (filterSources.hasNext()) { @@ -102,12 +105,17 @@ public class SearchFilter if (filterQuery.isCanceled()) return; - filterQuery.addContactQuery( - applyFilter(filterSource)); + ContactQuery query = applyFilter(filterSource); + + if (query.getStatus() == ContactQuery.QUERY_IN_PROGRESS) + filterQuery.addContactQuery(query); } // Closes this filter to indicate that we finished adding queries to it. - filterQuery.close(); + if (filterQuery.isRunning()) + filterQuery.close(); + else if (!sourceContactList.isEmpty()) + sourceContactList.selectFirstContact(); } /** @@ -133,7 +141,7 @@ public class SearchFilter // Add first available results. this.addMatching(contactQuery.getQueryResults()); - contactQuery.addContactQueryListener(GuiActivator.getContactList()); + contactQuery.addContactQueryListener(sourceContactList); return contactQuery; } @@ -215,7 +223,10 @@ public class SearchFilter */ private boolean isMatching(String text) { - return filterPattern.matcher(text).find(); + if (filterPattern != null) + return filterPattern.matcher(text).find(); + + return true; } /** @@ -240,7 +251,7 @@ public class SearchFilter = sourceContact.getContactSource(); UIContactSource sourceUI - = GuiActivator.getContactList().getContactSource(contactSource); + = sourceContactList.getContactSource(contactSource); if (sourceUI != null // ExtendedContactSourceService has already matched the @@ -248,7 +259,7 @@ public class SearchFilter && (contactSource instanceof ExtendedContactSourceService) || isMatching(sourceContact)) { - GuiActivator.getContactList().addContact( + sourceContactList.addContact( sourceUI.createUIContact(sourceContact), sourceUI.getUIGroup(), false, @@ -257,56 +268,4 @@ public class SearchFilter else sourceUI.removeUIContact(sourceContact); } - - /** - * Sets the search source type: DEFAULT_SOURCE or HISTORY_SOURCE. - * @param searchSourceType the type of the search source to set - */ - public void setSearchSourceType(int searchSourceType) - { - this.searchSourceType = searchSourceType; - - switch(searchSourceType) - { - case DEFAULT_SOURCE: - contactSources - = GuiActivator.getContactList().getContactSources(); - break; - case HISTORY_SOURCE: - { - Collection<UIContactSource> historySources - = new LinkedList<UIContactSource>(); - UIContactSource historySource - = GuiActivator.getContactList().getContactSource( - ContactSourceService.CALL_HISTORY); - - historySources.add(historySource); - contactSources = historySources; - break; - } - } - } - - /** - * Returns the list of <tt>ExternalContactSource</tt> this filter searches - * in. - * @return the list of <tt>ExternalContactSource</tt> this filter searches - * in - */ - public Collection<UIContactSource> getContactSources() - { - if (contactSources == null) - contactSources = GuiActivator.getContactList().getContactSources(); - return contactSources; - } - - /** - * Indicates if this filter contains a default source. - * @return <tt>true</tt> if this filter contains a default source, - * <tt>false</tt> otherwise - */ - public boolean hasDefaultSource() - { - return (searchSourceType == DEFAULT_SOURCE); - } } diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java index 545955c..f703aaa 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java @@ -124,7 +124,7 @@ public class TreeContactList */ private MouseListener[] originalMouseListeners; - private final Collection<UIContactSource> + private final LinkedList<UIContactSource> contactSources = new LinkedList<UIContactSource>(); private static NotificationContactSource notificationSource; @@ -139,6 +139,11 @@ public class TreeContactList private static boolean imageSearchCanceled = false; /** + * Indicates if the contact buttons should be disabled. + */ + private boolean isContactButtonsVisible = true; + + /** * Creates the <tt>TreeContactList</tt>. */ public TreeContactList() @@ -319,7 +324,7 @@ public class TreeContactList } if (uiGroup != null) - GuiActivator.getContactList().addGroup(uiGroup, true); + this.addGroup(uiGroup, true); } /** @@ -737,6 +742,45 @@ public class TreeContactList } /** + * Returns a collection of all direct child <tt>UIContact</tt>s of the given + * <tt>UIGroup</tt>. + * + * @param group the parent <tt>UIGroup</tt> + * @return a collection of all direct child <tt>UIContact</tt>s of the given + * <tt>UIGroup</tt> + */ + public Collection<UIContact> getContacts(final UIGroup group) + { + if (group != null && !(group instanceof UIGroupImpl)) + return null; + + GroupNode groupNode; + + if (group == null) + groupNode = treeModel.getRoot(); + else + groupNode = ((UIGroupImpl) group).getGroupNode(); + + if (groupNode == null) + return null; + + Collection<ContactNode> contactNodes = groupNode.getContacts(); + + if (contactNodes == null) + return null; + + Collection<UIContact> childContacts = new ArrayList<UIContact>(); + + Iterator<ContactNode> contactNodesIter = contactNodes.iterator(); + while (contactNodesIter.hasNext()) + { + childContacts.add(contactNodesIter.next().getContactDescriptor()); + } + + return childContacts; + } + + /** * Adds a listener for <tt>ContactListEvent</tt>s. * * @param listener the listener to add @@ -822,7 +866,7 @@ public class TreeContactList if (currentFilterQuery != null && !currentFilterQuery.isCanceled()) currentFilterQuery.cancel(); - currentFilterQuery = new UIFilterQuery(); + currentFilterQuery = new UIFilterQuery(this); if (filterThread == null) { @@ -911,13 +955,16 @@ public class TreeContactList public void setDefaultFilter(ContactListFilter filter) { this.defaultFilter = filter; + } - if (defaultFilter.equals(presenceFilter)) - TreeContactList.searchFilter - .setSearchSourceType(SearchFilter.DEFAULT_SOURCE); - else if (defaultFilter.equals(historyFilter)) - TreeContactList.searchFilter - .setSearchSourceType(SearchFilter.HISTORY_SOURCE); + /** + * Gets the default filter for this contact list. + * + * @return the default filter for this contact list + */ + public ContactListFilter getDefaultFilter() + { + return defaultFilter; } /** @@ -930,6 +977,15 @@ public class TreeContactList } /** + * Returns the currently applied filter. + * @return the currently applied filter + */ + public FilterQuery getCurrentFilterQuery() + { + return currentFilterQuery; + } + + /** * Indicates if this contact list is empty. * @return <tt>true</tt> if this contact list contains no children, * otherwise returns <tt>false</tt> @@ -1508,7 +1564,14 @@ public class TreeContactList for (ContactSourceService contactSource : GuiActivator.getContactSources()) { - contactSources.add(new ExternalContactSource(contactSource, this)); + ExternalContactSource extContactSource + = new ExternalContactSource(contactSource, this); + + int sourceIndex = contactSource.getIndex(); + if (sourceIndex >= 0 && contactSources.size() >= sourceIndex) + contactSources.add(sourceIndex, extContactSource); + else + contactSources.add(extContactSource); } GuiActivator.bundleContext.addServiceListener( new ContactSourceServiceListener()); @@ -1524,6 +1587,47 @@ public class TreeContactList } /** + * Adds the given contact source to the list of available contact sources. + * + * @param contactSource the <tt>ContactSourceService</tt> + */ + public void addContactSource(ContactSourceService contactSource) + { + contactSources.add(new ExternalContactSource(contactSource, this)); + } + + /** + * Removes the given contact source from the list of available contact + * sources. + * + * @param contactSource + */ + public void removeContactSource(ContactSourceService contactSource) + { + Iterator<UIContactSource> extSourcesIter + = contactSources.iterator(); + + while (extSourcesIter.hasNext()) + { + UIContactSource extSource = extSourcesIter.next(); + + if (extSource.getContactSourceService().equals(contactSource)) + { + contactSources.remove(extSource); + break; + } + } + } + + /** + * Removes all stored contact sources. + */ + public void removeAllContactSources() + { + contactSources.clear(); + } + + /** * Returns the notification contact source. * * @return the notification contact source @@ -1559,12 +1663,15 @@ public class TreeContactList } /** - * Returns the contact source with the given identifier. - * @param identifier the identifier we're looking for - * @return the contact source with the given identifier + * Returns all <tt>UIContactSource</tt>s of the given type. + * + * @param type the type of sources we're looking for + * @return a list of all <tt>UIContactSource</tt>s of the given type */ - public UIContactSource getContactSource(String identifier) + public List<UIContactSource> getContactSources(int type) { + List<UIContactSource> sources = new ArrayList<UIContactSource>(); + Iterator<UIContactSource> extSourcesIter = contactSources.iterator(); @@ -1572,11 +1679,10 @@ public class TreeContactList { UIContactSource extSource = extSourcesIter.next(); - if (extSource.getContactSourceService().getIdentifier() - .equals(identifier)) - return extSource; + if (extSource.getContactSourceService().getType() == type) + sources.add(extSource); } - return null; + return sources; } /** @@ -2038,6 +2144,33 @@ public class TreeContactList } /** + * Returns the list of selected contacts. + * + * @return the list of selected contacts + */ + public List<UIContact> getSelectedContacts() + { + TreePath[] selectionPaths = getSelectionPaths(); + + if (selectionPaths == null) + return null; + + List<UIContact> selectedContacts = new ArrayList<UIContact>(); + + for (TreePath selectionPath : selectionPaths) + { + if (selectionPath.getLastPathComponent() instanceof ContactNode) + { + selectedContacts.add( + ((ContactNode) selectionPath.getLastPathComponent()) + .getContactDescriptor()); + } + } + + return selectedContacts; + } + + /** * Returns the currently selected <tt>UIGroup</tt> if there's one. * * @return the currently selected <tt>UIGroup</tt> if there's one. @@ -2057,6 +2190,33 @@ public class TreeContactList } /** + * Enables/disables multiple selection. + * + * @param isEnabled <tt>true</tt> to enable multiple selection, + * <tt>false</tt> - otherwise + */ + public void setMultipleSelectionEnabled(boolean isEnabled) + { + if (isEnabled) + getSelectionModel().setSelectionMode( + TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); + else + getSelectionModel().setSelectionMode( + TreeSelectionModel.SINGLE_TREE_SELECTION); + } + + /** + * Removes the current selection. + */ + public void removeSelection() + { + TreePath[] selectionPaths = getSelectionPaths(); + + if (selectionPaths != null) + removeSelectionPaths(selectionPaths); + } + + /** * Indicates that a selection has occurred on the tree. * * @param e the <tt>TreeSelectionEvent</tt> that notified us of the change @@ -2080,4 +2240,26 @@ public class TreeContactList } } } + + /** + * Shows/hides buttons shown in contact row. + * + * @param isVisible <tt>true</tt> to show contact buttons, <tt>false</tt> - + * otherwise. + */ + public void setContactButtonsVisible(boolean isVisible) + { + this.isContactButtonsVisible = isVisible; + } + + /** + * Shows/hides buttons shown in contact row. + * + * return <tt>true</tt> to indicate that contact buttons are shown, + * <tt>false</tt> - otherwise. + */ + public boolean isContactButtonsVisible() + { + return isContactButtonsVisible; + } } diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailImpl.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailImpl.java index 71b3634..6f07d37 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailImpl.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailImpl.java @@ -29,6 +29,32 @@ public class UIContactDetailImpl /** * Creates a <tt>UIContactDetailImpl</tt> by specifying the contact * <tt>address</tt>, the <tt>displayName</tt> and <tt>preferredProvider</tt>. + * + * @param address the contact address + * @param displayName the contact display name + * @param statusIcon the status icon of this contact detail + * @param descriptor the underlying object that this class is wrapping + */ + public UIContactDetailImpl( + String address, + String displayName, + ImageIcon statusIcon, + Object descriptor) + { + super( address, + displayName, + null, + null, + null, + null, + descriptor); + + setStatusIcon(statusIcon); + } + + /** + * Creates a <tt>UIContactDetailImpl</tt> by specifying the contact + * <tt>address</tt>, the <tt>displayName</tt> and <tt>preferredProvider</tt>. * @param address the contact address * @param displayName the contact display name * @param category the category of the underlying contact detail @@ -45,12 +71,13 @@ public class UIContactDetailImpl String category, Collection<String> labels, ImageIcon statusIcon, - ProtocolProviderService preferredProvider, - String preferredProtocol, + Map<Class<? extends OperationSet>, ProtocolProviderService> + preferredProviders, + Map<Class<? extends OperationSet>, String> preferredProtocols, Object descriptor) { - super(address, displayName, category, labels, preferredProvider, - preferredProtocol, descriptor); + super(address, displayName, category, labels, preferredProviders, + preferredProtocols, descriptor); setStatusIcon(statusIcon); } diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactImpl.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactImpl.java index bd15e4b..1e348d4 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactImpl.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactImpl.java @@ -31,18 +31,15 @@ public abstract class UIContactImpl public abstract void setContactNode(ContactNode contactNode); /** - * Returns the general status icon of the given MetaContact. Detects the - * status using the priority status table. The priority is defined on - * the "availability" factor and here the most "available" status is - * returned. + * Returns the general status icon of the given UIContact. * - * @return PresenceStatus The most "available" status from all + * @return PresenceStatus the most "available" status from all * sub-contact statuses. */ public abstract ImageIcon getStatusIcon(); /** - * Gets the avatar of a specific <tt>MetaContact</tt> in the form of an + * Gets the avatar of a specific <tt>UIContact</tt> in the form of an * <tt>ImageIcon</tt> value. * * @param isSelected indicates if the contact is selected diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIFilterQuery.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIFilterQuery.java index 441737d..d4072f4 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIFilterQuery.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIFilterQuery.java @@ -8,7 +8,6 @@ package net.java.sip.communicator.impl.gui.main.contactlist; import java.util.*; -import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.service.contactsource.*; import net.java.sip.communicator.service.gui.*; @@ -25,11 +24,6 @@ public class UIFilterQuery MetaContactQueryListener { /** - * The maximum result count for each contact source. - */ - public static final int MAX_EXTERNAL_RESULT_COUNT = 10; - - /** * A listener, which is notified when this query finishes. */ private FilterQueryListener filterQueryListener; @@ -46,6 +40,11 @@ public class UIFilterQuery private boolean isCanceled = false; /** + * Indicates if this query is currently running. + */ + private boolean isRunning = false; + + /** * Indicates if this query is closed, means no more queries could be added * to it. A <tt>FilterQuery</tt>, which is closed knows that it has to wait * for a final number of queries to finish before notifying interested @@ -66,6 +65,23 @@ public class UIFilterQuery private int runningQueries = 0; /** + * The parent contact list of this query. + */ + private final ContactList contactList; + + /** + * Creates an instance of <tt>UIFilterQuery</tt> by specifying the parent + * <tt>ContactList</tt>. + * + * @param contactList the <tt>ContactList</tt> on which the query is + * performed + */ + public UIFilterQuery(ContactList contactList) + { + this.contactList = contactList; + } + + /** * Adds the given <tt>contactQuery</tt> to the list of filterQueries. * @param contactQuery the <tt>ContactQuery</tt> to add */ @@ -99,6 +115,7 @@ public class UIFilterQuery else if (contactQuery instanceof MetaContactQuery) ((MetaContactQuery) contactQuery).addContactQueryListener(this); + isRunning = true; filterQueries.put(contactQuery, queryResults); runningQueries++; } @@ -136,6 +153,19 @@ public class UIFilterQuery } /** + * Indicates if this query is canceled. + * + * @return <tt>true</tt> if this query is canceled, <tt>false</tt> otherwise + */ + public boolean isRunning() + { + synchronized (filterQueries) + { + return isRunning; + } + } + + /** * Cancels this filter query. */ public void cancel() @@ -178,6 +208,8 @@ public class UIFilterQuery */ private void fireFilterQueryEvent() { + isRunning = false; + if (filterQueryListener == null) return; @@ -264,8 +296,7 @@ public class UIFilterQuery { ContactQuery contactQuery = (ContactQuery) query; contactQuery.cancel(); - contactQuery.removeContactQueryListener( - GuiActivator.getContactList()); + contactQuery.removeContactQueryListener(contactList); if (!isSucceeded && contactQuery.getQueryResults().size() > 0) isSucceeded = true; } @@ -273,8 +304,7 @@ public class UIFilterQuery { MetaContactQuery metaContactQuery = (MetaContactQuery) query; metaContactQuery.cancel(); - metaContactQuery.removeContactQueryListener( - GuiActivator.getContactList()); + metaContactQuery.removeContactQueryListener(contactList); if (!isSucceeded && metaContactQuery.getResultCount() > 0) isSucceeded = true; } @@ -306,20 +336,20 @@ public class UIFilterQuery queryResults.add(contact); - if (queryResults.size() == MAX_EXTERNAL_RESULT_COUNT) + if (getMaxResultShown() > -1 + && queryResults.size() == getMaxResultShown()) { - query.removeContactQueryListener(GuiActivator.getContactList()); + query.removeContactQueryListener(contactList); ShowMoreContact moreInfoContact - = new ShowMoreContact(query, queryResults); + = new ShowMoreContact(query, queryResults, getMaxResultShown()); ContactSourceService contactSource = query.getContactSource(); - GuiActivator.getContactList().addContact( + contactList.addContact( query, moreInfoContact, - GuiActivator.getContactList() - .getContactSource(contactSource).getUIGroup(), + contactList.getContactSource(contactSource).getUIGroup(), false); } } diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ExternalContactSource.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ExternalContactSource.java index 619d1b9..48934b8 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ExternalContactSource.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ExternalContactSource.java @@ -376,8 +376,12 @@ public class ExternalContactSource */ public int getSourceIndex() { - if (contactSource.getIdentifier() - .equals(ContactSourceService.CALL_HISTORY)) + int sourceIndex = contactSource.getIndex(); + + if (sourceIndex >= 0) + return sourceIndex; + + if (contactSource.getType() == ContactSourceService.HISTORY_TYPE) return Integer.MAX_VALUE; return Integer.MAX_VALUE - 1; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactListSource.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactListSource.java index 82ea955..6049ddf 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactListSource.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactListSource.java @@ -22,6 +22,7 @@ import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.contactlist.event.*; import net.java.sip.communicator.service.customcontactactions.*; import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.gui.event.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java index bb4b2f5..085351e 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java @@ -605,6 +605,7 @@ public class MetaUIContact /** * Creates an instance of <tt>MetaContactDetail</tt> by specifying the * underlying protocol <tt>Contact</tt>. + * * @param contact the protocol contact, on which this implementation * is based */ @@ -612,14 +613,25 @@ public class MetaUIContact { super( contact.getAddress(), contact.getDisplayName(), - null, - null, new ImageIcon(contact.getPresenceStatus().getStatusIcon()), - contact.getProtocolProvider(), - contact.getProtocolProvider().getProtocolName(), contact); this.contact = contact; + + ProtocolProviderService parentProvider + = contact.getProtocolProvider(); + + Iterator<Class<? extends OperationSet>> opSetClasses + = parentProvider.getSupportedOperationSetClasses().iterator(); + + while (opSetClasses.hasNext()) + { + Class<? extends OperationSet> opSetClass = opSetClasses.next(); + + addPreferredProtocolProvider(opSetClass, parentProvider); + addPreferredProtocol(opSetClass, + parentProvider.getProtocolName()); + } } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ProtocolContactSourceServiceImpl.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ProtocolContactSourceServiceImpl.java new file mode 100644 index 0000000..228d1e5 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ProtocolContactSourceServiceImpl.java @@ -0,0 +1,217 @@ +/* + * Jitsi, 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.contactlist.contactsource; + +import java.util.*; +import java.util.regex.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.protocol.*; + +/** + * + * @author Yana Stamcheva + */ +public class ProtocolContactSourceServiceImpl + implements ContactSourceService +{ + private final ProtocolProviderService protocolProvider; + + private final Class<? extends OperationSet> opSetClass; + + MetaContactListService metaContactListService + = GuiActivator.getContactListService(); + + /** + * The <tt>List</tt> of <tt>ProtocolContactQuery</tt> instances + * which have been started and haven't stopped yet. + */ + private final List<ProtocolCQuery> queries + = new LinkedList<ProtocolCQuery>(); + + /** + * Creates an instance of <tt>ProtocolContactSourceServiceImpl</tt>. + * + * @param protocolProvider the protocol provider which is the contact source + * @param opSetClass the <tt>OperationSet</tt> class that is supported by + * source contacts + */ + public ProtocolContactSourceServiceImpl( + ProtocolProviderService protocolProvider, + Class<? extends OperationSet> opSetClass) + { + this.protocolProvider = protocolProvider; + this.opSetClass = opSetClass; + } + + public int getType() + { + return DEFAULT_TYPE; + } + + public String getDisplayName() + { + return GuiActivator.getResources().getI18NString("service.gui.CONTACTS") + + " " + protocolProvider.getAccountID().getDisplayName(); + } + + public ContactQuery queryContactSource(String queryString) + { + return queryContactSource(queryString, -1); + } + + public ContactQuery queryContactSource( String queryString, + int contactCount) + { + if (queryString == null) + queryString = ""; + + ProtocolCQuery contactQuery + = new ProtocolCQuery(queryString, contactCount); + + synchronized (queries) + { + queries.add(contactQuery); + } + + boolean queryHasStarted = false; + + try + { + contactQuery.start(); + queryHasStarted = true; + } + finally + { + if (!queryHasStarted) + { + synchronized (queries) + { + if (queries.remove(contactQuery)) + queries.notify(); + } + } + } + return contactQuery; + } + + private class ProtocolCQuery + extends AsyncContactQuery<ProtocolContactSourceServiceImpl> + { + private int contactCount; + + private String queryString; + + public ProtocolCQuery(String queryString, int contactCount) + { + super(ProtocolContactSourceServiceImpl.this, + Pattern.compile(queryString, Pattern.CASE_INSENSITIVE + | Pattern.LITERAL)); + + this.queryString = queryString; + this.contactCount = contactCount; + } + + @Override + protected String normalizePhoneNumber(String phoneNumber) + { + return phoneNumber; + } + + @Override + protected boolean phoneNumberMatches(String phoneNumber) + { + return false; + } + + public void run() + { + Iterator<MetaContact> contactListIter = metaContactListService + .findAllMetaContactsForProvider(protocolProvider); + + while (contactListIter.hasNext()) + { + MetaContact metaContact = contactListIter.next(); + + if (getStatus() == QUERY_CANCELED) + return; + + this.addResultContact(metaContact); + } + + if (getStatus() != QUERY_CANCELED) + setStatus(QUERY_COMPLETED); + } + + /** + * Adds the result for the given group. + * + * @param group the group + */ + private void addResultContact(MetaContact metaContact) + { + Iterator<Contact> contacts + = metaContact.getContactsForProvider(protocolProvider); + + while (contacts.hasNext()) + { + if (getStatus() == QUERY_CANCELED) + return; + + if(contactCount > 0 && getQueryResultCount() > contactCount) + break; + + Contact contact = contacts.next(); + + if (queryString == null + || queryString.length() <= 0 + || metaContact.getDisplayName().startsWith(queryString) + || contact.getAddress().startsWith(queryString) + || contact.getDisplayName().startsWith(queryString)) + { + ArrayList<ContactDetail> contactDetails + = new ArrayList<ContactDetail>(); + + ContactDetail contactDetail + = new ContactDetail(contact.getAddress()); + + ArrayList<Class<? extends OperationSet>> + supportedOpSets + = new ArrayList<Class<? extends OperationSet>>(); + supportedOpSets.add(opSetClass); + contactDetail.setSupportedOpSets(supportedOpSets); + + contactDetails.add(contactDetail); + + GenericSourceContact sourceContact + = new GenericSourceContact( + ProtocolContactSourceServiceImpl.this, + contact.getDisplayName(), + contactDetails); + + sourceContact.setImage(metaContact.getAvatar()); + sourceContact + .setPresenceStatus(contact.getPresenceStatus()); + + addQueryResult(sourceContact); + } + } + } + } + + /** + * Returns the index of the contact source in the result list. + * + * @return the index of the contact source in the result list + */ + public int getIndex() + { + return 1; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ShowMoreContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ShowMoreContact.java index d3ed3da..0ce9f0f 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ShowMoreContact.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ShowMoreContact.java @@ -12,7 +12,6 @@ import javax.swing.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; -import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactsource.*; import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.gui.event.*; @@ -56,19 +55,27 @@ public class ShowMoreContact /** * The count of shown contacts corresponding to the underlying query. */ - private int shownResultsCount = UIFilterQuery.MAX_EXTERNAL_RESULT_COUNT; + private int shownResultsCount; + + /** + * The maximum result count by show. + */ + private int maxResultCount; /** * Creates an instance of <tt>MoreInfoContact</tt>. * - * @param contactQuery - * @param queryResults + * @param contactQuery the contact query + * @param queryResults the result list + * @param maxResultCount the maximum result count */ public ShowMoreContact( ContactQuery contactQuery, - List<SourceContact> queryResults) + List<SourceContact> queryResults, + int maxResultCount) { this.contactQuery = contactQuery; this.queryResults = queryResults; + this.maxResultCount = maxResultCount; GuiActivator.getContactList().addContactListListener(this); } @@ -264,7 +271,7 @@ public class ShowMoreContact = new ArrayList<SourceContact>(queryResults); int newCount - = shownResultsCount + UIFilterQuery.MAX_EXTERNAL_RESULT_COUNT; + = shownResultsCount + maxResultCount; int resultSize = contacts.size(); diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java index 2bbd010..4f891d8 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java @@ -98,10 +98,10 @@ public class SourceUIContact /** * The parent group of source contacts could not be changed. + * * @param parentGroup the parent group to set */ - public void setParentGroup(UIGroup parentGroup) - {} + public void setParentGroup(UIGroup parentGroup) {} /** * Returns -1 to indicate that the source index of the underlying @@ -160,6 +160,7 @@ public class SourceUIContact /** * Returns the default <tt>ContactDetail</tt> to use for any operations * depending to the given <tt>OperationSet</tt> class. + * * @param opSetClass the <tt>OperationSet</tt> class we're interested in * @return the default <tt>ContactDetail</tt> to use for any operations * depending to the given <tt>OperationSet</tt> class @@ -200,18 +201,6 @@ public class SourceUIContact */ public List<UIContactDetail> getContactDetails() { - return getContactDetails(sourceContact); - } - - /** - * Returns a list of all contained <tt>UIContactDetail</tt>s. - * - * @param sourceContact the source contact we get details from. - * @return a list of all contained <tt>UIContactDetail</tt>s - */ - public static List<UIContactDetail> getContactDetails( - SourceContact sourceContact) - { List<UIContactDetail> resultList = new LinkedList<UIContactDetail>(); @@ -315,8 +304,8 @@ public class SourceUIContact detail.getCategory(), detail.getLabels(), null, - detail.getPreferredProtocolProvider(opSetClass), - detail.getPreferredProtocol(opSetClass), + null, + null, detail); ContactSourceService contactSource @@ -330,6 +319,11 @@ public class SourceUIContact if (prefix != null) setPrefix(prefix); } + + addPreferredProtocolProvider(opSetClass, + detail.getPreferredProtocolProvider(opSetClass)); + addPreferredProtocol(opSetClass, + detail.getPreferredProtocol(opSetClass)); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/StringContactSourceServiceImpl.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/StringContactSourceServiceImpl.java new file mode 100644 index 0000000..10c5c5d --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/StringContactSourceServiceImpl.java @@ -0,0 +1,203 @@ +/* + * Jitsi, 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.contactlist.contactsource; + +import java.util.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.protocol.*; + +/** + * The <tt>StringContactSourceServiceImpl</tt> is an implementation of the + * <tt>ContactSourceService</tt> that returns the searched string as a result + * contact. + * + * @author Yana Stamcheva + */ +public class StringContactSourceServiceImpl + implements ContactSourceService +{ + /** + * The protocol provider to be used with this string contact source. + */ + private final ProtocolProviderService protocolProvider; + + /** + * The operation set supported by this string contact source. + */ + private final Class<? extends OperationSet> opSetClass; + + /** + * Creates an instance of <tt>StringContactSourceServiceImpl</tt>. + * + * @param protocolProvider the protocol provider to be used with this string + * contact source + * @param opSet the operation set supported by this string contact source + */ + public StringContactSourceServiceImpl( + ProtocolProviderService protocolProvider, + Class<? extends OperationSet> opSet) + { + this.protocolProvider = protocolProvider; + this.opSetClass = opSet; + } + + /** + * Returns the type of this contact source. + * + * @return the type of this contact source + */ + public int getType() + { + return SEARCH_TYPE; + } + + /** + * Returns a user-friendly string that identifies this contact source. + * + * @return the display name of this contact source + */ + public String getDisplayName() + { + return GuiActivator.getResources().getI18NString( + "service.gui.SEARCH_STRING_CONTACT_SOURCE"); + } + + /** + * Queries this search source for the given <tt>queryString</tt>. + * + * @param queryString the string to search for + * @return the created query + */ + public ContactQuery queryContactSource(String queryString) + { + return queryContactSource(queryString, -1); + } + + /** + * Queries this search source for the given <tt>queryString</tt>. + * + * @param queryString the string to search for + * @param contactCount the maximum count of result contacts + * @return the created query + */ + public ContactQuery queryContactSource( String queryString, + int contactCount) + { + return new StringQuery(queryString); + } + + /** + * The query implementation. + */ + private class StringQuery + extends AbstractContactQuery<ContactSourceService> + { + /** + * The query string. + */ + private String queryString; + + /** + * The query result list. + */ + private final List<SourceContact> results; + + /** + * Creates an instance of this query implementation. + * + * @param queryString the string to query + */ + public StringQuery(String queryString) + { + super(StringContactSourceServiceImpl.this); + + this.queryString = queryString; + this.results = new ArrayList<SourceContact>(); + + results.add(getSourceContact()); + + if (getStatus() != QUERY_CANCELED) + setStatus(QUERY_COMPLETED); + } + + /** + * Returns the query string. + * + * @return the query string + */ + public String getQueryString() + { + return queryString; + } + + /** + * Returns the list of query results. + * + * @return the list of query results + */ + public List<SourceContact> getQueryResults() + { + return results; + } + + /** + * Returns the source contact corresponding to the query string. + * + * @return the source contact corresponding to the query string + */ + private SourceContact getSourceContact() + { + ArrayList<ContactDetail> contactDetails + = new ArrayList<ContactDetail>(); + + ContactDetail contactDetail = new ContactDetail(queryString); + + // Init supported operation sets. + ArrayList<Class<? extends OperationSet>> + supportedOpSets + = new ArrayList<Class<? extends OperationSet>>(); + supportedOpSets.add(opSetClass); + contactDetail.setSupportedOpSets(supportedOpSets); + + // Init preferred protocol providers. + Map<Class<? extends OperationSet>,ProtocolProviderService> + providers = new HashMap<Class<? extends OperationSet>, + ProtocolProviderService>(); + + providers.put(opSetClass, protocolProvider); + + contactDetail.setPreferredProviders(providers); + + contactDetails.add(contactDetail); + + GenericSourceContact sourceContact + = new GenericSourceContact( StringContactSourceServiceImpl.this, + queryString, + contactDetails); + + sourceContact.setDisplayDetails( + GuiActivator.getResources().getI18NString( + "service.gui.CALL_VIA") + + " " + + protocolProvider.getAccountID().getDisplayName()); + + return sourceContact; + } + } + + /** + * Returns the index of the contact source in the result list. + * + * @return the index of the contact source in the result list + */ + public int getIndex() + { + return 0; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContact.java index 4d0877b..e65ae28 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContact.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContact.java @@ -471,12 +471,20 @@ public class NotificationContact { super( messageAccount, messageAccount, - null, - null, ImageLoader.getAccountStatusImage(protocolProvider), - protocolProvider, - protocolProvider.getProtocolName(), notificationMessage); + + Iterator<Class<? extends OperationSet>> opSetClasses + = protocolProvider.getSupportedOperationSetClasses().iterator(); + + while (opSetClasses.hasNext()) + { + Class<? extends OperationSet> opSetClass = opSetClasses.next(); + + addPreferredProtocolProvider(opSetClass, protocolProvider); + addPreferredProtocol(opSetClass, + protocolProvider.getProtocolName()); + } } /** diff --git a/src/net/java/sip/communicator/impl/gui/utils/InviteContactListFilter.java b/src/net/java/sip/communicator/impl/gui/utils/InviteContactListFilter.java new file mode 100644 index 0000000..0c90fd0 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/utils/InviteContactListFilter.java @@ -0,0 +1,80 @@ +/* + * Jitsi, 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.utils; + +import java.util.*; + +import net.java.sip.communicator.impl.gui.main.contactlist.*; +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; + +/** + * The <tt>InviteContactListFilter</tt> is a <tt>SearchFilter</tt> that filters + * the contact list to fit invite operations. + * + * @author Yana Stamcheva + */ +public class InviteContactListFilter + extends SearchFilter +{ + /** + * Creates an instance of <tt>InviteContactListFilter</tt>. + * + * @param sourceContactList the contact list to filter + */ + public InviteContactListFilter(ContactList sourceContactList) + { + super(sourceContactList); + } + + /** + * Applies this filter to the default contact source. + * @param filterQuery the query that tracks this filter. + */ + public void applyFilter(FilterQuery filterQuery) + { + filterQuery.setMaxResultShown(-1); + + List<UIContactSource> filterSources + = sourceContactList.getContactSources( + ContactSourceService.DEFAULT_TYPE); + + if (filterString != null && filterString.length() > 0) + { + filterSources.addAll(sourceContactList + .getContactSources(ContactSourceService.SEARCH_TYPE)); + } + + Iterator<UIContactSource> filterSourceIter = filterSources.iterator(); + + // If we have stopped filtering in the mean time we return here. + if (filterQuery.isCanceled()) + return; + + // Then we apply the filter on all its contact sources. + while (filterSourceIter.hasNext()) + { + final UIContactSource filterSource + = filterSourceIter.next(); + + // If we have stopped filtering in the mean time we return here. + if (filterQuery.isCanceled()) + return; + + ContactQuery query = applyFilter(filterSource); + + if (query.getStatus() == ContactQuery.QUERY_IN_PROGRESS) + filterQuery.addContactQuery(query); + } + + // Closes this filter to indicate that we finished adding queries to it. + if (filterQuery.isRunning()) + filterQuery.close(); + else if (!sourceContactList.isEmpty()) + sourceContactList.selectFirstContact(); + } +}
\ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/gui/utils/InviteContactTransferHandler.java b/src/net/java/sip/communicator/impl/gui/utils/InviteContactTransferHandler.java index e4be964..7d291c5 100644 --- a/src/net/java/sip/communicator/impl/gui/utils/InviteContactTransferHandler.java +++ b/src/net/java/sip/communicator/impl/gui/utils/InviteContactTransferHandler.java @@ -13,7 +13,6 @@ import java.util.*; import javax.swing.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; -import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; @@ -24,6 +23,7 @@ import net.java.sip.communicator.util.swing.*; * simple string addresses to the conference invite dialog. * * @author Sebastien Vincent + * @author Yana Stamcheva */ public class InviteContactTransferHandler extends ExtendedTransferHandler @@ -46,15 +46,19 @@ public class InviteContactTransferHandler = new DataFlavor(UIContact.class, "UIContact"); /** - * The data flavor used when transferring <tt>UIContact</tt>s. + * The source contact list. */ - protected static final DataFlavor metaContactDataFlavor - = new DataFlavor(MetaContact.class, "MetaContact"); + private final ContactList srcContactList; /** - * The invite dialog. + * The destination contact list. */ - private final InviteDialog dialog; + private final ContactList destContactList; + + /** + * The backup provider to use if no provider is specified. + */ + private ProtocolProviderService backupProvider; /** * If the component is the selected contact list or not @@ -67,15 +71,19 @@ public class InviteContactTransferHandler * @param dialog the invite dialog * @param selected if the column is the selected ones */ - public InviteContactTransferHandler(InviteDialog dialog, boolean selected) + public InviteContactTransferHandler(ContactList srcContactList, + ContactList destContactList, + boolean selected) { - this.dialog = dialog; + this.srcContactList = srcContactList; + this.destContactList = destContactList; this.selected = selected; } /** * Creates a transferable for text pane components in order to enable drag * and drop of text. + * * @param component the component for which to create a * <tt>Transferable</tt> * @return the created <tt>Transferable</tt> @@ -83,11 +91,12 @@ public class InviteContactTransferHandler @Override protected Transferable createTransferable(JComponent component) { - if (component instanceof DefaultContactList) + if (component instanceof ContactList) { - MetaContact c = - (MetaContact)((DefaultContactList)component).getSelectedValue(); - return new MetaContactTransferable(c); + List<UIContact> c = ((ContactList) component).getSelectedContacts(); + + if (c != null) + return new UIContactTransferable(c); } return super.createTransferable(component); @@ -109,10 +118,9 @@ public class InviteContactTransferHandler { for (int i = 0, n = flavor.length; i < n; i++) { - if (flavor[i].equals(uiContactDataFlavor) || - flavor[i].equals(metaContactDataFlavor)) + if (flavor[i].equals(uiContactDataFlavor)) { - if (comp instanceof DefaultContactList) + if (comp instanceof ContactList) { return true; } @@ -156,102 +164,111 @@ public class InviteContactTransferHandler logger.debug("Failed to drop meta contact.", e); } - if (o instanceof ContactNode) + if (o instanceof Collection) { - UIContact uiContact - = ((ContactNode) o).getContactDescriptor(); - - Object obj = uiContact.getDescriptor(); - - if(!(obj instanceof MetaContact)) - return false; - - Iterator<UIContactDetail> contactDetails - = uiContact.getContactDetailsForOperationSet( - OperationSetBasicTelephony.class).iterator(); - if(!contactDetails.hasNext()) - return false; + Iterator<?> c = ((Collection<?>) o).iterator(); - MetaContact metaContact = - (MetaContact)uiContact.getDescriptor(); + while (c.hasNext()) + { + Object nextO = c.next(); + + if (nextO instanceof UIContact) + { + destContactList.addContact( + new InviteUIContact((UIContact) nextO, + backupProvider), + null, false, false); + } + } - dialog.addSelectedMetaContact(metaContact); return true; } - } - else if(t.isDataFlavorSupported(metaContactDataFlavor)) - { - MetaContact c = null; - - try - { - c = (MetaContact)t.getTransferData(metaContactDataFlavor); - } - catch(Exception e) + else if (o instanceof UIContact) { - e.printStackTrace(); - } + destContactList.addContact( + new InviteUIContact((UIContact) o, + backupProvider), + null, false, false); - if(selected) - { - dialog.removeMetaContact(c); - dialog.addSelectedMetaContact(c); return true; } - else + else if (o instanceof ContactNode) { - dialog.removeSelectedMetaContact(c); - dialog.addMetaContact(c); + UIContact uiContact = ((ContactNode) o).getContactDescriptor(); + + if (uiContact != null) + { + destContactList.addContact( + new InviteUIContact(uiContact, + backupProvider), + null, false, false); + + return true; + } } - return true; } return false; } /** - * Transferable for DefaultContactList that enables drag and drop of - * meta contacts. + * The backup provider to use if no provider has been specified. + * + * @param backupProvider the backup provider to use if no provider has been + * specified */ - public class MetaContactTransferable + public void setBackupProvider(ProtocolProviderService backupProvider) + { + this.backupProvider = backupProvider; + } + + /** + * Transferable for TreeContactList that enables drag and drop of + * ui contacts. + */ + public class UIContactTransferable implements Transferable { /** - * The meta contact. + * The ui contact. */ - private final MetaContact metaContact; + private final List<UIContact> uiContacts; /** - * Creates an instance of <tt>MetaContactTransferable</tt>. - * @param metaContact the meta contact to transfer + * Creates an instance of <tt>UIContactTransferable</tt>. + * + * @param uiContacts the ui contacts to transfer */ - public MetaContactTransferable(MetaContact metaContact) + public UIContactTransferable(List<UIContact> uiContacts) { - this.metaContact = metaContact; + this.uiContacts = uiContacts; } /** * Returns supported flavors. + * * @return an array of supported flavors */ public DataFlavor[] getTransferDataFlavors() { - return new DataFlavor[] { metaContactDataFlavor}; + return new DataFlavor[] {uiContactDataFlavor}; } /** * Returns <tt>true</tt> if the given <tt>flavor</tt> is supported, * otherwise returns <tt>false</tt>. + * * @param flavor the data flavor to verify * @return <tt>true</tt> if the given <tt>flavor</tt> is supported, * otherwise returns <tt>false</tt> */ public boolean isDataFlavorSupported(DataFlavor flavor) { - return metaContactDataFlavor.equals(flavor); + return uiContactDataFlavor.equals(flavor); } /** * Returns the selected text. + * * @param flavor the flavor * @return the selected text * @exception UnsupportedFlavorException if the requested data flavor @@ -263,17 +280,17 @@ public class InviteContactTransferHandler throws UnsupportedFlavorException, IOException { - return metaContact; + return uiContacts; } /** - * Returns meta contact. + * Returns the ui contacts. * - * @return meta contact + * @return the ui contacts */ - public MetaContact getMetaContact() + public List<UIContact> getUIContacts() { - return metaContact; + return uiContacts; } } } diff --git a/src/net/java/sip/communicator/impl/gui/utils/InviteDialog.java b/src/net/java/sip/communicator/impl/gui/utils/InviteDialog.java index 8dcf07f..47a7cd7 100644 --- a/src/net/java/sip/communicator/impl/gui/utils/InviteDialog.java +++ b/src/net/java/sip/communicator/impl/gui/utils/InviteDialog.java @@ -8,17 +8,19 @@ package net.java.sip.communicator.impl.gui.utils; import java.awt.*; import java.awt.event.*; -import java.util.*; import javax.swing.*; import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.lookandfeel.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; -import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.gui.event.*; +import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.skin.*; import net.java.sip.communicator.util.swing.*; +import java.util.*; +import java.util.List; /** * The invite dialog is a widget that shows a list of contacts, from which the * user could pick in order to create a conference chat or call. @@ -28,52 +30,61 @@ import net.java.sip.communicator.util.swing.*; */ public class InviteDialog extends SIPCommDialog - implements Skinnable + implements Skinnable, + ContactListContainer { private static final long serialVersionUID = 0L; + /** + * Text area where user can specify a reason for the invitation. + */ private final JTextArea reasonArea = new JTextArea(); + /** + * The button, which performs the invite. + */ private final JButton inviteButton = new JButton( GuiActivator.getResources().getI18NString("service.gui.INVITE")); + /** + * The button, which cancels the operation. + */ private final JButton cancelButton = new JButton( GuiActivator.getResources().getI18NString("service.gui.CANCEL")); - private final DefaultListModel contactListModel = new DefaultListModel(); + /** + * The search field. + */ + private final SearchField searchField; - protected final DefaultListModel selectedContactListModel - = new DefaultListModel(); + /** + * The source contact list. + */ + protected ContactList srcContactList; - protected final SIPCommTextField newContactField - = new SIPCommTextField(GuiActivator.getResources() - .getI18NString("service.gui.OR_ENTER_PHONE_NUMBER")); + /** + * The destination contact list. + */ + protected ContactList destContactList; /** - * Icon label. + * The invite contact transfer handler. */ - private final JLabel iconLabel; + private InviteContactTransferHandler inviteContactTransferHandler; /** - * Constructs an <tt>InviteDialog</tt>, by specifying the initial list of - * contacts available for invite. - * - * @param title the title to show on the top of this dialog - * @param metaContacts the list of contacts available for invite + * Currently selected protocol provider. */ - public InviteDialog(String title, java.util.List<MetaContact> metaContacts) - { - this(title); + private ProtocolProviderService currentProvider; - // Initialize contacts list. - for(MetaContact metaContact : metaContacts) - { - this.addMetaContact(metaContact); - } - } + /** + * Icon label. + */ + private final JLabel iconLabel; /** * Constructs an <tt>InviteDialog</tt>. + * * @param title the title to show on the top of this dialog */ public InviteDialog (String title) @@ -120,78 +131,22 @@ public class InviteDialog buttonsPanel.add(inviteButton); buttonsPanel.add(cancelButton); - this.getRootPane().setDefaultButton(inviteButton); inviteButton.setMnemonic( GuiActivator.getResources().getI18nMnemonic("service.gui.INVITE")); cancelButton.setMnemonic( GuiActivator.getResources().getI18nMnemonic("service.gui.CANCEL")); - final DefaultContactList contactList = new DefaultContactList(); - final DefaultContactList selectedContactList = new DefaultContactList(); + Component contactListComponent = createSrcContactListComponent(); - contactList.setModel(contactListModel); - contactList.setDragEnabled(true); - contactList.setTransferHandler(new InviteContactTransferHandler(this, - false)); - selectedContactList.setModel(selectedContactListModel); - selectedContactList.setTransferHandler( - new InviteContactTransferHandler(this, true)); - selectedContactList.setDragEnabled(true); + ContactListSearchFilter inviteFilter + = new InviteContactListFilter(srcContactList); - contactList.addMouseListener(new MouseAdapter() - { - public void mouseClicked(MouseEvent e) - { - if (e.getClickCount() > 1) - { - Object[] metaContacts = contactList.getSelectedValues(); - - moveContactsFromLeftToRight(metaContacts); - } - } - }); + srcContactList.setDefaultFilter(inviteFilter); - selectedContactList.addMouseListener(new MouseAdapter() - { - public void mouseClicked(MouseEvent e) - { - if (e.getClickCount() > 1) - { - Object[] metaContacts - = selectedContactList.getSelectedValues(); - - moveContactsFromRightToLeft(metaContacts); - } - } - }); - - JScrollPane contactListScrollPane = new JScrollPane(); - - contactListScrollPane.setOpaque(false); - contactListScrollPane.getViewport().setOpaque(false); - contactListScrollPane.getViewport().add(contactList); - contactListScrollPane.getViewport().setBorder(null); - contactListScrollPane.setViewportBorder(null); - contactListScrollPane.setBorder(null); - - JScrollPane selectedListScrollPane = new JScrollPane(); - - selectedListScrollPane.setOpaque(false); - selectedListScrollPane.getViewport().setOpaque(false); - selectedListScrollPane.getViewport().add(selectedContactList); - selectedListScrollPane.getViewport().setBorder(null); - selectedListScrollPane.setViewportBorder(null); - selectedListScrollPane.setBorder( - SIPCommBorders.getRoundBorder()); - - // New contact text field panel. - newContactField.getInputMap().put( - KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), - "moveStringFromLeftToRight"); - newContactField.getActionMap().put("moveStringFromLeftToRight", - new MoveStringToRight()); - - newContactField.addFocusListener(new FocusAdapter() + searchField = new SearchField(null, inviteFilter); + searchField.setPreferredSize(new Dimension(200, 25)); + searchField.setContactList(srcContactList); + searchField.addFocusListener(new FocusAdapter() { /** * Removes all other selections. @@ -199,21 +154,20 @@ public class InviteDialog */ public void focusGained(FocusEvent e) { - contactList.removeSelectionInterval( - 0, contactList.getMaxSelectionIndex()); + srcContactList.removeSelection(); } }); - TransparentPanel leftPanel = new TransparentPanel(new BorderLayout()); - leftPanel.setBorder(SIPCommBorders.getRoundBorder()); - leftPanel.add(contactListScrollPane); - leftPanel.add(newContactField, BorderLayout.SOUTH); + TransparentPanel leftPanel + = new TransparentPanel(new BorderLayout(5, 5)); + leftPanel.add(searchField, BorderLayout.NORTH); + leftPanel.add(contactListComponent); JPanel listPanel = new JPanel(new GridLayout(0, 2, 5, 5)); listPanel.setPreferredSize(new Dimension(400, 200)); listPanel.add(leftPanel); - listPanel.add(selectedListScrollPane); + listPanel.add(createDestContactListComponent()); listPanel.setOpaque(false); // Add remove buttons panel. @@ -233,12 +187,11 @@ public class InviteDialog { public void actionPerformed(ActionEvent e) { - Object[] metaContacts = contactList.getSelectedValues(); - - if (metaContacts != null && metaContacts.length > 0) - moveContactsFromLeftToRight(metaContacts); + List<UIContact> selectedContacts + = srcContactList.getSelectedContacts(); - moveStringFromLeftToRight(); + if (selectedContacts != null && selectedContacts.size() > 0) + moveContactsFromLeftToRight(selectedContacts.iterator()); } }); @@ -246,10 +199,11 @@ public class InviteDialog { public void actionPerformed(ActionEvent e) { - Object[] metaContacts = selectedContactList.getSelectedValues(); + List<UIContact> selectedContacts + = destContactList.getSelectedContacts(); - if (metaContacts != null && metaContacts.length > 0) - moveContactsFromRightToLeft(metaContacts); + if (selectedContacts != null && selectedContacts.size() > 0) + moveContactsFromRightToLeft(selectedContacts.iterator()); } }); @@ -267,211 +221,251 @@ public class InviteDialog mainPanel.add(southPanel, BorderLayout.SOUTH); this.getContentPane().add(mainPanel); - } - /** - * Adds the given <tt>metaContact</tt> to the right list (selected) of - * contacts for invite. - * @param metaContact the <tt>MetaContact</tt> to add - */ - public void addSelectedMetaContact(MetaContact metaContact) - { - selectedContactListModel.addElement(metaContact); - } + initTransferHandler(); - /** - * Removes the given <tt>metaContact</tt> from the right list (selected) of - * contacts available for invite. - * @param metaContact the <tt>MetaContact</tt> to remove - */ - public void removeSelectedMetaContact(MetaContact metaContact) - { - selectedContactListModel.removeElement(metaContact); + KeyboardFocusManager keyManager + = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + + ContactListSearchKeyDispatcher clKeyDispatcher + = new ContactListSearchKeyDispatcher( keyManager, + searchField, + this); + + clKeyDispatcher.setContactList(srcContactList); + + keyManager.addKeyEventDispatcher(clKeyDispatcher); } /** - * Adds the given <tt>metaContact</tt> to the left list of contacts - * available for invite. - * @param metaContact the <tt>MetaContact</tt> to add + * Returns the reason of this invite, if the user has specified one. + * + * @return the reason of this invite */ - public void addMetaContact(MetaContact metaContact) + public String getReason() { - contactListModel.addElement(metaContact); + return reasonArea.getText(); } /** - * Removes the given <tt>metaContact</tt> from the left list of contacts - * available for invite. - * @param metaContact the <tt>MetaContact</tt> to remove + * Adds an <tt>ActionListener</tt> to the contained "Invite" button. + * + * @param l the <tt>ActionListener</tt> to add */ - public void removeMetaContact(MetaContact metaContact) + public void addInviteButtonListener(ActionListener l) { - contactListModel.removeElement(metaContact); + this.inviteButton.addActionListener(l); } /** - * Removes all <tt>MetaContact</tt>-s from the left list of contacts - * available for invite. + * Adds an <tt>ActionListener</tt> to the contained "Cancel" button. + * + * @param l the <tt>ActionListener</tt> to add */ - public void removeAllMetaContacts() + public void addCancelButtonListener(ActionListener l) { - contactListModel.removeAllElements(); + this.cancelButton.addActionListener(l); } /** - * Removes all <tt>MetaContact</tt>-s from the right list of selected - * contacts for invite. + * Closes this dialog by clicking on the "Cancel" button. + * + * @param isEscaped indicates if this <tt>close</tt> is provoked by an + * escape */ - public void removeAllSelectedContacts() + protected void close(boolean isEscaped) { - selectedContactListModel.removeAllElements(); + this.cancelButton.doClick(); } /** - * Returns an enumeration of the list of selected <tt>MetaContact</tt>s. - * @return an enumeration of the list of selected <tt>MetaContact</tt>s + * Sets the current provider selected for this invite dialog. + * + * @param protocolProvider the protocol provider selected for this invite + * dialog */ - public Enumeration<MetaContact> getSelectedMetaContacts() + protected void setCurrentProvider(ProtocolProviderService protocolProvider) { - if (selectedContactListModel.getSize() == 0) - return null; - - Vector<MetaContact> selectedMetaContacts = new Vector<MetaContact>(); - Enumeration<?> selectedContacts = selectedContactListModel.elements(); - while(selectedContacts.hasMoreElements()) - { - Object contact = selectedContacts.nextElement(); - if (contact instanceof MetaContact) - selectedMetaContacts.add((MetaContact)contact); - } + this.currentProvider = protocolProvider; - return selectedMetaContacts.elements(); + inviteContactTransferHandler.setBackupProvider(currentProvider); } /** - * Returns an enumeration of the list of selected Strings. - * @return an enumeration of the list of selected Strings + * Moves contacts from the left list to the right. + * + * @param contacts an Iterator over a list of <tt>UIContact</tt>s */ - public Enumeration<String> getSelectedStrings() + private void moveContactsFromLeftToRight(Iterator<UIContact> contacts) { - if (selectedContactListModel.getSize() == 0) - return null; - - Vector<String> selectedStrings = new Vector<String>(); - Enumeration<?> selectedContacts = selectedContactListModel.elements(); - while(selectedContacts.hasMoreElements()) + while (contacts.hasNext()) { - Object contact = selectedContacts.nextElement(); - if (contact instanceof String) - selectedStrings.add((String)contact); + moveContactFromLeftToRight(contacts.next()); } - - return selectedStrings.elements(); } /** - * Returns the reason of this invite, if the user has specified one. - * @return the reason of this invite + * Moves the given <tt>UIContact</tt> from left list to the right. + * + * @param uiContact the contact to move */ - public String getReason() + private void moveContactFromLeftToRight(UIContact uiContact) { - return reasonArea.getText(); + destContactList.addContact( + new InviteUIContact(uiContact, currentProvider), null, false, false); } /** - * Adds an <tt>ActionListener</tt> to the contained "Invite" button. - * @param l the <tt>ActionListener</tt> to add + * Moves contacts from the right list to the left. + * + * @param contacts an Iterator over a list of <tt>UIContact</tt>s */ - public void addInviteButtonListener(ActionListener l) + protected void moveContactsFromRightToLeft(Iterator<UIContact> contacts) { - this.inviteButton.addActionListener(l); + while (contacts.hasNext()) + { + moveContactFromRightToLeft(contacts.next()); + } } /** - * Adds an <tt>ActionListener</tt> to the contained "Cancel" button. - * @param l the <tt>ActionListener</tt> to add + * Moves the given <tt>UIContact</tt> from left list to the right. + * + * @param uiContact the contact to move */ - public void addCancelButtonListener(ActionListener l) + private void moveContactFromRightToLeft(UIContact uiContact) { - this.cancelButton.addActionListener(l); + destContactList.removeContact(uiContact); } /** - * Closes this dialog by clicking on the "Cancel" button. - * @param isEscaped indicates if this <tt>close</tt> is provoked by an - * escape + * Reloads icon for icon label. */ - protected void close(boolean isEscaped) + public void loadSkin() { - this.cancelButton.doClick(); + iconLabel.setIcon(new ImageIcon( + ImageLoader.getImage(ImageLoader.INVITE_DIALOG_ICON))); } /** - * Moves contacts from the left list to the right. + * Creates the source contact list component. * - * @param metaContacts the contacts to move. + * @return the created contact list component */ - private void moveContactsFromLeftToRight(Object[] metaContacts) + private Component createSrcContactListComponent() { - for (Object metaContact : metaContacts) + srcContactList + = GuiActivator.getUIService().createContactListComponent(); + + srcContactList.setDragEnabled(true); + srcContactList.setContactButtonsVisible(false); + srcContactList.setMultipleSelectionEnabled(true); + srcContactList.addContactListListener(new ContactListListener() { - contactListModel.removeElement(metaContact); + public void groupSelected(ContactListEvent evt) {} - selectedContactListModel.addElement(metaContact); - } - } + public void groupClicked(ContactListEvent evt) {} - /** - * Moves a string from left to right. - */ - protected void moveStringFromLeftToRight() - { - String newContactText = newContactField.getText(); + public void contactSelected(ContactListEvent evt) {} + + public void contactClicked(ContactListEvent evt) + { + if (evt.getClickCount() > 1) + moveContactFromLeftToRight(evt.getSourceContact()); + } + }); - if (newContactText != null && newContactText.length() > 0) - selectedContactListModel.addElement(newContactField.getText()); + // By default we set the current filter to be the presence filter. + JScrollPane contactListScrollPane = new JScrollPane(); + + contactListScrollPane.setOpaque(false); + contactListScrollPane.getViewport().setOpaque(false); + contactListScrollPane.getViewport().add(srcContactList.getComponent()); + contactListScrollPane.getViewport().setBorder(null); + contactListScrollPane.setViewportBorder(null); + contactListScrollPane.setBorder(null); - newContactField.setText(""); + return contactListScrollPane; } /** - * Moves a contact from the right list to the left. + * Creates the destination contact list component. * - * @param contacts the contact to move. + * @return the created contact list component */ - protected void moveContactsFromRightToLeft(Object[] contacts) + private Component createDestContactListComponent() { - for (Object contact : contacts) + destContactList + = GuiActivator.getUIService().createContactListComponent(); + + destContactList.setContactButtonsVisible(false); + destContactList.setMultipleSelectionEnabled(true); + destContactList.addContactListListener(new ContactListListener() { - selectedContactListModel.removeElement(contact); + public void groupSelected(ContactListEvent evt) {} - // If this is a MetaContact re-add it in the left list. - if (contact instanceof MetaContact) - contactListModel.addElement(contact); - } + public void groupClicked(ContactListEvent evt) {} + + public void contactSelected(ContactListEvent evt) {} + + public void contactClicked(ContactListEvent evt) + { + if (evt.getClickCount() > 1) + moveContactFromRightToLeft(evt.getSourceContact()); + } + }); + + // By default we set the current filter to be the presence filter. + JScrollPane contactListScrollPane = new JScrollPane(); + + contactListScrollPane.setOpaque(false); + contactListScrollPane.getViewport().setOpaque(false); + contactListScrollPane.getViewport().add(destContactList.getComponent()); + contactListScrollPane.getViewport().setBorder(null); + contactListScrollPane.setViewportBorder(null); + contactListScrollPane.setBorder(null); + + return contactListScrollPane; } /** - * The <tt>MoveStringToRight</tt> is an <tt>AbstractAction</tt> that moves - * the text to right panel containing selected contacts. + * Called when the ENTER key was typed when this container was the focused + * container. Performs the appropriate actions depending on the current + * state of the contained contact list. */ - private class MoveStringToRight - extends UIAction + public void enterKeyTyped() { - private static final long serialVersionUID = 0L; + List<UIContact> selectedContacts = srcContactList.getSelectedContacts(); - public void actionPerformed(ActionEvent e) - { - moveStringFromLeftToRight(); - } + if (selectedContacts == null) + return; + + moveContactsFromLeftToRight(selectedContacts.iterator()); } /** - * Reloads icon for icon label. + * Called when the CTRL-ENTER or CMD-ENTER keys were typed when this + * container was the focused container. Performs the appropriate actions + * depending on the current state of the contained contact list. */ - public void loadSkin() + public void ctrlEnterKeyTyped() {} + + /** + * Initializes the transfer handler. + */ + private void initTransferHandler() { - iconLabel.setIcon(new ImageIcon( - ImageLoader.getImage(ImageLoader.INVITE_DIALOG_ICON))); + inviteContactTransferHandler + = new InviteContactTransferHandler( srcContactList, + destContactList, + true); + + if (srcContactList.getComponent() instanceof JComponent) + ((JComponent) srcContactList).setTransferHandler( + inviteContactTransferHandler); + + if (destContactList.getComponent() instanceof JComponent) + ((JComponent) destContactList).setTransferHandler( + inviteContactTransferHandler); } } diff --git a/src/net/java/sip/communicator/impl/gui/utils/OneChoiceInviteDialog.java b/src/net/java/sip/communicator/impl/gui/utils/OneChoiceInviteDialog.java index 3c98513..b2da16c 100644 --- a/src/net/java/sip/communicator/impl/gui/utils/OneChoiceInviteDialog.java +++ b/src/net/java/sip/communicator/impl/gui/utils/OneChoiceInviteDialog.java @@ -10,12 +10,12 @@ import java.awt.*; import java.awt.event.*; import javax.swing.*; -import javax.swing.event.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.lookandfeel.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; -import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.gui.event.*; import net.java.sip.communicator.util.swing.*; /** @@ -26,6 +26,7 @@ import net.java.sip.communicator.util.swing.*; */ public class OneChoiceInviteDialog extends SIPCommDialog + implements ContactListContainer { /** * The information text area. @@ -52,38 +53,12 @@ public class OneChoiceInviteDialog /** * The contact list. */ - private DefaultContactList contactList; + protected ContactList contactList; /** - * The contact list model. + * The search field. */ - private final DefaultListModel contactListModel = new DefaultListModel(); - - /** - * The new contact field. - */ - private final SIPCommTextField newContactField - = new SIPCommTextField(GuiActivator.getResources() - .getI18NString("service.gui.OR_ENTER_PHONE_NUMBER")); - - /** - * Constructs an <tt>OneChoiceInviteDialog</tt>, by specifying the initial - * list of contacts available. - * - * @param title the title to show on the top of this dialog - * @param metaContacts the list of contacts available for invite - */ - public OneChoiceInviteDialog(String title, - java.util.List<MetaContact> metaContacts) - { - this(title); - - // Initialize contacts list. - for(MetaContact metaContact : metaContacts) - { - this.addMetaContact(metaContact); - } - } + private final SearchField searchField; /** * Constructs an <tt>OneChoiceInviteDialog</tt>. @@ -125,7 +100,15 @@ public class OneChoiceInviteDialog Component contactListComponent = createContactListComponent(); - newContactField.addFocusListener(new FocusAdapter() + ContactListSearchFilter inviteFilter + = new InviteContactListFilter(contactList); + + contactList.setDefaultFilter(inviteFilter); + + searchField = new SearchField(null, inviteFilter); + searchField.setPreferredSize(new Dimension(200, 25)); + searchField.setContactList(contactList); + searchField.addFocusListener(new FocusAdapter() { /** * Removes all other selections. @@ -133,60 +116,42 @@ public class OneChoiceInviteDialog */ public void focusGained(FocusEvent e) { - contactList.removeSelectionInterval( - contactList.getMinSelectionIndex(), - contactList.getMaxSelectionIndex()); + contactList.removeSelection(); } }); TransparentPanel listPanel = new TransparentPanel(new BorderLayout()); listPanel.setBorder(SIPCommBorders.getRoundBorder()); listPanel.add(contactListComponent); - listPanel.add(newContactField, BorderLayout.SOUTH); + + northPanel.add(searchField, BorderLayout.SOUTH); mainPanel.add(northPanel, BorderLayout.NORTH); mainPanel.add(listPanel, BorderLayout.CENTER); mainPanel.add(buttonsPanel, BorderLayout.SOUTH); this.getContentPane().add(mainPanel); - } - /** - * Adds the given <tt>metaContact</tt> to the left list of contacts - * available for invite. - * @param metaContact the <tt>MetaContact</tt> to add - */ - public void addMetaContact(MetaContact metaContact) - { - contactListModel.addElement(metaContact); - } + KeyboardFocusManager keyManager + = KeyboardFocusManager.getCurrentKeyboardFocusManager(); - /** - * Removes the given <tt>metaContact</tt> from the left list of contacts - * available for invite. - * @param metaContact the <tt>MetaContact</tt> to add - */ - public void removeMetaContact(MetaContact metaContact) - { - contactListModel.removeElement(metaContact); - } + ContactListSearchKeyDispatcher clKeyDispatcher + = new ContactListSearchKeyDispatcher( keyManager, + searchField, + this); - /** - * Removes all <tt>MetaContact</tt>-s from the left list of contacts - * available for invite. - */ - public void removeAllMetaContacts() - { - contactListModel.removeAllElements(); + clKeyDispatcher.setContactList(contactList); + + keyManager.addKeyEventDispatcher(clKeyDispatcher); } /** * Returns an enumeration of the list of selected <tt>MetaContact</tt>s. * @return an enumeration of the list of selected <tt>MetaContact</tt>s */ - public MetaContact getSelectedMetaContact() + public UIContact getSelectedContact() { - return (MetaContact) contactList.getSelectedValue(); + return contactList.getSelectedContact(); } /** @@ -195,7 +160,7 @@ public class OneChoiceInviteDialog */ public String getSelectedString() { - return newContactField.getText(); + return searchField.getText(); } /** @@ -276,28 +241,71 @@ public class OneChoiceInviteDialog */ private Component createContactListComponent() { - contactList = new DefaultContactList(); - - contactList.setModel(contactListModel); + contactList + = GuiActivator.getUIService().createContactListComponent(); - contactList.addListSelectionListener(new ListSelectionListener() + contactList.setContactButtonsVisible(false); + contactList.addContactListListener(new ContactListListener() { - public void valueChanged(ListSelectionEvent e) + public void groupSelected(ContactListEvent evt) {} + + public void groupClicked(ContactListEvent evt) {} + + public void contactSelected(ContactListEvent evt) {} + + public void contactClicked(ContactListEvent evt) { - if (contactList.getSelectedIndex() >= 0) - newContactField.setText(""); + int clickCount = evt.getClickCount(); + + if (clickCount > 1) + { + okButton.doClick(); + } } }); + // By default we set the current filter to be the presence filter. JScrollPane contactListScrollPane = new JScrollPane(); contactListScrollPane.setOpaque(false); contactListScrollPane.getViewport().setOpaque(false); - contactListScrollPane.getViewport().add(contactList); + contactListScrollPane.getViewport().add(contactList.getComponent()); contactListScrollPane.getViewport().setBorder(null); contactListScrollPane.setViewportBorder(null); contactListScrollPane.setBorder(null); return contactListScrollPane; } + + /** + * Adds the given contact to this contact list. + * + * @param contact + */ + protected void addContact(UIContact contact) + { + contactList.addContact(contact, null, true, false); + } + + /** + * Called when the ENTER key was typed when this container was the focused + * container. Performs the appropriate actions depending on the current + * state of the contained contact list. + */ + public void enterKeyTyped() + { + UIContact selectedContact = contactList.getSelectedContact(); + + if (selectedContact != null) + { + okButton.doClick(); + } + } + + /** + * Called when the CTRL-ENTER or CMD-ENTER keys were typed when this + * container was the focused container. Performs the appropriate actions + * depending on the current state of the contained contact list. + */ + public void ctrlEnterKeyTyped() {} } diff --git a/src/net/java/sip/communicator/impl/ldap/LdapContactSourceService.java b/src/net/java/sip/communicator/impl/ldap/LdapContactSourceService.java index 1ca8bca..dd90821 100644 --- a/src/net/java/sip/communicator/impl/ldap/LdapContactSourceService.java +++ b/src/net/java/sip/communicator/impl/ldap/LdapContactSourceService.java @@ -114,9 +114,9 @@ public class LdapContactSourceService * should be returned by all call history implementations of this interface) * @return the identifier of this contact source */ - public String getIdentifier() + public int getType() { - return "LDAP"; + return SEARCH_TYPE; } /** @@ -205,4 +205,14 @@ public class LdapContactSourceService queries.notify(); } } + + /** + * Returns the index of the contact source in the result list. + * + * @return the index of the contact source in the result list + */ + public int getIndex() + { + return -1; + } } diff --git a/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java b/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java index a07678e..8aaad0f 100644 --- a/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java +++ b/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java @@ -141,6 +141,47 @@ public class MockProvider } /** + * Returns a collection containing all operation sets classes supported by + * the current implementation. When querying this method users must be + * prepared to receive any subset of the OperationSet-s defined by this + * service. They MUST ignore any OperationSet-s that they are not aware of + * and that may be defined by future versions of this service. Such + * "unknown" OperationSet-s though not encouraged, may also be defined by + * service implementors. + * + * @return a {@link Collection} containing instances of all supported + * operation set classes (e.g. <tt>OperationSetPresence.class</tt>. + */ + @SuppressWarnings("unchecked") + public Collection<Class<? extends OperationSet>> + getSupportedOperationSetClasses() + { + Collection<Class<? extends OperationSet>> opSetClasses + = new ArrayList<Class<? extends OperationSet>>(); + + Iterator<String> opSets + = getSupportedOperationSets().keySet().iterator(); + + while (opSets.hasNext()) + { + String opSetClassName = opSets.next(); + try + { + opSetClasses.add( + (Class<? extends OperationSet>) getSupportedOperationSets() + .get(opSetClassName).getClass().getClassLoader() + .loadClass(opSetClassName)); + } + catch (ClassNotFoundException e) + { + e.printStackTrace(); + } + } + + return opSetClasses; + } + + /** * Returns the operation set corresponding to the specified class or null * if this operation set is not supported by the provider implementation. * diff --git a/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactSourceService.java b/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactSourceService.java index 26c3857..1e75e7e 100644 --- a/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactSourceService.java +++ b/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactSourceService.java @@ -65,11 +65,11 @@ public class MacOSXAddrBookContactSourceService *
* @return a <tt>String</tt> which uniquely identifies the instances of the
* <tt>MacOSXAddrBookContactSourceService</tt> implementation
- * @see ContactSourceService#getIdentifier()
+ * @see ContactSourceService#getType()
*/
- public String getIdentifier()
+ public int getType()
{
- return "MacOSXAddressBook";
+ return SEARCH_TYPE;
}
/**
@@ -129,6 +129,16 @@ public class MacOSXAddrBookContactSourceService }
/**
+ * Returns the index of the contact source in the result list.
+ *
+ * @return the index of the contact source in the result list
+ */
+ public int getIndex()
+ {
+ return -1;
+ }
+
+ /**
* Stops a native <tt>MacOSXAddrBookContactSourceService</tt>.
*
* @param ptr the pointer to the native
diff --git a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java index f94dac5..1f270ac 100644 --- a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java +++ b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java @@ -93,11 +93,11 @@ public class MsOutlookAddrBookContactSourceService *
* @return a <tt>String</tt> which uniquely identifies the instances of the
* <tt>MsOutlookAddrBookContactSourceService</tt> implementation
- * @see ContactSourceService#getIdentifier()
+ * @see ContactSourceService#getType()
*/
- public String getIdentifier()
+ public int getType()
{
- return "MsOutlookAddressBook";
+ return SEARCH_TYPE;
}
private static native void MAPIInitialize(long version, long flags)
@@ -206,4 +206,14 @@ public class MsOutlookAddrBookContactSourceService queries.notify();
}
}
+
+ /**
+ * Returns the index of the contact source in the result list.
+ *
+ * @return the index of the contact source in the result list
+ */
+ public int getIndex()
+ {
+ return -1;
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PNContactSourceActivator.java b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PNContactSourceActivator.java new file mode 100644 index 0000000..90657e5 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PNContactSourceActivator.java @@ -0,0 +1,217 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.phonenumbercontactsource; + +import java.util.*; + +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; + +import org.jitsi.service.resources.*; +import org.osgi.framework.*; + +/** + * The activator for the phone number contact source bundle. + * + * @author Yana Stamcheva + */ +public class PNContactSourceActivator + implements BundleActivator +{ + /** + * The <tt>Logger</tt> used by the + * <tt>PNContactSourceActivator</tt> class for logging output. + */ + private static final Logger logger + = Logger.getLogger(PNContactSourceActivator.class); + + /** + * The bundle context. + */ + static BundleContext bundleContext = null; + + /** + * Providers of contact info. + */ + private static List<ProtocolProviderService> phoneProviders; + + /** + * The contact source. + */ + private static final PhoneNumberContactSource phoneNumberContactSource + = new PhoneNumberContactSource(); + + /** + * The resource service. + */ + private static ResourceManagementService resources = null; + + /** + * Starts this bundle. + * + * @param context the bundle context where we register and obtain services. + */ + public void start(BundleContext context) throws Exception + { + bundleContext = context; + + bundleContext.registerService( + ContactSourceService.class.getName(), + phoneNumberContactSource, + null); + } + + public void stop(BundleContext context) throws Exception + { + } + + /** + * Returns a reference to the ResourceManagementService implementation + * currently registered in the bundle context or null if no such + * implementation was found. + * + * @return a reference to a ResourceManagementService implementation + * currently registered in the bundle context or null if no such + * implementation was found. + */ + public static ResourceManagementService getResources() + { + if (resources == null) + { + resources + = ServiceUtils.getService( + bundleContext, ResourceManagementService.class); + } + return resources; + } + + /** + * Returns a list of all currently registered server stored contact info + * providers. + * + * @return a list of all currently registered server stored contact info + * providers + */ + public static List<ProtocolProviderService> getPhoneNumberProviders() + { + if (phoneProviders != null) + return phoneProviders; + + phoneProviders = new LinkedList<ProtocolProviderService>(); + + bundleContext.addServiceListener(new ProtocolProviderRegListener()); + + ServiceReference[] serRefs = null; + try + { + // get all registered provider factories + serRefs + = bundleContext.getServiceReferences( + ProtocolProviderFactory.class.getName(), + null); + } + catch (InvalidSyntaxException e) + { + logger.error("LoginManager : " + e); + } + + if (serRefs != null) + { + for (ServiceReference serRef : serRefs) + { + ProtocolProviderFactory providerFactory + = (ProtocolProviderFactory) + bundleContext.getService(serRef); + + ProtocolProviderService protocolProvider; + + for (AccountID accountID + : providerFactory.getRegisteredAccounts()) + { + serRef = providerFactory.getProviderForAccount(accountID); + + protocolProvider + = (ProtocolProviderService) bundleContext + .getService(serRef); + + handleProviderAdded(protocolProvider); + } + } + } + return phoneProviders; + } + + /** + * Listens for <tt>ProtocolProviderService</tt> registrations. + */ + private static class ProtocolProviderRegListener + implements ServiceListener + { + public void serviceChanged(ServiceEvent event) + { + ServiceReference serviceRef = event.getServiceReference(); + + // if the event is caused by a bundle being stopped, we don't want to + // know + if (serviceRef.getBundle().getState() == Bundle.STOPPING) + { + return; + } + + Object service = bundleContext.getService(serviceRef); + + // we don't care if the source service is not a protocol provider + if (!(service instanceof ProtocolProviderService)) + { + return; + } + + switch (event.getType()) + { + case ServiceEvent.REGISTERED: + handleProviderAdded((ProtocolProviderService) service); + break; + case ServiceEvent.UNREGISTERING: + handleProviderRemoved((ProtocolProviderService) service); + break; + } + } + } + + /** + * Handles the registration of a new <tt>ProtocolProviderService</tt>. Adds + * the given <tt>protocolProvider</tt> to the list of queried providers. + * + * @param protocolProvider the <tt>ProtocolProviderService</tt> to add + */ + private static void handleProviderAdded( + ProtocolProviderService protocolProvider) + { + if (protocolProvider.getOperationSet( + OperationSetServerStoredContactInfo.class) != null + && protocolProvider.isRegistered() + && !phoneProviders.contains(protocolProvider)) + { + phoneProviders.add(protocolProvider); + } + } + + /** + * Handles the un-registration of a <tt>ProtocolProviderService</tt>. + * Removes the given <tt>protocolProvider</tt> from the list of queried + * providers. + * + * @param protocolProvider the <tt>ProtocolProviderService</tt> to remove + */ + private static void handleProviderRemoved( + ProtocolProviderService protocolProvider) + { + if (phoneProviders.contains(protocolProvider)) + phoneProviders.remove(protocolProvider); + } +} diff --git a/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberContactQuery.java b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberContactQuery.java new file mode 100644 index 0000000..e65ba51 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberContactQuery.java @@ -0,0 +1,228 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.phonenumbercontactsource; + +import java.util.*; +import java.util.regex.*; + +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.ServerStoredDetails.*; + +/** + * The <tt>PhoneNumberContactQuery</tt> is a query over the + * <tt>PhoneNumberContactSource</tt>. + * + * @author Yana Stamcheva + */ +public class PhoneNumberContactQuery + extends AsyncContactQuery<PhoneNumberContactSource> +{ + /** + * The query string. + */ + private String queryString; + + /** + * The contact count. + */ + private int contactCount; + + /** + * Creates an instance of <tt>PhoneNumberContactQuery</tt> by specifying + * the parent contact source, the query string to match and the maximum + * result contacts to return. + * + * @param contactSource the parent contact source + * @param queryString the query string to match + * @param contactCount the maximum result contact count + */ + public PhoneNumberContactQuery( PhoneNumberContactSource contactSource, + String queryString, + int contactCount) + { + super(contactSource, + Pattern.compile(queryString, Pattern.CASE_INSENSITIVE + | Pattern.LITERAL)); + + this.queryString = queryString; + this.contactCount = contactCount; + } + + /** + * Do all the work in different thread. + */ + public void run() + { + Iterator<ProtocolProviderService> providers + = PNContactSourceActivator + .getPhoneNumberProviders().iterator(); + + while (providers.hasNext()) + { + if(contactCount > 0 && getQueryResultCount() > contactCount) + break; + + ProtocolProviderService provider = providers.next(); + + OperationSetPersistentPresence persPresOpSet + = provider.getOperationSet( + OperationSetPersistentPresence.class); + + // If there's no presence operation set continue to the + // next protocol provider. + if (persPresOpSet == null) + continue; + + ContactGroup rootGroup + = persPresOpSet.getServerStoredContactListRoot(); + + addResultContactsForGroup(rootGroup); + + Iterator<ContactGroup> subgroups = rootGroup.subgroups(); + + while (subgroups.hasNext()) + { + ContactGroup group = subgroups.next(); + + addResultContactsForGroup(group); + } + } + + if (getStatus() != QUERY_CANCELED) + setStatus(QUERY_COMPLETED); + } + + /** + * Adss the result contacts for the given group. + * + * @param group the <tt>ContactGroup</tt> to check for matching contacts + */ + private void addResultContactsForGroup(ContactGroup group) + { + Iterator<Contact> contacts = group.contacts(); + while (contacts.hasNext()) + { + if(contactCount > 0 && getQueryResultCount() > contactCount) + break; + + Contact contact = contacts.next(); + + addAdditionalNumbers(contact); + } + } + + /** + * Returns all additional phone numbers corresponding to the given + * contact. + * + * @param contact the <tt>contact</tt>, which phone details we're + * looking for + * @return a list of all additional phone numbers corresponding to the + * given contact + */ + private void addAdditionalNumbers(Contact contact) + { + OperationSetServerStoredContactInfo infoOpSet + = contact.getProtocolProvider().getOperationSet( + OperationSetServerStoredContactInfo.class); + + Iterator<GenericDetail> details; + + if(infoOpSet != null) + { + details = infoOpSet.getAllDetailsForContact(contact); + + while(details.hasNext()) + { + if(contactCount > 0 && getQueryResultCount() > contactCount) + break; + + GenericDetail d = details.next(); + if(d instanceof PhoneNumberDetail && + !(d instanceof PagerDetail) && + !(d instanceof FaxDetail)) + { + PhoneNumberDetail pnd = (PhoneNumberDetail)d; + if(pnd.getNumber() != null && + pnd.getNumber().length() > 0) + { + String localizedType = null; + + if(d instanceof WorkPhoneDetail) + { + localizedType = + PNContactSourceActivator.getResources() + .getI18NString("service.gui.WORK_PHONE"); + } + else if(d instanceof MobilePhoneDetail) + { + localizedType = + PNContactSourceActivator.getResources() + .getI18NString("service.gui.MOBILE_PHONE"); + } + else + { + localizedType = + PNContactSourceActivator.getResources() + .getI18NString("service.gui.PHONE"); + } + + String contactName = contact.getDisplayName(); + String contactAddress = contact.getAddress(); + String numberString = pnd.getNumber(); + + if(queryString == null + || (queryString != null + && (numberString.startsWith( + queryString) + || contactName.startsWith(queryString) + || contactAddress.startsWith(queryString) + ))) + { + ArrayList<ContactDetail> contactDetails + = new ArrayList<ContactDetail>(); + + ContactDetail detail + = new ContactDetail(pnd.getNumber()); + ArrayList<Class<? extends OperationSet>> + supportedOpSets + = new ArrayList<Class<? extends OperationSet>>(); + supportedOpSets + .add(OperationSetBasicTelephony.class); + detail.setSupportedOpSets(supportedOpSets); + + contactDetails.add(detail); + + PhoneNumberSourceContact numberSourceContact + = new PhoneNumberSourceContact( + getContactSource(), + contact, + contactDetails, + pnd.getNumber() + + "(" + localizedType + ")"); + + addQueryResult(numberSourceContact); + } + } + } + } + } + } + + @Override + protected String normalizePhoneNumber(String phoneNumber) + { + return null; + } + + @Override + protected boolean phoneNumberMatches(String phoneNumber) + { + return false; + } +}
\ No newline at end of file diff --git a/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberContactSource.java b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberContactSource.java new file mode 100644 index 0000000..a5c662e --- /dev/null +++ b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberContactSource.java @@ -0,0 +1,114 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.phonenumbercontactsource; + +import java.util.*; + +import net.java.sip.communicator.service.contactsource.*; + +/** + * The <tt>PhoneNumberContactSource</tt> is a source of phone numbers coming + * from the server stored contact info of all contacts for all protocol + * providers. + * + * @author Yana Stamcheva + */ +public class PhoneNumberContactSource + implements ContactSourceService +{ + /** + * The <tt>List</tt> of <tt>PhoneNumberContactQuery</tt> instances + * which have been started and haven't stopped yet. + */ + private final List<PhoneNumberContactQuery> queries + = new LinkedList<PhoneNumberContactQuery>(); + + /** + * Returns DEFAULT_TYPE to indicate that this contact source is a default + * source. + * + * @return the type of this contact source + */ + public int getType() + { + return DEFAULT_TYPE; + } + + /** + * Returns a user-friendly string that identifies this contact source. + * + * @return the display name of this contact source + */ + public String getDisplayName() + { + return PNContactSourceActivator.getResources().getI18NString( + "plugin.phonenumbercontactsource.DISPLAY_NAME"); + } + + /** + * Queries this contact source for the given <tt>queryString</tt>. + * + * @param queryString the string to search for + * @return the created query + */ + public ContactQuery queryContactSource(String queryString) + { + return queryContactSource(queryString, -1); + } + + /** + * Queries this contact source for the given <tt>queryString</tt>. + * + * @param queryString the string to search for + * @param contactCount the maximum count of result contacts + * @return the created query + */ + public ContactQuery queryContactSource( String queryString, + int contactCount) + { + if (queryString == null) + queryString = ""; + + PhoneNumberContactQuery contactQuery + = new PhoneNumberContactQuery(this, queryString, contactCount); + + synchronized (queries) + { + queries.add(contactQuery); + } + + boolean queryHasStarted = false; + + try + { + contactQuery.start(); + queryHasStarted = true; + } + finally + { + if (!queryHasStarted) + { + synchronized (queries) + { + if (queries.remove(contactQuery)) + queries.notify(); + } + } + } + return contactQuery; + } + + /** + * Returns the index of the contact source in the result list. + * + * @return the index of the contact source in the result list + */ + public int getIndex() + { + return -1; + } +} diff --git a/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberSourceContact.java b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberSourceContact.java new file mode 100644 index 0000000..00943f3 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberSourceContact.java @@ -0,0 +1,85 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.phonenumbercontactsource; + +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.protocol.*; + +import java.util.*; + +/** + * The <tt>PhoneNumberSourceContact</tt> extends the + * <tt>GenericSourceContact</tt> and represents a contact in the + * <tt>PhoneNumberContactSource</tt>. + * + * @author Yana Stamcheva + */ +public class PhoneNumberSourceContact + extends GenericSourceContact +{ + /** + * The display details of this contact. + */ + private String displayDetails; + + /** + * Creates an instance of <tt>PhoneNumberSourceContact</tt>. + * + * @param contactSource the parent contact source + * @param contact the protocol contact corresponding to this source contact + * information about the phone number corresponding to this source contact + * @param detailDisplayName the display name of the phone number detail + */ + public PhoneNumberSourceContact(PhoneNumberContactSource contactSource, + Contact contact, + List<ContactDetail> contactDetails, + String detailDisplayName) + { + super( contactSource, + contact.getDisplayName(), + contactDetails); + + displayDetails = detailDisplayName; + } + + /** + * Returns the display details of this search contact. This could be any + * important information that should be shown to the user. + * + * @return the display details of the search contact + */ + public String getDisplayDetails() + { + return displayDetails; + } + + /** + * Compares object display names. + */ + @Override + public boolean equals(Object o) + { + if(this == o) + return true; + + if(o == null) + return false; + + if(o == null || getClass() != o.getClass()) + return false; + + PhoneNumberSourceContact that = (PhoneNumberSourceContact) o; + + String displayName = getDisplayName(); + if(displayName != null ? + !displayName.equals(that.getDisplayName()) + : that.getDisplayName() != null) + return false; + + return true; + } +} diff --git a/src/net/java/sip/communicator/plugin/phonenumbercontactsource/phonenumbercontactsource.manifest.mf b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/phonenumbercontactsource.manifest.mf new file mode 100644 index 0000000..ba3c1ff --- /dev/null +++ b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/phonenumbercontactsource.manifest.mf @@ -0,0 +1,12 @@ +Bundle-Activator: net.java.sip.communicator.plugin.phonenumbercontactsource.PNContactSourceActivator +Bundle-Name: Phone number contact source +Bundle-Description: Phone number contact source +Bundle-Vendor: jitsi.org +Bundle-Version: 0.0.1 +System-Bundle: yes +Import-Package: org.osgi.framework, + net.java.sip.communicator.service.contactsource, + net.java.sip.communicator.service.protocol, + net.java.sip.communicator.service.protocol.event, + net.java.sip.communicator.util, + org.jitsi.service.resources
\ No newline at end of file diff --git a/src/net/java/sip/communicator/service/contactsource/AsyncContactQuery.java b/src/net/java/sip/communicator/service/contactsource/AsyncContactQuery.java index 20b06bb..aed89b3 100644 --- a/src/net/java/sip/communicator/service/contactsource/AsyncContactQuery.java +++ b/src/net/java/sip/communicator/service/contactsource/AsyncContactQuery.java @@ -88,6 +88,7 @@ public abstract class AsyncContactQuery<T extends ContactSourceService> }
if (changed)
fireContactReceived(sourceContact);
+
return changed;
}
diff --git a/src/net/java/sip/communicator/service/contactsource/ContactDetail.java b/src/net/java/sip/communicator/service/contactsource/ContactDetail.java index 0de7e69..23e7092 100644 --- a/src/net/java/sip/communicator/service/contactsource/ContactDetail.java +++ b/src/net/java/sip/communicator/service/contactsource/ContactDetail.java @@ -315,6 +315,7 @@ public class ContactDetail * Returns a list of all supported <tt>OperationSet</tt> classes, which * would indicate what are the supported actions by this contact * (e.g. write a message, make a call, etc.) + * * @return a list of all supported <tt>OperationSet</tt> classes */ public List<Class<? extends OperationSet>> getSupportedOperationSets() diff --git a/src/net/java/sip/communicator/service/contactsource/ContactSourceService.java b/src/net/java/sip/communicator/service/contactsource/ContactSourceService.java index 35001c8..0077c47 100644 --- a/src/net/java/sip/communicator/service/contactsource/ContactSourceService.java +++ b/src/net/java/sip/communicator/service/contactsource/ContactSourceService.java @@ -16,26 +16,37 @@ package net.java.sip.communicator.service.contactsource; public interface ContactSourceService { /** - * Constants to identify <tt>ContactSource</tt> in call history. + * Type of a default source. */ - public static final String CALL_HISTORY = "CallHistory"; + public static final int DEFAULT_TYPE = 0; /** - * Returns the identifier of this contact source. Some of the common - * identifiers are defined here (For example the CALL_HISTORY identifier - * should be returned by all call history implementations of this interface) - * @return the identifier of this contact source + * Type of a search source. Queried only when searches are performed. */ - public String getIdentifier(); + public static final int SEARCH_TYPE = 1; + + /** + * Type of a history source. Queries only when history should be shown. + */ + public static final int HISTORY_TYPE = 2; + + /** + * Returns the type of this contact source. + * + * @return the type of this contact source + */ + public int getType(); /** * Returns a user-friendly string that identifies this contact source. + * * @return the display name of this contact source */ public String getDisplayName(); /** * Queries this search source for the given <tt>queryString</tt>. + * * @param queryString the string to search for * @return the created query */ @@ -50,4 +61,11 @@ public interface ContactSourceService */ public ContactQuery queryContactSource(String queryString, int contactCount); + + /** + * Returns the index of the contact source in the result list. + * + * @return the index of the contact source in the result list + */ + public int getIndex(); } diff --git a/src/net/java/sip/communicator/service/contactsource/GenericSourceContact.java b/src/net/java/sip/communicator/service/contactsource/GenericSourceContact.java index 4214c16..f2897ab 100644 --- a/src/net/java/sip/communicator/service/contactsource/GenericSourceContact.java +++ b/src/net/java/sip/communicator/service/contactsource/GenericSourceContact.java @@ -38,6 +38,16 @@ public class GenericSourceContact private final String displayName;
/**
+ * The display details of this contact.
+ */
+ private String displayDetails;
+
+ /**
+ * The presence status of this contact.
+ */
+ private PresenceStatus presenceStatus;
+
+ /**
* The image/avatar of this <tt>SourceContact</tt>
*/
private byte[] image;
@@ -139,8 +149,17 @@ public class GenericSourceContact */
public String getDisplayDetails()
{
- // TODO Auto-generated method stub
- return null;
+ return displayDetails;
+ }
+
+ /**
+ * Sets the display details of this <tt>SourceContact</tt>.
+ *
+ * @param displayDetails the display details of this <tt>SourceContact</tt>
+ */
+ public String setDisplayDetails(String displayDetails)
+ {
+ return this.displayDetails = displayDetails;
}
/**
@@ -200,6 +219,16 @@ public class GenericSourceContact */
public PresenceStatus getPresenceStatus()
{
- return null;
+ return presenceStatus;
+ }
+
+ /**
+ * Sets the status of the source contact.
+ *
+ * @param presenceStatus the status of this contact
+ */
+ public void setPresenceStatus(PresenceStatus presenceStatus)
+ {
+ this.presenceStatus = presenceStatus;
}
}
diff --git a/src/net/java/sip/communicator/service/gui/ContactList.java b/src/net/java/sip/communicator/service/gui/ContactList.java index 1a448ba..ca57886 100644 --- a/src/net/java/sip/communicator/service/gui/ContactList.java +++ b/src/net/java/sip/communicator/service/gui/ContactList.java @@ -8,6 +8,7 @@ package net.java.sip.communicator.service.gui; import java.awt.*; import java.util.*; +import java.util.List; import net.java.sip.communicator.service.contactsource.*; import net.java.sip.communicator.service.gui.event.*; @@ -20,6 +21,8 @@ import net.java.sip.communicator.service.gui.event.*; * @author Yana Stamcheva */ public interface ContactList + extends ContactQueryListener, + MetaContactQueryListener { /** * Returns the actual component corresponding to the contact list. @@ -30,6 +33,7 @@ public interface ContactList /** * Returns the list of registered contact sources to search in. + * * @return the list of registered contact sources to search in */ public Collection<UIContactSource> getContactSources(); @@ -37,6 +41,7 @@ public interface ContactList /** * Returns the <tt>ExternalContactSource</tt> corresponding to the given * <tt>ContactSourceService</tt>. + * * @param contactSource the <tt>ContactSourceService</tt>, which * corresponding external source implementation we're looking for * @return the <tt>ExternalContactSource</tt> corresponding to the given @@ -45,7 +50,49 @@ public interface ContactList public UIContactSource getContactSource(ContactSourceService contactSource); /** + * Adds the given contact source to the list of available contact sources. + * + * @param contactSource the <tt>ContactSourceService</tt> + */ + public void addContactSource(ContactSourceService contactSource); + + /** + * Removes the given contact source from the list of available contact + * sources. + * + * @param contactSource + */ + public void removeContactSource(ContactSourceService contactSource); + + /** + * Removes all stored contact sources. + */ + public void removeAllContactSources(); + + /** + * Sets the default filter to the given <tt>filter</tt>. + * @param filter the <tt>ContactListFilter</tt> to set as default + */ + public void setDefaultFilter(ContactListFilter filter); + + /** + * Gets the default filter for this contact list. + * + * @return the default filter for this contact list + */ + public ContactListFilter getDefaultFilter(); + + /** + * Returns all <tt>UIContactSource</tt>s of the given type. + * + * @param type the type of sources we're looking for + * @return a list of all <tt>UIContactSource</tt>s of the given type + */ + public List<UIContactSource> getContactSources(int type); + + /** * Adds the given group to this list. + * * @param group the <tt>UIGroup</tt> to add * @param isSorted indicates if the contact should be sorted regarding to * the <tt>GroupNode</tt> policy @@ -54,12 +101,14 @@ public interface ContactList /** * Removes the given group and its children from the list. + * * @param group the <tt>UIGroup</tt> to remove */ public void removeGroup(final UIGroup group); /** * Adds the given <tt>contact</tt> to this list. + * * @param contact the <tt>UIContact</tt> to add * @param group the <tt>UIGroup</tt> to add to * @param isContactSorted indicates if the contact should be sorted @@ -75,6 +124,7 @@ public interface ContactList /** * Adds the given <tt>contact</tt> to this list. + * * @param query the <tt>ContactQuery</tt> that adds the given contact * @param contact the <tt>UIContact</tt> to add * @param group the <tt>UIGroup</tt> to add to @@ -89,6 +139,7 @@ public interface ContactList /** * Removes the node corresponding to the given <tt>MetaContact</tt> from * this list. + * * @param contact the <tt>UIContact</tt> to remove * @param removeEmptyGroup whether we should delete the group if is empty */ @@ -98,18 +149,38 @@ public interface ContactList /** * Removes the node corresponding to the given <tt>MetaContact</tt> from * this list. + * * @param contact the <tt>UIContact</tt> to remove */ public void removeContact(UIContact contact); /** + * Returns a collection of all direct child <tt>UIContact</tt>s of the given + * <tt>UIGroup</tt>. + * + * @param group the parent <tt>UIGroup</tt> + * @return a collection of all direct child <tt>UIContact</tt>s of the given + * <tt>UIGroup</tt> + */ + public Collection<UIContact> getContacts(final UIGroup group); + + /** * Returns the currently applied filter. + * * @return the currently applied filter */ public ContactListFilter getCurrentFilter(); /** + * Returns the currently applied filter. + * + * @return the currently applied filter + */ + public FilterQuery getCurrentFilterQuery(); + + /** * Applies the given <tt>filter</tt>. + * * @param filter the <tt>ContactListFilter</tt> to apply. * @return the filter query */ @@ -117,18 +188,27 @@ public interface ContactList /** * Applies the default filter. + * * @return the filter query that keeps track of the filtering results */ public FilterQuery applyDefaultFilter(); /** - * Returns the currently selected <tt>UIContact</tt> if there's one. + * Returns the currently selected <tt>UIContact</tt>. In case of a multiple + * selection returns the first contact in the selection. * * @return the currently selected <tt>UIContact</tt> if there's one. */ public UIContact getSelectedContact(); /** + * Returns the list of selected contacts. + * + * @return the list of selected contacts + */ + public List<UIContact> getSelectedContacts(); + + /** * Returns the currently selected <tt>UIGroup</tt> if there's one. * * @return the currently selected <tt>UIGroup</tt> if there's one. @@ -150,6 +230,17 @@ public interface ContactList public void setSelectedGroup(UIGroup uiGroup); /** + * Selects the first found contact node from the beginning of the contact + * list. + */ + public void selectFirstContact(); + + /** + * Removes the current selection. + */ + public void removeSelection(); + + /** * Adds a listener for <tt>ContactListEvent</tt>s. * * @param listener the listener to add @@ -169,4 +260,44 @@ public interface ContactList * @param uiContact the contact to refresh */ public void refreshContact(UIContact uiContact); + + /** + * Indicates if this contact list is empty. + * + * @return <tt>true</tt> if this contact list contains no children, + * otherwise returns <tt>false</tt> + */ + public boolean isEmpty(); + + /** + * Shows/hides buttons shown in contact row. + * + * @param isVisible <tt>true</tt> to show contact buttons, <tt>false</tt> - + * otherwise. + */ + public void setContactButtonsVisible(boolean isVisible); + + /** + * Shows/hides buttons shown in contact row. + * + * return <tt>true</tt> to indicate that contact buttons are shown, + * <tt>false</tt> - otherwise. + */ + public boolean isContactButtonsVisible(); + + /** + * Enables/disables multiple selection. + * + * @param isEnabled <tt>true</tt> to enable multiple selection, + * <tt>false</tt> - otherwise + */ + public void setMultipleSelectionEnabled(boolean isEnabled); + + /** + * Enables/disables drag operations on this contact list. + * + * @param isEnabled <tt>true</tt> to enable drag operations, <tt>false</tt> + * otherwise + */ + public void setDragEnabled(boolean isEnabled); } diff --git a/src/net/java/sip/communicator/service/gui/ContactListContainer.java b/src/net/java/sip/communicator/service/gui/ContactListContainer.java new file mode 100644 index 0000000..41746da --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/ContactListContainer.java @@ -0,0 +1,39 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui; + +/** + * The <tt>ContactListContainer</tt> is a container of a <tt>ContactList</tt> + * component. + * + * @author Yana Stamcheva + */ +public interface ContactListContainer +{ + /** + * Called when the ENTER key was typed when this container was the focused + * container. Performs the appropriate actions depending on the current + * state of the contained contact list. + */ + public void enterKeyTyped(); + + /** + * Called when the CTRL-ENTER or CMD-ENTER keys were typed when this + * container was the focused container. Performs the appropriate actions + * depending on the current state of the contained contact list. + */ + public void ctrlEnterKeyTyped(); + + /** + * Returns <tt>true</tt> if this contact list container has the focus, + * otherwise returns <tt>false</tt>. + * + * @return <tt>true</tt> if this contact list container has the focus, + * otherwise returns <tt>false</tt> + */ + public boolean isFocused(); +} diff --git a/src/net/java/sip/communicator/service/gui/ContactListSearchFilter.java b/src/net/java/sip/communicator/service/gui/ContactListSearchFilter.java new file mode 100644 index 0000000..7f2db25 --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/ContactListSearchFilter.java @@ -0,0 +1,22 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui; + +/** + * The <tt>ContactListSearchFilter</tt> is a <tt>ContactListFilter</tt> specific + * for string search. + */ +public interface ContactListSearchFilter + extends ContactListFilter +{ + /** + * Creates the <tt>SearchFilter</tt> by specifying the string used for + * filtering. + * @param filter the String used for filtering + */ + public void setFilterString(String filter); +} diff --git a/src/net/java/sip/communicator/service/gui/FilterQuery.java b/src/net/java/sip/communicator/service/gui/FilterQuery.java index 7b2cda9..ad5fd0a 100644 --- a/src/net/java/sip/communicator/service/gui/FilterQuery.java +++ b/src/net/java/sip/communicator/service/gui/FilterQuery.java @@ -17,6 +17,11 @@ import net.java.sip.communicator.service.gui.event.*; public abstract class FilterQuery { /** + * The maximum result count for each contact source. + */ + private int maxResultCount = 10; + + /** * A listener, which is notified when this query finishes. */ private FilterQueryListener filterQueryListener; @@ -47,6 +52,13 @@ public abstract class FilterQuery public abstract boolean isCanceled(); /** + * Indicates if this query is canceled. + * + * @return <tt>true</tt> if this query is canceled, <tt>false</tt> otherwise + */ + public abstract boolean isRunning(); + + /** * Cancels this filter query. */ public abstract void cancel(); @@ -81,4 +93,25 @@ public abstract class FilterQuery * filter query, <tt>false</tt> - otherwise */ public abstract boolean containsQuery(Object query); + + + /** + * Sets the maximum result count shown. + * + * @param resultCount the maximum result count shown + */ + public void setMaxResultShown(int resultCount) + { + this.maxResultCount = resultCount; + } + + /** + * Gets the maximum result count shown. + * + * @return the maximum result count shown + */ + public int getMaxResultShown() + { + return maxResultCount; + } } diff --git a/src/net/java/sip/communicator/service/gui/UIContactDetail.java b/src/net/java/sip/communicator/service/gui/UIContactDetail.java index 88f8a8e..6ae1182 100644 --- a/src/net/java/sip/communicator/service/gui/UIContactDetail.java +++ b/src/net/java/sip/communicator/service/gui/UIContactDetail.java @@ -37,13 +37,14 @@ public abstract class UIContactDetail /** * The <tt>ProtocolProviderService</tt> corresponding to this detail. */ - private final ProtocolProviderService protocolProvider; + private Map<Class<? extends OperationSet>, ProtocolProviderService> + preferredProviders; /** * The protocol to be used for this contact detail if no protocol provider * is set. */ - private final String preferredProtocol; + private Map<Class<? extends OperationSet>, String> preferredProtocols; /** * The collection of labels associated with this detail. @@ -63,6 +64,29 @@ public abstract class UIContactDetail /** * Creates a <tt>UIContactDetail</tt> by specifying the contact * <tt>address</tt>, the <tt>displayName</tt> and <tt>preferredProvider</tt>. + * + * @param address the contact address + * @param displayName the contact display name + * @param descriptor the underlying object that this class is wrapping + */ + public UIContactDetail( + String address, + String displayName, + Object descriptor) + { + this( address, + displayName, + null, + null, + null, + null, + descriptor); + } + + /** + * Creates a <tt>UIContactDetail</tt> by specifying the contact + * <tt>address</tt>, the <tt>displayName</tt> and <tt>preferredProvider</tt>. + * * @param address the contact address * @param displayName the contact display name * @param category the category of the underlying contact detail @@ -78,16 +102,17 @@ public abstract class UIContactDetail String displayName, String category, Collection<String> labels, - ProtocolProviderService preferredProvider, - String preferredProtocol, + Map<Class<? extends OperationSet>, ProtocolProviderService> + preferredProviders, + Map<Class<? extends OperationSet>, String> preferredProtocols, Object descriptor) { this.address = address; this.displayName = displayName; this.category = category; this.labels = labels; - this.protocolProvider = preferredProvider; - this.preferredProtocol = preferredProtocol; + this.preferredProviders = preferredProviders; + this.preferredProtocols = preferredProtocols; this.descriptor = descriptor; } @@ -147,7 +172,25 @@ public abstract class UIContactDetail public ProtocolProviderService getPreferredProtocolProvider( Class<? extends OperationSet> opSetClass) { - return protocolProvider; + return preferredProviders.get(opSetClass); + } + + /** + * Adds a preferred protocol provider for a given OperationSet class. + * + * @param opSetClass the <tt>OperationSet</tt> class for which we're looking + * for protocol + * @param protocol the preferred protocol provider to add + */ + public void addPreferredProtocolProvider( + Class<? extends OperationSet> opSetClass, + ProtocolProviderService protocolProvider) + { + if (preferredProviders == null) + preferredProviders = new HashMap< Class<? extends OperationSet>, + ProtocolProviderService>(); + + preferredProviders.put(opSetClass, protocolProvider); } /** @@ -160,7 +203,25 @@ public abstract class UIContactDetail */ public String getPreferredProtocol(Class<? extends OperationSet> opSetClass) { - return preferredProtocol; + return preferredProtocols.get(opSetClass); + } + + /** + * Adds a preferred protocol for a given OperationSet class. + * + * @param opSetClass the <tt>OperationSet</tt> class for which we're looking + * for protocol + * @param protocol the preferred protocol to add + */ + public void addPreferredProtocol( + Class<? extends OperationSet> opSetClass, + String protocol) + { + if (preferredProtocols == null) + preferredProtocols = new HashMap< Class<? extends OperationSet>, + String>(); + + preferredProtocols.put(opSetClass, protocol); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactQuery.java b/src/net/java/sip/communicator/service/gui/event/MetaContactQuery.java index caeae4b..9af6ff1 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactQuery.java +++ b/src/net/java/sip/communicator/service/gui/event/MetaContactQuery.java @@ -4,7 +4,7 @@ * Distributable under LGPL license. * See terms of license at gnu.org. */ -package net.java.sip.communicator.impl.gui.main.contactlist.contactsource; +package net.java.sip.communicator.service.gui.event; import java.util.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactQueryEvent.java b/src/net/java/sip/communicator/service/gui/event/MetaContactQueryEvent.java index 44c143c..2e8bf2e 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactQueryEvent.java +++ b/src/net/java/sip/communicator/service/gui/event/MetaContactQueryEvent.java @@ -4,7 +4,7 @@ * Distributable under LGPL license. * See terms of license at gnu.org. */ -package net.java.sip.communicator.impl.gui.main.contactlist.contactsource; +package net.java.sip.communicator.service.gui.event; import java.util.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactQueryListener.java b/src/net/java/sip/communicator/service/gui/event/MetaContactQueryListener.java index 7994810..a8f5ee4 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactQueryListener.java +++ b/src/net/java/sip/communicator/service/gui/event/MetaContactQueryListener.java @@ -4,7 +4,7 @@ * Distributable under LGPL license. * See terms of license at gnu.org. */ -package net.java.sip.communicator.impl.gui.main.contactlist.contactsource; +package net.java.sip.communicator.service.gui.event; /** * The <tt>MetaContactQueryListener</tt> listens for events coming from a diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactQueryStatusEvent.java b/src/net/java/sip/communicator/service/gui/event/MetaContactQueryStatusEvent.java index d0c8854..9d06713 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactQueryStatusEvent.java +++ b/src/net/java/sip/communicator/service/gui/event/MetaContactQueryStatusEvent.java @@ -4,7 +4,7 @@ * Distributable under LGPL license. * See terms of license at gnu.org. */ -package net.java.sip.communicator.impl.gui.main.contactlist.contactsource; +package net.java.sip.communicator.service.gui.event; import java.util.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaGroupQueryEvent.java b/src/net/java/sip/communicator/service/gui/event/MetaGroupQueryEvent.java index 500eebf..546c8f9 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaGroupQueryEvent.java +++ b/src/net/java/sip/communicator/service/gui/event/MetaGroupQueryEvent.java @@ -4,7 +4,7 @@ * Distributable under LGPL license. * See terms of license at gnu.org. */ -package net.java.sip.communicator.impl.gui.main.contactlist.contactsource; +package net.java.sip.communicator.service.gui.event; import java.util.*; diff --git a/src/net/java/sip/communicator/service/gui/gui.manifest.mf b/src/net/java/sip/communicator/service/gui/gui.manifest.mf index 0708371..1797cf6 100644 --- a/src/net/java/sip/communicator/service/gui/gui.manifest.mf +++ b/src/net/java/sip/communicator/service/gui/gui.manifest.mf @@ -7,7 +7,10 @@ System-Bundle: yes Import-Package: org.osgi.framework, org.jitsi.service.resources, net.java.sip.communicator.service.resources, - net.java.sip.communicator.util + net.java.sip.communicator.util, + net.java.sip.communicator.service.contactsource, + net.java.sip.communicator.service.contactlist, + net.java.sip.communicator.service.protocol Export-Package: net.java.sip.communicator.service.gui, net.java.sip.communicator.service.gui.event, net.java.sip.communicator.service.shutdown diff --git a/src/net/java/sip/communicator/service/protocol/AbstractProtocolProviderService.java b/src/net/java/sip/communicator/service/protocol/AbstractProtocolProviderService.java index a4423f5..a78ea45 100644 --- a/src/net/java/sip/communicator/service/protocol/AbstractProtocolProviderService.java +++ b/src/net/java/sip/communicator/service/protocol/AbstractProtocolProviderService.java @@ -211,6 +211,48 @@ public abstract class AbstractProtocolProviderService return new Hashtable<String, OperationSet>(supportedOperationSets); } + + /** + * Returns a collection containing all operation sets classes supported by + * the current implementation. When querying this method users must be + * prepared to receive any subset of the OperationSet-s defined by this + * service. They MUST ignore any OperationSet-s that they are not aware of + * and that may be defined by future versions of this service. Such + * "unknown" OperationSet-s though not encouraged, may also be defined by + * service implementors. + * + * @return a {@link Collection} containing instances of all supported + * operation set classes (e.g. <tt>OperationSetPresence.class</tt>. + */ + @SuppressWarnings("unchecked") + public Collection<Class<? extends OperationSet>> + getSupportedOperationSetClasses() + { + Collection<Class<? extends OperationSet>> opSetClasses + = new ArrayList<Class<? extends OperationSet>>(); + + Iterator<String> opSets + = getSupportedOperationSets().keySet().iterator(); + + while (opSets.hasNext()) + { + String opSetClassName = opSets.next(); + try + { + opSetClasses.add( + (Class<? extends OperationSet>) getSupportedOperationSets() + .get(opSetClassName).getClass().getClassLoader() + .loadClass(opSetClassName)); + } + catch (ClassNotFoundException e) + { + e.printStackTrace(); + } + } + + return opSetClasses; + } + /** * Indicates whether or not this provider is registered * diff --git a/src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java b/src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java index caf053d..d3d4b53 100644 --- a/src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java +++ b/src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java @@ -146,6 +146,21 @@ public interface ProtocolProviderService public Map<String, OperationSet> getSupportedOperationSets(); /** + * Returns a collection containing all operation sets classes supported by + * the current implementation. When querying this method users must be + * prepared to receive any subset of the OperationSet-s defined by this + * service. They MUST ignore any OperationSet-s that they are not aware of + * and that may be defined by future versions of this service. Such + * "unknown" OperationSet-s though not encouraged, may also be defined by + * service implementors. + * + * @return a {@link Collection} containing instances of all supported + * operation set classes (e.g. <tt>OperationSetPresence.class</tt>. + */ + public Collection<Class<? extends OperationSet>> + getSupportedOperationSetClasses(); + + /** * Returns the operation set corresponding to the specified class or * <tt>null</tt> if this operation set is not supported by the provider * implementation. |