Fixes contact list behavior and introduces more smooth writing in the search field.

cusax-fix
Yana Stamcheva 16 years ago
parent 2fb1f2db0c
commit ab366d7717

@ -76,6 +76,12 @@ private class CallHistoryContactQuery
*/
private CallHistoryQuery callHistoryQuery;
/**
* Indicates the status of this query. When created this query is in
* progress.
*/
private int status = QUERY_IN_PROGRESS;
/**
* Creates an instance of <tt>CallHistoryContactQuery</tt> by specifying
* the list of call records results.
@ -86,13 +92,16 @@ public CallHistoryContactQuery(Collection<CallRecord> callRecords)
{
Iterator<CallRecord> recordsIter = callRecords.iterator();
while (recordsIter.hasNext())
while (recordsIter.hasNext() && status != QUERY_CANCELED)
{
sourceContacts.add(
new CallHistorySourceContact(
CallHistoryContactSource.this,
recordsIter.next()));
}
if (status != QUERY_CANCELED)
status = QUERY_COMPLETED;
}
/**
@ -118,7 +127,8 @@ public void callRecordReceived(CallRecordEvent event)
public void queryStatusChanged(
CallHistoryQueryStatusEvent event)
{
fireQueryStatusEvent(event.getEventType());
status = event.getEventType();
fireQueryStatusEvent(status);
}
});
}
@ -141,10 +151,22 @@ public void addContactQueryListener(ContactQueryListener l)
*/
public void cancel()
{
status = QUERY_CANCELED;
if (callHistoryQuery != null)
callHistoryQuery.cancel();
}
/**
* Returns the status of this query. One of the static constants defined
* in this class.
* @return the status of this query
*/
public int getStatus()
{
return status;
}
/**
* Removes the given <tt>ContactQueryListener</tt> from the list of
* query listeners.

@ -95,8 +95,6 @@ public void actionPerformed(ActionEvent e)
{
if (isHistoryVisible && !isMissedCallView)
{
TreeContactList.searchFilter
.setSearchSourceType(SearchFilter.DEFAULT_SOURCE);
GuiActivator.getContactList()
.setDefaultFilter(TreeContactList.presenceFilter);
GuiActivator.getContactList().applyDefaultFilter();
@ -105,8 +103,6 @@ public void actionPerformed(ActionEvent e)
}
else
{
TreeContactList.searchFilter
.setSearchSourceType(SearchFilter.HISTORY_SOURCE);
GuiActivator.getContactList()
.setDefaultFilter(TreeContactList.historyFilter);
GuiActivator.getContactList().applyDefaultFilter();

@ -11,7 +11,6 @@
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.util.*;
/**
* The <tt>CallHistoryFilter</tt> is a filter over the history contact sources.
@ -21,23 +20,13 @@
public class CallHistoryFilter
implements ContactListFilter
{
/**
* This class logger.
*/
private final Logger logger = Logger.getLogger(CallHistoryFilter.class);
/**
* The current <tt>ContactQuery</tt>.
*/
private ContactQuery currentQuery;
/**
* Applies this filter and stores the result in the given <tt>treeModel</tt>.
* @param filterQuery the <tt>FilterQuery</tt> that tracks the results of
* this filtering
*/
public void applyFilter()
public void applyFilter(FilterQuery filterQuery)
{
logger.debug("Call history filter applied.");
Collection<ExternalContactSource> contactSources
= TreeContactList.getContactSources();
@ -51,13 +40,16 @@ public void applyFilter()
continue;
// We're in a case of call history contact source.
currentQuery = sourceService.queryContactSource("");
ContactQuery query = sourceService.queryContactSource("");
filterQuery.addContactQuery(query);
// Add first available results.
this.addMatching( currentQuery.getQueryResults(),
this.addMatching( query.getQueryResults(),
contactSource);
currentQuery.addContactQueryListener(GuiActivator.getContactList());
// We know that this query should be finished here and we do not
// expect any further results from it.
filterQuery.removeQuery(query);
}
}
@ -111,13 +103,4 @@ private void addMatching( List<SourceContact> sourceContacts,
false);
}
}
/**
* Stops this filter current queries.
*/
public void stopFilter()
{
if (currentQuery != null)
currentQuery.cancel();
}
}

@ -34,11 +34,8 @@ public interface ContactListFilter
/**
* Applies this filter to any interested sources
* @param filterQuery the <tt>FilterQuery</tt> that tracks the results of
* this filtering
*/
public void applyFilter();
/**
* Stops this filter current queries.
*/
public void stopFilter();
public void applyFilter(FilterQuery filterQuery);
}

@ -97,15 +97,7 @@ public void initList(MetaContactListService contactListService)
GuiActivator.setContactList(contactList);
// By default we set the current filter to be the presence filter.
new Thread()
{
public void run()
{
TreeContactList.presenceFilter
.setShowOffline(ConfigurationManager.isShowOffline());
contactList.applyFilter(TreeContactList.presenceFilter);
}
}.start();
contactList.applyFilter(TreeContactList.presenceFilter);
TransparentPanel transparentPanel
= new TransparentPanel(new BorderLayout());

