Resolves: fdo#73936 make FormFieldDropDowns a real fieldportion

split the checkbox and list and use a field portion for the list.
That way it knows how to line break correctly wrt hardspaces and doesn't hang
when the situation arises.

Change-Id: I46d73f19ef8e51e7c21c8783ce70bb80d98a784c
diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx
index ea96e08..85ea319 100644
--- a/sw/source/core/text/inftxt.cxx
+++ b/sw/source/core/text/inftxt.cxx
@@ -1065,7 +1065,7 @@
    }
}

void SwTxtPaintInfo::DrawCheckBox( const SwFieldFormPortion &rPor, bool checked) const
void SwTxtPaintInfo::DrawCheckBox(const SwFieldFormCheckboxPortion &rPor, bool bChecked) const
{
    SwRect aIntersect;
    CalcRect( rPor, &aIntersect, 0 );
@@ -1087,7 +1087,8 @@
        m_pOut->SetLineColor( Color(0, 0, 0));
        m_pOut->SetFillColor();
        m_pOut->DrawRect( r );
        if (checked) {
        if (bChecked)
        {
            m_pOut->DrawLine(r.TopLeft(), r.BottomRight());
            m_pOut->DrawLine(r.TopRight(), r.BottomLeft());
        }
diff --git a/sw/source/core/text/inftxt.hxx b/sw/source/core/text/inftxt.hxx
index 5b133e8..24ce4cb 100644
--- a/sw/source/core/text/inftxt.hxx
+++ b/sw/source/core/text/inftxt.hxx
@@ -485,7 +485,7 @@
    **/
    void DrawBorder( const SwLinePortion &rPor ) const;

    void DrawCheckBox( const SwFieldFormPortion &rPor, bool checked) const;
    void DrawCheckBox(const SwFieldFormCheckboxPortion &rPor, bool bChecked) const;

    inline void NotifyURL( const SwLinePortion &rPor ) const
        { if( URLNotify() ) _NotifyURL( rPor ); }
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index 1ba49c8..5edca1d 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -54,6 +54,7 @@
#include <doc.hxx>
#include <pormulti.hxx>
#include <unotools/charclass.hxx>
#include <xmloff/odffields.hxx>

#include <vector>

@@ -872,10 +873,31 @@
    }
}

namespace {
    using namespace sw::mark;
    static OUString getCurrentListIndex(IFieldmark* pBM)
    {
        const IFieldmark::parameter_map_t* const pParameters = pBM->GetParameters();
        sal_Int32 nCurrentIdx = 0;
        const IFieldmark::parameter_map_t::const_iterator pResult = pParameters->find(OUString(ODF_FORMDROPDOWN_RESULT));
        if(pResult != pParameters->end())
            pResult->second >>= nCurrentIdx;

        const IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(OUString(ODF_FORMDROPDOWN_LISTENTRY));
        if (pListEntries != pParameters->end())
        {
            uno::Sequence< OUString > vListEntries;
            pListEntries->second >>= vListEntries;
            if (nCurrentIdx < vListEntries.getLength())
                return vListEntries[nCurrentIdx];
        }
        return OUString();
    }
}

/*************************************************************************
 *                      SwTxtFormatter::WhichTxtPor()
 *************************************************************************/

