void PersonsModel::onContactsFetched()
{
    Q_D(PersonsModel);

    KABC::Addressee::Map addresseeMap;

    //fetch all already loaded contacts from plugins
    Q_FOREACH (const AllContactsMonitorPtr &contactWatcher, d->m_sourceMonitors) {
        addresseeMap.unite(contactWatcher->contacts());
    }

    //add metacontacts
    QMultiHash<QString, QString> contactMapping = PersonManager::instance()->allPersons();

    Q_FOREACH (const QString &key, contactMapping.uniqueKeys()) {
        KABC::Addressee::Map contacts;
        Q_FOREACH (const QString &contact, contactMapping.values(key)) {
            d->contactToPersons[contact] = key;
            if (addresseeMap.contains(contact)) {
                contacts[contact] = addresseeMap.take(contact);
            }
        }
        if (!contacts.isEmpty()) {
            addPerson(MetaContact(key, contacts));
        }
    }

    //add remaining contacts
    KABC::Addressee::Map::const_iterator i;
    for (i = addresseeMap.constBegin(); i != addresseeMap.constEnd(); ++i) {
        addPerson(MetaContact(i.key(), i.value()));
    }

    Q_FOREACH(const AllContactsMonitorPtr monitor, d->m_sourceMonitors) {
        connect(monitor.data(), SIGNAL(contactAdded(QString,KABC::Addressee)), SLOT(onContactAdded(QString,KABC::Addressee)));
        connect(monitor.data(), SIGNAL(contactChanged(QString,KABC::Addressee)), SLOT(onContactChanged(QString,KABC::Addressee)));
        connect(monitor.data(), SIGNAL(contactRemoved(QString)), SLOT(onContactRemoved(QString)));
    }
}
bool UnicodeTournamentTrie::Preprocess( IImporter* importer, QString dir )
{
	QString filename = fileInDirectory( dir, "Unicode Tournament Trie" );

	QFile subTrieFile( filename + "_sub" );
	QFile wayFile( filename + "_ways" );

	if ( !openQFile( &subTrieFile, QIODevice::WriteOnly ) )
		return false;
	if ( !openQFile( &wayFile, QIODevice::WriteOnly ) )
		return false;

	std::vector< IImporter::Place > inputPlaces;
	std::vector< IImporter::Address > inputAddress;
	std::vector< UnsignedCoordinate > inputWayBuffer;
	std::vector< QString > inputWayNames;
	if ( !importer->GetAddressData( &inputPlaces, &inputAddress, &inputWayBuffer, &inputWayNames ) )
		return false;

	Timer time;

	std::sort( inputAddress.begin(), inputAddress.end() );
	qDebug() << "Unicode Tournament Trie: sorted addresses by importance:" << time.restart() << "ms";

	std::vector< UnsignedCoordinate > wayBuffer;
	std::vector< utt::Node > trie( 1 );
	unsigned address = 0;

	// build address name index
	QMultiHash< unsigned, unsigned > addressByName;
	for ( ; address < inputAddress.size(); address++ ) {
		addressByName.insert( inputAddress[address].name, address );
	}

	// compute way lengths
	QList< unsigned > uniqueNames = addressByName.uniqueKeys();
	std::vector< std::pair< double, unsigned > > wayLengths;
	for ( unsigned name = 0; name < ( unsigned ) uniqueNames.size(); name++ ) {
		QList< unsigned > segments = addressByName.values( uniqueNames[name] );
		double distance = 0;
		for( unsigned segment = 0; segment < ( unsigned ) segments.size(); segment++ ) {
			const IImporter::Address segmentAddress = inputAddress[segment];
			for ( unsigned coord = 1; coord < segmentAddress.pathLength; ++coord ) {
				GPSCoordinate sourceGPS = inputWayBuffer[segmentAddress.pathID + coord - 1].ToProjectedCoordinate().ToGPSCoordinate();
				GPSCoordinate targetGPS = inputWayBuffer[segmentAddress.pathID + coord].ToProjectedCoordinate().ToGPSCoordinate();
				distance += sourceGPS.ApproximateDistance( targetGPS );
			}
		}
		wayLengths.push_back( std::pair< double, unsigned >( distance, name ) );
	}

	// sort ways by aggregate lengths
	std::sort( wayLengths.begin(), wayLengths.end() );
	std::vector< unsigned > wayImportance( uniqueNames.size() );
	for ( unsigned way = 0; way < wayLengths.size(); way++ )
		wayImportance[wayLengths[way].second] = way;
	wayLengths.clear();

	std::vector< utt::Node > subTrie( 1 );

	for ( unsigned name = 0; name < ( unsigned ) uniqueNames.size(); name++ ) {
		QList< unsigned > segments = addressByName.values( uniqueNames[name] );

		// build edge connector data structures
		std::vector< EdgeConnector< UnsignedCoordinate>::Edge > connectorEdges;
		std::vector< unsigned > resultSegments;
		std::vector< unsigned > resultSegmentDescriptions;
		std::vector< bool > resultReversed;

		for ( unsigned segment = 0; segment < ( unsigned ) segments.size(); segment++ ) {
			const IImporter::Address& segmentAddress = inputAddress[segments[segment]];
			EdgeConnector< UnsignedCoordinate >::Edge newEdge;
			newEdge.source = inputWayBuffer[segmentAddress.pathID];
			newEdge.target = inputWayBuffer[segmentAddress.pathID + segmentAddress.pathLength - 1];
			newEdge.reverseable = true;
			connectorEdges.push_back( newEdge );
		}

		EdgeConnector< UnsignedCoordinate >::run( &resultSegments, &resultSegmentDescriptions, &resultReversed, connectorEdges );

		// string places with the same name together
		unsigned nextID = 0;
		for ( unsigned segment = 0; segment < resultSegments.size(); segment++ ) {
			utt::Data subEntry;
			subEntry.start = wayBuffer.size();

			for ( unsigned description = 0; description < resultSegments[segment]; description++ ) {
				unsigned segmentID = resultSegmentDescriptions[nextID + description];
				const IImporter::Address& segmentAddress = inputAddress[segments[segmentID]];
				std::vector< UnsignedCoordinate > path;
				for ( unsigned pathID = 0; pathID < segmentAddress.pathLength; pathID++ )
					path.push_back( inputWayBuffer[pathID + segmentAddress.pathID]);
				if ( resultReversed[segmentID] )
					std::reverse( path.begin(), path.end() );
				int skipFirst = description == 0 ? 0 : 1;
				assert( skipFirst == 0 || wayBuffer.back() == path.front() );
				wayBuffer.insert( wayBuffer.end(), path.begin() + skipFirst, path.end() );
			}
			
			utt::PlaceData placeData;
			placeData.name = inputPlaces[inputAddress[segments[resultSegmentDescriptions[nextID]]].nearPlace].name;

			subEntry.length = wayBuffer.size() - subEntry.start;
			insert( &subTrie, wayImportance[name], inputWayNames[uniqueNames[name]], subEntry, placeData );

			nextID += resultSegments[segment];
		}
	}

	writeTrie( &subTrie, subTrieFile );

	assert( address == inputAddress.size() );
	qDebug() << "Unicode Tournament Trie: build tries and tournament trees:" << time.restart() << "ms";

	for ( std::vector< UnsignedCoordinate >::const_iterator i = wayBuffer.begin(), e = wayBuffer.end(); i != e; ++i ) {
		wayFile.write( ( char* ) &i->x, sizeof( i->x ) );
		wayFile.write( ( char* ) &i->y, sizeof( i->y ) );
	}
	qDebug() << "Unicode Tournament Trie: wrote ways:" << time.restart() << "ms";

	return true;
}