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/latex/export/para.cc

681 lines
18 KiB

/*
** A program to convert the XML rendered by KWord into LATEX.
**
** Copyright (C) 2000, 2001, 2002 Robert JACOLIN
**
** 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.
**
** To receive a copy of the GNU Library General Public License, write to the
** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
**
*/
#include <stdlib.h> /* for atoi function */
#include <kdebug.h> /* for kdDebug() stream */
#include "para.h"
#include "textFrame.h" /* father class. */
#include "format.h" /* children classes. */
//#include "picturezone.h"
#include "fileheader.h"
#include "textzone.h"
#include "variablezone.h"
#include "footnote.h"
#include "anchor.h"
/* static data */
TQPtrStack<EType> Para::_historicList;
int Para::_tabulation = 0;
/*******************************************/
/* Constructor */
/*******************************************/
Para::Para(TextFrame* textFrame)
{
_element = textFrame;
_lines = 0;
_name = 0;
_info = EP_NONE; /* the parag is not a footnote */
//_hardbrk = EP_FLOW; /* and it's not a new page */
_currentPos = 0; /* At the beginning of the paragraph */
_tabulation = 0;
_text = "";
}
/*******************************************/
/* Destructor */
/*******************************************/
Para::~Para()
{
kdDebug(30522) << "Destruction of a parag." << endl;
if(_lines != 0)
delete _lines;
}
/*******************************************/
/* GetFrameType */
/*******************************************/
/* To know if it's the text or it's a */
/* header or a footer. */
/*******************************************/
SSect Para::getFrameType() const
{
return _element->getSection();
}
/*******************************************/
/* getTypeFormat */
/*******************************************/
/* To know if the zone is a textzone, a */
/* footnote, a picture, a variable. */
/*******************************************/
EFormat Para::getTypeFormat(const TQDomNode balise) const
{
//<FORMAT id="1" ...>
return (EFormat) getAttr(balise, "id").toInt();
}
/*******************************************/
/* getNbCharPara */
/*******************************************/
/* To know the size of a paragraph. */
/*******************************************/
int Para::getNbCharPara() const
{
int nb = 0;
Format* zone = 0;
if(_lines != 0)
{
kdDebug(30522) << " NB ZONE : " << _lines->count() << endl;
for(zone = _lines->first(); zone != 0; zone = _lines->next())
{
switch(zone->getId())
{
case EF_TEXTZONE:
nb = nb + ((TextZone*) zone)->getSize();
break;
case EF_PICTURE:
break;
case EF_TABULATOR:
break;
case EF_VARIABLE:
break;
case EF_FOOTNOTE:
break;
case EF_ANCHOR:
break;
case EF_ERROR:
break;
}
}
}
return nb;
}
/*******************************************/
/* Analyse */
/*******************************************/
void Para::analyse(const TQDomNode balise)
{
/* MARKUP TYPE : PARAGRAPH */
kdDebug(30522) << "**** PARAGRAPH ****" << endl;
/* Analyse of the children markups */
for(int index = 0; index < getNbChild(balise); index++)
{
if(getChildName(balise, index).compare("TEXT")== 0)
{
_text = getData(balise, index);
kdDebug(30522) << "TEXT : " << _text << endl;
}
else if(getChildName(balise, index).compare("NAME")== 0)
{
analyseName(getChild(balise, index));
}
else if(getChildName(balise, index).compare("INFO")== 0)
{
analyseInfo(getChild(balise, index));
}
/*else if(getChildName(balise, index).compare("HARDBRK")== 0)
{
analyseBrk(getChild(balise, index));
}*/
else if(getChildName(balise, index).compare("FORMATS")== 0)
{
// IMPORTANT ==> police + style
kdDebug(30522) << "FORMATS" << endl;
analyseFormats(getChild(balise, index));
}
else if(getChildName(balise, index).compare("LAYOUT")== 0)
{
kdDebug(30522) << "LAYOUT" << endl;
analyseLayoutPara(getChild(balise, index));
}
}
kdDebug(30522) << " **** END PARAGRAPH ****" << endl;
}
/*******************************************/
/* AnalyseName */
/*******************************************/
/* If a footnote have a name : it's a */
/* footnote/endnote. */
/*******************************************/
void Para::analyseName(const TQDomNode balise)
{
/* <NAME name="Footnote/Endnote_1"> */
_name = new TQString(getAttr(balise, "NAME"));
}
/*******************************************/
/* AnalyseInfo */
/*******************************************/
/* Type of the parag. : if info is 1, it's */
/* a footnote/endnote (so it have a name). */
/*******************************************/
void Para::analyseInfo(const TQDomNode balise)
{
/* <INFO info="1"> */
_info = (EP_INFO) getAttr(balise, "INFO").toInt();
}
/*******************************************/
/* AnalyseBrk */
/*******************************************/
/* There is a new page before this */
/* paragraph. */
/*******************************************/
/*void Para::analyseBrk(const TQDomNode balise)
{
//<NAME name="Footnote/Endnote_1">
_hardbrk = (EP_HARDBRK) getAttr(balise, "FRAME").toInt();
}*/
/*******************************************/
/* AnalyseLayoutPara */
/*******************************************/
/* Analyse the layout of a para. */
/* For each format, keep the type (picture,*/
/* text, variable, footnote) and put the */
/* zone in a list. */
/*******************************************/
void Para::analyseLayoutPara(const TQDomNode balise)
{
Format* zone = 0;
analyseLayout(balise);
for(int index= 0; index < getNbChild(balise); index++)
{
if(getChildName(balise, index).compare("FORMAT")== 0)
{
//analyseFormat(balise);
/* No more format : verify if all the text zone has been formated */
if(_currentPos != _text.length())
{
zone = new TextZone(_text, this);
((TextZone*) zone)->setPos(_currentPos);
((TextZone*) zone)->setLength(_currentPos - _text.length());
((TextZone*) zone)->analyse();
if(_lines == 0)
_lines = new TQPtrList<Format>;
/* add the text */
_lines->append(zone);
_currentPos = _currentPos + ((TextZone*) zone)->getLength();
}
}
/*else
kdDebug(30522) << " FORMAT FIELD UNKNOWN" << endl;*/
}
}
/*******************************************/
/* AnalyseFormats */
/*******************************************/
/* Analyse several formats. */
/* keep the type (picture, text, variable,*/
/* footnote) and put the zone in a list. */
/*******************************************/
void Para::analyseFormats(const TQDomNode balise)
{
for(int index= 0; index < getNbChild(balise, "FORMAT"); index++)
{
if(getChildName(balise, index).compare("FORMAT")== 0)
{
kdDebug(30522) << "A FORMAT !!!" << endl;
analyseFormat(getChild(balise, index));
}
else
kdDebug(30522) << " FORMAT UNUSEFULL HERE" << endl;
}
}
/*******************************************/
/* AnalyseFormat */
/*******************************************/
/* Analyse one format. */
/* keep the type (picture, text, variable,*/
/* footnote) and put the zone in a list. */
/*******************************************/
void Para::analyseFormat(const TQDomNode balise)
{
Format *zone = 0;
Format *zoneFirst = 0;
kdDebug(30522) << "ANALYSE FORMAT BODY" << endl;
switch(getTypeFormat(balise))
{
case EF_ERROR: kdDebug(30522) << "Id format error" << endl;
break;
case EF_TEXTZONE: /* It's a text line (1) */
zone = new TextZone(_text, this);
if(_currentPos != _text.length())
{
zone->analyse(balise);
if(zone->getPos() != _currentPos)
{
if(_lines == 0)
_lines = new TQPtrList<Format>;
/* Create first a default format */
zoneFirst = new TextZone(_text, this);
zoneFirst->setPos(_currentPos);
zoneFirst->setLength(zone->getPos() - _currentPos);
((TextZone*) zoneFirst)->analyse();
/* Add the text without format */
_lines->append(zoneFirst);
_currentPos = _currentPos + ((TextZone*) zoneFirst)->getLength();
}
}
break;
case EF_PICTURE: /* It's a picture (2) */
/*zone = new PictureZone(this);
zone->analyse(balise);*/
break;
case EF_VARIABLE: /* It's a variable (4) */
zone = new VariableZone(this);
zone->analyse(balise);
break;
case EF_FOOTNOTE: /* It's a footnote (5) */
zone = new Footnote(this);
zone->analyse(balise);
break;
case EF_ANCHOR: /* It's an anchor (6) */
zone = new Anchor(this);
zone->analyse(balise);
break;
default: /* Unknown */
kdDebug(30522) << "Format not yet supported" << endl;
}
if(zone->getPos() != _currentPos)
{
if(_lines == 0)
_lines = new TQPtrList<Format>;
/* Create first a default format */
zoneFirst = new TextZone(_text, this);
zoneFirst->setPos(_currentPos);
zoneFirst->setLength(zone->getPos() - _currentPos);
((TextZone*) zoneFirst)->analyse();
kdDebug(30522) << "pos courante : " << _currentPos << endl;
/* Add the text without format */
_lines->append(zoneFirst);
_currentPos = _currentPos + zoneFirst->getLength();
}
if(zone != 0)
{
if(_lines == 0)
_lines = new TQPtrList<Format>;
/* add the text */
_lines->append(zone);
_currentPos = _currentPos + zone->getLength();
}
}
/*******************************************/
/* Generate */
/*******************************************/
/* Generate each text zone with the parag. */
/* markup. */
/*******************************************/
void Para::generate(TQTextStream &out)
{
kdDebug(30522) << " GENERATION PARA" << endl;
if(getInfo() != EP_FOOTNOTE && getFrameType() != SS_HEADERS &&
getFrameType() != SS_FOOTERS)
{
/* We generate center, itemize tag and new page only for
* parag not for footnote
* If a parag. have a special format (begining)
*/
if(isHardBreak())
out << "\\newpage" << endl;
generateDebut(out);
}
/* If text is a \n, then it's a break line. */
if(_text == "\n")
out << "\\\\" << endl;
else if(_lines != 0)
{
Format* zone = 0;
kdDebug(30522) << " NB ZONE : " << _lines->count() << endl;
for(zone = _lines->first(); zone != 0; zone = _lines->next())
{
zone->generate(out);
}
/* To separate the text zones. */
}
if(getInfo() != EP_FOOTNOTE && getFrameType() != SS_HEADERS &&
getFrameType() != SS_FOOTERS)
{
/* id than above : a parag. have a special format. (end)
* only it's not a header, nor a footer nor a footnote/endnote
*/
generateFin(out);
if(isHardBreakAfter())
out << "\\newpage" << endl;
}
kdDebug(30522) << "PARA GENERATED" << endl;
}
/*******************************************/
/* GenerateDebut */
/*******************************************/
/* Generate the begining paragraph markup. */
/*******************************************/
void Para::generateDebut(TQTextStream &out)
{
/* Be careful we are in a table !
* You can't use directly environment, ...
*/
if(getFrameType() == SS_TABLE)
{
//int sizeCell = 5;
/* first number depends with the cell size (next number}
* and with the number of characters in the para.
* It can be 20 char. / 5 cm = 4 char / cm so */
/* nbLines = nb_char_para / (4 * cell size) + 1 */
//sizeCell = (_element->getRight() - _element->getLeft()) / 27;
//kdDebug(30522) << "SIZE OF CELL : " << sizeCell << endl;
// TODO : arrondir au superieur avec tgmath.h ??
//_nbLines = ((_element->getBottom() - _element->getTop()) / 27) + 1;
//kdDebug(30522) << "NB OF LINES : " << _nbLines << endl;
/* 2 at least, 1 for the line, 1 for the space line */
/*if(_nbLines < 2)
_nbLines = 2;
out << "\\multirow{" << _nbLines << "}{"<< sizeCell << "cm}{" << endl;*/
}
/* if it's a chapter */
if(isChapter())
{
/* switch the type, the depth do */
generateTitle(out);
Config::instance()->indent();
}
else if(isEnum())
{
Config::instance()->writeIndent(out);
out << "\\item ";
}
else
Config::instance()->writeIndent(out);
}
void Para::generateBeginEnv(TQTextStream &out)
{
kdDebug(30522) << "Begin new Env : " << getEnv() << endl;
Config::instance()->writeIndent(out);
switch(getEnv())
{
case ENV_LEFT: out << "\\begin{flushleft}" << endl;
break;
case ENV_RIGHT: out << "\\begin{flushright}" << endl;
break;
case ENV_CENTER: out << "\\begin{center}" << endl;
break;
case ENV_JUSTIFY: out << endl;
break;
case ENV_NONE:
break;
}
Config::instance()->indent();
}
/*******************************************/
/* openList */
/*******************************************/
/* Generate the markup to begin a list and */
/* push the type in the historic stack. */
/*******************************************/
void Para::openList(TQTextStream &out)
{
EType *type_temp = 0;
Config::instance()->writeIndent(out);
switch(getCounterType())
{
case TL_NONE:
break;
case TL_ARABIC:
out << "\\begin{enumerate}" << endl;
break;
case TL_LLETTER: /* a, b, ... */
out << "\\begin{enumerate}[a]" << endl;
break;
case TL_CLETTER: /* A, B, ... */
out << "\\begin{enumerate}[A]" << endl;
break;
case TL_LLNUMBER: /* i, ii, ... */
out << "\\begin{enumerate}[i]" << endl;
break;
case TL_CLNUMBER: /* I, II, ... */
out << "\\begin{enumerate}[I]" << endl;
break;
case TL_CUSTOM_SIMPLE: /* - */
out << "\\begin{enumerate}[" << convertSpecialChar(getCounterBullet()) << "]" << endl;
break;
case TL_CUSTOM_COMPLEX: /* - */
out << "\\begin{enumerate}[" << convertSpecialChar(getCounterBullet()) << "]" << endl;
break;
case TL_CIRCLE_BULLET:
out << "\\begin{itemize}" << endl;
break;
case TL_SQUARE_BULLET:
out << "\\begin{itemize}" << endl;
break;
case TL_DISC_BULLET:
out << "\\begin{itemize}" << endl;
break;
default:
out << "\\begin{itemize}[SPECIAL]" << endl;
}
Config::instance()->indent();
/* Keep the list type */
type_temp = new EType(getCounterType());
kdDebug(30522) << " type list to open : " << *type_temp << endl;
_historicList.push(type_temp);
}
/*******************************************/
/* GenerateFin */
/*******************************************/
/* Generate the closing paragraph markup. */
/*******************************************/
void Para::generateFin(TQTextStream &out)
{
/* Close a title of chapter */
if(isChapter())
out << "}";
}
/*******************************************/
/* GenerateEndEnv */
/*******************************************/
/* Generate the closing environment markup.*/
/*******************************************/
void Para::generateEndEnv(TQTextStream &out)
{
kdDebug(30522) << "end of an environment : " << getEnv() << endl;
Config::instance()->desindent();
switch(getEnv())
{
case ENV_LEFT:
out << endl;
Config::instance()->writeIndent(out);
out << "\\end{flushleft}";
break;
case ENV_RIGHT:
out << endl;
Config::instance()->writeIndent(out);
out << "\\end{flushright}";
break;
case ENV_CENTER:
out << endl;
Config::instance()->writeIndent(out);
out << "\\end{center}";
break;
case ENV_JUSTIFY:
break;
case ENV_NONE:
break;
}
Config::instance()->desindent();
}
/*******************************************/
/* closeList */
/*******************************************/
/* Generate the closing list markup for a */
/* list type (letter, custom, ...) and */
/* remove the last list saved. */
/*******************************************/
void Para::closeList(TQTextStream &out, Para* next)
{
closeList(getCounterType(), out);
if(((getCounterDepth() - 1) >= 0) && ((next!= 0 && !next->isEnum()) || next == 0))
{
/* We must close all the lists since
* after this paragraph it's a normal paragraph.
*/
kdDebug(30522) << "lists to close" << endl;
while(!_historicList.isEmpty())
{
EType *type_temp = 0;
type_temp = _historicList.pop();
if(type_temp != 0)
closeList(*type_temp, out);
}
}
}
/*******************************************/
/* closeList */
/*******************************************/
/* Generate the closing list markup for a */
/* list type (letter, custom, ...) and */
/* remove the last list saved. */
/*******************************************/
void Para::closeList(EType type, TQTextStream &out)
{
//out << endl;
kdDebug(30522) << " type list to close : " << type << endl;
/* Because of a new markup, we need a new line. */
out << endl;
Config::instance()->desindent();
Config::instance()->writeIndent(out);
/* but the next parag is not a same list */
switch(type)
{
case TL_NONE: //out << endl;
break;
case TL_ARABIC:
case TL_LLETTER: /* a, b, ... */
case TL_CLETTER: /* A, B, ... P. 250*/
case TL_LLNUMBER: /* i, ii, ... */
case TL_CLNUMBER: /* I, II, ... */
case TL_CUSTOM_SIMPLE: /* - */
case TL_CUSTOM_COMPLEX: /* - */
out << "\\end{enumerate}" << endl;
break;
case TL_CIRCLE_BULLET:
out << "\\end{itemize}" << endl;
break;
case TL_SQUARE_BULLET:
case TL_DISC_BULLET:
out << "\\end{itemize}" << endl;
break;
default:
out << "no suported" << endl;
}
Config::instance()->writeIndent(out);
/* Pop the list which has been closed */
_historicList.remove();
kdDebug(30522) << "removed" << endl;
}
/*******************************************/
/* GenerateTitle */
/*******************************************/
void Para::generateTitle(TQTextStream &out)
{
switch(getCounterDepth())
{
case 0:
out << "\\section{";
break;
case 1:
out << "\\subsection{";
break;
case 2:
out << "\\subsubsection{";
break;
case 3:
out << "\\paragraph{";
break;
case 4:
out << "\\subparagraph{";
break;
case 5:
out << "% section too deep" << endl;
out << "\\textbf{";
}
}