SwTxtPortion *SwTxtFormatter::WhichTxtPor( SwTxtFormatInfo &rInf ) const
{
    SwTxtPortion *pPor = 0;
@@ -907,7 +929,29 @@
                else if( rInf.GetTxt()[rInf.GetIdx()]==CH_TXT_ATR_FIELDEND )
                    pPor = new SwFieldMarkPortion();
                else if( rInf.GetTxt()[rInf.GetIdx()]==CH_TXT_ATR_FORMELEMENT )
                    pPor = new SwFieldFormPortion();
                {
                    SwTxtNode *pNd = const_cast<SwTxtNode *>(rInf.GetTxtFrm()->GetTxtNode());
                    const SwDoc *doc = pNd->GetDoc();
                    SwIndex aIndex(pNd, rInf.GetIdx());
                    SwPosition aPosition(*pNd, aIndex);
                    sw::mark::IFieldmark *pBM = doc->getIDocumentMarkAccess()->getFieldmarkFor(aPosition);
                    OSL_ENSURE(pBM != NULL, "Where is my form field bookmark???");
                    if (pBM != NULL)
                    {
                        if (pBM->GetFieldname( ) == ODF_FORMCHECKBOX)
                        {
                            pPor = new SwFieldFormCheckboxPortion();
                        }
                        else if (pBM->GetFieldname( ) == ODF_FORMDROPDOWN)
                        {
                            pPor = new SwFieldFormDropDownPortion(getCurrentListIndex(pBM));
                        }
                        else
                        {
                            assert( false );        // unknown type...
                        }
                    }
                }
            }
            if( !pPor )
            {
@@ -1004,7 +1048,6 @@
/*************************************************************************
 *                 SwTxtFormatter::WhichFirstPortion()
 *************************************************************************/

SwLinePortion *SwTxtFormatter::WhichFirstPortion(SwTxtFormatInfo &rInf)
{
    SwLinePortion *pPor = 0;
diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx
index 3a74264..61c5063 100644
--- a/sw/source/core/text/porfld.cxx
+++ b/sw/source/core/text/porfld.cxx
@@ -40,7 +40,6 @@
#include <porftn.hxx>
#include <accessibilityoptions.hxx>
#include <editeng/lrspitem.hxx>

#include <unicode/ubidi.h>

using namespace ::com::sun::star;
@@ -1314,4 +1313,9 @@
    return SwFldPortion::GetViewWidth( rInf );
}

SwFldPortion *SwFieldFormDropDownPortion::Clone(const OUString &rExpand) const
{
    return new SwFieldFormDropDownPortion(rExpand);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/porfld.hxx b/sw/source/core/text/porfld.hxx
index 3107a19..59ee2dc 100644
--- a/sw/source/core/text/porfld.hxx
+++ b/sw/source/core/text/porfld.hxx
@@ -247,6 +247,21 @@
    OUTPUT_OPERATOR_OVERRIDE
};

namespace sw { namespace mark {
    class IFieldmark;
} }

class SwFieldFormDropDownPortion : public SwFldPortion
{
public:
    SwFieldFormDropDownPortion(const OUString &rExpand)
        : SwFldPortion(rExpand)
    {
    }
    // Field cloner for SplitGlue
    virtual SwFldPortion *Clone( const OUString &rExpand ) const;
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/portxt.cxx b/sw/source/core/text/portxt.cxx
index 422d9d6..ebeef8e 100644
--- a/sw/source/core/text/portxt.cxx
+++ b/sw/source/core/text/portxt.cxx
@@ -900,32 +900,7 @@
    return false;
}

namespace {
    static sal_Int32 getCurrentListIndex( IFieldmark* pBM,
            OUString* io_pCurrentText = NULL )
    {
        const IFieldmark::parameter_map_t* const pParameters = pBM->GetParameters();
        sal_Int32 nCurrentIdx = 0;
        const IFieldmark::parameter_map_t::const_iterator pResult = pParameters->find(OUString(ODF_FORMDROPDOWN_RESULT));
        if(pResult != pParameters->end())
            pResult->second >>= nCurrentIdx;
        if(io_pCurrentText)
        {
            const IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(OUString(ODF_FORMDROPDOWN_LISTENTRY));
            if(pListEntries != pParameters->end())
            {
                uno::Sequence< OUString > vListEntries;
                pListEntries->second >>= vListEntries;
                if(nCurrentIdx < vListEntries.getLength())
                    *io_pCurrentText = vListEntries[nCurrentIdx];
            }
        }
        return nCurrentIdx;
    }
}

//FIXME Fieldbk
void SwFieldFormPortion::Paint( const SwTxtPaintInfo& rInf ) const
void SwFieldFormCheckboxPortion::Paint( const SwTxtPaintInfo& rInf ) const
{
    SwTxtNode* pNd = const_cast<SwTxtNode*>(rInf.GetTxtFrm()->GetTxtNode());
    const SwDoc *doc=pNd->GetDoc();
@@ -934,61 +909,30 @@

    IFieldmark* pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition );

    OSL_ENSURE( pBM,
        "SwFieldFormPortion::Paint(..)"
        " - Where is my form field bookmark???");
    OSL_ENSURE(pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX,
        "Where is my form field bookmark???");

    if ( pBM != NULL )
    if (pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX)
    {
        if ( pBM->GetFieldname( ) == ODF_FORMCHECKBOX )
        { // a checkbox...
            const ICheckboxFieldmark* pCheckboxFm = dynamic_cast< ICheckboxFieldmark* >(pBM);
            bool checked = pCheckboxFm && pCheckboxFm->IsChecked();
            rInf.DrawCheckBox(*this, checked);
        }
        else if ( pBM->GetFieldname( ) == ODF_FORMDROPDOWN )
        { // a list...
            OUString aTxt;
            getCurrentListIndex( pBM, &aTxt );
            rInf.DrawViewOpt( *this, POR_FLD );
            rInf.DrawText( aTxt, *this, 0, aTxt.getLength(), false );
        }
        else
        {
            assert(false); // unknown type...
        }
        const ICheckboxFieldmark* pCheckboxFm = dynamic_cast< ICheckboxFieldmark* >(pBM);
        bool bChecked = pCheckboxFm && pCheckboxFm->IsChecked();
        rInf.DrawCheckBox(*this, bChecked);
    }
}