@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.impl.gui.main.contactlist;
import java.lang.reflect.*;
import javax.swing.*;
import javax.swing.tree.*;
@ -60,22 +62,38 @@ public ContactNode findFirstContactNode()
*/
public void clear()
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
if (!SwingUtilities.isEventDispatchThread())
try
{
int childCount = rootGroupNode.getChildCount();
int[] removedIndexs = new int[childCount];
Object[] removedNodes = new Object[childCount];
for (int i = 0; i < childCount; i ++)
SwingUtilities.invokeAndWait(new Runnable()
{
removedIndexs[i] = i;
removedNodes[i] = rootGroupNode.getChildAt(i);
}
rootGroupNode.clear();
nodesWereRemoved(rootGroupNode, removedIndexs, removedNodes);
public void run()
{
clear();
}
});
}
});
catch (InterruptedException e)
{
e.printStackTrace();
}
catch (InvocationTargetException e)
{
e.printStackTrace();
}
// The following code is always invoked in the swing thread.
int childCount = rootGroupNode.getChildCount();
int[] removedIndexs = new int[childCount];
Object[] removedNodes = new Object[childCount];
for (int i = 0; i < childCount; i ++)
{
removedIndexs[i] = i;
removedNodes[i] = rootGroupNode.getChildAt(i);
}
rootGroupNode.clear();
nodesWereRemoved(rootGroupNode, removedIndexs, removedNodes);
}
/**

@ -8,6 +8,8 @@
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.*;
/**
@ -16,7 +18,8 @@
* @author Yana Stamcheva
*/
public class FilterQuery
implements ContactQueryListener
implements ContactQueryListener,
MetaContactQueryListener
{
/**
* A listener, which is notified when this query finishes.
@ -37,17 +40,23 @@ public class FilterQuery
/**
* The list of filter queries.
*/
private Collection<ContactQuery> filterQueries
= new LinkedList<ContactQuery>();
private Collection<Object> filterQueries = new Vector<Object>();
private int runningQueries = 0;
/**
* Adds the given <tt>contactQuery</tt> to the list of filterQueries.
* @param contactQuery the <tt>ContactQuery</tt> to add
*/
public void addContactQuery(ContactQuery contactQuery)
public void addContactQuery(Object contactQuery)
{
filterQueries.add(contactQuery);
contactQuery.addContactQueryListener(this);
runningQueries++;
if (contactQuery instanceof ContactQuery)
((ContactQuery) contactQuery).addContactQueryListener(this);
else if (contactQuery instanceof MetaContactQuery)
((MetaContactQuery) contactQuery).addContactQueryListener(this);
}
/**
@ -84,8 +93,31 @@ public boolean isCanceled()
public void cancel()
{
isCanceled = true;
filterQueries.clear();
fireFilterQueryEvent();
Iterator<Object> queriesIter = filterQueries.iterator();
while (queriesIter.hasNext())
{
Object query = queriesIter.next();
if (query instanceof ContactQuery)
{
ContactQuery contactQuery = ((ContactQuery) query);
contactQuery.cancel();
contactQuery.removeContactQueryListener(
GuiActivator.getContactList());
if (!isSucceeded && contactQuery.getQueryResults().size() > 0)
isSucceeded = true;
}
else if (query instanceof MetaContactQuery)
{
MetaContactQuery metaContactQuery = ((MetaContactQuery) query);
metaContactQuery.cancel();
metaContactQuery.removeContactQueryListener(
GuiActivator.getContactList());
if (!isSucceeded && metaContactQuery.getResultCount() > 0)
isSucceeded = true;
}
}
}
/**
@ -121,22 +153,67 @@ public void queryStatusChanged(ContactQueryStatusEvent event)
ContactQuery query = event.getQuerySource();
// Check if this query is in our filter queries list.
if (!filterQueries.contains(query))
if (!filterQueries.contains(query)
|| event.getEventType() == ContactQuery.QUERY_IN_PROGRESS)
return;
removeQuery(query);
}
/**
* Removes the given query from this filter query, updates the related data
* and notifies interested parties if this was the last query to process.
* @param query the <tt>ContactQuery</tt> to remove.
*/
public void removeQuery(ContactQuery query)
{
// First set the isSucceeded property.
if (!isSucceeded() && !query.getQueryResults().isEmpty())
setSucceeded(true);
// Then remove the wait result from the filterQuery.
filterQueries.remove(query);
runningQueries--;
query.removeContactQueryListener(this);
// If no queries have rest we notify interested listeners that query
// has finished.
if (filterQueries.isEmpty())
if (runningQueries == 0)
fireFilterQueryEvent();
}
/**
* Indicates that a query has changed its status.
* @param event the <tt>ContactQueryStatusEvent</tt> that notified us
*/
public void metaContactQueryStatusChanged(MetaContactQueryStatusEvent event)
{
MetaContactQuery query = event.getQuerySource();
// Check if this query is in our filter queries list.
if (!filterQueries.contains(query))
return;
// First set the isSucceeded property.
if (!isSucceeded() && query.getResultCount() > 0)
setSucceeded(true);
// We don't remove the query from our list, because even if the query
// has finished its GUI part is scheduled in the Swing thread and we
// don't know anything about these events, so if someone calls cancel()
// we need to explicitly cancel all contained queries even they are
// finished.
runningQueries--;
query.removeContactQueryListener(this);
// If no queries have rest we notify interested listeners that query
// has finished.
if (runningQueries == 0)
fireFilterQueryEvent();
}
public void contactReceived(ContactReceivedEvent event) {}
public void metaContactReceived(MetaContactQueryEvent event) {}
public void metaGroupReceived(MetaGroupQueryEvent event) {}
}

@ -72,7 +72,10 @@ public ContactNode addContact(UIContact uiContact)
add(contactNode);
fireNodeInserted(getIndex(contactNode));
int contactIndex = getIndex(contactNode);
if (contactIndex > -1)
fireNodeInserted(contactIndex);
return contactNode;
}
@ -94,7 +97,10 @@ public ContactNode sortedAddContact(UIContact uiContact)
// TODO: Optimize!
Collections.sort(children, nodeComparator);
fireNodeInserted(getIndex(contactNode));
int contactIndex = getIndex(contactNode);
if (contactIndex > -1)
fireNodeInserted(contactIndex);
return contactNode;
}
@ -136,7 +142,10 @@ public GroupNode addContactGroup(UIGroup uiGroup)
add(groupNode);
fireNodeInserted(getIndex(groupNode));
int groupIndex = getIndex(groupNode);
if (groupIndex > -1)
fireNodeInserted(groupIndex);
return groupNode;
}
@ -182,7 +191,10 @@ public GroupNode sortedAddContactGroup(UIGroup uiGroup)
// TODO: Optimize!
Collections.sort(children, nodeComparator);
fireNodeInserted(getIndex(groupNode));
int contactIndex = getIndex(groupNode);
if (contactIndex > -1)
fireNodeInserted(contactIndex);
return groupNode;
}

