virtual boolean callback(
		const IPluginObjectDesc& rPluginObjectDesc)
	{
		string l_sFullName=string(rPluginObjectDesc.getCategory())+"/"+string(rPluginObjectDesc.getName());
		map<string, const IPluginObjectDesc* >::iterator itPluginObjectDesc=m_vPluginObjectDesc.find(l_sFullName);
		if(itPluginObjectDesc!=m_vPluginObjectDesc.end())
		{
			m_rKernelContext.getLogManager() << LogLevel_ImportantWarning << "Duplicate plugin object name " << CString(l_sFullName.c_str()) << " " << itPluginObjectDesc->second->getCreatedClass() << " and " << rPluginObjectDesc.getCreatedClass() << "\n";
		}
		m_vPluginObjectDesc[l_sFullName]=&rPluginObjectDesc;
		return true;
	}
	virtual boolean callback(
		const IPluginObjectDesc& rPluginObjectDesc)
	{
		// Outputs plugin info to console
		m_rKernelContext.getLogManager() << LogLevel_Trace << "Plugin <" << rPluginObjectDesc.getName() << ">\n";
		m_rKernelContext.getLogManager() << LogLevel_Debug << " | Plugin category        : " << rPluginObjectDesc.getCategory() << "\n";
		m_rKernelContext.getLogManager() << LogLevel_Debug << " | Class identifier       : " << rPluginObjectDesc.getCreatedClass() << "\n";
		m_rKernelContext.getLogManager() << LogLevel_Debug << " | Author name            : " << rPluginObjectDesc.getAuthorName() << "\n";
		m_rKernelContext.getLogManager() << LogLevel_Debug << " | Author company name    : " << rPluginObjectDesc.getAuthorCompanyName() << "\n";
		m_rKernelContext.getLogManager() << LogLevel_Debug << " | Short description      : " << rPluginObjectDesc.getShortDescription() << "\n";
		m_rKernelContext.getLogManager() << LogLevel_Debug << " | Detailed description   : " << rPluginObjectDesc.getDetailedDescription() << "\n";

		return true;
	}
