FormSubmitXml.vb
'' 
'' このコードは、DioDocs for PDF のサンプルの一部として提供されています。
'' © MESCIUS inc. All rights reserved.
'' 
Imports System.Drawing
Imports System.IO
Imports System.Linq
Imports System.Xml
Imports System.Text
Imports System.Collections.Generic
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Pdf.AcroForms
Imports GrapeCity.Documents.Pdf.Actions
Imports GrapeCity.Documents.Pdf.Annotations
Imports GrapeCity.Documents.Text

'' 新しい FormDataSubmit サンプルでは、より簡単にフォームデータを送信する方法を紹介しています。
'' 
'' このサンプルは、サーバーに送信できる AcroForm PDF を作成します。
'' これはサーバーに依存しており、送信されたデータを XML に入れ、その XML を
'' 同様のフォームを含む PDF にインポートし、ロードされたデータを含むフォームを
'' クライアントに送り返します。
'' フォームフィールドが満たされた生成後の PDF は、クライアントブラウザのデフォルト
'' の PDF ビューワに表示されることに注意してください。
'' このコードは FormSubmit に類似しています。
Public Class FormSubmitXml
    Function CreatePDF(ByVal stream As Stream) As Integer
        Dim doc = New GcPdfDocument()
        Dim page = doc.NewPage()

        Dim rc = Util.AddNote("フォームのフィールドに入力し、「送信」をクリックしてサーバーに" +
            "送り返します。サンプルサーバーは、送信されたデータを XML に入れ、" +
            "その XML を別の互換性のあるフォームで PDF にフィードし、送信された" +
            "データで満たされた結果のフォームをブラウザに送り返します。" +
            "送信されたデータを含むフォームは、ブラウザのデフォルトの PDF ビューワで" +
            "開かれ、「送信」および「リセット」ボタンはありません。", page)

        Dim g = page.Graphics
        Dim tf = New TextFormat() With {.Font = StandardFonts.Times, .FontSize = 14}
        Dim ip = New PointF(72, rc.Bottom + 36)
        Dim fldOffset = 72 * 2 + 46
        Dim fldHeight = tf.FontSize * 1.2F
        Dim dY = 32

        '' テキストフィールド。
        g.DrawString("First name:", tf, ip)
        Dim fldFirstName = New TextField() With {.Name = "FirstName", .Value = "John"}
        fldFirstName.Widget.Page = page
        fldFirstName.Widget.Rect = New RectangleF(ip.X + fldOffset, ip.Y, 72 * 3, fldHeight)
        fldFirstName.Widget.DefaultAppearance.Font = tf.Font
        fldFirstName.Widget.DefaultAppearance.FontSize = tf.FontSize
        doc.AcroForm.Fields.Add(fldFirstName)
        ip.Y += dY

        '' テキストフィールド。
        g.DrawString("Last name:", tf, ip)
        Dim fldLastName = New TextField() With {.Name = "LastName", .Value = "Smith"}
        fldLastName.Widget.Page = page
        fldLastName.Widget.Rect = New RectangleF(ip.X + fldOffset, ip.Y, 72 * 3, fldHeight)
        fldLastName.Widget.DefaultAppearance.Font = tf.Font
        fldLastName.Widget.DefaultAppearance.FontSize = tf.FontSize
        doc.AcroForm.Fields.Add(fldLastName)
        ip.Y += dY

        '' チェックボックス。
        g.DrawString("Subscribe to Mailing List:", tf, ip)
        Dim fldCheckbox = New CheckBoxField() With {.Name = "Subscribe", .Checked = True}
        fldCheckbox.Widget.Page = page
        fldCheckbox.Widget.Rect = New RectangleF(ip.X + fldOffset, ip.Y, fldHeight, fldHeight)
        doc.AcroForm.Fields.Add(fldCheckbox)
        ip.Y += dY

        '' 複数行テキストボックス。
        g.DrawString("Additional information:", tf, ip)
        Dim fldAdditionalInfo = New TextField() With {.Name = "AdditionalInfo", .Multiline = True}
        fldAdditionalInfo.Widget.Page = page
        fldAdditionalInfo.Widget.Rect = New RectangleF(ip.X + fldOffset, ip.Y, 72 * 3, fldHeight * 2)
        fldAdditionalInfo.Widget.DefaultAppearance.Font = tf.Font
        fldAdditionalInfo.Widget.DefaultAppearance.FontSize = tf.FontSize
        doc.AcroForm.Fields.Add(fldAdditionalInfo)
        ip.Y += dY * 2

        '' フォーム送信ボタン。
        Dim btnSubmit = New PushButtonField()
        btnSubmit.Widget.Rect = New RectangleF(ip.X + fldOffset, ip.Y, 72, fldHeight)
        btnSubmit.Widget.ButtonAppearance.Caption = "Submit"
        btnSubmit.Widget.Highlighting = HighlightingMode.Invert
        btnSubmit.Widget.Page = page

        '' 送信用の URL。
        btnSubmit.Widget.Activate = New ActionSubmitForm("/Samples/HandleFormSubmitXml")
        doc.AcroForm.Fields.Add(btnSubmit)

        '' フォームリセットボタン。
        Dim btnReset = New PushButtonField()
        btnReset.Widget.Rect = New RectangleF(ip.X + fldOffset + 72 * 1.5F, ip.Y, 72, fldHeight)
        btnReset.Widget.ButtonAppearance.Caption = "Reset"
        btnReset.Widget.Highlighting = HighlightingMode.Invert
        btnReset.Widget.Page = page
        btnReset.Widget.Activate = New ActionResetForm()
        doc.AcroForm.Fields.Add(btnReset)
        ip.Y += dY

        '' PDF ドキュメントを保存します。
        doc.Save(stream)
        Return doc.Pages.Count
    End Function

    '' 
    '' メモ:以下のコードは、このサンプルで準備されたフォームが送信されるときに Web サンプルブラウザ
    '' コントローラーによって使用され、CreatePDF() メソッドによって直接呼び出されることはありません。
    ''     

    '' GcPdfDocument を作成し、AcroForm PDF を ロードして、
    '' GcPdfDocument.ImportFormDataFromXML() メソッドを使用してデータを入力します。
    '' 
    '' このメソッドは、このサンプルで準備されたフォームがユーザーによって送信
    '' されると、サンプルコントローラーによって呼び出されます。サンプルコント
    '' ローラは、クライアントの応答を解析し、送信されたフィールド値で満たされた
    '' 「値」コレクションを構築し、このメソッドを呼び出して XML を準備し、新しく
    '' 作成した PDF にインポートして、結果の PDF をコントローラに返し、それを
    '' クライアントに戻します。
    Public Shared Function ImportFormData(ByVal values As List(Of FieldExportEntry)) As Stream
        Dim pdf = New GcPdfDocument()
        Using fs = New FileStream(Path.Combine("Resources", "PDFs", "ImportFormXML.pdf"), FileMode.Open, FileAccess.Read)
            pdf.Load(fs)
            Using ms = New MemoryStream()
                SaveFieldsToXML(values, ms)
                ms.Seek(0, SeekOrigin.Begin)
                pdf.ImportFormDataFromXML(ms)
            End Using
            Dim outMs = New MemoryStream()
            pdf.Save(outMs)
            outMs.Seek(0, SeekOrigin.Begin)
            Return outMs
        End Using
    End Function

    '' XML にエクスポートするためのフォームフィールドとその値を表します。
    Public Class FieldExportEntry
        Public Property Name As String
        Public Property Values As List(Of String)
        '' 注意:このサンプルは子フィールドをサポートしていません。
        '' public List<FieldTreeNode> Children { get set }
    End Class

    '' フィールドとその値をストリームに保存します。
    '' 
    '' このメソッドは GcPdfDocument.ExportFormDataToXML()に似て
    '' いますが、次の重要な制限があります。
    '' - 子フィールド(field.Children コレクション)はサポートしていません。
    '' - 有効な XML 名(xfdf:original)ではない名前のフィールドは処理しません。
    Public Shared Sub SaveFieldsToXML(ByVal values As List(Of FieldExportEntry), ByVal stream As Stream)
        Dim xws = New XmlWriterSettings() With
            {
                .Indent = True,
                .CloseOutput = False,
                .Encoding = Encoding.UTF8
            }
        Using xw = XmlWriter.Create(stream, xws)
            xw.WriteStartElement("fields")
            xw.WriteAttributeString("xmlns", "xfdf", Nothing, "http:''ns.adobe.com/xfdf-transition/")
            For Each ftn In values
                xw.WriteStartElement(ftn.Name)
                For Each v In ftn.Values
                    xw.WriteStartElement("value")
                    '' メモ:配列の値はクライアント PDF ビューワによって形成され、 'on'
                    '' チェックボックス値を 'true' として表しますが、ImportFormDataFromXML
                    '' は 'on'値が "Yes"として表されることを期待します(これが、Acrobat の
                    '' ように ExportFormDataToXML を動作させる仕組みです)。 これは、
                    '' このサンプルのためだけに行った、迅速で汚いハックです。
                    If v = "true" Then
                        xw.WriteString("Yes")
                    Else
                        xw.WriteString(v)
                    End If
                    xw.WriteEndElement()
                Next
                xw.WriteEndElement()
            Next
            xw.WriteEndElement()
        End Using
    End Sub
End Class