/*
* 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 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 FilterQuery gives information about a current filtering.
*
* @author Yana Stamcheva
*/
public class UIFilterQuery
extends FilterQuery
implements ContactQueryListener,
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;
/**
* Indicates if the query succeeded, i.e. if any of the filters associated
* with this query has returned any results.
*/
private boolean isSucceeded = false;
/**
* Indicates if this query has been canceled.
*/
private boolean isCanceled = false;
/**
* Indicates if this query is closed, means no more queries could be added
* to it. A FilterQuery , which is closed knows that it has to wait
* for a final number of queries to finish before notifying interested
* parties of the result.
*/
private boolean isClosed = false;
/**
* The list of filter queries.
*/
private final Map> filterQueries
= Collections.synchronizedMap(
new Hashtable>());
/**
* Indicates the number of running queries.
*/
private int runningQueries = 0;
/**
* Adds the given contactQuery to the list of filterQueries.
* @param contactQuery the ContactQuery to add
*/
public void addContactQuery(Object contactQuery)
{
synchronized (filterQueries)
{
// If this filter query has been already canceled and someone wants
// to add something to it, we just cancel the incoming query and
// return.
if (isCanceled)
{
cancelQuery(contactQuery);
return;
}
List queryResults = new ArrayList();
if (contactQuery instanceof ContactQuery)
{
ContactQuery externalQuery = (ContactQuery) contactQuery;
List externalResults
= externalQuery.getQueryResults();
if (externalResults != null && externalResults.size() > 0)
queryResults = new ArrayList(externalResults);
externalQuery.addContactQueryListener(this);
}
else if (contactQuery instanceof MetaContactQuery)
((MetaContactQuery) contactQuery).addContactQueryListener(this);
filterQueries.put(contactQuery, queryResults);
runningQueries++;
}
}
/**
* Sets the isSucceeded property.
* @param isSucceeded indicates if this query has succeeded
*/
public void setSucceeded(boolean isSucceeded)
{
this.isSucceeded = isSucceeded;
}
/**
* Indicates if this query has succeeded.
* @return true if this query has succeeded, false -
* otherwise
*/
public boolean isSucceeded()
{
return isSucceeded;
}
/**
* Indicates if this query is canceled.
* @return true if this query is canceled, false otherwise
*/
public boolean isCanceled()
{
synchronized (filterQueries)
{
return isCanceled;
}
}
/**
* Cancels this filter query.
*/
public void cancel()
{
synchronized(filterQueries)
{
isCanceled = true;
Iterator queriesIter = filterQueries.keySet().iterator();
while (queriesIter.hasNext())
cancelQuery(queriesIter.next());
}
}
/**
* Closes this query to indicate that no more contact sub-queries would be
* added to it.
*/
public void close()
{
isClosed = true;
if (runningQueries == 0)
fireFilterQueryEvent();
}
/**
* Sets the given FilterQueryListener .
* @param l the FilterQueryListener to set
*/
public void setQueryListener(FilterQueryListener l)
{
filterQueryListener = l;
}
/**
* Notifies the FilterQueryListener of the result status of
* this query.
*/
private void fireFilterQueryEvent()
{
if (filterQueryListener == null)
return;
if (isSucceeded)
filterQueryListener.filterQuerySucceeded(this);
else
filterQueryListener.filterQueryFailed(this);
}
/**
* Indicates that a query has changed its status.
* @param event the ContactQueryStatusEvent that notified us
*/
public void queryStatusChanged(ContactQueryStatusEvent event)
{
ContactQuery query = event.getQuerySource();
// Check if this query is in our filter queries list.
if (!filterQueries.containsKey(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 ContactQuery 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.
runningQueries--;
query.removeContactQueryListener(this);
// If no queries have rest we notify interested listeners that query
// has finished.
if (runningQueries == 0 && isClosed)
fireFilterQueryEvent();
}
/**
* Indicates that a query has changed its status.
* @param event the ContactQueryStatusEvent that notified us
*/
public void metaContactQueryStatusChanged(MetaContactQueryStatusEvent event)
{
MetaContactQuery query = event.getQuerySource();
// Check if this query is in our filter queries list.
if (!filterQueries.containsKey(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 && isClosed)
fireFilterQueryEvent();
}
/**
* Cancels the given query.
* @param query the query to cancel
*/
private void cancelQuery(Object query)
{
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;
}
}
/**
* Verifies if the given query is contained in this filter query.
*
* @param query the query we're looking for
* @return true if the given query is contained in this
* filter query, false - otherwise
*/
public boolean containsQuery(Object query)
{
return filterQueries.containsKey(query);
}
/**
* Cancels asynchronous queries after the maximum desired result count is
* reached.
*
* @param query the query we're interested in
* @param contact the source contact we just received as a result of the
* given query
*/
private void contactReceived(ContactQuery query, SourceContact contact)
{
List queryResults = filterQueries.get(query);
queryResults.add(contact);
if (queryResults.size() == MAX_EXTERNAL_RESULT_COUNT)
{
query.removeContactQueryListener(GuiActivator.getContactList());
ShowMoreContact moreInfoContact
= new ShowMoreContact(query, queryResults);
ContactSourceService contactSource = query.getContactSource();
GuiActivator.getContactList().addContact(
query,
moreInfoContact,
GuiActivator.getContactList()
.getContactSource(contactSource).getUIGroup(),
false);
}
}
/**
* Indicates that a contact has been received as a result of a query.
*
* @param event the ContactReceivedEvent that notified us
*/
public void contactReceived(ContactReceivedEvent event)
{
contactReceived(event.getQuerySource(), event.getContact());
}
/**
* Indicates that a contact has been removed after a search.
* @param event the ContactQueryEvent containing information
* about the received SourceContact
*/
public void contactRemoved(ContactRemovedEvent event)
{}
/**
* Indicates that a contact has been updated after a search.
* @param event the ContactQueryEvent containing information
* about the updated SourceContact
*/
public void contactChanged(ContactChangedEvent event)
{}
public void metaContactReceived(MetaContactQueryEvent event) {}
public void metaGroupReceived(MetaGroupQueryEvent event) {}
}