@ -13,7 +13,6 @@
import net.java.sip.communicator.impl.gui.utils.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
/**
* The <tt>PresenceFilter</tt> is used to filter offline contacts from the
@ -24,42 +23,49 @@
public class PresenceFilter
implements ContactListFilter
{
/**
* This class logger.
*/
private final Logger logger = Logger.getLogger(PresenceFilter.class);
/**
* Indicates if this presence filter shows or hides the offline contacts.
*/
private boolean isShowOffline;
/**
* Indicates if there's a presence filtering going on.
* The initial result count below which we insert all filter results
* directly to the contact list without firing events.
*/
private boolean isFiltering = false;
private final int INITIAL_CONTACT_COUNT = 30;
/**
* Creates an instance of <tt>PresenceFilter</tt>.
*/
public PresenceFilter()
{
this.setShowOffline(ConfigurationManager.isShowOffline());
isShowOffline = ConfigurationManager.isShowOffline();
}
/**
* 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()
public void applyFilter(FilterQuery filterQuery)
{
logger.debug("Presence filter applied.");
// Create the query that will track filtering.
MetaContactQuery query = new MetaContactQuery();
isFiltering = true;
// Add this query to the filterQuery.
filterQuery.addContactQuery(query);
addMatching(GuiActivator.getContactListService().getRoot());
query.addContactQueryListener(GuiActivator.getContactList());
isFiltering = false;
int resultCount = 0;
addMatching(GuiActivator.getContactListService().getRoot(),
query,
resultCount);
if (!query.isCanceled())
query.fireQueryEvent(MetaContactQueryStatusEvent.QUERY_COMPLETED);
else
query.fireQueryEvent(MetaContactQueryStatusEvent.QUERY_CANCELED);
}
/**
@ -99,6 +105,8 @@ public boolean isMatching(UIGroup uiGroup)
public void setShowOffline(boolean isShowOffline)
{
this.isShowOffline = isShowOffline;
ConfigurationManager.setShowOffline(isShowOffline);
}
/**
@ -163,40 +171,65 @@ private boolean isContactOnline(MetaContact contact)
* 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
* listeners of the results of this matching
* @param resultCount the initial result count we would insert directly to
* the contact list without firing events
*/
private void addMatching(MetaContactGroup metaGroup)
private void addMatching( MetaContactGroup metaGroup,
MetaContactQuery query,
int resultCount)
{
Iterator<MetaContact> childContacts = metaGroup.getChildContacts();
while(childContacts.hasNext() && isFiltering)
while(childContacts.hasNext() && !query.isCanceled())
{
MetaContact metaContact = childContacts.next();
if(isMatching(metaContact))
{
MetaContactListSource.fireQueryEvent(metaContact);
resultCount++;
if (resultCount <= INITIAL_CONTACT_COUNT)
{
UIGroup uiGroup = null;
if (!MetaContactListSource.isRootGroup(metaGroup))
{
uiGroup = MetaContactListSource
.getUIGroup(metaGroup);
if (uiGroup == null)
uiGroup = MetaContactListSource
.createUIGroup(metaGroup);
}
GuiActivator.getContactList().addContact(
MetaContactListSource.createUIContact(metaContact),
uiGroup,
true);
query.setInitialResultCount(resultCount);
}
else
query.fireQueryEvent(metaContact);
}
}
// If in the meantime the filtering has been stopped we return here.
if (query.isCanceled())
return;
Iterator<MetaContactGroup> subgroups = metaGroup.getSubgroups();
while(subgroups.hasNext() && isFiltering)
while(subgroups.hasNext() && !query.isCanceled())
{
MetaContactGroup subgroup = subgroups.next();
if (subgroup.countChildContacts() == 0
&& subgroup.countSubgroups() == 0
&& isMatching(subgroup))
MetaContactListSource.fireQueryEvent(subgroup);
GuiActivator.getContactList().addGroup(
MetaContactListSource.createUIGroup(subgroup), true);
else
addMatching(subgroup);
addMatching(subgroup, query, resultCount);
}
}
/**
* Stops this filter current queries.
*/
public void stopFilter()
{
isFiltering = false;
}
}

