/*
* PDFedit - free program for PDF document manipulation.
* Copyright (C) 2006, 2007 PDFedit team: Michal Hocko,
* Miroslav Jahoda,
* Jozef Misutka,
* Martin Petricek
*
* Project is hosted on http://sourceforge.net/projects/pdfedit
*/
/** @file
QObject wrapper around CPage (Page in document)
Export some functions to scripting.
See doc/user/scripting.xml or kernel documentation for more informations about these functions
@author Martin Petricek
*/
#include "qspage.h"
#include "qtcompat.h"
#include "qsdict.h"
#include QLIST
#include "qscontentstream.h"
#include "qsannotation.h"
#include "qspdfoperatorstack.h"
#include "util.h"
#include
namespace gui {
using namespace std;
using namespace util;
/** List of fonts returned ftom CPage::getFontIdsAndNames */
typedef vector > FontList;
/**
Construct wrapper with given CPage
@param _page CPage shared pointer
@param _base scripting base
*/
QSPage::QSPage(boost::shared_ptr _page,BaseCore *_base) : QSCObject ("Page",_base) {
obj=_page;
numStreams=-1;
}
/**
Copy constructor
@param source Source page to copy
*/
QSPage::QSPage(const QSPage &source) : QSCObject ("Page",source.base) {
obj=source.obj;
numStreams=-1;
}
/** destructor */
QSPage::~QSPage() {
}
/** Call CPage::getDictionary */
QSDict* QSPage::getDictionary() {
return new QSDict(obj->getDictionary(),base);
}
/**
\see CPage::moveAbove
@param cs Content stream to move one level up painting order
*/
void QSPage::moveAbove(QSContentStream* cs) {
try {
obj->moveAbove(cs->get());
} catch (CObjInvalidOperation &e) {
base->errorException("Page","moveAbove",tr("Invalid operation"));
} catch (ReadOnlyDocumentException &e) {
base->errorException("Page","moveAbove",QObject::tr("Document is read-only"));
} catch (OutOfRange &e) {
base->errorException("Page","moveAbove",tr("Out of range"));
} catch(...) {
base->errorException("Page","moveAbove",tr("Unknown exception"));
}
}
/**
\see CPage::moveBelow
@param cs Content stream to move one level below in painting order
*/
void QSPage::moveBelow(QSContentStream* cs) {
try {
obj->moveBelow(cs->get());
} catch (CObjInvalidOperation &e) {
base->errorException("Page","moveBelow",tr("Invalid operation"));
} catch (ReadOnlyDocumentException &e) {
base->errorException("Page","moveBelow",QObject::tr("Document is read-only"));
} catch (OutOfRange &e) {
base->errorException("Page","moveBelow",tr("Out of range"));
} catch(...) {
base->errorException("Page","moveBelow",tr("Unknown exception"));
}
}
/**
\see CPage::moveAbove
@param cs Content stream to move one level up painting order
*/
void QSPage::moveAbove(QObject* cs) {
QSContentStream *qsc=qobject_cast(cs,"moveAbove",1,"ContentStream");
if (!qsc) return;//Something invalid passed
moveAbove(qsc);
}
/**
\see CPage::moveBelow
@param cs Content stream to move one level up painting order
*/
void QSPage::moveBelow(QObject* cs) {
QSContentStream *qsc=qobject_cast(cs,"moveBelow",1,"ContentStream");
if (!qsc) return;//Something invalid passed
moveBelow(qsc);
}
/**
\see CPage::moveAbove
@param csi Index of content stream to move one level up painting order
*/
void QSPage::moveAbove(int csi) {
try {
obj->moveAbove(csi);
} catch (CObjInvalidOperation &e) {
base->errorException("Page","moveAbove",tr("Invalid operation"));
} catch (ReadOnlyDocumentException &e) {
base->errorException("Page","moveAbove",QObject::tr("Document is read-only"));
} catch (OutOfRange &e) {
base->errorException("Page","moveAbove",tr("Out of range"));
} catch(...) {
base->errorException("Page","moveAbove",tr("Unknown exception"));
}
}
/**
\see CPage::moveBelow
@param csi Index of content stream to move one level below in painting order
*/
void QSPage::moveBelow(int csi) {
try {
obj->moveBelow(csi);
} catch (CObjInvalidOperation &e) {
base->errorException("Page","moveBelow",tr("Invalid operation"));
} catch (ReadOnlyDocumentException &e) {
base->errorException("Page","moveBelow",QObject::tr("Document is read-only"));
} catch (OutOfRange &e) {
base->errorException("Page","moveBelow",tr("Out of range"));
} catch(...) {
base->errorException("Page","moveBelow",tr("Unknown exception"));
}
}
/**
Set transform matrix of this page
\see CPage::setTransformMatrix
@param tMatrix Array with 6 integers
*/
void QSPage::setTransformMatrix(QVariant tMatrix) {
double tm[6]={0};
Q_List list=tMatrix.toList();
Q_List::Iterator it = list.begin();
int i=0;
while(it!=list.end()) {
if (i>=6) break;//We filled all 6 values
tm[i]=(*it).toDouble();
++it;
++i;
}
try {
obj->setTransformMatrix(tm);
} catch (ReadOnlyDocumentException &e) {
base->errorException("Page","setTransformMatrix",QObject::tr("Document is read-only"));
}
}
/**
Add content stream to page, created from new operator stack
Content stream is prepended before other content streams
\see CPage::addContentStreamToFront
@param opStack PDF Operator stack
*/
void QSPage::prependContentStream(QSPdfOperatorStack* opStack) {
assert(opStack);
try {
obj->addContentStreamToFront(opStack->get());
} catch (ReadOnlyDocumentException &e) {
base->errorException("Page","prependContentStream",QObject::tr("Document is read-only"));
}
}
/**
Add content stream to page, created from new operator stack
Content stream in appended after other content streams
\see CPage::addContentStreamToBack
@param opStack PDF Operator stack
*/
void QSPage::appendContentStream(QSPdfOperatorStack* opStack) {
assert(opStack);
try {
obj->addContentStreamToBack(opStack->get());
} catch (ReadOnlyDocumentException &e) {
base->errorException("Page","appendContentStream",QObject::tr("Document is read-only"));
}
}
/** \copydoc appendContentStream(QSPdfOperatorStack*) */
void QSPage::prependContentStream(QObject* opStack) {
QSPdfOperatorStack* in=dynamic_cast(opStack);
if (!in) return;
appendContentStream(in);
}
/** \copydoc prependContentStream(QSPdfOperatorStack*) */
void QSPage::appendContentStream(QObject* opStack) {
QSPdfOperatorStack* in=dynamic_cast(opStack);
if (!in) return;
prependContentStream(in);
}
/** Call CPage::getText(ret); return ret */
QString QSPage::getText() {
std::string text;
std::string encoding="UTF-8";
obj->getText(text,&encoding);
return QString::fromUtf8(text.c_str());
}
/**
Return stream with given number from page.
Get the streams from CPage and store for later use if necessary
@param streamNumber number of stream to get
@return ContentStream with given number, or NULL if number is outside range
*/
QSContentStream* QSPage::getContentStream(int streamNumber) {
if (numStreams<0) loadContentStreams();
if (streamNumber<0) return NULL; //Stream number outside range
if (streamNumber>=numStreams) return NULL; //Stream number outside range
return new QSContentStream(streams[streamNumber],base);
}
/**
Remove stream with given number from page.
@param streamNumber number of stream to remove
*/
void QSPage::removeContentStream(int streamNumber) {
if (numStreams<0) loadContentStreams();
if (streamNumber<0) return; //Stream number outside range
if (streamNumber>=numStreams) return; //Stream number outside range
obj->removeContentStream (streamNumber);
}
/**
Return number of content streams in page
Get the streams from CPage and store for later use if necessary
@return number of streams in this Page
*/
int QSPage::getContentStreamCount() {
if (numStreams<0) loadContentStreams();
return numStreams;
}
/**
Return change with given number as content stream
@param changeNumber number of change to get
@return ContentStream with given change, or NULL if number is outside range
*/
QSContentStream* QSPage::getChange(int changeNumber) {
if (changeNumber<0) return NULL; //number outside range
try {
boost::shared_ptr c=obj->getChange((size_t)changeNumber);
return new QSContentStream(c,base);
} catch(...) {
//Some error occured
return NULL;
}
}
/**
Return number of changes
@return number of changes in this Page
*/
int QSPage::getChangeCount() {
return (int)obj->getChangeCount();
}
/** Call CPage::getContentStreams(), store result */
void QSPage::loadContentStreams() {
obj->getContentStreams(streams);
//Store number of streams
numStreams=streams.size();
}
//TODO: get list of annotations
/**
Add copy of given annotation to this page
@param an Annotation to add
*/
void QSPage::addAnnotation(QSAnnotation* an) {
try {
obj->addAnnotation(an->get());
} catch (ReadOnlyDocumentException &e) {
base->errorException("Page","addAnnotation",QObject::tr("Document is read-only"));
}
}
/** \copydoc addAnnotation(QSAnnotation*) */
void QSPage::addAnnotation(QObject *an) {
QSAnnotation* annot=dynamic_cast(an);
if (!annot) return;
addAnnotation(annot);
}
/**
Return mediabox from Page
\see CPage::getMediabox
*/
QVariant QSPage::mediabox() {
Rectangle r=obj->getMediabox();
Q_List rect;
rect.append(r.xleft);
rect.append(r.yleft);
rect.append(r.xright);
rect.append(r.yright);
return QVariant(rect);
}
/**
Set mediabox for this page
\see CPage::getMediabox
@param x1 X coordinate of upper left media box corner
@param y1 Y coordinate of upper left media box corner
@param x2 X coordinate of lower right media box corner
@param y2 Y coordinate of lower right media box corner
*/
void QSPage::setMediabox(double x1,double y1,double x2,double y2) {
Rectangle r(x1,y1,x2,y2);
try {
obj->setMediabox(r);
} catch (ReadOnlyDocumentException &e) {
base->errorException("Page","setMediaBox",QObject::tr("Document is read-only"));
}
}
/**
Set mediabox for this page
\see CPage::getMediabox
@param rc rectangle specifying media box
*/
void QSPage::setMediabox(QRect rc) {
//Note that Rectangle uses double coordinates, while Qrect use int coordinates.
//However, media box is often array of int, so this may not be a problem
Rectangle r(rc.left(),rc.top(),rc.right(),rc.bottom());
try {
obj->setMediabox(r);
} catch (ReadOnlyDocumentException &e) {
base->errorException("Page","setMediaBox",QObject::tr("Document is read-only"));
}
}
/**
Return list of font id's and names,
for each font id and name return two elements in output array (id followed by name)
@param onlyNames if true, id's are ommited and only list of names is returned instead.
@return list of font id's and names
*/
QStringList QSPage::getFontIdsAndNames(bool onlyNames/*=false*/) {
FontList fonts;
//Format is like "pair"
obj->getFontIdsAndNames(fonts);
QStringList ret;
FontList::iterator it;
for( it=fonts.begin();it!=fonts.end();++it) { // for each font
if (!onlyNames) ret+=convertToUnicode(it->first,PDF);
ret+=convertToUnicode(it->second,PDF);
}
return ret;
}
/**
For given font name (case sensitive) return it's ID if present on page.
If the font is not present, returns NULL
@param fontName name of desired font
@return ID of font with given name, or NULL if not found in the page
*/
QString QSPage::getFontId(const QString &fontName) {
FontList fonts;
//Format is like "pair"
obj->getFontIdsAndNames(fonts);
QStringList ret;
FontList::iterator it;
string fontNameString=convertFromUnicode(fontName,PDF);
for( it=fonts.begin();it!=fonts.end();++it) { // for each font
if (it->second==fontNameString) return convertToUnicode(it->first,PDF);
}
//Not found
return QString::null;
}
/**
Add new Type 1 font to this page resource dictionary
\see CPage::addSystemType1Font
@param fontName name of font
*/
void QSPage::addSystemType1Font(const QString &fontName) {
try {
obj->addSystemType1Font(convertFromUnicode(fontName,PDF));
} catch (ReadOnlyDocumentException &e) {
base->errorException("Page","addSystemType1Font",QObject::tr("Document is read-only"));
}
}
/** get CPage held inside this class. Not exposed to scripting */
boost::shared_ptr QSPage::get() const {
return obj;
}
} // namespace gui