/********************************************************************** * * dynamicclassifieraction.cpp -- * Copyright (C) 2008 DL Consulting Ltd * * A component of the Greenstone digital library software * from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *********************************************************************/ #include "dynamicclassifieraction.h" #include "recptprototools.h" dynamicclassifieraction::dynamicclassifieraction () { recpt = NULL; cgiarginfo arg_ainfo; arg_ainfo.shortname = "dcl"; arg_ainfo.longname = "dynamic classifier ID"; arg_ainfo.multiplechar = true; arg_ainfo.defaultstatus = cgiarginfo::weak; arg_ainfo.argdefault = ""; arg_ainfo.savedarginfo = cgiarginfo::must; argsinfo.addarginfo (NULL, arg_ainfo); arg_ainfo.shortname = "dcn"; arg_ainfo.longname = "dynamic classifier node"; arg_ainfo.multiplechar = true; arg_ainfo.defaultstatus = cgiarginfo::weak; arg_ainfo.argdefault = ""; arg_ainfo.savedarginfo = cgiarginfo::must; argsinfo.addarginfo (NULL, arg_ainfo); } dynamicclassifieraction::~dynamicclassifieraction() { } bool dynamicclassifieraction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, recptprotolistclass *protos, ostream &logout) { return true; } void dynamicclassifieraction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos, response_t &response,text_t &response_data, ostream &logout) { response = content; response_data = "text/html"; } // define all the macros which might be used by other actions to produce pages. void dynamicclassifieraction::define_external_macros (displayclass &disp, cgiargsclass &args, recptprotolistclass *protos, ostream &logout) { // A valid collection server is vital recptproto *collectproto = protos->getrecptproto (args["c"], logout); if (collectproto == NULL) { logout << "dynamicclassifieraction::define_external_macros called with NULL collectproto\n"; return; } // Define _dynamicclassifiernavbarentries_ to add buttons to the navigation bar for the dynamic classifiers text_t navigation_bar_entries = ""; ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout); text_tmap::iterator dynamic_classifier_iterator = cinfo->dynamic_classifiers.begin(); while (dynamic_classifier_iterator != cinfo->dynamic_classifiers.end()) { text_t dynamic_classifier_id = (*dynamic_classifier_iterator).first; navigation_bar_entries += "_navbarspacer_"; navigation_bar_entries += "_navtab_(_gwcgi_?c=" + args["c"] + "&a=dc&dcl=" + dynamic_classifier_id + "," + dynamic_classifier_id; if (args["a"] == "dc" && args["dcl"] == dynamic_classifier_id) { navigation_bar_entries += ",selected"; } navigation_bar_entries += ")"; dynamic_classifier_iterator++; } disp.setmacro("dynamicclassifiernavbarentries", displayclass::defaultpackage, navigation_bar_entries); } // define all the macros which are related to pages generated // by this action. we also load up the formatinfo structure // here (it's used in do_action as well as here) void dynamicclassifieraction::define_internal_macros (displayclass &disp, cgiargsclass &args, recptprotolistclass *protos, ostream &logout) { // define_internal_macros sets the following macros: } bool dynamicclassifieraction::do_action(cgiargsclass &args, recptprotolistclass *protos, browsermapclass *browsers, displayclass &disp, outconvertclass &outconvert, ostream &textout, ostream &logout) { // A valid collection server is vital recptproto *collectproto = protos->getrecptproto (args["c"], logout); if (collectproto == NULL) { logout << "dynamicclassifieraction::do_action called with NULL collectproto\n"; return false; } textout << outconvert << disp << "_document:header_\n"; textout << outconvert << disp << "_document:content_\n"; // Check a dynamic classifier ID has been specified text_t arg_dcl = args["dcl"]; if (arg_dcl.empty()) { textout << outconvert << disp << "Error: Missing dcl argument.\n"; textout << outconvert << disp << "_document:footer_\n"; return true; } // Check the dynamic classifier ID is valid (ie. there is an entry in the collect.cfg file for it) ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout); if (cinfo->dynamic_classifiers.find(arg_dcl) == cinfo->dynamic_classifiers.end()) { textout << outconvert << disp << "Error: Invalid dcl value \"" << arg_dcl << "\".\n"; textout << outconvert << disp << "_document:footer_\n"; return true; } // Produce the page text_t metadata_element_name = cinfo->dynamic_classifiers[arg_dcl]; if (args["dcn"].empty()) { // Simple case for the top-level page output_top_level_page (metadata_element_name, args, collectproto, browsers, disp, outconvert, textout, logout); } else { // More complex case for an internal page output_internal_page (metadata_element_name, args, collectproto, browsers, disp, outconvert, textout, logout); } textout << outconvert << disp << "_document:footer_\n"; return true; } void dynamicclassifieraction::output_top_level_page (text_t metadata_element_name, cgiargsclass &args, recptproto *collectproto, browsermapclass *browsers, displayclass &disp, outconvertclass &outconvert, ostream &textout, ostream &logout) { // Get all the metadata values for the specified element (these become the classifier nodes at the top level) FilterResponse_t metadata_values_response; get_metadata_values (metadata_element_name, "", args["c"], collectproto, metadata_values_response, logout); // Deal with any hierarchical metadata values map classifier_nodes; ResultDocInfo_tarray::iterator metadata_value_iterator = metadata_values_response.docInfo.begin(); while (metadata_value_iterator != metadata_values_response.docInfo.end()) { // Is this metadata value hierarchical? text_t metadata_value = (*metadata_value_iterator).OID; text_t::iterator hierarchy_split_position = findchar(metadata_value.begin(), metadata_value.end(), '|'); if (hierarchy_split_position != metadata_value.end()) { // Yes, so use the first part of the hierarchy only metadata_value = substr(metadata_value.begin(), hierarchy_split_position); } // Create a node for this metadata value if we haven't seen it before if (classifier_nodes.find(metadata_value) == classifier_nodes.end()) { classifier_nodes[metadata_value] = 0; } // Increment the occurrence count classifier_nodes[metadata_value] += (*metadata_value_iterator).result_num; metadata_value_iterator++; } // Display the top-level classifier nodes map::iterator classifier_nodes_iterator = classifier_nodes.begin(); while (classifier_nodes_iterator != classifier_nodes.end()) { text_t classifier_node_OID = (*classifier_nodes_iterator).first; text_t classifier_node_label = (*classifier_nodes_iterator).first; int classifier_node_numleafdocs = (*classifier_nodes_iterator).second; output_classifier_node (classifier_node_OID, classifier_node_label, classifier_node_numleafdocs, 0, args, collectproto, browsers, disp, outconvert, textout, logout); classifier_nodes_iterator++; } } void dynamicclassifieraction::output_internal_page (text_t metadata_element_name, cgiargsclass &args, recptproto *collectproto, browsermapclass *browsers, displayclass &disp, outconvertclass &outconvert, ostream &textout, ostream &logout) { text_t arg_dcn = args["dcn"]; text_t classifier_node_metadata_value = arg_dcn; int node_indent = 0; // Get all the classifier nodes at this level text_t metadata_value_filter = classifier_node_metadata_value + "|*"; FilterResponse_t metadata_values_response; get_metadata_values (metadata_element_name, metadata_value_filter, args["c"], collectproto, metadata_values_response, logout); // Get all the documents at this level FilterResponse_t document_OIDs_response; get_documents_with_metadata_value (metadata_element_name, classifier_node_metadata_value, "dls.Title", args["c"], collectproto, document_OIDs_response, logout); // Check there are some classifier nodes or some documents at this level, otherwise the "dcn" argument was invalid if (metadata_values_response.docInfo.empty() && document_OIDs_response.docInfo.empty()) { textout << outconvert << disp << "Error: Invalid dcn value \"" << arg_dcn << "\".\n"; return; } // Determine the parent classifier nodes text_tarray parent_classifier_node_labels; splitchar(classifier_node_metadata_value.begin(), classifier_node_metadata_value.end(), '|', parent_classifier_node_labels); // Display the parent classifier nodes text_t parent_classifier_node_OID = ""; text_tarray::iterator parent_classifier_node_labels_iterator = parent_classifier_node_labels.begin(); while (parent_classifier_node_labels_iterator != parent_classifier_node_labels.end()) { parent_classifier_node_OID += (parent_classifier_node_OID != "" ? "|" : ""); parent_classifier_node_OID += *parent_classifier_node_labels_iterator; text_t parent_classifier_node_label = *parent_classifier_node_labels_iterator; text_t parent_classifier_node_numleafdocs = "?"; output_classifier_node (parent_classifier_node_OID, parent_classifier_node_label, parent_classifier_node_numleafdocs, node_indent, args, collectproto, browsers, disp, outconvert, textout, logout); node_indent++; parent_classifier_node_labels_iterator++; } // Display the classifier nodes at this level map classifier_nodes; ResultDocInfo_tarray::iterator metadata_value_iterator = metadata_values_response.docInfo.begin(); while (metadata_value_iterator != metadata_values_response.docInfo.end()) { text_t metadata_value = (*metadata_value_iterator).OID; if (starts_with(metadata_value, arg_dcn + "|")) { metadata_value = substr(metadata_value.begin() + (arg_dcn + "|").size(), metadata_value.end()); } // Is this metadata value hierarchical? text_t::iterator hierarchy_split_position = findchar(metadata_value.begin(), metadata_value.end(), '|'); if (hierarchy_split_position != metadata_value.end()) { // Yes, so split off the first part of the hierarchy for the classifier node metadata_value = substr(metadata_value.begin(), hierarchy_split_position); } // Create a node for this metadata value if we haven't seen it before if (classifier_nodes.find(metadata_value) == classifier_nodes.end()) { classifier_nodes[metadata_value] = 0; } // Increment the occurrence count classifier_nodes[metadata_value] += (*metadata_value_iterator).result_num; metadata_value_iterator++; } // Display the classifier nodes at this level map::iterator classifier_nodes_iterator = classifier_nodes.begin(); while (classifier_nodes_iterator != classifier_nodes.end()) { text_t classifier_node_OID = parent_classifier_node_OID + "|" + (*classifier_nodes_iterator).first; text_t classifier_node_label = (*classifier_nodes_iterator).first; int classifier_node_numleafdocs = (*classifier_nodes_iterator).second; output_classifier_node (classifier_node_OID, classifier_node_label, classifier_node_numleafdocs, node_indent, args, collectproto, browsers, disp, outconvert, textout, logout); classifier_nodes_iterator++; } // Display the documents at this level text_tarray document_OIDs; ResultDocInfo_tarray::iterator document_OID_iterator = document_OIDs_response.docInfo.begin(); while (document_OID_iterator != document_OIDs_response.docInfo.end()) { document_OIDs.push_back ((*document_OID_iterator).OID); document_OID_iterator++; } output_document_nodes (document_OIDs, node_indent, args, collectproto, browsers, disp, outconvert, textout, logout); } void dynamicclassifieraction::output_classifier_node (text_t classifier_node_OID, text_t classifier_node_label, text_t classifier_node_numleafdocs, int classifier_node_indent, cgiargsclass &args, recptproto *collectproto, browsermapclass *browsers, displayclass &disp, outconvertclass &outconvert, ostream &textout, ostream &logout) { // Generate the ResultDocInfo_t containing the information for the classifier node ResultDocInfo_t classifier_node; classifier_node.OID = classifier_node_OID; classifier_node.metadata["doctype"].values.push_back ("classify"); classifier_node.metadata["haschildren"].values.push_back ("1"); classifier_node.metadata["numleafdocs"].values.push_back (classifier_node_numleafdocs); classifier_node.metadata["Title"].values.push_back (classifier_node_label); // Get the format statement for this classifier if there is one, or use the browser's default otherwise text_t formatstring; text_t classifier_type = "VList"; browserclass *bptr = browsers->getbrowser (classifier_type); ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout); if (!get_formatstring (args["dcl"], classifier_type, cinfo->format, formatstring)) { formatstring = bptr->get_default_formatstring(); } format_t *formatlistptr = new format_t(); text_tset metadata; bool getParents = false; parse_formatstring (formatstring, formatlistptr, metadata, getParents); bool use_table = is_table_content (formatlistptr); // Display the classifier node bptr->output_section_group (classifier_node, args, args["c"], classifier_node_indent, formatlistptr, use_table, metadata, getParents, collectproto, disp, outconvert, textout, logout); } void dynamicclassifieraction::output_document_nodes (text_tarray document_OIDs, int document_nodes_indent, cgiargsclass &args, recptproto *collectproto, browsermapclass *browsers, displayclass &disp, outconvertclass &outconvert, ostream &textout, ostream &logout) { // Get the format statement for this classifier if there is one, or use the browser's default otherwise text_t formatstring; text_t classifier_type = "VList"; browserclass *bptr = browsers->getbrowser (classifier_type); ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout); if (!get_formatstring (args["dcl"], classifier_type, cinfo->format, formatstring)) { formatstring = bptr->get_default_formatstring(); } format_t *formatlistptr = new format_t(); text_tset metadata; bool getParents = false; parse_formatstring (formatstring, formatlistptr, metadata, getParents); bool use_table = is_table_content (formatlistptr); // Request the necessary metadata for the documents FilterResponse_t document_OIDs_response; get_info (document_OIDs, args["c"], args["l"], metadata, getParents, collectproto, document_OIDs_response, logout); // Display the document nodes bptr->output_section_group (document_OIDs_response, args, args["c"], document_nodes_indent, formatlistptr, use_table, metadata, getParents, collectproto, disp, outconvert, textout, logout); }