@ -22,8 +22,9 @@ public class SearchField
implements TextFieldChangeListener,
FilterQueryListener
{
private final Logger logger = Logger.getLogger(SearchField.class);
/**
* The main application window.
*/
private final MainFrame mainFrame;
/**
@ -32,8 +33,6 @@ public class SearchField
*/
private boolean lastHasMatching = true;
private SearchThread searchThread = null;
/**
* Creates the <tt>SearchField</tt>.
* @param frame the main application window
@ -81,7 +80,7 @@ public void textInserted()
if (filterString == null || filterString.length() <= 0)
return;
scheduleUpdate();
updateContactListView();
}
/**
@ -89,7 +88,7 @@ public void textInserted()
*/
public void textRemoved()
{
scheduleUpdate();
updateContactListView();
}
/**
@ -101,92 +100,39 @@ public void changedUpdate(DocumentEvent e) {}
/**
* Schedules an update if necessary.
*/
private void scheduleUpdate()
private void updateContactListView()
{
GuiActivator.getContactList().stopFiltering();
String filterString = getText();
if (searchThread == null)
FilterQuery filterQuery = null;
if (filterString != null && filterString.length() > 0)
{
searchThread = new SearchThread();
searchThread.start();
TreeContactList.searchFilter
.setFilterString(filterString);
filterQuery = GuiActivator.getContactList()
.applyFilter(TreeContactList.searchFilter);
}
else
synchronized (searchThread)
{
searchThread.notify();
}
}
/**
* The <tt>SearchThread</tt> is meant to launch the search in a separate
* thread.
*/
private class SearchThread extends Thread
{
public void run()
{
while (true)
{
String filterString = getText();
if (filterString != null && filterString.length() > 0)
{
TreeContactList.searchFilter
.setFilterString(filterString);
}
updateContactListView(filterString);
synchronized (this)
{
try
{
if (filterString == getText() //both are null or equal
|| (filterString != null
&& filterString.equals(getText())))
{
//filter still has the same value as the one
//we did a search for, so we can wait for a
//while
this.wait();
filterString = getText();
}
}
catch (InterruptedException e)
{
logger.debug("Search thread was interrupted.", e);
}
}
}
filterQuery = GuiActivator.getContactList().applyDefaultFilter();
}
}
/**
* Updates the current contact list view to match the given
* <tt>filterString</tt>. If the <tt>filterString</tt> is null or
* empty we reset the presence filter.
* @param filterString the current filter string entered in
* this search field
*/
public void updateContactListView(String filterString)
{
TreeContactList contactList = GuiActivator.getContactList();
if (filterString != null && filterString.length() > 0)
if (filterQuery != null && !filterQuery.isCanceled())
{
FilterQuery filterQuery
= contactList.applyFilter(TreeContactList.searchFilter);
if (filterQuery != null)
// If we already have a result here we update the interface.
if (filterQuery.isSucceeded())
enableUnknownContactView(false);
else
// Otherwise we will listen for events for changes in status
// of this query.
filterQuery.setQueryListener(this);
}
else
{
contactList.applyDefaultFilter();
enableUnknownContactView(false);
}
// If the query is null or is canceled, we would simply check the
// contact list content.
enableUnknownContactView(GuiActivator.getContactList().isEmpty());
}
/**

@ -12,7 +12,6 @@
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.util.*;
/**
* The <tt>SearchFilter</tt> is a <tt>ContactListFilter</tt> that filters the
@ -21,13 +20,8 @@
* @author Yana Stamcheva
*/
public class SearchFilter
implements ContactListSourceFilter
implements ContactListFilter
{
/**
* This class logger.
*/
private final Logger logger = Logger.getLogger(SearchFilter.class);
/**
* The default contact source search type.
*/
@ -58,17 +52,11 @@ public class SearchFilter
*/
private Collection<ExternalContactSource> contactSources;
/**
* The list of currently running queries.
*/
private Collection<ContactQuery> currentQueries
= new LinkedList<ContactQuery>();
/**
* The type of the search source. One of the above defined DEFAUT_SOURCE or
* HISTORY_SOURCE.
*/
private int searchSourceType;
private int searchSourceType = DEFAULT_SOURCE;
/**
* Creates an instance of <tt>SearchFilter</tt>.
@ -80,14 +68,40 @@ public SearchFilter()
/**
* Applies this filter to the default contact source.
* @param filterQuery the query that tracks this filter.
*/
public void applyFilter()
public void applyFilter(FilterQuery filterQuery)
{
logger.debug("Search filter applied on default source");
// If the filter has a default contact source, we apply it first.
if (searchSourceType == DEFAULT_SOURCE)
{
MetaContactQuery defaultQuery
= mclSource.queryMetaContactSource(filterPattern);
defaultQuery.addContactQueryListener(GuiActivator.getContactList());
// First add the MetaContactListSource
mclSource.filter(filterPattern);
filterQuery.addContactQuery(defaultQuery);
}
// If we have stopped filtering in the mean time we return here.
if (filterQuery.isCanceled())
return;
Iterator<ExternalContactSource> filterSources
= getContactSources().iterator();
// Then we apply the filter on all its contact sources.
while (filterSources.hasNext())
{
final ExternalContactSource filterSource = filterSources.next();
// If we have stopped filtering in the mean time we return here.
if (filterQuery.isCanceled())
return;
filterQuery.addContactQuery(
applyFilter(filterSource));
}
}
@ -100,9 +114,6 @@ public void applyFilter()
*/
public ContactQuery applyFilter(ExternalContactSource contactSource)
{
logger.debug("Search filter applied on source: "
+ contactSource.getContactSourceService());
ContactSourceService sourceService
= contactSource.getContactSourceService();
@ -117,7 +128,6 @@ public ContactQuery applyFilter(ExternalContactSource contactSource)
// Add first available results.
this.addMatching(contactQuery.getQueryResults());
currentQueries.add(contactQuery);
contactQuery.addContactQueryListener(GuiActivator.getContactList());
return contactQuery;
@ -174,26 +184,6 @@ public void setFilterString(String filter)
| Pattern.UNICODE_CASE);
}
/**
* Stops all currently running queries.
*/
public void stopFilter()
{
mclSource.stopFiltering();
Iterator<ContactQuery> queriesIter = currentQueries.iterator();
while (queriesIter.hasNext())
queriesIter.next().cancel();
}
/**
* Removes the given query from the list of currently processed queries.
* @param contactQuery the <tt>ContactQuery</tt> to remove
*/
public void removeCurrentQuery(ContactQuery contactQuery)
{
currentQueries.remove(contactQuery);
}
/**
* Checks if the given <tt>contact</tt> is matching the current filter.
* A <tt>SourceContact</tt> would be matching the filter if its display

@ -114,10 +114,9 @@ public class TreeContactList
private static final Collection<ExternalContactSource> contactSources
= new LinkedList<ExternalContactSource>();
/**
* The filter query used to track advanced source filtering.
*/
FilterQuery filterQuery;
private FilterQuery currentFilterQuery;
private FilterThread filterThread;
/**
* Creates the <tt>TreeContactList</tt>.
@ -147,8 +146,6 @@ public TreeContactList()
this.initKeyActions();
this.initContactSources();
MetaContactListSource.setMetaContactQueryListener(this);
}
/**
@ -532,7 +529,9 @@ public void contactReceived(ContactReceivedEvent event)
if((contactSource instanceof ExtendedContactSourceService)
|| currentFilter.isMatching(uiContact))
{
addContact(uiContact, sourceUI.getUIGroup(), false);
addContact(event.getQuerySource(),
uiContact,
sourceUI.getUIGroup(), false);
}
else
uiContact = null;
@ -541,15 +540,13 @@ public void contactReceived(ContactReceivedEvent event)
/**
* Indicates that a <tt>MetaContact</tt> has been received for a search in
* the <tt>MetaContactListService</tt>.
* @param metaContact the received <tt>MetaContact</tt>
* @param event the received <tt>MetaContactQueryEvent</tt>
*/
public void metaContactReceived(MetaContact metaContact)
public void metaContactReceived(MetaContactQueryEvent event)
{
MetaContact metaContact = event.getMetaContact();
MetaContactGroup parentGroup = metaContact.getParentMetaContactGroup();
if (filterQuery != null)
filterQuery.setSucceeded(true);
UIGroup uiGroup = null;
if (!MetaContactListSource.isRootGroup(parentGroup))
{
@ -561,21 +558,22 @@ public void metaContactReceived(MetaContact metaContact)
.createUIGroup(parentGroup);
}
GuiActivator.getContactList().addContact(
MetaContactListSource.createUIContact(metaContact),
uiGroup,
true);
addContact( event.getQuerySource(),
MetaContactListSource.createUIContact(metaContact),
uiGroup,
true);
}
/**
* Indicates that a <tt>MetaGroup</tt> has been received from a search in
* the <tt>MetaContactListService</tt>.
* @param metaGroup the <tt>MetaGroup</tt> that has been received
* @param event the <tt>MetaContactGroupQueryEvent</tt> that has been
* received
*/
public void metaGroupReceived(MetaContactGroup metaGroup)
public void metaGroupReceived(MetaGroupQueryEvent event)
{
GuiActivator.getContactList().addGroup(
MetaContactListSource.createUIGroup(metaGroup), true);
MetaContactListSource.createUIGroup(event.getMetaGroup()), true);
}
/**
@ -590,7 +588,21 @@ public void queryStatusChanged(ContactQueryStatusEvent event)
{
//TODO: Show the error to the user??
}
searchFilter.removeCurrentQuery(event.getQuerySource());
event.getQuerySource().removeContactQueryListener(this);
}
/**
* Indicates that the status of a query has changed.
* @param event the <tt>ContactQueryStatusEvent</tt> that notified us
*/
public void metaContactQueryStatusChanged(MetaContactQueryStatusEvent event)
{
int eventType = event.getEventType();
if (eventType == ContactQueryStatusEvent.QUERY_ERROR)
{
//TODO: Show the error to the user??
}
event.getQuerySource().removeContactQueryListener(this);
}
@ -718,7 +730,62 @@ public void run()
if ((!currentFilter.equals(presenceFilter)
|| !groupNode.isCollapsed()))
this.expandGroup(groupNode);
this.expandGroup(groupNode);
}
/**
* Adds the given <tt>contact</tt> to this list.
* @param query the <tt>MetaContactQuery</tt> that adds the given contact
* @param contact the <tt>UIContact</tt> to add
* @param group the <tt>UIGroup</tt> to add to
* @param isSorted indicates if the contact should be sorted regarding to
* the <tt>GroupNode</tt> policy
*/
private void addContact(final MetaContactQuery query,
final UIContact contact,
final UIGroup group,
final boolean isSorted)
{
if (!SwingUtilities.isEventDispatchThread())
{
LowPriorityEventQueue.invokeLater(new Runnable()
{
public void run()
{
if (query != null && !query.isCanceled())
addContact(contact, group, isSorted);
}
});
return;
}
}
/**
* 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
* @param isSorted indicates if the contact should be sorted regarding to
* the <tt>GroupNode</tt> policy
*/
private void addContact( final ContactQuery query,
final UIContact contact,
final UIGroup group,
final boolean isSorted)
{
if (!SwingUtilities.isEventDispatchThread())
{
LowPriorityEventQueue.invokeLater(new Runnable()
{
public void run()
{
if (query != null
&& query.getStatus() != ContactQuery.QUERY_CANCELED)
addContact(contact, group, isSorted);
}
});
return;
}
}
/**
@ -870,23 +937,14 @@ public void setGroupClickConsumed(boolean isGroupClickConsumed)
this.isGroupClickConsumed = isGroupClickConsumed;
}
/**
* Stops the current filtering if there's one active.
*/
public void stopFiltering()
{
if (currentFilter != null)
currentFilter.stopFilter();
if (filterQuery != null)
filterQuery.cancel();
}
/**
* Applies the default filter.
* @return the filter query that keeps track of the filtering results
*/
public void applyDefaultFilter()
public FilterQuery applyDefaultFilter()
{
FilterQuery filterQuery = null;
final MainFrame mainFrame = GuiActivator.getUIService().getMainFrame();
String currentSearchText = mainFrame.getCurrentSearchText();
@ -908,94 +966,88 @@ public void run()
}
else
{
treeModel.clear();
applyFilter(defaultFilter, null);
filterQuery = applyFilter(defaultFilter);
}
return filterQuery;
}
/**
* Applies the given <tt>filter</tt>.
* @param filter the <tt>ContactListFilter</tt> to apply.
* @return the filter query
*/
public void applyFilter(ContactListFilter filter)
public FilterQuery applyFilter(ContactListFilter filter)
{
treeModel.clear();
applyFilter(filter, null);
}
if (currentFilterQuery != null && !currentFilterQuery.isCanceled())
currentFilterQuery.cancel();
/**
* Applies the given <tt>ContactListSourceFilter</tt>.
* @param filter the <tt>ContactListSourceFilter</tt> to apply
* @return the <tt>FilterQuery</tt> through which the filter could be
* tracked
*/
public FilterQuery applyFilter(final ContactListSourceFilter filter)
{
filterQuery = new FilterQuery();
treeModel.clear();
currentFilterQuery = new FilterQuery();
// If the filter has a default contact source, we apply it first.
if (filter.hasDefaultSource())
applyFilter(filter, null);
Iterator<ExternalContactSource> filterSources
= filter.getContactSources().iterator();
// Then we apply the filter on all its contact sources.
while (filterSources.hasNext())
if (filterThread == null)
{
final ExternalContactSource filterSource = filterSources.next();
if (filterQuery.isCanceled())
return filterQuery;
filterThread = new FilterThread();
filterThread.setFilter(filter);
filterThread.start();
}
else
{
filterThread.setFilter(filter);
applyFilter(filter, filterSource);
synchronized (filterThread)
{
filterThread.notify();
}
}
return filterQuery;
return currentFilterQuery;
}
/**
* Applies the given <tt>filter</tt> and changes the content of the
* contact list according to it.
* @param filter the new filter to set
* @param contactSource the <tt>ExternalContactSource</tt> to apply the
* filter to
* The <tt>SearchThread</tt> is meant to launch the search in a separate
* thread.
*/
private void applyFilter( final ContactListFilter filter,
final ExternalContactSource contactSource)
private class FilterThread extends Thread
{
// If we're in the event dispatch thread we move to another thread
// for the filtering.
if (SwingUtilities.isEventDispatchThread())
private ContactListFilter filter;
public void setFilter(ContactListFilter filter)
{
new Thread()
{
public void run()
{
applyFilter(filter, contactSource);
}
}.start();
return;
this.filter = filter;
}
if (currentFilter == null || !currentFilter.equals(filter))
this.currentFilter = filter;
// If we have a specific contact source and we're dealing with
// a ContactListSourceFilter then we would apply the filter only
// to this source.
if (contactSource != null
&& filter instanceof ContactListSourceFilter)
public void run()
{
ContactQuery contactQuery
= ((ContactListSourceFilter) currentFilter)
.applyFilter(contactSource);
while (true)
{
FilterQuery filterQuery = currentFilterQuery;
filterQuery.addContactQuery(contactQuery);
treeModel.clear();
if (!filterQuery.isCanceled())
{
if (currentFilter == null || !currentFilter.equals(filter))
currentFilter = filter;
currentFilter.applyFilter(filterQuery);
}
synchronized (this)
{
try
{
// If in the mean time someone has changed the filter
// we don't wait here.
if (filterQuery == currentFilterQuery)
this.wait();
}
catch (InterruptedException e)
{
logger.debug("Search thread was interrupted.", e);
}
}
}
}
else
currentFilter.applyFilter();
}
/**
@ -1005,6 +1057,13 @@ public void run()
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);
}
/**
@ -1016,6 +1075,16 @@ public ContactListFilter getCurrentFilter()
return currentFilter;
}
/**
* 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()
{
return (treeModel.getRoot().getChildCount() <= 0);
}
/**
* Selects the first found contact node from the beginning of the contact
* list.
@ -1107,9 +1176,7 @@ public void run()
});
}
else
{
expandPath(path);
}
}
/**
@ -1681,8 +1748,7 @@ public void contactPresenceStatusChanged(
if (currentFilter != null && !currentFilter.isMatching(uiContact))
removeContact(uiContact);
else
treeModel
.nodeChanged(uiContact.getContactNode());
treeModel.nodeChanged(uiContact.getContactNode());
}
}
}

@ -40,15 +40,10 @@ public class MetaContactListSource
= MetaUIGroup.class.getName() + ".uiGroupDescriptor";
/**
* Indicates if we should be filtering.
* The initial result count below which we insert all filter results
* directly to the contact list without firing events.
*/
private boolean isFiltering = false;
/**
* The <tt>MetaContactQueryListener</tt> listens for <tt>MetaContact</tt>s
* and <tt>MetaGroup</tt>s received as a result of a filtering.
*/
private static MetaContactQueryListener queryListener;
private final int INITIAL_CONTACT_COUNT = 30;
/**
* Returns the <tt>UIContact</tt> corresponding to the given
@ -137,27 +132,38 @@ public static boolean isRootGroup(MetaContactGroup group)
return group.equals(GuiActivator.getContactListService().getRoot());
}
/**
* Stops the meta contact list filtering.
*/
public void stopFiltering()
{
isFiltering = false;
}
/**
* Filters the <tt>MetaContactListService</tt> to match the given
* <tt>filterPattern</tt> and stores the result in the given
* <tt>treeModel</tt>.
* @param filterPattern the pattern to filter through
* @return the created <tt>MetaContactQuery</tt> corresponding to the
* query this method does
*/
public void filter(Pattern filterPattern)
public MetaContactQuery queryMetaContactSource(final Pattern filterPattern)
{
isFiltering = true;
final MetaContactQuery query = new MetaContactQuery();
filter(filterPattern, GuiActivator.getContactListService().getRoot());
new Thread()
{
public void run()
{
int resultCount = 0;
queryMetaContactSource( filterPattern,
GuiActivator.getContactListService().getRoot(),
query,
resultCount);
if (!query.isCanceled())
query.fireQueryEvent(
MetaContactQueryStatusEvent.QUERY_COMPLETED);
else
query.fireQueryEvent(
MetaContactQueryStatusEvent.QUERY_CANCELED);
}
}.start();
isFiltering = false;
return query;
}
/**
@ -166,28 +172,60 @@ public void filter(Pattern filterPattern)
* <tt>treeModel</tt>.
* @param filterPattern the pattern to filter through
* @param parentGroup the <tt>MetaContactGroup</tt> to filter
* @param query the object that tracks the query
* @param resultCount the initial result count we would insert directly to
* the contact list without firing events
*/
private void filter(Pattern filterPattern,
MetaContactGroup parentGroup)
private void queryMetaContactSource(Pattern filterPattern,
MetaContactGroup parentGroup,
MetaContactQuery query,
int resultCount)
{
Iterator<MetaContact> childContacts = parentGroup.getChildContacts();
while (childContacts.hasNext() && isFiltering)
while (childContacts.hasNext() && !query.isCanceled())
{
MetaContact metaContact = childContacts.next();
if (isMatching(filterPattern, metaContact))
{
fireQueryEvent(metaContact);
resultCount++;
if (resultCount <= INITIAL_CONTACT_COUNT)
{
UIGroup uiGroup = null;
if (!MetaContactListSource.isRootGroup(parentGroup))
{
uiGroup = MetaContactListSource
.getUIGroup(parentGroup);
if (uiGroup == null)
uiGroup = MetaContactListSource
.createUIGroup(parentGroup);
}
GuiActivator.getContactList().addContact(
MetaContactListSource.createUIContact(metaContact),
uiGroup,
true);
query.setInitialResultCount(resultCount);
}
else
query.fireQueryEvent(metaContact);
}
}
// If in the meantime the query is canceled we return here.
if(query.isCanceled())
return;
Iterator<MetaContactGroup> subgroups = parentGroup.getSubgroups();
while (subgroups.hasNext() && isFiltering)
while (subgroups.hasNext() && !query.isCanceled())
{
MetaContactGroup subgroup = subgroups.next();
filter(filterPattern, subgroup);
queryMetaContactSource(filterPattern, subgroup, query, resultCount);
}
}
@ -251,45 +289,4 @@ public boolean isMatching(Pattern filterPattern, MetaContactGroup metaGroup)
}
return false;
}
/**
* Sets the given <tt>MetaContactQueryListener</tt> to listen for query
* events coming from <tt>MetaContactListService</tt> filtering.
* @param l the <tt>MetaContactQueryListener</tt> to set
*/
public static void setMetaContactQueryListener(MetaContactQueryListener l)
{
queryListener = l;
}
/**
* Returns the currently registered <tt>MetaContactQueryListener</tt>.
* @return the currently registered <tt>MetaContactQueryListener</tt>
*/
public static MetaContactQueryListener getMetaContactQueryListener()
{
return queryListener;
}
/**
* Notifies the <tt>MetaContactQueryListener</tt> that a new
* <tt>MetaContact</tt> has been received as a result of a search.
* @param metaContact the received <tt>MetaContact</tt>
*/
public static void fireQueryEvent(MetaContact metaContact)
{
if (queryListener != null)
queryListener.metaContactReceived(metaContact);
}
/**
* Notifies the <tt>MetaContactQueryListener</tt> that a new
* <tt>MetaGroup</tt> has been received as a result of a search.
* @param metaGroup the received <tt>MetaGroup</tt>
*/
public static void fireQueryEvent(MetaContactGroup metaGroup)
{
if (queryListener != null)
queryListener.metaGroupReceived(metaGroup);
}
}

