diff --git a/src/gui/painting/qpaintengine.h b/src/gui/painting/qpaintengine.h index c02b638ed94..0348fb69838 100644 --- a/src/gui/painting/qpaintengine.h +++ b/src/gui/painting/qpaintengine.h @@ -166,14 +166,23 @@ class Q_GUI_EXPORT QPaintEngine virtual void addHyperlink(const QRectF &r, const QUrl &url) {Q_UNUSED(r); Q_UNUSED(url);} virtual void addAnchor(const QRectF &r, const QString &name) {Q_UNUSED(r); Q_UNUSED(name);} virtual void addLink(const QRectF &r, const QString &anchor) {Q_UNUSED(r); Q_UNUSED(anchor);} - virtual void addTextField(const QRectF &r, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength) { - Q_UNUSED(r); Q_UNUSED(text); Q_UNUSED(name); Q_UNUSED(multiLine); Q_UNUSED(password); Q_UNUSED(readOnly); Q_UNUSED(maxLength); + virtual void addTextField(const QRectF &r,const QMap &data, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength) { + Q_UNUSED(r); Q_UNUSED(text); Q_UNUSED(name); Q_UNUSED(multiLine); Q_UNUSED(password); Q_UNUSED(readOnly); Q_UNUSED(maxLength); Q_UNUSED(data); } - virtual void addCheckBox(const QRectF &r, bool checked, const QString &name, bool readOnly) { - Q_UNUSED(r); Q_UNUSED(checked); Q_UNUSED(name); Q_UNUSED(readOnly); + virtual void addHiddenField(const QRectF &r, const QMap &data, const QString &value, const QString &name) { + Q_UNUSED(r); Q_UNUSED(name); Q_UNUSED(value); Q_UNUSED(data); } - virtual void addRadioButton(const QRectF &r, const QString & group="", bool checked=false, const QString &name="", bool readOnly=false) { - Q_UNUSED(r); Q_UNUSED(checked); Q_UNUSED(name); Q_UNUSED(readOnly); Q_UNUSED(group); + virtual void addCheckBox(const QRectF &r, const QMap &data, bool checked, const QString &name, bool readOnly) { + Q_UNUSED(r); Q_UNUSED(checked); Q_UNUSED(name); Q_UNUSED(readOnly); Q_UNUSED(data); + } + virtual void addRadioButton(const QRectF &r, const QMap &data, bool checked=false, const QString &name="", const QString &value="", bool readOnly=false) { + Q_UNUSED(r); Q_UNUSED(checked); Q_UNUSED(name); Q_UNUSED(readOnly); Q_UNUSED(value); Q_UNUSED(data); + } + virtual void addComboBox(const QRectF &r, const QMap &data, const QString &name="", const QString &option_list="[]", const QString &default_value="", bool readOnly=false) { + Q_UNUSED(r); Q_UNUSED(default_value); Q_UNUSED(name); Q_UNUSED(readOnly); Q_UNUSED(option_list); Q_UNUSED(data); + } + virtual void addPageJavaScript(const QMap &data, const QString &script) { + Q_UNUSED(data); Q_UNUSED(script); } virtual void drawLines(const QLine *lines, int lineCount); diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 924e02c1c0a..1f9c3206ef7 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -7420,32 +7420,59 @@ void QPainter::addHyperlink(const QRectF &r, const QUrl &url) d->engine->addHyperlink(worldTransform().mapRect(r), url); } -void QPainter::addTextField(const QRectF &r, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength) { +void QPainter::addHiddenField(const QRectF &r, const QMap &data, const QString &value, const QString &name) { + Q_D(QPainter); + if (!d->engine) { + qWarning("QPainter::addHiddenField: Painter not active"); + return; + } + d->engine->addHiddenField(worldTransform().mapRect(r), data, value, name); +} + +void QPainter::addTextField(const QRectF &r, const QMap &data, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength) { Q_D(QPainter); if (!d->engine) { qWarning("QPainter::addTextField: Painter not active"); return; } - d->engine->addTextField(worldTransform().mapRect(r), text, name, multiLine, password, readOnly, maxLength); + d->engine->addTextField(worldTransform().mapRect(r), data, text, name, multiLine, password, readOnly, maxLength); +} + +void QPainter::addPageJavaScript(const QMap &data, const QString &script) { + Q_D(QPainter); + if (!d->engine) { + qWarning("QPainter::addPageJavascript: Painter not active"); + return; + } + d->engine->addPageJavaScript(data, script); } -void QPainter::addCheckBox(const QRectF &r, bool checked, const QString &name, bool readOnly) { +void QPainter::addCheckBox(const QRectF &r, const QMap &data, bool checked, const QString &name, bool readOnly) { Q_D(QPainter); if (!d->engine) { qWarning("QPainter::addCheckBox: Painter not active"); return; } - d->engine->addCheckBox(worldTransform().mapRect(r), checked, name, readOnly); + d->engine->addCheckBox(worldTransform().mapRect(r), data, checked, name, readOnly); } -void QPainter::addRadioButton(const QRectF &r, const QString & group, bool checked, const QString &name, bool readOnly) { +void QPainter::addRadioButton(const QRectF &r, const QMap &data, bool checked, const QString &name, const QString &value, bool readOnly) { Q_D(QPainter); if (!d->engine) { qWarning("QPainter::addRadioButton: Painter not active"); return; } - d->engine->addRadioButton(worldTransform().mapRect(r), group, checked, name, readOnly); + d->engine->addRadioButton(worldTransform().mapRect(r), data, checked, name, value, readOnly); +} + +void QPainter::addComboBox(const QRectF &r, const QMap &data, const QString &name, const QString &option_list, const QString &default_value, bool readOnly) { + Q_D(QPainter); + if (!d->engine) { + qWarning("QPainter::addComboBox: Painter not active"); + return; + } + d->engine->addComboBox(worldTransform().mapRect(r), data, name, option_list, default_value, readOnly); } /*! diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index cfba5f60f41..89ad72ecd46 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -454,10 +454,13 @@ class Q_GUI_EXPORT QPainter inline void addLink(int x, int y, int w, int h, const QString &anchor); inline void addLink(const QRect &r, const QString &anchor); void addLink(const QRectF &r, const QString &anchor); - - void addTextField(const QRectF &r, const QString &text="", const QString &name="", bool multiLine=false, bool password=false, bool readOnly=false, int maxLength=-1); - void addCheckBox(const QRectF &r, bool checked=false, const QString &name="", bool readOnly=false); - void addRadioButton(const QRectF &r, const QString & group="", bool checked=false, const QString &name="", bool readOnly=false);; + + void addHiddenField(const QRectF &r, const QMap &data, const QString &value="", const QString &name=""); + void addPageJavaScript(const QMap &data, const QString &script); + void addTextField(const QRectF &r, const QMap &data, const QString &text="", const QString &name="", bool multiLine=false, bool password=false, bool readOnly=false, int maxLength=-1); + void addCheckBox(const QRectF &r, const QMap &data, bool checked=false, const QString &name="", bool readOnly=false); + void addRadioButton(const QRectF &r, const QMap &data, bool checked=false, const QString &name="", const QString &value="", bool readOnly=false); + void addComboBox(const QRectF &r, const QMap &data, const QString &name="", const QString &option_list="[]", const QString &default_value="", bool readOnly=false); inline void addHyperlink(int x, int y, int w, int h, const QUrl &url); inline void addHyperlink(const QRect &r, const QUrl &url); diff --git a/src/gui/painting/qprintengine_pdf.cpp b/src/gui/painting/qprintengine_pdf.cpp index a906e3243be..305985b851c 100644 --- a/src/gui/painting/qprintengine_pdf.cpp +++ b/src/gui/painting/qprintengine_pdf.cpp @@ -196,6 +196,44 @@ bool QPdfEngine::end() d->outlineRoot->firstChild->obj, d->outlineRoot->lastChild->obj); } + + QMapIterator i(d->formFieldParents); + while (i.hasNext()) { + i.next(); + QFormFieldParent* formFieldParent = i.value(); + d->addXrefEntry(formFieldParent->ref); + d->xprintf("<<"); + if (formFieldParent->JSvalidation_ref != -1) { + d->xprintf("/AA<>",formFieldParent->JSvalidation_ref); + } + d->xprintf("/Kids["); + foreach(const uint & i, formFieldParent->children) + d->xprintf("%d 0 R ",i); + d->xprintf("]\n" + "/Parent %d 0 R\n", d->formFieldList); + d->xprintf("/FT/%s\n",formFieldParent->type.toUtf8().constData()); + if (!formFieldParent->name.isEmpty()) { + d->xprintf("/T"); + d->printString(formFieldParent->name); + } + if (!formFieldParent->value.isEmpty()) { + d->xprintf("/V"); + d->printString(formFieldParent->value); + d->xprintf("\n"); + d->xprintf("/DV"); + d->printString(formFieldParent->value); + d->xprintf("\n"); + } + if (formFieldParent->type == "Ch") { + d->xprintf("/Opt %s\n", formFieldParent->option_list.toUtf8().constData()); + d->xprintf("/Ff 131072\n"); + } else if (formFieldParent->type == "Btn") { + // Radio buttons have children + d->xprintf("/Ff 49154\n"); + } + d->xprintf(">>endobj\n"); + } + if (d->formFields.size()) { uint font = d->addXrefEntry(-1); d->xprintf("<>\n" @@ -212,6 +250,22 @@ bool QPdfEngine::end() "endobj\n", font); } + int named_javascript_ref = -1; + if (d->pageJavaScripts.size()) { + int jsNamesRef = d->addXrefEntry(-1); + d->xprintf("< i(d->pageJavaScripts); + while (i.hasNext()) { + i.next(); + d->xprintf("(%s)", i.key().toUtf8().constData()); + d->xprintf("%d 0 R", i.value()); + } + d->xprintf("]>>\nendobj\n"); + + named_javascript_ref = d->addXrefEntry(-1); + d->xprintf("<>\nendobj\n", jsNamesRef); + } + d->catalog = d->addXrefEntry(-1); d->xprintf("<<\n" "/Type /Catalog\n" @@ -226,6 +280,8 @@ bool QPdfEngine::end() if (d->anchors.size()) d->xprintf("/Dests %d 0 R\n", dests); + if (named_javascript_ref > 0) + d->xprintf("/Names %d 0 R\n", named_javascript_ref); d->xprintf(">>\n" "endobj\n"); @@ -238,16 +294,311 @@ bool QPdfEngine::end() return true; } -void QPdfEngine::addCheckBox(const QRectF &r, bool checked, const QString &name, bool readOnly) { +uint QPdfEngine::addJavaScript(const QString &script) { Q_D(QPdfEngine); - uint obj = d->addXrefEntry(-1); + uint ref = d->addXrefEntry(-1); + d->xprintf("<>\nendobj\n",script.toUtf8().constData()); + return ref; +} + +void QPdfEngine::addPageJavaScript(const QMap &data, const QString &script) { + Q_D(QPdfEngine); + QString script_name; + if (data.contains("acroform-script-name")) { + script_name = data["acroform-script-name"]; + } else { + script_name = QString("UntitledScript%1").arg(d->pageJavaScripts.count()); + } + d->pageJavaScripts[script_name] = this->addJavaScript(script); +} + +// Create resources for radio buttons +void QPdfEngine::addRadioBtnResources(QRectF rr, int *formRadioBtnResourceChecked, int *formRadioBtnResourceUnChecked) { + Q_D(QPdfEngine); + float k = 0.552284749831; + float cx=((rr.right()-rr.left())/2); + float cy=((rr.bottom()-rr.top())/2); + float r=cx; // radius is half the total space we have just like the middle of the space. + char streambuf[1024]; + + // Drawing a circle. use b to stroke, fill, end on checked. Just stroke, end with f on unchecked. + snprintf(streambuf,sizeof(streambuf),"1 g\n" + "%.3f %.3f m\n" + "%.3f %.3f %.3f %.3f %.3f %.3f c\n" + "%.3f %.3f %.3f %.3f %.3f %.3f c\n" + "%.3f %.3f %.3f %.3f %.3f %.3f c\n" + "%.3f %.3f %.3f %.3f %.3f %.3f c\n", + (cx-r), cy, + cx - r, cy + k * r, cx - k * r, cy + r, cx, cy + r, + cx + k * r, cy + r, cx + r, cy + k * r, cx + r, cy, + cx + r, cy - k * r, cx + k * r, cy - r, cx, cy - r, + cx - k * r, cy - r, cx - r, cy - k * r, cx - r, cy); + + *formRadioBtnResourceChecked = d->addXrefEntry(-1); + d->xprintf("<<\n" + " /BBox [\n" + " 0.0\n" + " 0.0\n" + " %.3f\n" + " %.3f\n" + " ]\n" + " /FormType 1\n" + " /Resources <<\n" + " /ProcSet [\n" + " /PDF\n" + " ]\n" + " >>\n" + " /Subtype /Form\n" + " /Type /XObject\n" + " /Length %d\n" + ">>\n" + "stream\n" + "%sb\n" + "endstream\n" + "endobj\n", (rr.right()-rr.left()), (rr.bottom()-rr.top()), strlen(streambuf)+2, streambuf); + + *formRadioBtnResourceUnChecked = d->addXrefEntry(-1); + d->xprintf("<<\n" + " /BBox [\n" + " 0.0\n" + " 0.0\n" + " %.3f\n" + " %.3f\n" + " ]\n" + " /FormType 1\n" + " /Resources <<\n" + " /ProcSet [\n" + " /PDF\n" + " ]\n" + " >>\n" + " /Subtype /Form\n" + " /Type /XObject\n" + " /Length %d\n" + ">>\n" + "stream\n" + "%sf\n" + "endstream\n" + "endobj\n", (rr.right()-rr.left()), (rr.bottom()-rr.top()), strlen(streambuf)+2, streambuf); +} + +// Create resources used by all checkboxes once +void QPdfEngine::addCheckBoxResources() { + Q_D(QPdfEngine); + d->formChkBoxResourceChecked = d->addXrefEntry(-1); + d->xprintf("<<" + "/BBox [\n" + " 0.0\n" + " 0.0\n" + " 9.5321\n" + " 10.7023\n" + "]\n" + "/FormType 1\n" + "/Matrix [\n" + " 1.0\n" + " 0.0\n" + " 0.0\n" + " 1.0\n" + " 0.0\n" + " 0.0\n" + "]\n" + "/Resources <<\n" + " /Font <<\n" + " /BaseFont /ZapfDingbats\n" + " /Name /ZaDb\n" + " /Subtype /Type1\n" + " /Type /Font\n" + " >>\n" + " /ProcSet [\n" + " /PDF\n" + " /Text\n" + " ]\n" + ">>\n" + "/Subtype /Form\n" + "/Type /XObject\n" + "/Length 51\n" + ">>\n" + "stream\n" + "q\n" + "0 0 1 rg\n" + "BT\n" + "/ZaDb 4 Tf\n" + "0 0 Td\n" + "(4) Tj\n" + "ET\n" + "Q\n" + "endstream\n" + "endobj\n"); + + d->formChkBoxResourceUnChecked = d->addXrefEntry(-1); + d->xprintf("<<" + " /BBox [\n" + " 0.0\n" + " 0.0\n" + " 9.5321\n" + " 10.7023\n" + " ]\n" + " /FormType 1\n" + " /Matrix [\n" + " 1.0\n" + " 0.0\n" + " 0.0\n" + " 1.0\n" + " 0.0\n" + " 0.0\n" + " ]\n" + " /Resources <<\n" + " /ProcSet [\n" + " /PDF\n" + " ]\n" + " >>\n" + " /Subtype /Form\n" + " /Type /XObject\n" + " /Length 216\n" + ">>\n" + "stream\n" + "1 g\n" + "0 0 9.5321 10.7023 re\n" + "f\n" + "0.501953 g\n" + "1 1 m\n" + "1 9.7023 l\n" + "8.5321 9.7023 l\n" + "7.5321 8.7023 l\n" + "2 8.7023 l\n" + "2 2 l\n" + "f\n" + "0.75293 g\n" + "8.5321 9.7023 m\n" + "8.5321 1 l\n" + "1 1 l\n" + "2 2 l\n" + "7.5321 2 l\n" + "7.5321 8.7023 l\n" + "f\n" + "0 G\n" + "0.5 0.5 8.5321 9.7023 re\n" + "s\n" + "endstream\n" + "endobj\n"); +} + +void QPdfEngine::addRadioButton(const QRectF &r, const QMap &data, bool checked, const QString &name, const QString &value, bool readOnly) { + Q_D(QPdfEngine); + uint obj; char buf[256]; QRectF rr = d->pageMatrix().mapRect(r); + int onBlurRef = -1; + int formRadioBtnResourceChecked, formRadioBtnResourceUnChecked; + + addRadioBtnResources(rr, &formRadioBtnResourceChecked, &formRadioBtnResourceUnChecked); + if (d->formFieldList == -1) d->formFieldList = d->requestObject(); + + if (!d->formFieldParents.contains(name)) { + QFormFieldParent* form = new QFormFieldParent(); + form->ref = d->requestObject(); + form->type = "Btn"; + form->name = name; + form->value = value; + if (data.contains("acroform-validation")) { + form->JSvalidation_ref = this->addJavaScript(data["acroform-validation"]); + } + else { + form->JSvalidation_ref = -1; + } + d->formFields.push_back(form->ref); + d->formFieldParents[name] = form; + } + + //handling javascript + if (data.contains("acroform-on-blur")) { + onBlurRef = this->addJavaScript(data["acroform-on-blur"]); + } + + obj = d->addXrefEntry(-1); d->xprintf("<<\n" "/Type /Annot\n" + "/Subtype/Widget\n" "/Parent %d 0 R\n" "/F 4\n" + "/AP << /N << /%s %d 0 R /Off %d 0 R >> >>\n" +// "/BS <<\n" +// "/S\n" +// "/W 1\n" +// ">>\n" +// "/MK <<\n" +// "/BC [\n" +// "0.0\n" +// "0.0\n" +// "0.0\n" +// "]\n" +// ">>\n" + "/Rect[", d->formFieldParents[name]->ref, value.toUtf8().data(), + formRadioBtnResourceChecked, formRadioBtnResourceUnChecked); + + d->xprintf("%s ", qt_real_to_string(rr.left(),buf)); + d->xprintf("%s ", qt_real_to_string(rr.top(),buf)); + d->xprintf("%s ", qt_real_to_string(rr.right(),buf)); + d->xprintf("%s", qt_real_to_string(rr.bottom(),buf)); + d->xprintf("]\n" + "/P %d 0 R\n", d->pages.back()); + + if (checked) { + d->xprintf("/AS /%s\n", value.toUtf8().constData()); + } + + // writing javascript actions + if (onBlurRef > 0) { + d->xprintf("/AA<>", onBlurRef); + } + // alignment + if (data.contains("acroform-align")) { + uint align = -1; + if (data["acroform-align"].compare("left", Qt::CaseInsensitive) == 0) { + align = 0; + } + else if (data["acroform-align"].compare("center", Qt::CaseInsensitive) == 0){ + align = 1; + } + else if (data["acroform-align"].compare("right", Qt::CaseInsensitive) == 0){ + align = 2; + } + if (align != -1) { + d->xprintf("/Q %d\n",align); + } + } + +// if (!text.isEmpty()) { +// d->xprintf("/V"); +// d->printString(text); +// d->xprintf("\n"); +// } + d->xprintf(">>\n" + "endobj\n"); + d->currentPage->annotations.push_back(obj); + + d->formFieldParents[name]->children.push_back(obj); +} + +void QPdfEngine::addCheckBox(const QRectF &r, const QMap &data, bool checked, const QString &name, bool readOnly) { + Q_D(QPdfEngine); + char buf[256]; + uint obj; + QRectF rr; + + // Put out the resources we need for a checkbox once + if (d->formChkBoxResourceChecked == -1) { + addCheckBoxResources(); + } + obj = d->addXrefEntry(-1); + rr = d->pageMatrix().mapRect(r); + + if (d->formFieldList == -1) d->formFieldList = d->requestObject(); + d->xprintf("<<\n" + "/Type /Annot\n" + "/Parent %d 0 R\n" + "/F 4\n" + "/V /Yes\n" "/Rect[", d->formFieldList); d->xprintf("%s ", qt_real_to_string(rr.left(),buf)); d->xprintf("%s ", qt_real_to_string(rr.top(),buf)); @@ -255,8 +606,20 @@ void QPdfEngine::addCheckBox(const QRectF &r, bool checked, const QString &name, d->xprintf("%s", qt_real_to_string(rr.bottom(),buf)); d->xprintf("]\n" "/FT/Btn\n" - "/Subtype/Widget\n" - "/P %d 0 R\n", d->pages.back()); + "/Subtype /Widget\n" + "/AP << /N << /Yes %d 0 R /Off %d 0 R >> >>\n" + "/BS <<\n" + "/S\n" + "/W 1\n" + ">>\n" + "/MK <<\n" + "/BC [\n" + "0.0\n" + "0.0\n" + "0.0\n" + "]\n" + ">>\n" + "/P %d 0 R\n", d->formChkBoxResourceChecked, d->formChkBoxResourceUnChecked, d->pages.back()); if (checked) d->xprintf("/AS /Yes\n"); if (!name.isEmpty()) { @@ -272,7 +635,7 @@ void QPdfEngine::addCheckBox(const QRectF &r, bool checked, const QString &name, d->formFields.push_back(obj); } -void QPdfEngine::addTextField(const QRectF &r, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength) +void QPdfEngine::addHiddenField(const QRectF &r, const QMap &data, const QString &value, const QString &name) { Q_D(QPdfEngine); uint obj = d->addXrefEntry(-1); @@ -282,7 +645,6 @@ void QPdfEngine::addTextField(const QRectF &r, const QString &text, const QStrin d->xprintf("<<\n" "/Type /Annot\n" "/Parent %d 0 R\n" - "/F 4\n" "/Rect[", d->formFieldList); d->xprintf("%s ", qt_real_to_string(rr.left(),buf)); d->xprintf("%s ", qt_real_to_string(rr.top(),buf)); @@ -291,11 +653,12 @@ void QPdfEngine::addTextField(const QRectF &r, const QString &text, const QStrin d->xprintf("]\n" "/BS<>\n" "/FT/Tx\n" + "/F 6" "/Subtype/Widget\n" "/P %d 0 R\n", d->pages.back()); - if (!text.isEmpty()) { + if (!value.isEmpty()) { d->xprintf("/V"); - d->printString(text); + d->printString(value); d->xprintf("\n"); } if (!name.isEmpty()) { @@ -303,16 +666,160 @@ void QPdfEngine::addTextField(const QRectF &r, const QString &text, const QStrin d->printString(name); d->xprintf("\n"); } + d->xprintf("/DA(/Helv 12 Tf 0 g)\n" + "/Ff 0\n" + ">>\n" + "endobj\n"); + d->currentPage->annotations.push_back(obj); + d->formFields.push_back(obj); +} +void QPdfEngine::addTextField(const QRectF &r, const QMap &data, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength) +{ + Q_D(QPdfEngine); + if (d->formFieldList == -1) d->formFieldList = d->requestObject(); + + if (!d->formFieldParents.contains(name)) { + QFormFieldParent* form = new QFormFieldParent(); + form->ref = d->requestObject(); + form->type = "Tx"; + form->name = name; + form->value = text; + if (data.contains("acroform-validation")) { + form->JSvalidation_ref = this->addJavaScript(data["acroform-validation"]); + } + else { + form->JSvalidation_ref = -1; + } + d->formFields.push_back(form->ref); + d->formFieldParents[name] = form; + } + int onBlurRef = -1; + + //handling javascript + if (data.contains("acroform-on-blur")) { + onBlurRef = this->addJavaScript(data["acroform-on-blur"]); + } + + uint obj = d->addXrefEntry(-1); + char buf[256]; + QRectF rr = d->pageMatrix().mapRect(r); + d->xprintf("<<\n" + "/Type /Annot\n" + "/Parent %d 0 R\n" + "/F 4\n" + "/Rect[", d->formFieldParents[name]->ref); + + d->xprintf("%s ", qt_real_to_string(rr.left(),buf)); + d->xprintf("%s ", qt_real_to_string(rr.top(),buf)); + d->xprintf("%s ", qt_real_to_string(rr.right(),buf)); + d->xprintf("%s", qt_real_to_string(rr.bottom(),buf)); + d->xprintf("]\n" + "/BS<>\n" + "/FT/Tx\n" + "/Subtype/Widget\n" + "/P %d 0 R\n", d->pages.back()); + // writing javascript actions + if (onBlurRef > 0) { + d->xprintf("/AA<>", onBlurRef); + } + // alignment + if (data.contains("acroform-align")) { + uint align = -1; + if (data["acroform-align"].compare("left", Qt::CaseInsensitive) == 0) { + align = 0; + } + else if (data["acroform-align"].compare("center", Qt::CaseInsensitive) == 0){ + align = 1; + } + else if (data["acroform-align"].compare("right", Qt::CaseInsensitive) == 0){ + align = 2; + } + if (align != -1) { + d->xprintf("/Q %d\n",align); + } + } + +// if (!text.isEmpty()) { +// d->xprintf("/V"); +// d->printString(text); +// d->xprintf("\n"); +// } if (maxLength >= 0) d->xprintf("/MaxLen %d\n",maxLength); - d->xprintf("/DA(/Helv 12 Tf 0 g)\n" - "/Ff %d\n" + d->xprintf("/Ff %d\n" ">>\n" "endobj\n", (readOnly?1:0)<<0 | (password?1:0)<<13 | (multiLine?1:0)<<12 ); d->currentPage->annotations.push_back(obj); - d->formFields.push_back(obj); + + d->formFieldParents[name]->children.push_back(obj); +} + +void QPdfEngine::addComboBox(const QRectF &r, const QMap &data, const QString &name,const QString &option_list,const QString &default_value, bool readOnly) { + Q_D(QPdfEngine); + //Note that the pdf spec sayes that we should add some sort of default appearence atleast for yes, which we dont ghost script provides one, however acroread does not + if (d->formFieldList == -1) d->formFieldList = d->requestObject(); + + if (!d->formFieldParents.contains(name)) { + QFormFieldParent* form = new QFormFieldParent(); + form->ref = d->requestObject(); + form->type = "Ch"; + form->name = name; + form->value = default_value; + form->option_list = option_list; + if (data.contains("acroform-validation")) { + form->JSvalidation_ref = this->addJavaScript(data["acroform-validation"]); + } + else { + form->JSvalidation_ref = -1; + } + d->formFields.push_back(form->ref); + d->formFieldParents[name] = form; + } + int onBlurRef = -1; + //handling javascript + if (data.contains("acroform-on-blur")) { + onBlurRef = this->addJavaScript(data["acroform-on-blur"]); + } + + uint obj = d->addXrefEntry(-1); + char buf[256]; + QRectF rr = d->pageMatrix().mapRect(r); + d->xprintf("<

pages.back()); + d->xprintf("/Parent %d 0 R", d->formFieldParents[name]->ref); + // writing javascript actions + if (onBlurRef != -1) { + d->xprintf("/AA<>", onBlurRef); + } + // alignment + if (data.contains("acroform-align")) { + uint align = -1; + if (data["acroform-align"].compare("left", Qt::CaseInsensitive) == 0) { + align = 0; + } + else if (data["acroform-align"].compare("center", Qt::CaseInsensitive) == 0){ + align = 1; + } + else if (data["acroform-align"].compare("right", Qt::CaseInsensitive) == 0){ + align = 2; + } + if (align != -1) { + d->xprintf("/Q %d\n",align); + } + } + d->xprintf("/F 4"); + d->xprintf("/Subtype/Widget/TI 1/Type/Annot"); + d->xprintf("/Rect["); + d->xprintf("%s ", qt_real_to_string(rr.left(),buf)); + d->xprintf("%s ", qt_real_to_string(rr.top(),buf)); + d->xprintf("%s ", qt_real_to_string(rr.right(),buf)); + d->xprintf("%s", qt_real_to_string(rr.bottom(),buf)); + d->xprintf("]>>\nendobj\n"); + + d->currentPage->annotations.push_back(obj); + //d->formFields.push_back(obj); + d->formFieldParents[name]->children.push_back(obj); } void QPdfEngine::drawPixmap (const QRectF &rectangle, const QPixmap &pixmap, const QRectF &sr, const QByteArray * data) @@ -1268,6 +1775,9 @@ void QPdfEnginePrivate::writeHeader() pageRoot = requestObject(); formFieldList = -1; + formChkBoxResourceChecked = -1; + formChkBoxResourceUnChecked = -1; + // graphics state graphicsState = addXrefEntry(-1); xprintf("<<\n" diff --git a/src/gui/painting/qprintengine_pdf_p.h b/src/gui/painting/qprintengine_pdf_p.h index 773706deeb9..108b6bd42a8 100644 --- a/src/gui/painting/qprintengine_pdf_p.h +++ b/src/gui/painting/qprintengine_pdf_p.h @@ -116,8 +116,15 @@ class QPdfEngine : public QPdfBaseEngine virtual void addHyperlink(const QRectF &r, const QUrl &url); virtual void addAnchor(const QRectF &r, const QString &name); virtual void addLink(const QRectF &r, const QString &anchor); - virtual void addTextField(const QRectF &r, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength); - virtual void addCheckBox(const QRectF &r, bool checked, const QString &name, bool readOnly); + virtual uint addJavaScript(const QString &script); + virtual void addHiddenField(const QRectF &, const QMap &data, const QString &value, const QString &name); + virtual void addTextField(const QRectF &r, const QMap &data, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength); + virtual void addPageJavaScript(const QMap &data, const QString &script); + virtual void addRadioBtnResources(QRectF rr, int *formRadioBtnResourceChecked, int *formRadioBtnResourceUnChecked); + virtual void addCheckBoxResources(); + virtual void addCheckBox(const QRectF &r, const QMap &data, bool checked, const QString &name, bool readOnly); + virtual void addRadioButton(const QRectF &r, const QMap &data, bool checked, const QString &name, const QString &value, bool readOnly); + virtual void addComboBox(const QRectF &r, const QMap &data, const QString &name, const QString &option_list, const QString &default_value, bool readOnly); // ### unused, should have something for this in QPrintEngine void setAuthor(const QString &author); @@ -135,7 +142,18 @@ class QPdfEngine : public QPdfBaseEngine QPrinter::PrinterState state; }; - +class QFormFieldParent +{ + public: + QVector children; + QString type; + QString name; + QString option_list; + QString value; + int JSonBlur_ref; + int JSvalidation_ref; + int ref; +}; class QPdfEnginePrivate : public QPdfBaseEnginePrivate { Q_DECLARE_PUBLIC(QPdfEngine) @@ -209,6 +227,10 @@ class QPdfEnginePrivate : public QPdfBaseEnginePrivate void embedFont(QFontSubset *font); int formFieldList; + int formChkBoxResourceChecked; + int formChkBoxResourceUnChecked; + QMap formFieldParents; + QMap pageJavaScripts; QVector formFields; QVector xrefPositions; QDataStream* stream;