bool SwFieldFormPortion::Format( SwTxtFormatInfo & rInf )
bool SwFieldFormCheckboxPortion::Format( SwTxtFormatInfo & rInf )
{
    SwTxtNode *pNd = const_cast < SwTxtNode * >( rInf.GetTxtFrm(  )->GetTxtNode(  ) );
    const SwDoc *doc = pNd->GetDoc(  );
    SwIndex aIndex( pNd, rInf.GetIdx(  ) );
    SwPosition aPosition( *pNd, aIndex );
    IFieldmark *pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition );
    OSL_ENSURE( pBM != NULL, "Where is my form field bookmark???" );
    if ( pBM != NULL )
    OSL_ENSURE(pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX, "Where is my form field bookmark???");
    if (pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX)
    {
        if ( pBM->GetFieldname( ) == ODF_FORMCHECKBOX )
        {
            Width( rInf.GetTxtHeight(  ) );
            Height( rInf.GetTxtHeight(  ) );
            SetAscent( rInf.GetAscent(  ) );
        }
        else if ( pBM->GetFieldname( ) == ODF_FORMDROPDOWN )
        {
            OUString aTxt;
            getCurrentListIndex( pBM, &aTxt );
            SwPosSize aPosSize = rInf.GetTxtSize( aTxt );
            Width( aPosSize.Width(  ) );
            Height( aPosSize.Height(  ) );
            SetAscent( rInf.GetAscent(  ) );
        }
        else
        {
            assert( false );        // unknown type...
        }
        Width( rInf.GetTxtHeight(  ) );
        Height( rInf.GetTxtHeight(  ) );
        SetAscent( rInf.GetAscent(  ) );
    }
    return false;
}
diff --git a/sw/source/core/text/portxt.hxx b/sw/source/core/text/portxt.hxx
index 2a9b275..b84dd2a 100644
--- a/sw/source/core/text/portxt.hxx
+++ b/sw/source/core/text/portxt.hxx
@@ -107,11 +107,12 @@
        virtual bool Format( SwTxtFormatInfo &rInf ) SAL_OVERRIDE;
};

class SwFieldFormPortion : public SwTxtPortion
class SwFieldFormCheckboxPortion : public SwTxtPortion
{
    public:
        inline SwFieldFormPortion() : SwTxtPortion()
            { }
public:
    SwFieldFormCheckboxPortion() : SwTxtPortion()
    {
    }
    virtual void Paint( const SwTxtPaintInfo &rInf ) const SAL_OVERRIDE;
    virtual bool Format( SwTxtFormatInfo &rInf ) SAL_OVERRIDE;
};