@ -0,0 +1,178 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.gui.main.contactlist.contactsource;
import java.util.*;
import net.java.sip.communicator.service.contactlist.*;
/**
* The <tt>MetaContactQuery</tt> corresponds to a particular query made through
* the <tt>MetaContactListSource</tt>. Each query once started could be
* canceled. One could also register a listener in order to be notified for
* changes in query status and query contact results.
*
* @author Yana Stamcheva
*/
public class MetaContactQuery
{
private boolean isCanceled = false;
private int resultCount = 0;
/**
* A list of all registered query listeners.
*/
private final List<MetaContactQueryListener> queryListeners
= new LinkedList<MetaContactQueryListener>();
/**
* Cancels this query.
*/
public void cancel()
{
isCanceled = true;
queryListeners.clear();
}
/**
* Returns <tt>true</tt> if this query has been canceled, otherwise returns
* <tt>false</tt>.
* @return <tt>true</tt> if this query has been canceled, otherwise returns
* <tt>false</tt>.
*/
public boolean isCanceled()
{
return isCanceled;
}
/**
* Returns the current number of results received for this query.
* @return the current number of results received for this query
*/
public int getResultCount()
{
return resultCount;
}
/**
* Sets the result count of this query. This method is meant to be used to
* set the initial result count which is before firing any events. The
* result count would be then augmented each time the fireQueryEvent is
* called.
* @param resultCount the initial result count to set
*/
public void setInitialResultCount(int resultCount)
{
this.resultCount = resultCount;
}
/**
* Adds the given <tt>MetaContactQueryListener</tt> to the list of
* registered listeners. The <tt>MetaContactQueryListener</tt> would be
* notified each time a new <tt>MetaContactQuery</tt> result has been
* received or if the query has been completed or has been canceled by user
* or for any other reason.
* @param l the <tt>MetaContactQueryListener</tt> to add
*/
public void addContactQueryListener(MetaContactQueryListener l)
{
synchronized (queryListeners)
{
queryListeners.add(l);
}
}
/**
* Removes the given <tt>MetaContactQueryListener</tt> to the list of
* registered listeners. The <tt>MetaContactQueryListener</tt> would be
* notified each time a new <tt>MetaContactQuery</tt> result has been
* received or if the query has been completed or has been canceled by user
* or for any other reason.
* @param l the <tt>MetaContactQueryListener</tt> to remove
*/
public void removeContactQueryListener(MetaContactQueryListener l)
{
synchronized (queryListeners)
{
queryListeners.remove(l);
}
}
/**
* Notifies the <tt>MetaContactQueryListener</tt> that a new
* <tt>MetaContact</tt> has been received as a result of a search.
* @param metaContact the received <tt>MetaContact</tt>
*/
public void fireQueryEvent(MetaContact metaContact)
{
resultCount++;
MetaContactQueryEvent event
= new MetaContactQueryEvent(this, metaContact);
List<MetaContactQueryListener> listeners;
synchronized (queryListeners)
{
listeners = new LinkedList<MetaContactQueryListener>(queryListeners);
}
Iterator<MetaContactQueryListener> listenersIter = listeners.iterator();
while (listenersIter.hasNext())
{
MetaContactQueryListener listener = listenersIter.next();
listener.metaContactReceived(event);
}
}
/**
* Notifies the <tt>MetaContactQueryListener</tt> that a new
* <tt>MetaGroup</tt> has been received as a result of a search.
* @param metaGroup the received <tt>MetaGroup</tt>
*/
public void fireQueryEvent(MetaContactGroup metaGroup)
{
MetaGroupQueryEvent event
= new MetaGroupQueryEvent(this, metaGroup);
List<MetaContactQueryListener> listeners;
synchronized (queryListeners)
{
listeners = new LinkedList<MetaContactQueryListener>(queryListeners);
}
Iterator<MetaContactQueryListener> listenersIter = listeners.iterator();
while (listenersIter.hasNext())
{
listenersIter.next().metaGroupReceived(event);
}
}
/**
* Notifies the <tt>MetaContactQueryListener</tt> that this query has
* changed its status.
* @param queryStatus the new query status
*/
public void fireQueryEvent(int queryStatus)
{
MetaContactQueryStatusEvent event
= new MetaContactQueryStatusEvent(this, queryStatus);
List<MetaContactQueryListener> listeners;
synchronized (queryListeners)
{
listeners = new LinkedList<MetaContactQueryListener>(queryListeners);
}
Iterator<MetaContactQueryListener> listenersIter = listeners.iterator();
while (listenersIter.hasNext())
{
listenersIter.next().metaContactQueryStatusChanged(event);
}
}
}

