/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* This file is part of the libepubgen project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <numeric>
#include <sstream>
#include <librevenge/librevenge.h>
#include "libepubgen_utils.h"
#include "EPUBCSSSink.h"
#include "EPUBTableStyleManager.h"
namespace libepubgen
{
using librevenge::RVNGPropertyList;
using librevenge::RVNGPropertyListVector;
using librevenge::RVNGString;
void EPUBTableStyleManager::openTable(RVNGPropertyList const &propList)
{
const librevenge::RVNGPropertyListVector *columns = propList.child("librevenge:table-columns");
if (columns)
{
std::vector<double> colWidths;
std::vector<double> relColWidths;
for (unsigned long i = 0; i < columns->count(); i++)
{
RVNGPropertyList const &prop=(*columns)[i];
double width=0;
if (prop["style:column-width"])
{
librevenge::RVNGUnit unit=prop["style:column-width"]->getUnit();
if (unit==librevenge::RVNG_POINT)
width=prop["style:column-width"]->getDouble()/72.;
else if (unit==librevenge::RVNG_INCH)
width=prop["style:column-width"]->getDouble();
else if (unit==librevenge::RVNG_TWIP)
width=prop["style:column-width"]->getDouble()/1440.;
}
colWidths.push_back(width);
if (prop["style:rel-column-width"])
{
width = prop["style:rel-column-width"]->getDouble();
relColWidths.push_back(width);
}
}
m_columnWidthsStack.push_back(colWidths);
m_relColumnWidthsStack.push_back(relColWidths);
}
}
void EPUBTableStyleManager::closeTable()
{
if (!m_columnWidthsStack.size())
{
EPUBGEN_DEBUG_MSG(("EPUBTableStyleManager::closeTable: can not find the columns width\n"));
return;
}
m_columnWidthsStack.pop_back();
}
namespace
{
bool extractColumnsWidth(const std::vector< std::vector<double> > &columnWidthsStack, int col, int numSpanned, bool relative, double &w)
{
if (!columnWidthsStack.size())
return false;
std::vector<double> const &widths=columnWidthsStack.back();
double total = std::accumulate(widths.begin(), widths.end(), static_cast<double>(0));
if (col < 0 || size_t(col+numSpanned-1) >= widths.size())
{
if (!relative)
{
EPUBGEN_DEBUG_MSG(("EPUBTableStyleManager::getColumnsWidth: can not compute the columns width\n"));
}
return false;
}
bool fixed = true;
w = 0;
for (auto i=size_t(col); i < size_t(col+numSpanned); i++)
{
if (widths[i] < 0)
{
w += -widths[i];
fixed = false;
}
else if (widths[i] > 0)
w += widths[i];
else
{
w = 0;
return true;
}
}
if (!fixed) w = -w;
if (relative)
// Expected unit is percents.
w = w * 100 / total;
return true;
}
}
bool EPUBTableStyleManager::getColumnsWidth(int col, int numSpanned, double &w) const
{
return extractColumnsWidth(m_columnWidthsStack, col, numSpanned, false, w);
}
bool EPUBTableStyleManager::getRelColumnsWidth(int col, int numSpanned, double &w) const
{
return extractColumnsWidth(m_relColumnWidthsStack, col, numSpanned, true, w);
}
std::string EPUBTableStyleManager::getCellClass(RVNGPropertyList const &pList)
{
EPUBCSSProperties content;
extractCellProperties(pList, content);
ContentNameMap_t::const_iterator it=m_cellContentNameMap.find(content);
if (it != m_cellContentNameMap.end())
return it->second;
std::stringstream s;
s << "cellTable" << m_cellContentNameMap.size();
m_cellContentNameMap[content]=s.str();
return s.str();
}
std::string EPUBTableStyleManager::getCellStyle(RVNGPropertyList const &pList)
{
EPUBCSSProperties content;
extractCellProperties(pList, content);
std::stringstream s;
for (const auto &property : content)
s << property.first << ": " << property.second << "; ";
return s.str();
}
std::string EPUBTableStyleManager::getRowClass(RVNGPropertyList const &pList)
{
EPUBCSSProperties content;
extractRowProperties(pList, content);
ContentNameMap_t::const_iterator it=m_rowContentNameMap.find(content);
if (it != m_rowContentNameMap.end())
return it->second;
std::stringstream s;
s << "rowTable" << m_rowContentNameMap.size();
m_rowContentNameMap[content]=s.str();
return s.str();
}
std::string EPUBTableStyleManager::getRowStyle(RVNGPropertyList const &pList)
{
EPUBCSSProperties content;
extractRowProperties(pList, content);
std::stringstream s;
for (const auto &property : content)
s << property.first << ": " << property.second << "; ";
return s.str();
}
std::string EPUBTableStyleManager::getTableClass(RVNGPropertyList const &pList)
{
EPUBCSSProperties content;
extractTableProperties(pList, content);
ContentNameMap_t::const_iterator it=m_tableContentNameMap.find(content);
if (it != m_tableContentNameMap.end())
return it->second;
std::stringstream s;
s << "table" << m_tableContentNameMap.size();
m_tableContentNameMap[content]=s.str();
return s.str();
}
std::string EPUBTableStyleManager::getTableStyle(RVNGPropertyList const &pList)
{
EPUBCSSProperties content;
extractTableProperties(pList, content);
std::stringstream s;
for (const auto &property : content)
s << property.first << ": " << property.second << "; ";
return s.str();
}
void EPUBTableStyleManager::send(EPUBCSSSink &out)
{
for (ContentNameMap_t::const_iterator it=m_cellContentNameMap.begin(); m_cellContentNameMap.end() != it; ++it)
{
RVNGPropertyList props;
fillPropertyList(it->first, props);
out.insertRule(("." + it->second).c_str(), props);
}
for (ContentNameMap_t::const_iterator it=m_rowContentNameMap.begin(); m_rowContentNameMap.end() != it; ++it)
{
RVNGPropertyList props;
fillPropertyList(it->first, props);
out.insertRule(("." + it->second).c_str(), props);
}
for (ContentNameMap_t::const_iterator it=m_tableContentNameMap.begin(); m_tableContentNameMap.end() != it; ++it)
{
RVNGPropertyList props;
fillPropertyList(it->first, props);
out.insertRule(("." + it->second).c_str(), props);
}
}
void EPUBTableStyleManager::extractCellProperties(RVNGPropertyList const &pList, EPUBCSSProperties &cssProps) const
{
// try to get the cell width
if (pList["librevenge:column"])
{
int c=pList["librevenge:column"]->getInt();
int span=1;
if (pList["table:number-columns-spanned"])
span = pList["table:number-columns-spanned"]->getInt();
double w;
if (!getColumnsWidth(c,span,w))
{
EPUBGEN_DEBUG_MSG(("EPUBTableStyleManager::getCellContent: can not find columns witdth for %d[%d]\n", c, span));
}
else if (w > 0)
{
std::ostringstream width;
width << w << "in";
cssProps["width"] = width.str();
}
else if (w < 0)
{
std::ostringstream width;
width << -w << "in";
cssProps["min-width"] = width.str();
}
if (getRelColumnsWidth(c, span, w))
{
std::ostringstream width;
width << w << "%";
cssProps["width"] = width.str();
}
}
if (pList["fo:text-align"])
{
if (pList["fo:text-align"]->getStr() == RVNGString("end")) // stupid OOo convention..
cssProps["text-align"] = "right";
else
cssProps["text-align"] = pList["fo:text-align"]->getStr().cstr();
}
if (pList["style:vertical-align"])
cssProps["vertical-align"] = pList["style:vertical-align"]->getStr().cstr();
else
cssProps["vertical-align"] = "top";
if (pList["fo:background-color"])
cssProps["background-color"] = pList["fo:background-color"]->getStr().cstr();
static char const *(type[]) = {"border", "border-left", "border-top", "border-right", "border-bottom" };
for (auto &i : type)
{
std::string field("fo:");
field+=i;
if (!pList[field.c_str()])
continue;
cssProps[i] = pList[field.c_str()]->getStr().cstr();
}
}
void EPUBTableStyleManager::extractRowProperties(RVNGPropertyList const &pList, EPUBCSSProperties &cssProps) const
{
if (pList["style:min-row-height"])
cssProps["min-height"] = pList["style:min-row-height"]->getStr().cstr();
else if (pList["style:row-height"])
cssProps["height"] = pList["style:row-height"]->getStr().cstr();
}
void EPUBTableStyleManager::extractTableProperties(RVNGPropertyList const &pList, EPUBCSSProperties &cssProps) const
{
if (pList["style:rel-width"])
cssProps["width"] = pList["style:rel-width"]->getStr().cstr();
else if (pList["style:width"])
cssProps["width"] = pList["style:width"]->getStr().cstr();
}
}
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */