| /* poppler-document.cc: qt interface to poppler |
| * Copyright (C) 2005, Net Integration Technologies, Inc. |
| * Copyright (C) 2005, 2008, Brad Hards <bradh@frogmouth.net> |
| * Copyright (C) 2005-2010, 2012, 2013, 2015, 2017-2019, Albert Astals Cid <aacid@kde.org> |
| * Copyright (C) 2006-2010, Pino Toscano <pino@kde.org> |
| * Copyright (C) 2010, 2011 Hib Eris <hib@hiberis.nl> |
| * Copyright (C) 2012 Koji Otani <sho@bbr.jp> |
| * Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de> |
| * Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it> |
| * Copyright (C) 2014, 2018 Adam Reichold <adam.reichold@t-online.de> |
| * Copyright (C) 2015 William Bader <williambader@hotmail.com> |
| * Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com> |
| * Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com> |
| * Copyright (C) 2017 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp> |
| * Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich |
| * Copyright (C) 2019 Oliver Sander <oliver.sander@tu-dresden.de> |
| * |
| * 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, or (at your option) |
| * any later version. |
| * |
| * This program 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 General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "poppler-qt5.h" |
| |
| #include <config.h> |
| #include <ErrorCodes.h> |
| #include <GlobalParams.h> |
| #include <Outline.h> |
| #include <PDFDoc.h> |
| #include <Stream.h> |
| #include <Catalog.h> |
| #include <ViewerPreferences.h> |
| #include <DateInfo.h> |
| #include <GfxState.h> |
| |
| #include <QtCore/QDebug> |
| #include <QtCore/QFile> |
| #include <QtCore/QByteArray> |
| |
| #include "poppler-private.h" |
| #include "poppler-page-private.h" |
| #include "poppler-outline-private.h" |
| |
| #if defined(USE_CMS) |
| #include <lcms2.h> |
| #endif |
| |
| namespace Poppler { |
| |
| int DocumentData::count = 0; |
| QMutex DocumentData::mutex; |
| |
| Document *Document::load(const QString &filePath, const QByteArray &ownerPassword, |
| const QByteArray &userPassword) |
| { |
| DocumentData *doc = new DocumentData(filePath, |
| new GooString(ownerPassword.data()), |
| new GooString(userPassword.data())); |
| return DocumentData::checkDocument(doc); |
| } |
| |
| Document *Document::loadFromData(const QByteArray &fileContents, |
| const QByteArray &ownerPassword, |
| const QByteArray &userPassword) |
| { |
| // create stream |
| DocumentData *doc = new DocumentData(fileContents, |
| new GooString(ownerPassword.data()), |
| new GooString(userPassword.data())); |
| return DocumentData::checkDocument(doc); |
| } |
| |
| Document *DocumentData::checkDocument(DocumentData *doc) |
| { |
| Document *pdoc; |
| if (doc->doc->isOk() || doc->doc->getErrorCode() == errEncrypted) { |
| pdoc = new Document(doc); |
| if (doc->doc->getErrorCode() == errEncrypted) |
| pdoc->m_doc->locked = true; |
| else |
| { |
| pdoc->m_doc->locked = false; |
| pdoc->m_doc->fillMembers(); |
| } |
| return pdoc; |
| } |
| else |
| { |
| delete doc; |
| } |
| return nullptr; |
| } |
| |
| Document::Document(DocumentData *dataA) |
| { |
| m_doc = dataA; |
| } |
| |
| Document::~Document() |
| { |
| delete m_doc; |
| } |
| |
| Page *Document::page(int index) const |
| { |
| Page *page = new Page(m_doc, index); |
| if (page->m_page->page == nullptr) { |
| delete page; |
| return nullptr; |
| } |
| |
| return page; |
| } |
| |
| bool Document::isLocked() const |
| { |
| return m_doc->locked; |
| } |
| |
| bool Document::unlock(const QByteArray &ownerPassword, |
| const QByteArray &userPassword) |
| { |
| if (m_doc->locked) { |
| /* racier then it needs to be */ |
| DocumentData *doc2; |
| if (!m_doc->fileContents.isEmpty()) |
| { |
| doc2 = new DocumentData(m_doc->fileContents, |
| new GooString(ownerPassword.data()), |
| new GooString(userPassword.data())); |
| } |
| else |
| { |
| doc2 = new DocumentData(m_doc->m_filePath, |
| new GooString(ownerPassword.data()), |
| new GooString(userPassword.data())); |
| } |
| if (!doc2->doc->isOk()) { |
| delete doc2; |
| } else { |
| delete m_doc; |
| m_doc = doc2; |
| m_doc->locked = false; |
| m_doc->fillMembers(); |
| } |
| } |
| return m_doc->locked; |
| } |
| |
| Document::PageMode Document::pageMode() const |
| { |
| switch (m_doc->doc->getCatalog()->getPageMode()) { |
| case Catalog::pageModeNone: |
| return UseNone; |
| case Catalog::pageModeOutlines: |
| return UseOutlines; |
| case Catalog::pageModeThumbs: |
| return UseThumbs; |
| case Catalog::pageModeFullScreen: |
| return FullScreen; |
| case Catalog::pageModeOC: |
| return UseOC; |
| case Catalog::pageModeAttach: |
| return UseAttach; |
| default: |
| return UseNone; |
| } |
| } |
| |
| Document::PageLayout Document::pageLayout() const |
| { |
| switch (m_doc->doc->getCatalog()->getPageLayout()) { |
| case Catalog::pageLayoutNone: |
| return NoLayout; |
| case Catalog::pageLayoutSinglePage: |
| return SinglePage; |
| case Catalog::pageLayoutOneColumn: |
| return OneColumn; |
| case Catalog::pageLayoutTwoColumnLeft: |
| return TwoColumnLeft; |
| case Catalog::pageLayoutTwoColumnRight: |
| return TwoColumnRight; |
| case Catalog::pageLayoutTwoPageLeft: |
| return TwoPageLeft; |
| case Catalog::pageLayoutTwoPageRight: |
| return TwoPageRight; |
| default: |
| return NoLayout; |
| } |
| } |
| |
| Qt::LayoutDirection Document::textDirection() const |
| { |
| if (!m_doc->doc->getCatalog()->getViewerPreferences()) |
| return Qt::LayoutDirectionAuto; |
| |
| switch (m_doc->doc->getCatalog()->getViewerPreferences()->getDirection()) { |
| case ViewerPreferences::directionL2R: |
| return Qt::LeftToRight; |
| case ViewerPreferences::directionR2L: |
| return Qt::RightToLeft; |
| default: |
| return Qt::LayoutDirectionAuto; |
| } |
| } |
| |
| int Document::numPages() const |
| { |
| return m_doc->doc->getNumPages(); |
| } |
| |
| QList<FontInfo> Document::fonts() const |
| { |
| QList<FontInfo> ourList; |
| FontIterator it( 0, m_doc ); |
| while ( it.hasNext() ) |
| { |
| ourList += it.next(); |
| } |
| return ourList; |
| } |
| |
| QList<EmbeddedFile*> Document::embeddedFiles() const |
| { |
| return m_doc->m_embeddedFiles; |
| } |
| |
| FontIterator* Document::newFontIterator( int startPage ) const |
| { |
| return new FontIterator( startPage, m_doc ); |
| } |
| |
| QByteArray Document::fontData(const FontInfo &fi) const |
| { |
| QByteArray result; |
| if (fi.isEmbedded()) |
| { |
| XRef *xref = m_doc->doc->getXRef()->copy(); |
| |
| Object refObj(fi.m_data->embRef); |
| Object strObj = refObj.fetch(xref); |
| if (strObj.isStream()) |
| { |
| int c; |
| strObj.streamReset(); |
| while ((c = strObj.streamGetChar()) != EOF) |
| { |
| result.append((char)c); |
| } |
| strObj.streamClose(); |
| } |
| delete xref; |
| } |
| return result; |
| } |
| |
| QString Document::info( const QString & type ) const |
| { |
| if (m_doc->locked) { |
| return QString(); |
| } |
| |
| QScopedPointer<GooString> goo(m_doc->doc->getDocInfoStringEntry(type.toLatin1().constData())); |
| return UnicodeParsedString(goo.data()); |
| } |
| |
| bool Document::setInfo( const QString & key, const QString & val ) |
| { |
| if (m_doc->locked) { |
| return false; |
| } |
| |
| GooString *goo = QStringToUnicodeGooString(val); |
| m_doc->doc->setDocInfoStringEntry(key.toLatin1().constData(), goo); |
| return true; |
| } |
| |
| QString Document::title() const |
| { |
| if (m_doc->locked) { |
| return QString(); |
| } |
| |
| QScopedPointer<GooString> goo(m_doc->doc->getDocInfoTitle()); |
| return UnicodeParsedString(goo.data()); |
| } |
| |
| bool Document::setTitle( const QString & val ) |
| { |
| if (m_doc->locked) { |
| return false; |
| } |
| |
| m_doc->doc->setDocInfoTitle(QStringToUnicodeGooString(val)); |
| return true; |
| } |
| |
| QString Document::author() const |
| { |
| if (m_doc->locked) { |
| return QString(); |
| } |
| |
| QScopedPointer<GooString> goo(m_doc->doc->getDocInfoAuthor()); |
| return UnicodeParsedString(goo.data()); |
| } |
| |
| bool Document::setAuthor( const QString & val ) |
| { |
| if (m_doc->locked) { |
| return false; |
| } |
| |
| m_doc->doc->setDocInfoAuthor(QStringToUnicodeGooString(val)); |
| return true; |
| } |
| |
| QString Document::subject() const |
| { |
| if (m_doc->locked) { |
| return QString(); |
| } |
| |
| QScopedPointer<GooString> goo(m_doc->doc->getDocInfoSubject()); |
| return UnicodeParsedString(goo.data()); |
| } |
| |
| bool Document::setSubject( const QString & val ) |
| { |
| if (m_doc->locked) { |
| return false; |
| } |
| |
| m_doc->doc->setDocInfoSubject(QStringToUnicodeGooString(val)); |
| return true; |
| } |
| |
| QString Document::keywords() const |
| { |
| if (m_doc->locked) { |
| return QString(); |
| } |
| |
| QScopedPointer<GooString> goo(m_doc->doc->getDocInfoKeywords()); |
| return UnicodeParsedString(goo.data()); |
| } |
| |
| bool Document::setKeywords( const QString & val ) |
| { |
| if (m_doc->locked) { |
| return false; |
| } |
| |
| m_doc->doc->setDocInfoKeywords(QStringToUnicodeGooString(val)); |
| return true; |
| } |
| |
| QString Document::creator() const |
| { |
| if (m_doc->locked) { |
| return QString(); |
| } |
| |
| QScopedPointer<GooString> goo(m_doc->doc->getDocInfoCreator()); |
| return UnicodeParsedString(goo.data()); |
| } |
| |
| bool Document::setCreator( const QString & val ) |
| { |
| if (m_doc->locked) { |
| return false; |
| } |
| |
| m_doc->doc->setDocInfoCreator(QStringToUnicodeGooString(val)); |
| return true; |
| } |
| |
| QString Document::producer() const |
| { |
| if (m_doc->locked) { |
| return QString(); |
| } |
| |
| QScopedPointer<GooString> goo(m_doc->doc->getDocInfoProducer()); |
| return UnicodeParsedString(goo.data()); |
| } |
| |
| bool Document::setProducer( const QString & val ) |
| { |
| if (m_doc->locked) { |
| return false; |
| } |
| |
| m_doc->doc->setDocInfoProducer(QStringToUnicodeGooString(val)); |
| return true; |
| } |
| |
| bool Document::removeInfo() |
| { |
| if (m_doc->locked) { |
| return false; |
| } |
| |
| m_doc->doc->removeDocInfo(); |
| return true; |
| } |
| |
| QStringList Document::infoKeys() const |
| { |
| QStringList keys; |
| |
| if ( m_doc->locked ) |
| return QStringList(); |
| |
| QScopedPointer<XRef> xref(m_doc->doc->getXRef()->copy()); |
| if (!xref) |
| return QStringList(); |
| Object info = xref->getDocInfo(); |
| if ( !info.isDict() ) |
| return QStringList(); |
| |
| Dict *infoDict = info.getDict(); |
| // somehow iterate over keys in infoDict |
| keys.reserve(infoDict->getLength()); |
| for( int i=0; i < infoDict->getLength(); ++i ) { |
| keys.append( QString::fromLatin1(infoDict->getKey(i)) ); |
| } |
| |
| return keys; |
| } |
| |
| QDateTime Document::date( const QString & type ) const |
| { |
| if (m_doc->locked) { |
| return QDateTime(); |
| } |
| |
| QScopedPointer<GooString> goo(m_doc->doc->getDocInfoStringEntry(type.toLatin1().constData())); |
| QString str = UnicodeParsedString(goo.data()); |
| return Poppler::convertDate(str.toLatin1().constData()); |
| } |
| |
| bool Document::setDate( const QString & key, const QDateTime & val ) |
| { |
| if (m_doc->locked) { |
| return false; |
| } |
| |
| m_doc->doc->setDocInfoStringEntry(key.toLatin1().constData(), QDateTimeToUnicodeGooString(val)); |
| return true; |
| } |
| |
| QDateTime Document::creationDate() const |
| { |
| if (m_doc->locked) { |
| return QDateTime(); |
| } |
| |
| QScopedPointer<GooString> goo(m_doc->doc->getDocInfoCreatDate()); |
| QString str = UnicodeParsedString(goo.data()); |
| return Poppler::convertDate(str.toLatin1().constData()); |
| } |
| |
| bool Document::setCreationDate( const QDateTime & val ) |
| { |
| if (m_doc->locked) { |
| return false; |
| } |
| |
| m_doc->doc->setDocInfoCreatDate(QDateTimeToUnicodeGooString(val)); |
| return true; |
| } |
| |
| QDateTime Document::modificationDate() const |
| { |
| if (m_doc->locked) { |
| return QDateTime(); |
| } |
| |
| QScopedPointer<GooString> goo(m_doc->doc->getDocInfoModDate()); |
| QString str = UnicodeParsedString(goo.data()); |
| return Poppler::convertDate(str.toLatin1().constData()); |
| } |
| |
| bool Document::setModificationDate( const QDateTime & val ) |
| { |
| if (m_doc->locked) { |
| return false; |
| } |
| |
| m_doc->doc->setDocInfoModDate(QDateTimeToUnicodeGooString(val)); |
| return true; |
| } |
| |
| bool Document::isEncrypted() const |
| { |
| return m_doc->doc->isEncrypted(); |
| } |
| |
| bool Document::isLinearized() const |
| { |
| return m_doc->doc->isLinearized(); |
| } |
| |
| bool Document::okToPrint() const |
| { |
| return m_doc->doc->okToPrint(); |
| } |
| |
| bool Document::okToPrintHighRes() const |
| { |
| return m_doc->doc->okToPrintHighRes(); |
| } |
| |
| bool Document::okToChange() const |
| { |
| return m_doc->doc->okToChange(); |
| } |
| |
| bool Document::okToCopy() const |
| { |
| return m_doc->doc->okToCopy(); |
| } |
| |
| bool Document::okToAddNotes() const |
| { |
| return m_doc->doc->okToAddNotes(); |
| } |
| |
| bool Document::okToFillForm() const |
| { |
| return m_doc->doc->okToFillForm(); |
| } |
| |
| bool Document::okToCreateFormFields() const |
| { |
| return ( okToFillForm() && okToChange() ); |
| } |
| |
| bool Document::okToExtractForAccessibility() const |
| { |
| return m_doc->doc->okToAccessibility(); |
| } |
| |
| bool Document::okToAssemble() const |
| { |
| return m_doc->doc->okToAssemble(); |
| } |
| |
| void Document::getPdfVersion(int *major, int *minor) const |
| { |
| if (major) |
| *major = m_doc->doc->getPDFMajorVersion(); |
| if (minor) |
| *minor = m_doc->doc->getPDFMinorVersion(); |
| } |
| |
| Page *Document::page(const QString &label) const |
| { |
| GooString label_g(label.toLatin1().data()); |
| int index; |
| |
| if (!m_doc->doc->getCatalog()->labelToIndex (&label_g, &index)) { |
| std::unique_ptr<GooString> label_ug(QStringToUnicodeGooString(label)); |
| if (!m_doc->doc->getCatalog()->labelToIndex (label_ug.get(), &index)) { |
| return nullptr; |
| } |
| } |
| |
| return page(index); |
| } |
| |
| bool Document::hasEmbeddedFiles() const |
| { |
| return (!(0 == m_doc->doc->getCatalog()->numEmbeddedFiles())); |
| } |
| |
| QDomDocument *Document::toc() const |
| { |
| Outline * outline = m_doc->doc->getOutline(); |
| if ( !outline ) |
| return nullptr; |
| |
| const std::vector<::OutlineItem*> * items = outline->getItems(); |
| if ( !items || items->size() < 1 ) |
| return nullptr; |
| |
| QDomDocument *toc = new QDomDocument(); |
| if ( items->size() > 0 ) |
| m_doc->addTocChildren( toc, toc, items ); |
| |
| return toc; |
| } |
| |
| QVector<OutlineItem> Document::outline() const |
| { |
| QVector<OutlineItem> result; |
| |
| if (::Outline *outline = m_doc->doc->getOutline()) { |
| if (const std::vector<::OutlineItem*> *items = outline->getItems()) { |
| for (void *item : *items) { |
| result.push_back(OutlineItem{new OutlineItemData{static_cast<::OutlineItem *>(item), m_doc}}); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| LinkDestination *Document::linkDestination( const QString &name ) |
| { |
| GooString * namedDest = QStringToGooString( name ); |
| LinkDestinationData ldd(nullptr, namedDest, m_doc, false); |
| LinkDestination *ld = new LinkDestination(ldd); |
| delete namedDest; |
| return ld; |
| } |
| |
| void Document::setPaperColor(const QColor &color) |
| { |
| m_doc->setPaperColor(color); |
| } |
| |
| void Document::setColorDisplayProfile(void* outputProfileA) |
| { |
| #if defined(USE_CMS) |
| GfxColorSpace::setDisplayProfile((cmsHPROFILE)outputProfileA); |
| #else |
| Q_UNUSED(outputProfileA); |
| #endif |
| } |
| |
| void Document::setColorDisplayProfileName(const QString &name) |
| { |
| #if defined(USE_CMS) |
| GooString *profileName = QStringToGooString( name ); |
| GfxColorSpace::setDisplayProfileName(profileName); |
| delete profileName; |
| #else |
| Q_UNUSED(name); |
| #endif |
| } |
| |
| void* Document::colorRgbProfile() const |
| { |
| #if defined(USE_CMS) |
| return (void*)GfxColorSpace::getRGBProfile(); |
| #else |
| return nullptr; |
| #endif |
| } |
| |
| void* Document::colorDisplayProfile() const |
| { |
| #if defined(USE_CMS) |
| return (void*)GfxColorSpace::getDisplayProfile(); |
| #else |
| return nullptr; |
| #endif |
| } |
| |
| QColor Document::paperColor() const |
| { |
| return m_doc->paperColor; |
| } |
| |
| void Document::setRenderBackend( Document::RenderBackend backend ) |
| { |
| // no need to delete the outputdev as for the moment we always create a splash one |
| // as the arthur one does not allow "precaching" due to it's signature |
| // delete m_doc->m_outputDev; |
| // m_doc->m_outputDev = NULL; |
| m_doc->m_backend = backend; |
| } |
| |
| Document::RenderBackend Document::renderBackend() const |
| { |
| return m_doc->m_backend; |
| } |
| |
| QSet<Document::RenderBackend> Document::availableRenderBackends() |
| { |
| QSet<Document::RenderBackend> ret; |
| #if defined(HAVE_SPLASH) |
| ret << Document::SplashBackend; |
| #endif |
| ret << Document::ArthurBackend; |
| return ret; |
| } |
| |
| void Document::setRenderHint( Document::RenderHint hint, bool on ) |
| { |
| const bool touchesOverprinting = hint & Document::OverprintPreview; |
| |
| int hintForOperation = hint; |
| if (touchesOverprinting && !isOverprintPreviewAvailable()) |
| hintForOperation = hintForOperation & ~(int)Document::OverprintPreview; |
| |
| if ( on ) |
| m_doc->m_hints |= hintForOperation; |
| else |
| m_doc->m_hints &= ~hintForOperation; |
| |
| } |
| |
| Document::RenderHints Document::renderHints() const |
| { |
| return Document::RenderHints( m_doc->m_hints ); |
| } |
| |
| PSConverter *Document::psConverter() const |
| { |
| return new PSConverter(m_doc); |
| } |
| |
| PDFConverter *Document::pdfConverter() const |
| { |
| return new PDFConverter(m_doc); |
| } |
| |
| QString Document::metadata() const |
| { |
| QString result; |
| Catalog *catalog = m_doc->doc->getCatalog(); |
| if (catalog && catalog->isOk()) |
| { |
| GooString *s = catalog->readMetadata(); |
| if (s) result = UnicodeParsedString(s); |
| delete s; |
| } |
| return result; |
| } |
| |
| bool Document::hasOptionalContent() const |
| { |
| return ( m_doc->doc->getOptContentConfig() && m_doc->doc->getOptContentConfig()->hasOCGs() ); |
| } |
| |
| OptContentModel *Document::optionalContentModel() |
| { |
| if (m_doc->m_optContentModel.isNull()) { |
| m_doc->m_optContentModel = new OptContentModel(m_doc->doc->getOptContentConfig(), nullptr); |
| } |
| return (OptContentModel *)m_doc->m_optContentModel; |
| } |
| |
| QStringList Document::scripts() const |
| { |
| Catalog *catalog = m_doc->doc->getCatalog(); |
| const int numScripts = catalog->numJS(); |
| QStringList scripts; |
| for (int i = 0; i < numScripts; ++i) { |
| GooString *s = catalog->getJS(i); |
| if (s) { |
| scripts.append(UnicodeParsedString(s)); |
| delete s; |
| } |
| } |
| return scripts; |
| } |
| |
| bool Document::getPdfId(QByteArray *permanentId, QByteArray *updateId) const |
| { |
| GooString gooPermanentId; |
| GooString gooUpdateId; |
| |
| if (!m_doc->doc->getID(permanentId ? &gooPermanentId : nullptr, updateId ? &gooUpdateId : nullptr)) |
| return false; |
| |
| if (permanentId) |
| *permanentId = gooPermanentId.c_str(); |
| if (updateId) |
| *updateId = gooUpdateId.c_str(); |
| |
| return true; |
| } |
| |
| Document::FormType Document::formType() const |
| { |
| switch ( m_doc->doc->getCatalog()->getFormType() ) |
| { |
| case Catalog::NoForm: |
| return Document::NoForm; |
| case Catalog::AcroForm: |
| return Document::AcroForm; |
| case Catalog::XfaForm: |
| return Document::XfaForm; |
| } |
| |
| return Document::NoForm; // make gcc happy |
| } |
| |
| QVector<int> Document::formCalculateOrder() const |
| { |
| QVector<int> result; |
| |
| Form *form = m_doc->doc->getCatalog()->getForm(); |
| const std::vector<Ref> &calculateOrder = form->getCalculateOrder(); |
| for (uint i = 0; i < calculateOrder.size(); ++i) { |
| FormWidget *w = form->findWidgetByRef(calculateOrder[i]); |
| if (w) { |
| result << w->getID(); |
| } |
| } |
| |
| return result; |
| } |
| |
| QDateTime convertDate( const char *dateString ) |
| { |
| int year, mon, day, hour, min, sec, tzHours, tzMins; |
| char tz; |
| |
| if ( parseDateString( dateString, &year, &mon, &day, &hour, &min, &sec, &tz, &tzHours, &tzMins ) ) |
| { |
| QDate d( year, mon, day ); |
| QTime t( hour, min, sec ); |
| if ( d.isValid() && t.isValid() ) { |
| QDateTime dt( d, t, Qt::UTC ); |
| if ( tz ) { |
| // then we have some form of timezone |
| if ( 'Z' == tz ) { |
| // We are already at UTC |
| } else if ( '+' == tz ) { |
| // local time is ahead of UTC |
| dt = dt.addSecs(-1*((tzHours*60)+tzMins)*60); |
| } else if ( '-' == tz ) { |
| // local time is behind UTC |
| dt = dt.addSecs(((tzHours*60)+tzMins)*60); |
| } else { |
| qWarning("unexpected tz val"); |
| } |
| } |
| return dt; |
| } |
| } |
| return QDateTime(); |
| } |
| |
| QDateTime convertDate( char *dateString ) |
| { |
| return convertDate( (const char *) dateString ); |
| } |
| |
| |
| bool isCmsAvailable() |
| { |
| #if defined(USE_CMS) |
| return true; |
| #else |
| return false; |
| #endif |
| } |
| |
| bool isOverprintPreviewAvailable() { |
| #ifdef SPLASH_CMYK |
| return true; |
| #else |
| return false; |
| #endif |
| } |
| |
| } |
| |