@ -0,0 +1,59 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.gui.main.contactlist.contactsource;
import java.util.*;
import net.java.sip.communicator.service.contactlist.*;
/**
* The <tt>MetaContactQueryEvent</tt> is triggered each time a
* <tt>MetaContact</tt> is received as a result of a <tt>MetaContactQuery</tt>.
*
* @author Yana Stamcheva
*/
public class MetaContactQueryEvent
extends EventObject
{
/**
* The <tt>MetaContact</tt> this event is about.
*/
private final MetaContact metaContact;
/**
* Creates an instance of <tt>MetaGroupQueryEvent</tt> by specifying the
* <tt>source</tt> query this event comes from and the <tt>metaContact</tt>
* this event is about.
*
* @param source the <tt>MetaContactQuery</tt> that triggered this event
* @param metaContact the <tt>MetaContact</tt> this event is about
*/
public MetaContactQueryEvent( MetaContactQuery source,
MetaContact metaContact)
{
super(source);
this.metaContact = metaContact;
}
/**
* Returns the <tt>MetaContactQuery</tt> that triggered this event.
* @return the <tt>MetaContactQuery</tt> that triggered this event
*/
public MetaContactQuery getQuerySource()
{
return (MetaContactQuery) source;
}
/**
* Returns the <tt>MetaContact</tt> this event is about.
* @return the <tt>MetaContact</tt> this event is about
*/
public MetaContact getMetaContact()
{
return metaContact;
}
}

