You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
krecipes/krecipes/src/exporters/kreexporter.cpp

265 lines
8.8 KiB

/***************************************************************************
* Copyright (C) 2003 by *
* Cyril Bosselut (bosselut@b1project.com) *
* *
* Copyright (C) 2003-2005 by *
* Jason Kivlighn (jkivlighn@gmail.com) *
* *
* 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. *
***************************************************************************/
#include "kreexporter.h"
#include <ntqfile.h>
#include <ntqstylesheet.h>
#include <ntqbuffer.h>
#include <ntqimage.h>
#include <kdebug.h>
#include <tdelocale.h>
#include <kmdcodec.h>
#include <tdeglobal.h>
#include <kstandarddirs.h>
#include "backends/recipedb.h"
KreExporter::KreExporter( CategoryTree *_categories, const TQString& filename, const TQString &format ) :
BaseExporter( filename, format ), categories( _categories )
{
if ( format == "*.kre" ) {
setCompressed(true);
}
}
KreExporter::~KreExporter()
{
delete categories;
}
int KreExporter::supportedItems() const
{
return RecipeDB::All;
}
int KreExporter::headerFlags() const
{
return RecipeDB::Categories;
}
TQString KreExporter::createHeader( const RecipeList& recipes )
{
TQString xml;
xml += "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
xml += "<krecipes version=\"" + krecipes_version() + "\" lang=\"" + ( TDEGlobal::locale() )->language() + "\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"krecipes.xsd\">\n";
createCategoryStructure( xml, recipes );
return xml;
}
TQString KreExporter::createFooter()
{
return "</krecipes>\n";
}
TQString KreExporter::generateIngredient( const IngredientData &ing )
{
TQString xml;
xml += "<name>" + TQStyleSheet::escape( ( ing ).name ) + "</name>\n";
xml += "<amount>";
if ( ing.amount_offset < 1e-10 ) {
xml += TQString::number( ing.amount );
}
else {
xml += "<min>"+TQString::number( ing.amount )+"</min>";
xml += "<max>"+TQString::number( ing.amount + ing.amount_offset )+"</max>";
}
xml += "</amount>\n";
TQString unit_str = ( ing.amount+ing.amount_offset > 1 ) ? ing.units.plural : ing.units.name;
xml += "<unit>" + TQStyleSheet::escape( unit_str ) + "</unit>\n";
if ( ing.prepMethodList.count() > 0 )
xml += "<prep>" + TQStyleSheet::escape( ing.prepMethodList.join(",") ) + "</prep>\n";
return xml;
}
//TODO: use TQDOM (see recipemlexporter.cpp)?
TQString KreExporter::createContent( const RecipeList& recipes )
{
TQString xml;
RecipeList::const_iterator recipe_it;
for ( recipe_it = recipes.begin(); recipe_it != recipes.end(); ++recipe_it ) {
xml += "<krecipes-recipe>\n";
xml += "<krecipes-description>\n";
xml += "<title>" + TQStyleSheet::escape( ( *recipe_it ).title ) + "</title>\n";
for ( ElementList::const_iterator author_it = ( *recipe_it ).authorList.begin(); author_it != ( *recipe_it ).authorList.end(); ++author_it )
xml += "<author>" + TQStyleSheet::escape( ( *author_it ).name ) + "</author>\n";
xml += "<pictures>\n";
if ( !( *recipe_it ).photo.isNull() ) {
xml += "<pic format=\"JPEG\" id=\"1\"><![CDATA["; //fixed id until we implement multiple photos ability
TQByteArray data;
TQBuffer buffer( data );
buffer.open( IO_WriteOnly );
TQImageIO iio( &buffer, "JPEG" );
iio.setImage( ( *recipe_it ).photo.convertToImage() );
iio.write();
xml += KCodecs::base64Encode( data, true );
xml += "]]></pic>\n";
}
xml += "</pictures>\n";
xml += "<category>\n";
for ( ElementList::const_iterator cat_it = ( *recipe_it ).categoryList.begin(); cat_it != ( *recipe_it ).categoryList.end(); ++cat_it )
xml += "<cat>" + TQStyleSheet::escape( ( *cat_it ).name ) + "</cat>\n";
xml += "</category>\n";
xml += "<yield>";
xml += "<amount>";
if ( ( *recipe_it ).yield.amount_offset < 1e-10 ) {
xml += TQString::number( ( *recipe_it ).yield.amount );
}
else {
xml += "<min>"+TQString::number( ( *recipe_it ).yield.amount )+"</min>";
xml += "<max>"+TQString::number( ( *recipe_it ).yield.amount + ( *recipe_it ).yield.amount_offset )+"</max>";
}
xml += "</amount>";
xml += "<type>"+( *recipe_it ).yield.type+"</type>";
xml += "</yield>\n";
xml += "<preparation-time>";
xml += ( *recipe_it ).prepTime.toString( "hh:mm" );
xml += "</preparation-time>\n";
xml += "</krecipes-description>\n";
xml += "<krecipes-ingredients>\n";
IngredientList list_copy = ( *recipe_it ).ingList;
for ( IngredientList group_list = list_copy.firstGroup(); group_list.count() != 0; group_list = list_copy.nextGroup() ) {
TQString group = group_list[ 0 ].group; //just use the first's name... they're all the same
if ( !group.isEmpty() )
xml += "<ingredient-group name=\"" + TQStyleSheet::escape(group) + "\">\n";
for ( IngredientList::const_iterator ing_it = group_list.begin(); ing_it != group_list.end(); ++ing_it ) {
xml += "<ingredient>\n";
xml += generateIngredient(*ing_it);
if ( (*ing_it).substitutes.count() > 0 ) {
xml += "<substitutes>\n";
for ( TQValueList<IngredientData>::const_iterator sub_it = (*ing_it).substitutes.begin(); sub_it != (*ing_it).substitutes.end(); ++sub_it ) {
xml += "<ingredient>\n";
xml += generateIngredient(*sub_it);
xml += "</ingredient>\n";
}
xml += "</substitutes>\n";
}
xml += "</ingredient>\n";
}
if ( !group.isEmpty() )
xml += "</ingredient-group>\n";
}
/// @todo add ingredient properties
xml += "</krecipes-ingredients>\n";
xml += "<krecipes-instructions>\n";
xml += TQStyleSheet::escape( ( *recipe_it ).instructions );
xml += "</krecipes-instructions>\n";
//ratings
xml += "<krecipes-ratings>";
for ( RatingList::const_iterator rating_it = (*recipe_it).ratingList.begin(); rating_it != (*recipe_it).ratingList.end(); ++rating_it ) {
xml += "<rating>";
xml += "<comment>"+TQStyleSheet::escape( ( *rating_it ).comment )+"</comment>";
xml += "<rater>"+TQStyleSheet::escape( ( *rating_it ).rater )+"</rater>";
xml += "<criterion>";
for ( RatingCriteriaList::const_iterator rc_it = (*rating_it).ratingCriteriaList.begin(); rc_it != (*rating_it).ratingCriteriaList.end(); ++rc_it ) {
xml += "<criteria>";
xml += "<name>"+(*rc_it).name+"</name>";
xml += "<stars>"+TQString::number((*rc_it).stars)+"</stars>";
xml += "</criteria>";
}
xml += "</criterion>";
xml += "</rating>";
}
xml += "</krecipes-ratings>";
xml += "</krecipes-recipe>\n";
}
return xml;
}
void KreExporter::createCategoryStructure( TQString &xml, const RecipeList &recipes )
{
TQValueList<int> categoriesUsed;
for ( RecipeList::const_iterator recipe_it = recipes.begin(); recipe_it != recipes.end(); ++recipe_it ) {
for ( ElementList::const_iterator cat_it = ( *recipe_it ).categoryList.begin(); cat_it != ( *recipe_it ).categoryList.end(); ++cat_it ) {
if ( categoriesUsed.find( ( *cat_it ).id ) == categoriesUsed.end() )
categoriesUsed << ( *cat_it ).id;
}
}
if ( !categoriesUsed.empty() ) {
//only keep the relevant category structure
removeIfUnused( categoriesUsed, categories );
xml += "<krecipes-category-structure>\n";
writeCategoryStructure( xml, categories );
xml += "</krecipes-category-structure>\n";
}
}
bool KreExporter::removeIfUnused( const TQValueList<int> &cat_ids, CategoryTree *parent, bool parent_should_show )
{
for ( CategoryTree * it = parent->firstChild(); it; it = it->nextSibling() ) {
if ( cat_ids.find( it->category.id ) != cat_ids.end() ) {
parent_should_show = true;
removeIfUnused( cat_ids, it, true ); //still recurse, but doesn't affect 'parent'
}
else {
bool result = removeIfUnused( cat_ids, it );
if ( parent_should_show == false )
parent_should_show = result;
}
}
if ( !parent_should_show && parent->category.id != -1 ) {
//FIXME: CategoryTree is broken when deleting items
//delete parent;
parent->category.id = -2; //temporary workaround
}
return parent_should_show;
}
void KreExporter::writeCategoryStructure( TQString &xml, const CategoryTree *categoryTree )
{
if ( categoryTree->category.id != -2 ) {
if ( categoryTree->category.id != -1 )
xml += "<category name=\"" + TQStyleSheet::escape( categoryTree->category.name ).replace("\"","&quot;") + "\">\n";
for ( CategoryTree * child_it = categoryTree->firstChild(); child_it; child_it = child_it->nextSibling() ) {
writeCategoryStructure( xml, child_it );
}
if ( categoryTree->category.id != -1 )
xml += "</category>\n";
}
}