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.
koffice/filters/kword/abiword/ImportFormatting.cpp

422 lines
15 KiB

/* This file is part of the KDE project
Copyright (C) 2001, 2002, 2004 Nicolas GOUTTE <goutte@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <kdebug.h>
#include "ImportFormatting.h"
#include "ImportStyle.h"
StackItem::StackItem() : fontSize(0), /* No explicit font size */
pos(0), italic(false), bold(false), underline(false), strikeout(false),
textPosition(0)
{
}
StackItem::~StackItem()
{
}
void PopulateProperties(StackItem* stackItem, const TQString& strStyleProps,
const TQXmlAttributes& attributes, AbiPropsMap& abiPropsMap,
const bool allowInit)
// TODO: find a better name for this function
{
if (allowInit)
{
// Initialize the TQStrings with the previous values of the properties
// TODO: any others needed?
if (stackItem->italic)
{
abiPropsMap.setProperty("font-style","italic");
}
if (stackItem->bold)
{
abiPropsMap.setProperty("font-weight","bold");
}
if (stackItem->underline)
{
abiPropsMap.setProperty("text-decoration","underline");
}
else if (stackItem->strikeout)
{
abiPropsMap.setProperty("text-decoration","line-through");
}
}
// Style goes first
kdDebug(30506)<< "===== from style=\"" << strStyleProps << "\"" << endl;
abiPropsMap.splitAndAddAbiProps(strStyleProps);
// Treat the props attributes in the two available flavors: lower case and upper case.
kdDebug(30506)<< "========== props=\"" << attributes.value("props") << "\"" << endl;
abiPropsMap.splitAndAddAbiProps(attributes.value("props"));
abiPropsMap.splitAndAddAbiProps(attributes.value("PROPS")); // PROPS is deprecated
stackItem->italic=(abiPropsMap["font-style"].getValue()=="italic");
stackItem->bold=(abiPropsMap["font-weight"].getValue()=="bold");
TQString strDecoration=abiPropsMap["text-decoration"].getValue();
stackItem->underline=(strDecoration=="underline");
stackItem->strikeout=(strDecoration=="line-through");
TQString strTextPosition=abiPropsMap["text-position"].getValue();
if (strTextPosition=="subscript")
{
stackItem->textPosition=1;
}
else if (strTextPosition=="superscript")
{
stackItem->textPosition=2;
}
else if (!strTextPosition.isEmpty())
{
// we have any other new value, assume it means normal!
stackItem->textPosition=0;
}
TQString strColour=abiPropsMap["color"].getValue();
if (!strColour.isEmpty())
{
// The colour information is *not* lead by a hash (#)
stackItem->fgColor.setNamedColor("#"+strColour);
}
TQString strBackgroundTextColor=abiPropsMap["bgcolor"].getValue();
if (strBackgroundTextColor=="transparent")
{
// KWord has no idea what transparency is, so we use white
stackItem->bgColor.setRgb(255,255,255);
}
else if(!strBackgroundTextColor.isEmpty())
{
// The colour information is *not* lead by a hash (#)
stackItem->bgColor.setNamedColor("#"+strBackgroundTextColor);
}
TQString strFontSize=abiPropsMap["font-size"].getValue();
if (!strFontSize.isEmpty())
{
const int size=int(ValueWithLengthUnit(strFontSize));
if (size>0)
{
stackItem->fontSize=size;
}
}
TQString strFontFamily=abiPropsMap["font-family"].getValue();
if (!strFontFamily.isEmpty() && (strFontFamily!="(null)"))
{
// TODO: transform the font-family in a font that we have on the system on which KWord runs.
stackItem->fontName=strFontFamily;
}
}
void AddFormat(TQDomElement& formatElementOut, StackItem* stackItem, TQDomDocument& mainDocument)
{
TQDomElement element;
if (!stackItem->fontName.isEmpty())
{
element=mainDocument.createElement("FONT");
element.setAttribute("name",stackItem->fontName); // Font name
formatElementOut.appendChild(element); //Append to <FORMAT>
}
if (stackItem->fontSize>0)
{
element=mainDocument.createElement("SIZE");
element.setAttribute("value",stackItem->fontSize);
formatElementOut.appendChild(element); //Append to <FORMAT>
}
element=mainDocument.createElement("ITALIC");
element.setAttribute("value",stackItem->italic?1:0);
formatElementOut.appendChild(element); //Append to <FORMAT>
element=mainDocument.createElement("WEIGHT");
element.setAttribute("value",stackItem->bold?75:50);
formatElementOut.appendChild(element); //Append to <FORMAT>
element=mainDocument.createElement("UNDERLINE");
element.setAttribute("value",stackItem->underline?1:0);
formatElementOut.appendChild(element); //Append to <FORMAT>
element=mainDocument.createElement("STRIKEOUT");
element.setAttribute("value",stackItem->strikeout?1:0);
formatElementOut.appendChild(element); //Append to <FORMAT>
if ((stackItem->textPosition>=0) && (stackItem->textPosition<=2))
{
element=mainDocument.createElement("VERTALIGN");
element.setAttribute("value",stackItem->textPosition);
formatElementOut.appendChild(element); //Append to <FORMAT>
}
if (stackItem->fgColor.isValid())
{
element=mainDocument.createElement("COLOR");
element.setAttribute("red", stackItem->fgColor.red());
element.setAttribute("green",stackItem->fgColor.green());
element.setAttribute("blue", stackItem->fgColor.blue());
formatElementOut.appendChild(element); //Append to <FORMAT>
}
if (stackItem->bgColor.isValid())
{
element=mainDocument.createElement("TEXTBACKGROUNDCOLOR");
element.setAttribute("red", stackItem->bgColor.red());
element.setAttribute("green",stackItem->bgColor.green());
element.setAttribute("blue", stackItem->bgColor.blue());
formatElementOut.appendChild(element); //Append to <FORMAT>
}
}
void AddLayout(const TQString& strStyleName, TQDomElement& layoutElement,
StackItem* stackItem, TQDomDocument& mainDocument,
const AbiPropsMap& abiPropsMap, const int level, const bool isStyle)
{
TQDomElement element;
element=mainDocument.createElement("NAME");
element.setAttribute("value",strStyleName);
layoutElement.appendChild(element);
TQString strFollowing=abiPropsMap["followedby"].getValue();
TQDomElement followingElement=mainDocument.createElement("FOLLOWING");
followingElement.setAttribute("name",strFollowing);
if ((strFollowing.isEmpty())
|| (strFollowing=="Current Settings")) // "Current Settings" is only a pseudo-style!
{
// We have no idea what style follows
if (isStyle)
{
// We are a style, so we need a default
followingElement.setAttribute("name","Normal");
layoutElement.appendChild(followingElement);
}
// Else: we are a layout, so we leave the work to KWord (from the style)
}
else
{
// Following style is defined
// TODO: we should be sure that this style is defined!
layoutElement.appendChild(followingElement);
}
TQString strFlow=abiPropsMap["text-align"].getValue();
element=mainDocument.createElement("FLOW");
if ((strFlow=="left") || (strFlow=="center") || (strFlow=="right") || (strFlow=="justify"))
{
element.setAttribute("align",strFlow);
}
else
{
element.setAttribute("align","left");
}
layoutElement.appendChild(element);
int kwordDepth;
int kwordNumberingType;
int kwordType;
TQString kwordRightText;
// level is 1 based like AbiWord, any value lower than 1 means no level!
if ((level<=0) || (level>=15))
{
kwordDepth=0;
kwordNumberingType=2;
kwordType=0;
}
else
{
kwordDepth=level-1;
kwordNumberingType=1;
kwordType=1; // PROVISORY
kwordRightText=".";
}
element=mainDocument.createElement("COUNTER");
element.setAttribute("type",kwordType);
element.setAttribute("depth",kwordDepth);
element.setAttribute("start",1);
element.setAttribute("numberingtype",kwordNumberingType);
element.setAttribute("lefttext","");
element.setAttribute("righttext",kwordRightText);
element.setAttribute("bullet",64);
element.setAttribute("bulletfont","Symbol");
element.setAttribute("customdef","");
layoutElement.appendChild(element);
TQString strLeftMargin=abiPropsMap["margin-left"].getValue();
TQString strRightMargin=abiPropsMap["margin-right"].getValue();
TQString strTextIndent=abiPropsMap["text-indent"].getValue();
if ( !strLeftMargin.isEmpty()
|| !strRightMargin.isEmpty()
|| !strTextIndent.isEmpty() )
{
element=mainDocument.createElement("INDENTS");
if (!strLeftMargin.isEmpty())
element.setAttribute("left",ValueWithLengthUnit(strLeftMargin));
if (!strRightMargin.isEmpty())
element.setAttribute("right",ValueWithLengthUnit(strRightMargin));
if (!strTextIndent.isEmpty())
element.setAttribute("first",ValueWithLengthUnit(strTextIndent));
layoutElement.appendChild(element);
}
TQString strTopMargin=abiPropsMap["margin-top"].getValue();
TQString strBottomMargin=abiPropsMap["margin-bottom"].getValue();
if (!strTopMargin.isEmpty() || !strBottomMargin.isEmpty() )
{
element=mainDocument.createElement("OFFSETS");
const double margin_top=ValueWithLengthUnit(strTopMargin);
const double margin_bottom=ValueWithLengthUnit(strBottomMargin);
// Zero is propably a valid value!
if (!strBottomMargin.isEmpty())
element.setAttribute("after",margin_bottom);
if (!strTopMargin.isEmpty())
element.setAttribute("before",margin_top);
layoutElement.appendChild(element);
}
TQString strLineHeight=abiPropsMap["line-height"].getValue();
if(!strLineHeight.isEmpty())
{
element=mainDocument.createElement("LINESPACING");
double lineHeight;
// Do we have a unit symbol or not?
bool flag=false;
lineHeight=strLineHeight.toDouble(&flag);
if (flag)
{
if ( lineHeight == 1.0 )
{
element.setAttribute( "value", "single" );
element.setAttribute( "type", "single" );
}
else if (lineHeight==1.5)
{
element.setAttribute( "value", "oneandhalf" );
element.setAttribute( "type", "oneandhalf" );
}
else if (lineHeight==2.0)
{
element.setAttribute( "value", "double" );
element.setAttribute( "type", "double" );
}
else if ( lineHeight > 0.0 )
{
element.setAttribute( "type", "multiple" );
element.setAttribute( "spacingvalue", lineHeight );
}
else
{
kdWarning(30506) << "Unsupported line height " << lineHeight << " (Ignoring !)" << endl;
}
}
else
{
// Something went wrong, so we assume that an unit is specified
bool atleast = false;
lineHeight = ValueWithLengthUnit( strLineHeight, &atleast );
if (lineHeight>1.0)
{
if ( atleast )
{
kdDebug(30506) << "at-least" << endl;
element.setAttribute( "type", "atleast" );
}
else
{
element.setAttribute( "type", "exact" );
}
// We have a meaningful value, so use it!
//element.setAttribute( "value", lineHeight );
element.setAttribute( "spacingvalue", lineHeight );
}
}
layoutElement.appendChild(element);
}
TQString strTab=abiPropsMap["tabstops"].getValue();
if(!strTab.isEmpty())
{
TQStringList listTab=TQStringList::split(",",strTab);
for ( TQStringList::Iterator it = listTab.begin(); it != listTab.end(); ++it )
{
TQStringList tab=TQStringList::split("/",*it);
const TQChar tabType=tab[1].at(0);
const TQChar tabFilling=tab[1].at(1); // Might be empty in old AbiWord files
int type;
if (tabType=='L') // left
type=0;
else if (tabType=='C') // center
type=1;
else if (tabType=='R') // right
type=2;
else if(tabType=='D') // decimal
type=3;
else if(tabType=='B') // bar (unsupported by KWord)
type=0;
else
{
kdWarning(30506)<<"Unknown tabulator type: " << TQString(tabType) << endl;
type=0;
}
int filling;
int width=72; // Any non-null value
if (tabFilling.isNull() || tabFilling=='0') // No filling
filling=0;
else if (tabFilling=='1') // dot
{
filling=1;
width=2; // TODO: which width?
}
else if (tabFilling=='3') // underline
filling=2;
else
filling=0;
element=mainDocument.createElement("TABULATOR");
element.setAttribute("ptpos",ValueWithLengthUnit(tab[0]));
element.setAttribute("type",type);
element.setAttribute("filling",filling);
element.setAttribute("width",width);
layoutElement.appendChild(element);
}
}
TQDomElement formatElementOut=mainDocument.createElement("FORMAT");
layoutElement.appendChild(formatElementOut);
AddFormat(formatElementOut, stackItem, mainDocument);
}
void AddStyle(TQDomElement& styleElement, const TQString& strStyleName,
const StyleData& styleData, TQDomDocument& mainDocument)
{
// NOTE; styleElement is <STYLE> (singular), not <STYLES> (plural)
StackItem stackItem;
TQXmlAttributes attributes; // This is just a dummy for reusing already existing functions (TODO)
AbiPropsMap abiPropsMap;
PopulateProperties(&stackItem, styleData.m_props, attributes, abiPropsMap, false);
AddLayout(strStyleName, styleElement, &stackItem, mainDocument, abiPropsMap, styleData.m_level, true);
}