@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.gui.main.contactlist;
package net.java.sip.communicator.impl.gui.main.contactlist.contactsource;
import net.java.sip.communicator.service.contactlist.*;
@ -21,12 +21,18 @@ public interface MetaContactQueryListener
* the <tt>MetaContactListService</tt>.
* @param metaContact the received <tt>MetaContact</tt>
*/
public void metaContactReceived(MetaContact metaContact);
public void metaContactReceived(MetaContactQueryEvent event);
/**
* Indicates that a <tt>MetaGroup</tt> has been received from a search in
* the <tt>MetaContactListService</tt>.
* @param metaGroup the <tt>MetaGroup</tt> that has been received
*/
public void metaGroupReceived(MetaContactGroup metaGroup);
public void metaGroupReceived(MetaGroupQueryEvent event);
/**
* Indicates that a query has changed its status.
* @param event the <tt>MetaContactQueryStatusEvent</tt> that notified us
*/
public void metaContactQueryStatusChanged(MetaContactQueryStatusEvent event);
}

@ -0,0 +1,74 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.gui.main.contactlist.contactsource;
import java.util.*;
/**
* The <tt>MetaContactQueryStatusEvent</tt> is triggered each time a
* <tt>MetaContactQuery</tt> changes its status. Possible statuses are:
* QUERY_COMPLETED, QUERY_CANCELED and QUERY_ERROR.
*
* @author Yana Stamcheva
*/
public class MetaContactQueryStatusEvent
extends EventObject
{
/**
* Indicates that a query has been completed.
*/
public static final int QUERY_COMPLETED = 0;
/**
* Indicates that a query has been canceled.
*/
public static final int QUERY_CANCELED = 1;
/**
* Indicates that a query has been stopped because of an error.
*/
public static final int QUERY_ERROR = 2;
/**
* Indicates the type of this event.
*/
private final int eventType;
/**
* Creates a <tt>MetaContactQueryStatusEvent</tt> by specifying the source
* <tt>MetaContactQuery</tt> and the <tt>eventType</tt> indicating why
* initially this event occurred.
* @param source the initiator of the event
* @param eventType the type of the event. One of the QUERY_XXX constants
* defined in this class
*/
public MetaContactQueryStatusEvent( MetaContactQuery source,
int eventType)
{
super(source);
this.eventType = eventType;
}
/**
* Returns the <tt>ContactQuery</tt> that triggered this event.
* @return the <tt>ContactQuery</tt> that triggered this event
*/
public MetaContactQuery getQuerySource()
{
return (MetaContactQuery) source;
}
/**
* Returns the type of this event.
* @return the type of this event
*/
public int getEventType()
{
return eventType;
}
}