boolean CPluginObjectDescEnumBoxAlgorithmSnapshotGenerator::callback(const IPluginObjectDesc& rPluginObjectDesc)
{
	string l_sFullName=string(rPluginObjectDesc.getCategory().toASCIIString()) + "/" + string(rPluginObjectDesc.getName().toASCIIString());
	string l_sFilename="BoxAlgorithm_"+transform(rPluginObjectDesc.getName().toASCIIString());
	CIdentifier l_oBoxIdentifier;
	if(!m_pScenario->addBox(rPluginObjectDesc.getCreatedClassIdentifier(), l_oBoxIdentifier))
	{
		m_rKernelContext.getLogManager() << LogLevel_Warning << "Skipped [" << CString(l_sFilename.c_str()) << "] (could not create corresponding box)\n";
		return true;
	}
	IBox& l_rBox=*m_pScenario->getBoxDetails(l_oBoxIdentifier);
	IBox& rBox=*m_pScenario->getBoxDetails(l_oBoxIdentifier);

	m_rKernelContext.getLogManager() << LogLevel_Trace << "Working on [" << CString(l_sFilename.c_str()) << "]\n";

	::PangoContext* l_pPangoContext=gtk_widget_get_pango_context(m_pWidget);
	::PangoLayout* l_pPangoLayout=pango_layout_new(l_pPangoContext);
	::PangoRectangle l_oPangoRectangle;

	pango_layout_set_alignment(l_pPangoLayout, PANGO_ALIGN_CENTER);
	pango_layout_set_text(l_pPangoLayout, rPluginObjectDesc.getName(), -1);
	pango_layout_get_pixel_extents(l_pPangoLayout, NULL, &l_oPangoRectangle);

		uint32 i;
		const int xMargin=5;
		const int yMargin=5;
		const int iCircleSize=11;
		const int iCircleSpace=4;

	int xSize=l_oPangoRectangle.width+xMargin*2;
	int ySize=l_oPangoRectangle.height+yMargin*2;
	int xStart=16;
	int yStart=16;

	gdk_window_invalidate_rect(
		m_pWidget->window,
		NULL,
		true);

	while(gtk_events_pending())
	{
		gtk_main_iteration();
	}

	::GdkGC* l_pDrawGC=gdk_gc_new(m_pWidget->window);

		boolean l_bDeprecated=m_rKernelContext.getPluginManager().isPluginObjectFlaggedAsDeprecated(rBox.getAlgorithmClassIdentifier());
		if(l_bDeprecated)
		{
			gdk_gc_set_rgb_fg_color(l_pDrawGC, &m_vColors[Color_BoxBackgroundDeprecated]);
		}
		else
		{
			gdk_gc_set_rgb_fg_color(l_pDrawGC, &m_vColors[Color_BoxBackground]);
		}

	gdk_draw_rounded_rectangle(
		m_pWidget->window,
		l_pDrawGC,
		TRUE,
		xStart, yStart, xSize, ySize);
	gdk_gc_set_rgb_fg_color(l_pDrawGC, &m_vColors[Color_BoxBorder]);
	gdk_draw_rounded_rectangle(
		m_pWidget->window,
		l_pDrawGC,
		FALSE,
		xStart, yStart, xSize, ySize);

	int l_iInputOffset=(xSize-l_rBox.getInputCount()*(iCircleSpace+iCircleSize)+iCircleSize/2)/2;
	for(i=0; i<l_rBox.getInputCount(); i++)
	{
		CIdentifier l_oInputIdentifier;
		l_rBox.getInputType(i, l_oInputIdentifier);
		::GdkColor l_oInputColor=colorFromIdentifier(l_oInputIdentifier);

			::GdkPoint l_vPoint[4];
			l_vPoint[0].x=iCircleSize>>1;
			l_vPoint[0].y=iCircleSize;
			l_vPoint[1].x=0;
			l_vPoint[1].y=0;
			l_vPoint[2].x=iCircleSize-1;
			l_vPoint[2].y=0;
			for(int j=0; j<3; j++)
			{
				l_vPoint[j].x+=xStart+i*(iCircleSpace+iCircleSize)+l_iInputOffset;
				l_vPoint[j].y+=yStart-(iCircleSize>>1);
			}

		gdk_gc_set_rgb_fg_color(l_pDrawGC, &l_oInputColor);
		gdk_draw_polygon(
			m_pWidget->window,
			l_pDrawGC,
			TRUE,
			l_vPoint,
			3);
		gdk_gc_set_rgb_fg_color(l_pDrawGC, &m_vColors[Color_BoxInputBorder]);
		gdk_draw_polygon(
			m_pWidget->window,
			l_pDrawGC,
			FALSE,
			l_vPoint,
			3);
	}

	int l_iOutputOffset=(xSize-l_rBox.getOutputCount()*(iCircleSpace+iCircleSize)+iCircleSize/2)/2;
	for(i=0; i<l_rBox.getOutputCount(); i++)
	{
		CIdentifier l_oOutputIdentifier;
		l_rBox.getOutputType(i, l_oOutputIdentifier);
		::GdkColor l_oOutputColor=colorFromIdentifier(l_oOutputIdentifier);

			::GdkPoint l_vPoint[4];
			l_vPoint[0].x=iCircleSize>>1;
			l_vPoint[0].y=iCircleSize;
			l_vPoint[1].x=0;
			l_vPoint[1].y=0;
			l_vPoint[2].x=iCircleSize-1;
			l_vPoint[2].y=0;
			for(int j=0; j<3; j++)
			{
				l_vPoint[j].x+=xStart+i*(iCircleSpace+iCircleSize)+l_iOutputOffset;
				l_vPoint[j].y+=yStart-(iCircleSize>>1)+ySize;
			}

		gdk_gc_set_rgb_fg_color(l_pDrawGC, &l_oOutputColor);
		gdk_draw_polygon(
			m_pWidget->window,
			l_pDrawGC,
			TRUE,
			l_vPoint,
			3);
		gdk_gc_set_rgb_fg_color(l_pDrawGC, &m_vColors[Color_BoxOutputBorder]);
		gdk_draw_polygon(
			m_pWidget->window,
			l_pDrawGC,
			FALSE,
			l_vPoint,
			3);
	}

	gdk_draw_layout(
		m_pWidget->window,
		m_pWidget->style->text_gc[GTK_WIDGET_STATE(m_pWidget)],
		xStart+xMargin, yStart+yMargin, l_pPangoLayout);
	g_object_unref(l_pPangoLayout);
	g_object_unref(l_pDrawGC);

	::GdkPixbuf* l_pPixBuf=gdk_pixbuf_get_from_drawable(
		NULL,
		m_pWidget->window,
		NULL,
		0, 0,
		0, 0,
		xSize+32, ySize+32);
	gdk_pixbuf_save(l_pPixBuf, (m_sSnapshotDirectory+"/Doc_"+l_sFilename+".png").c_str(), "png", NULL, NULL);

	g_object_unref(l_pPixBuf);

	// --------------------------------------------------------------------------------------------------------------------

	m_vCategories.push_back(pair < string, string >(rPluginObjectDesc.getCategory().toASCIIString(), rPluginObjectDesc.getName().toASCIIString()));

	std::ofstream l_oFileSkeleton;
	std::ofstream l_oFilePart;
	l_oFileSkeleton.open((m_sDocTemplateDirectory+"/Doc_"+l_sFilename+".dox-skeleton").c_str());
	l_oFilePart.open((m_sDocTemplateDirectory+"/Doc_"+l_sFilename+".dox-part-skeleton").c_str());

	l_oFileSkeleton
		<< "/**\n"
		<< " * \\page Doc_" << l_sFilename.c_str() << " " << rPluginObjectDesc.getName().toASCIIString() << "\n"
		<< " * \\section Doc_" << l_sFilename.c_str() << "_Summary Summary\n"
		<< " * \\image html Doc_" << l_sFilename.c_str() << ".png\n"
		<< " *\n"
		<< " * - Plugin name : " << rPluginObjectDesc.getName() << "\n"
		<< " * - Version : " << rPluginObjectDesc.getVersion() << "\n"
		<< " * - Author : " << rPluginObjectDesc.getAuthorName() << "\n"
		<< " * - Company : " << rPluginObjectDesc.getAuthorCompanyName() << "\n"
		<< " * - Short description : " << rPluginObjectDesc.getShortDescription() << "\n"
		<< " * - Documentation template generation date : " << __DATE__ << "\n";

	boolean l_bDeprectated=m_rKernelContext.getPluginManager().isPluginObjectFlaggedAsDeprecated(rPluginObjectDesc.getCreatedClassIdentifier());
	if(l_bDeprectated)
	{
		l_oFileSkeleton
			<< " * - <b>WARNING : this box has been marked as DEPRECATED by the developer.</b>\n"
			<< " * It will be removed soon or later, so you should consider not using this\n"
			<< " * box and turn to another \"equivalent\" one.\n";
	}

	boolean l_bUnstable=m_rKernelContext.getPluginManager().isPluginObjectFlaggedAsUnstable(rPluginObjectDesc.getCreatedClassIdentifier());
	if(l_bUnstable)
	{
		l_oFileSkeleton
			<< " * - <b>WARNING : this box has been marked as UNSTABLE by the developer.\n"
			<< " * It means that its implementation may be incomplete or that the box can only work\n"
			<< " * under well known conditions. It may possibly crash or cause data loss.\n"
			<< " * Use this box at your own risk, you've been warned.</b>\n";
	}

	l_oFileSkeleton
		<< " *\n"
		<< " * \\section Doc_" << l_sFilename.c_str() << "_Description Description\n"
		<< " * " << rPluginObjectDesc.getDetailedDescription() << "\n"
		<< " *\n"
		<< " * @Doc_" << l_sFilename.c_str() << "_Description_Content@\n"
		<< " *\n";

	l_oFilePart
		<< "/**\n"
		<< " * \\page " << l_sFilename.c_str() << " " << rPluginObjectDesc.getName().toASCIIString() << "\n"
		<< "__________________________________________________________________\n"
		<< "\n"
		<< "Detailed description\n"
		<< "__________________________________________________________________\n"
		<< "\n"
		<< " * |OVP_DocBegin_" << l_sFilename.c_str() << "_Description|\n"
		<< " * |OVP_DocEnd_" << l_sFilename.c_str() << "_Description|\n";

	if(l_rBox.getInputCount())
	{
		l_oFileSkeleton
			<< " * \\section Doc_" << l_sFilename.c_str() << "_Inputs Inputs\n"
			// << " * Number of inputs : " << l_rBox.getInputCount() << "\n"
			<< " *\n"
			<< " * @Doc_" << l_sFilename.c_str() << "_Inputs_Content@\n";

		l_oFilePart
			<< "__________________________________________________________________\n"
			<< "\n"
			<< "Inputs description\n"
			<< "__________________________________________________________________\n"
			<< "\n"
			<< " * |OVP_DocBegin_" << l_sFilename.c_str() << "_Inputs|\n"
			<< " * |OVP_DocEnd_" << l_sFilename.c_str() << "_Inputs|\n";

		for(i=0; i<l_rBox.getInputCount(); i++)
		{
			CString l_sName;
			CIdentifier l_oTypeIdentifier;
			CString l_sTypeName;
			l_rBox.getInputName(i, l_sName);
			l_rBox.getInputType(i, l_oTypeIdentifier);
			l_sTypeName=m_rKernelContext.getTypeManager().getTypeName(l_oTypeIdentifier);

			l_oFileSkeleton
				<< " * \\subsection Doc_" << l_sFilename.c_str() << "_Input_" << i+1 << " " << i+1 << ". " << l_sName.toASCIIString() << "\n"
				<< " * @Doc_" << l_sFilename.c_str() << "_Input" << i+1 << "_Content@\n"
				<< " *\n"
				<< " * - Type identifier : \\ref Doc_Streams_" << transform(l_sTypeName.toASCIIString()).c_str() << " \"" << l_sTypeName.toASCIIString() << "\" <em>" << l_oTypeIdentifier.toString().toASCIIString() << "</em>\n"
				<< " *\n";

			l_oFilePart
				<< "\n"
				<< " * |OVP_DocBegin_" << l_sFilename.c_str() << "_Input" << i+1 << "|\n"
				<< " * |OVP_DocEnd_" << l_sFilename.c_str() << "_Input" << i+1 << "|\n";
		}
	}

	if(l_rBox.getOutputCount())
	{
		l_oFileSkeleton
			<< " * \\section Doc_" << l_sFilename.c_str() << "_Outputs Outputs\n"
			// << " * Number of outputs : " << l_rBox.getOutputCount() << "\n"
			<< " *\n"
			<< " * @Doc_" << l_sFilename.c_str() << "_Outputs_Content@\n";

		l_oFilePart
			<< "__________________________________________________________________\n"
			<< "\n"
			<< "Outputs description\n"
			<< "__________________________________________________________________\n"
			<< "\n"
			<< " * |OVP_DocBegin_" << l_sFilename.c_str() << "_Outputs|\n"
			<< " * |OVP_DocEnd_" << l_sFilename.c_str() << "_Outputs|\n";

		for(i=0; i<l_rBox.getOutputCount(); i++)
		{
			CString l_sName;
			CIdentifier l_oTypeIdentifier;
			CString l_sTypeName;
			l_rBox.getOutputName(i, l_sName);
			l_rBox.getOutputType(i, l_oTypeIdentifier);
			l_sTypeName=m_rKernelContext.getTypeManager().getTypeName(l_oTypeIdentifier);

			l_oFileSkeleton
				<< " * \\subsection Doc_" << l_sFilename.c_str() << "_Output_" << i+1 << " " << i+1 << ". " << l_sName.toASCIIString() << "\n"
				<< " * @Doc_" << l_sFilename.c_str() << "_Output" << i+1 << "_Content@\n"
				<< " *\n"
				<< " * - Type identifier : \\ref Doc_Streams_" << transform(l_sTypeName.toASCIIString()).c_str() << " \"" << l_sTypeName.toASCIIString() << "\" <em>" << l_oTypeIdentifier.toString().toASCIIString() << "</em>\n"
				<< " *\n";

			l_oFilePart
				<< "\n"
				<< " * |OVP_DocBegin_" << l_sFilename.c_str() << "_Output" << i+1 << "|\n"
				<< " * |OVP_DocEnd_" << l_sFilename.c_str() << "_Output" << i+1 << "|\n";
		}
	}

	if(l_rBox.getSettingCount())
	{
		l_oFileSkeleton
			<< " * \\section Doc_" << l_sFilename.c_str() << "_Settings Settings\n"
			// << " * Number of settings : " << l_rBox.getSettingCount() << "\n"
			<< " *\n"
			<< " * @Doc_" << l_sFilename.c_str() << "_Settings_Content@\n";

		l_oFilePart
			<< "__________________________________________________________________\n"
			<< "\n"
			<< "Settings description\n"
			<< "__________________________________________________________________\n"
			<< "\n"
			<< " * |OVP_DocBegin_" << l_sFilename.c_str() << "_Settings|\n"
			<< " * |OVP_DocEnd_" << l_sFilename.c_str() << "_Settings|\n";

		for(i=0; i<l_rBox.getSettingCount(); i++)
		{
			CString l_sName;
			CIdentifier l_oTypeIdentifier;
			CString l_sDefaultValue;
			CString l_sTypeName;
			l_rBox.getSettingName(i, l_sName);
			l_rBox.getSettingType(i, l_oTypeIdentifier);
			l_rBox.getSettingDefaultValue(i, l_sDefaultValue);
			l_sTypeName=m_rKernelContext.getTypeManager().getTypeName(l_oTypeIdentifier);

			l_oFileSkeleton
				<< " * \\subsection Doc_" << l_sFilename.c_str() << "_Setting_" << i+1 << " " << i+1 << ". " << l_sName.toASCIIString() << "\n"
				<< " * @Doc_" << l_sFilename.c_str() << "_Setting" << i+1 << "_Content@\n"
				<< " *\n"
// "\\ref Doc_Types_" << transform(l_sTypeName.toASCIIString()).c_str()
				<< " * - Type identifier : <em> " << l_sTypeName.toASCIIString() << " " << l_oTypeIdentifier.toString().toASCIIString() << "</em>\n"
				<< " *\n"
				<< " * - Default value : [ <em>" << l_sDefaultValue.toASCIIString() << "</em> ]\n"
				<< " *\n";

			l_oFilePart
				<< "\n"
				<< " * |OVP_DocBegin_" << l_sFilename.c_str() << "_Setting" << i+1 << "|\n"
				<< " * |OVP_DocEnd_" << l_sFilename.c_str() << "_Setting" << i+1 << "|\n";
		}
	}

	if(rPluginObjectDesc.hasFunctionality(PluginFunctionality_Visualization))
	{
		l_oFileSkeleton
			<< " * \\section Doc_" << l_sFilename.c_str() << "_OnlineVisualizationSettings Online visualisation settings\n"
			<< " *\n"
			<< " * @Doc_" << l_sFilename.c_str() << "_OnlineVisualizationSettings_Content@\n";

		l_oFilePart
			<< "__________________________________________________________________\n"
			<< "\n"
			<< "Online visualisation settings\n"
			<< "__________________________________________________________________\n"
			<< "\n"
			<< " * |OVP_DocBegin_" << l_sFilename.c_str() << "_OnlineVisualizationSettings|\n"
			<< " * |OVP_DocEnd_" << l_sFilename.c_str() << "_OnlineVisualizationSettings|\n";
	}

	l_oFileSkeleton
		<< " *\n"
		<< " * \\section Doc_" << l_sFilename.c_str() << "_Examples Examples\n"
		<< " * @Doc_" << l_sFilename.c_str() << "_Examples_Content@\n"
		<< " *\n"
		<< " *  \\section Doc_" << l_sFilename.c_str() << "_Miscellaneous Miscellaneous\n"
		<< " * @Doc_" << l_sFilename.c_str() << "_Miscellaneous_Content@\n"
		<< " */\n";

	l_oFilePart
		<< "__________________________________________________________________\n"
		<< "\n"
		<< "Examples description\n"
		<< "__________________________________________________________________\n"
		<< "\n"
		<< " * |OVP_DocBegin_" << l_sFilename.c_str() << "_Examples|\n"
		<< " * |OVP_DocEnd_" << l_sFilename.c_str() << "_Examples|\n"
		<< "__________________________________________________________________\n"
		<< "\n"
		<< "Miscellaneous description\n"
		<< "__________________________________________________________________\n"
		<< "\n"
		<< " * |OVP_DocBegin_" << l_sFilename.c_str() << "_Miscellaneous|\n"
		<< " * |OVP_DocEnd_" << l_sFilename.c_str() << "_Miscellaneous|\n"
		<< " */\n";

	l_oFileSkeleton.close();
	l_oFilePart.close();

	return true;
}