// // Groups results. // void ResultsTree::regroupResults(bool groupBySearchEngine) { ResultsModelColumns::ResultType currentType, newType; #ifdef DEBUG cout << "ResultsTree::regroupResults: called" << endl; #endif // What's the new grouping criteria ? if (groupBySearchEngine == true) { // By search engine currentType = ResultsModelColumns::RESULT_HOST; newType = ResultsModelColumns::RESULT_ROOT; } else { // By host currentType = ResultsModelColumns::RESULT_ROOT; newType = ResultsModelColumns::RESULT_HOST; } // Go through tree rows TreeModel::Children children = m_refStore->children(); if (children.empty() == true) { return; } // Clear the map m_resultsGroups.clear(); // Unselect results get_selection()->unselect_all(); TreeModel::Children::iterator iter = children.begin(); while (iter != children.end()) { TreeModel::Row row = *iter; #ifdef DEBUG cout << "ResultsTree::groupBySearchEngine: looking at " << row[m_resultsColumns.m_text] << endl; #endif ResultsModelColumns::ResultType type = row[m_resultsColumns.m_type]; // Skip new type rows if (type == newType) { iter++; continue; } TreeModel::Children child = iter->children(); if (child.empty() == false) { TreeModel::Children::iterator childIter = child.begin(); // Type RESULT_TITLE while (childIter != child.end()) { TreeModel::Row childRow = *childIter; TreeModel::iterator groupIter, newIter; bool success = false; // We will need the URL and engines columns in all cases string url = from_utf8(childRow[m_resultsColumns.m_url]); unsigned int engineIds = childRow[m_resultsColumns.m_engines]; unsigned int indexIds = childRow[m_resultsColumns.m_indexes]; // Get the name of the group this should go into if (newType == ResultsModelColumns::RESULT_HOST) { Url urlObj(url); #ifdef DEBUG cout << "ResultsTree::groupBySearchEngine: row " << url << endl; #endif string groupName = urlObj.getHost(); // Add group if (appendGroup(groupName, newType, groupIter) == true) { // Add result success = appendResult(childRow[m_resultsColumns.m_text], childRow[m_resultsColumns.m_url], (float)atof(from_utf8(childRow[m_resultsColumns.m_score]).c_str()), from_utf8(childRow[m_resultsColumns.m_language]), childRow[m_resultsColumns.m_rankDiff], from_utf8(childRow[m_resultsColumns.m_queryName]), engineIds, indexIds, newIter, &(*groupIter), true); } } else { // Look at the engines column and see which engines this result is for set<string> engineNames; m_settings.getEngineNames(engineIds, engineNames); if (engineNames.empty() == false) { #ifdef DEBUG cout << "ResultsTree::groupBySearchEngine: row is for " << engineNames.size() << endl; #endif // Are there indexes in the list ? set<string>::iterator xapianIter = engineNames.find("Xapian"); if ((xapianIter != engineNames.end()) && (indexIds > 0)) { // Erase this engineNames.erase(xapianIter); // Add entries for each index name so that we can loop once on engine names set<string> indexNames; m_settings.getIndexNames(indexIds, indexNames); for (set<string>::iterator iter = indexNames.begin(); iter != indexNames.end(); ++iter) { string indexName = (*iter); engineNames.insert(indexName); #ifdef DEBUG cout << "ResultsTree::groupBySearchEngine: row is for index " << indexName << endl; #endif } } for (set<string>::iterator iter = engineNames.begin(); iter != engineNames.end(); ++iter) { string engineName = (*iter); unsigned int indexId = 0; unsigned int engineId = m_settings.getEngineId(engineName); if (engineId == 0) { // This is actually an index, not an engine... indexId = m_settings.getIndexId(engineName); if (indexId > 0) { engineId = m_settings.getEngineId("Xapian"); } } // Add group if (appendGroup(engineName, newType, groupIter) == true) { // Add result appendResult(childRow[m_resultsColumns.m_text], childRow[m_resultsColumns.m_url], (float)atof(from_utf8(childRow[m_resultsColumns.m_score]).c_str()), from_utf8(childRow[m_resultsColumns.m_language]), childRow[m_resultsColumns.m_rankDiff], from_utf8(childRow[m_resultsColumns.m_queryName]), engineId, indexId, newIter, &(*groupIter), true); #ifdef DEBUG cout << "ResultsTree::groupBySearchEngine: row for " << *iter << endl; #endif } } // FIXME: make sure at least one row was added success = true; } } if (success == true) { // Delete it m_refStore->erase(*childIter); childIter = child.begin(); } else { // Don't delete anything then, just go to the next child childIter++; } } } // Erase this row m_refStore->erase(*iter); // Get the new first row, that way we don't have to worry about iterators validity iter = children.begin(); } for (std::map<string, TreeModel::iterator>::iterator mapIter = m_resultsGroups.begin(); mapIter != m_resultsGroups.end(); mapIter++) { TreeModel::iterator groupIter = mapIter->second; updateGroup(groupIter); } onSelectionChanged(); }
// // Adds a new row in the results tree. // bool ResultsTree::appendResult(const ustring &text, const ustring &url, float score, const string &language, int rankDiff, const string &queryName, unsigned int engineId, unsigned int indexId, TreeModel::iterator &newRowIter, const TreeModel::Row *parentRow, bool noDuplicates) { if (parentRow == NULL) { newRowIter = m_refStore->append(); } else { // Merge duplicates within groups ? if (noDuplicates == true) { // Look for a row with the same URL and query. For instance, in group // by host mode, if a page is returned by several search engines, it // should appear only once TreeModel::Children children = parentRow->children(); if (children.empty() == false) { TreeModel::Children::iterator childIter = children.begin(); for (; childIter != children.end(); ++childIter) { TreeModel::Row row = *childIter; if ((row[m_resultsColumns.m_url] == to_utf8(url)) && (row[m_resultsColumns.m_queryName] == to_utf8(queryName))) { // Update the engines column... row[m_resultsColumns.m_engines] = row[m_resultsColumns.m_engines] | engineId; // ...and the indexes column too row[m_resultsColumns.m_indexes] = row[m_resultsColumns.m_indexes] | engineId; #ifdef DEBUG cout << "ResultsTree::appendResult: merged " << text << " " << engineId << " (" << row[m_resultsColumns.m_engines] << "," << row[m_resultsColumns.m_indexes] << ")" << endl; #endif newRowIter = childIter; return true; } } } } newRowIter = m_refStore->append(parentRow->children()); #ifdef DEBUG cout << "ResultsTree::appendResult: added " << text << ", " << score << " to " << (*parentRow)[m_resultsColumns.m_text] << endl; #endif } XapianIndex index(m_settings.m_indexLocation); ViewHistory viewHistory(m_settings.m_historyDatabase); bool isIndexed = false; // Is this document indexed ? if ((index.isGood() == true) && (index.hasDocument(url) > 0)) { isIndexed = true; } // Has it been already viewed ? bool wasViewed = viewHistory.hasItem(url); char scoreStr[128]; snprintf(scoreStr, 128, "%.f", score); TreeModel::Row childRow = *newRowIter; updateRow(childRow, text, url, scoreStr, to_utf8(language), to_utf8(queryName), engineId, indexId, ResultsModelColumns::RESULT_TITLE, isIndexed, wasViewed, rankDiff); return true; }