@ -0,0 +1,60 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.gui.main.contactlist.contactsource;
import java.util.*;
import net.java.sip.communicator.service.contactlist.*;
/**
* The <tt>MetaGroupQueryEvent</tt> is triggered each time a
* <tt>MetaContactGroup</tt> is received as a result of a
* <tt>MetaContactQuery</tt>.
*
* @author Yana Stamcheva
*/
public class MetaGroupQueryEvent
extends EventObject
{
/**
* The <tt>MetaContactGroup</tt> this event is about.
*/
private final MetaContactGroup metaGroup;
/**
* Creates an instance of <tt>MetaGroupQueryEvent</tt> by specifying the
* <tt>source</tt> query this event comes from and the <tt>metaGroup</tt>
* this event is about.
*
* @param source the <tt>MetaContactQuery</tt> that triggered this event
* @param metaGroup the <tt>MetaContactGroup</tt> this event is about
*/
public MetaGroupQueryEvent( MetaContactQuery source,
MetaContactGroup metaGroup)
{
super(source);
this.metaGroup = metaGroup;
}
/**
* Returns the <tt>MetaContactQuery</tt> that triggered this event.
* @return the <tt>MetaContactQuery</tt> that triggered this event
*/
public MetaContactQuery getQuerySource()
{
return (MetaContactQuery) source;
}
/**
* Returns the <tt>MetaContactGroup</tt> this event is about.
* @return the <tt>MetaContactGroup</tt> this event is about
*/
public MetaContactGroup getMetaGroup()
{
return metaGroup;
}
}

@ -119,17 +119,9 @@ else if (itemName.equals("showHideOffline"))
TreeContactList.presenceFilter.setShowOffline(!isShowOffline);
new Thread()
{
public void run()
{
GuiActivator.getContactList()
.setDefaultFilter(TreeContactList.presenceFilter);
GuiActivator.getContactList().applyDefaultFilter();
}
}.start();
ConfigurationManager.setShowOffline(!isShowOffline);
GuiActivator.getContactList()
.setDefaultFilter(TreeContactList.presenceFilter);
GuiActivator.getContactList().applyDefaultFilter();
String itemTextKey = !isShowOffline
? "service.gui.HIDE_OFFLINE_CONTACTS"

@ -20,21 +20,6 @@
public class CallHistoryQueryStatusEvent
extends EventObject
{
/**
* Indicates that a query has been completed.
*/
public static final int QUERY_COMPLETED = 0;
/**
* Indicates that a query has been canceled.
*/
public static final int QUERY_CANCELED = 1;
/**
* Indicates that a query has been stopped because of an error.
*/
public static final int QUERY_ERROR = 2;
/**
* Indicates the type of this event.
*/
@ -46,7 +31,7 @@ public class CallHistoryQueryStatusEvent
* initially this event occurred.
* @param source the <tt>CallHistoryQuery</tt> this event is about
* @param eventType the type of the event. One of the QUERY_XXX constants
* defined in this class
* defined in the <tt>CallHistoryQuery</tt>
*/
public CallHistoryQueryStatusEvent( CallHistoryQuery source,
int eventType)

@ -18,6 +18,26 @@
*/
public interface ContactQuery
{
/**
* Indicates that this query has been completed.
*/
public static final int QUERY_COMPLETED = 0;
/**
* Indicates that this query has been canceled.
*/
public static final int QUERY_CANCELED = 1;
/**
* Indicates that this query has been stopped because of an error.
*/
public static final int QUERY_ERROR = 2;
/**
* Indicates that this query is in progress.
*/
public static final int QUERY_IN_PROGRESS = 3;
/**
* Returns the <tt>ContactSourceService</tt>, where this query was first
* initiated.
@ -37,6 +57,13 @@ public interface ContactQuery
*/
public void cancel();
/**
* Returns the status of this query. One of the static constants QUERY_XXXX
* defined in this class.
* @return the status of this query
*/
public int getStatus();
/**
* Adds the given <tt>ContactQueryListener</tt> to the list of registered
* listeners. The <tt>ContactQueryListener</tt> would be notified each

@ -0,0 +1,48 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.util.swing;
import java.awt.*;
import java.awt.event.*;
/**
* The <tt>LowPriorityEventQueue</tt> schedules low priority events to be
* dispatched through the system event queue.
*
* @author Yana Stamcheva
*/
public class LowPriorityEventQueue
{
/**
* Causes <code>runnable</code> to have its <code>run</code>
* method called in the event dispatch thread with low priority.
*
* @param runnable the <code>Runnable</code> whose <code>run</code>
* method should be executed synchronously on the <code>EventQueue</code>
*/
public static void invokeLater(Runnable runnable)
{
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(
new LowPriorityInvocationEvent(
Toolkit.getDefaultToolkit(), runnable));
}
/**
* The <tt>LowPriorityInvocationEvent</tt> is an <tt>InvocationEvent</tt>
* that replaces the default event id with the <tt>PaintEvent.UPDATE</tt>
* in order to indicate that this event should be dispatched with the same
* priority as an update paint event, which is normally with lower priority
* than other events.
*/
private static class LowPriorityInvocationEvent extends InvocationEvent
{
public LowPriorityInvocationEvent(Object source, Runnable runnable)
{
super(source, PaintEvent.UPDATE, runnable, null, false);
}
}
}
Loading…
Cancel
Save