[Libreoffice-commits] core.git: include/vcl sw/inc sw/Library_sw.mk sw/source

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Sat Mar 9 20:59:12 UTC 2019


 include/vcl/window.hxx                          |    2 
 sw/Library_sw.mk                                |    1 
 sw/inc/IDocumentMarkAccess.hxx                  |    4 
 sw/inc/strings.hrc                              |    3 
 sw/inc/view.hxx                                 |    4 
 sw/source/core/crsr/DropDownFormFieldButton.cxx |  255 ++++++++++++++++++++++++
 sw/source/core/crsr/bookmrk.cxx                 |   41 +++
 sw/source/core/crsr/crsrsh.cxx                  |    2 
 sw/source/core/doc/docbm.cxx                    |   61 +++++
 sw/source/core/inc/DropDownFormFieldButton.hxx  |   54 +++++
 sw/source/core/inc/MarkManager.hxx              |   10 
 sw/source/core/inc/bookmrk.hxx                  |   14 +
 sw/source/core/text/itrform2.cxx                |    2 
 sw/source/core/text/porfld.cxx                  |   16 +
 sw/source/core/text/porfld.hxx                  |    8 
 sw/source/uibase/docvw/edtwin.cxx               |    6 
 sw/source/uibase/shells/textsh1.cxx             |   14 -
 sw/source/uibase/uiview/view.cxx                |    3 
 sw/source/uibase/uiview/viewling.cxx            |  110 ----------
 19 files changed, 480 insertions(+), 130 deletions(-)

New commits:
commit 10be5b6ce972dff517f3ceed41cab04d3e051f57
Author:     Tamás Zolnai <tamas.zolnai at collabora.com>
AuthorDate: Mon Mar 4 20:52:38 2019 +0100
Commit:     Tamás Zolnai <tamas.zolnai at collabora.com>
CommitDate: Sat Mar 9 21:58:40 2019 +0100

    MSForms: Add a drop-down button for drop-down form field
    
    * Introduce a editing frame with a button for drop-down form field.
    ** The frame is mouse transparent.
    ** Pushing the button opens the popup window with the items of the field.
    * The button is visible when the cursor is inside the field.
    
    Change-Id: I5c7db138d14380899fee046c95a5afe14cfea213
    Reviewed-on: https://gerrit.libreoffice.org/68961
    Tested-by: Jenkins
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>

diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx
index 4294c4f1e520..fff03ed1ffb5 100644
--- a/include/vcl/window.hxx
+++ b/include/vcl/window.hxx
@@ -598,7 +598,7 @@ protected:
 
     SAL_DLLPRIVATE void                 ImplInvalidate( const vcl::Region* rRegion, InvalidateFlags nFlags );
 
-    SAL_DLLPRIVATE WindowHitTest        ImplHitTest( const Point& rFramePos );
+    virtual WindowHitTest               ImplHitTest( const Point& rFramePos );
 
     SAL_DLLPRIVATE void                 ImplSetMouseTransparent( bool bTransparent );
 
diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk
index 939838d3dfc2..1cd8d8cb1613 100644
--- a/sw/Library_sw.mk
+++ b/sw/Library_sw.mk
@@ -150,6 +150,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
     sw/source/core/crsr/crsrsh \
     sw/source/core/crsr/crstrvl \
     sw/source/core/crsr/crstrvl1 \
+    sw/source/core/crsr/DropDownFormFieldButton \
     sw/source/core/crsr/findattr \
     sw/source/core/crsr/findcoll \
     sw/source/core/crsr/findfmt \
diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx
index cbd523c012b1..d7111112612f 100644
--- a/sw/inc/IDocumentMarkAccess.hxx
+++ b/sw/inc/IDocumentMarkAccess.hxx
@@ -27,6 +27,7 @@
 class SwPaM;
 struct SwPosition;
 class SwTextNode;
+class SwCursorShell;
 
 namespace sw { namespace mark {
     class SaveBookmark; // FIXME: Ugly: SaveBookmark is a core-internal class, and should not be used in the interface
@@ -258,6 +259,9 @@ class IDocumentMarkAccess
         virtual void deleteFieldmarkAt(const SwPosition& rPos) = 0;
         virtual ::sw::mark::IFieldmark* changeNonTextFieldmarkType(::sw::mark::IFieldmark* pFieldmark, const OUString& rNewType) = 0;
 
+        virtual void NotifyCursorUpdate(const SwCursorShell& rCursorShell) = 0;
+        virtual void ClearFieldActivation() = 0;
+
         // Annotation Marks
         virtual const_iterator_t getAnnotationMarksBegin() const = 0;
         virtual const_iterator_t getAnnotationMarksEnd() const = 0;
diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc
index c8671f015e91..2093a2d8c14f 100644
--- a/sw/inc/strings.hrc
+++ b/sw/inc/strings.hrc
@@ -1328,6 +1328,9 @@
 #define STR_MENU_UP                             NC_("STR_MENU_UP", "~Upwards")
 #define STR_MENU_DOWN                           NC_("STR_MENU_DOWN", "Do~wnwards")
 
+
+#define STR_DROP_DOWN_EMPTY_LIST                NC_("STR_DROP_DOWN_EMPTY_LIST", "No Item specified")
+
 /*--------------------------------------------------------------------
     Description: Classification strings
  --------------------------------------------------------------------*/
diff --git a/sw/inc/view.hxx b/sw/inc/view.hxx
index 66c61eef6dc5..d2fade9a1901 100644
--- a/sw/inc/view.hxx
+++ b/sw/inc/view.hxx
@@ -208,7 +208,6 @@ class SW_DLLPUBLIC SwView: public SfxViewShell
     std::unique_ptr<SwPostItMgr> m_pPostItMgr;
 
     SelectionType       m_nSelectionType;
-    VclPtr<FloatingWindow> m_pFieldPopup;
     sal_uInt16          m_nPageCnt;
 
     // current draw mode
@@ -265,8 +264,6 @@ class SW_DLLPUBLIC SwView: public SfxViewShell
 
     DECL_DLLPRIVATE_LINK( TimeoutHdl, Timer*, void );
 
-    DECL_DLLPRIVATE_LINK( FieldPopupModeEndHdl, FloatingWindow*, void );
-
     inline long                  GetXScroll() const;
     inline long                  GetYScroll() const;
     SAL_DLLPRIVATE Point         AlignToPixel(const Point& rPt) const;
@@ -423,7 +420,6 @@ public:
 
     void            SpellError(LanguageType eLang);
     bool            ExecSpellPopup( const Point& rPt );
-    void                ExecFieldPopup( const Point& rPt, sw::mark::IFieldmark *fieldBM );
     void            ExecSmartTagPopup( const Point& rPt );
 
     DECL_LINK( OnlineSpellCallback, SpellCallbackInfo&, void );
diff --git a/sw/source/core/crsr/DropDownFormFieldButton.cxx b/sw/source/core/crsr/DropDownFormFieldButton.cxx
new file mode 100644
index 000000000000..a4614da8932e
--- /dev/null
+++ b/sw/source/core/crsr/DropDownFormFieldButton.cxx
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <DropDownFormFieldButton.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <edtwin.hxx>
+#include <basegfx/color/bcolortools.hxx>
+#include <viewopt.hxx>
+#include <bookmrk.hxx>
+#include <vcl/floatwin.hxx>
+#include <vcl/event.hxx>
+#include <vcl/lstbox.hxx>
+#include <xmloff/odffields.hxx>
+#include <IMark.hxx>
+#include <view.hxx>
+#include <docsh.hxx>
+#include <strings.hrc>
+
+/**
+ * Popup dialog for drop-down form field showing the list items of the field.
+ * The user can select the item using this popup while filling in a form.
+ */
+class SwFieldDialog : public FloatingWindow
+{
+private:
+    VclPtr<ListBox> aListBox;
+    sw::mark::IFieldmark* pFieldmark;
+
+    DECL_LINK(MyListBoxHandler, ListBox&, void);
+
+public:
+    SwFieldDialog(SwEditWin* parent, sw::mark::IFieldmark* fieldBM, long nMinListWidth);
+    virtual ~SwFieldDialog() override;
+    virtual void dispose() override;
+};
+
+SwFieldDialog::SwFieldDialog(SwEditWin* parent, sw::mark::IFieldmark* fieldBM, long nMinListWidth)
+    : FloatingWindow(parent, WB_BORDER | WB_SYSTEMWINDOW)
+    , aListBox(VclPtr<ListBox>::Create(this))
+    , pFieldmark(fieldBM)
+{
+    if (fieldBM != nullptr)
+    {
+        const sw::mark::IFieldmark::parameter_map_t* const pParameters = fieldBM->GetParameters();
+
+        OUString sListKey = ODF_FORMDROPDOWN_LISTENTRY;
+        sw::mark::IFieldmark::parameter_map_t::const_iterator pListEntries
+            = pParameters->find(sListKey);
+        if (pListEntries != pParameters->end())
+        {
+            css::uno::Sequence<OUString> vListEntries;
+            pListEntries->second >>= vListEntries;
+            for (OUString const& i : vListEntries)
+                aListBox->InsertEntry(i);
+        }
+        else
+        {
+            aListBox->InsertEntry(SwResId(STR_DROP_DOWN_EMPTY_LIST));
+        }
+
+        // Select the current one
+        OUString sResultKey = ODF_FORMDROPDOWN_RESULT;
+        sw::mark::IFieldmark::parameter_map_t::const_iterator pResult
+            = pParameters->find(sResultKey);
+        if (pResult != pParameters->end())
+        {
+            sal_Int32 nSelection = -1;
+            pResult->second >>= nSelection;
+            aListBox->SelectEntryPos(nSelection);
+        }
+    }
+
+    Size lbSize(aListBox->GetOptimalSize());
+    lbSize.AdjustWidth(50);
+    lbSize.AdjustHeight(20);
+    lbSize.setWidth(std::max(lbSize.Width(), nMinListWidth));
+    aListBox->SetSizePixel(lbSize);
+    aListBox->SetSelectHdl(LINK(this, SwFieldDialog, MyListBoxHandler));
+    aListBox->Show();
+
+    SetSizePixel(lbSize);
+}
+
+SwFieldDialog::~SwFieldDialog() { disposeOnce(); }
+
+void SwFieldDialog::dispose()
+{
+    aListBox.disposeAndClear();
+    FloatingWindow::dispose();
+}
+
+IMPL_LINK(SwFieldDialog, MyListBoxHandler, ListBox&, rBox, void)
+{
+    if (!rBox.IsTravelSelect())
+    {
+        OUString sSelection = rBox.GetSelectedEntry();
+        if (sSelection == SwResId(STR_DROP_DOWN_EMPTY_LIST))
+        {
+            EndPopupMode();
+            return;
+        }
+
+        sal_Int32 nSelection = rBox.GetSelectedEntryPos();
+        if (nSelection >= 0)
+        {
+            OUString sKey = ODF_FORMDROPDOWN_RESULT;
+            (*pFieldmark->GetParameters())[sKey] <<= nSelection;
+            pFieldmark->Invalidate();
+            SwView& rView = static_cast<SwEditWin*>(GetParent())->GetView();
+            rView.GetDocShell()->SetModified();
+        }
+
+        EndPopupMode();
+    }
+}
+
+DropDownFormFieldButton::DropDownFormFieldButton(SwEditWin* pEditWin,
+                                                 sw::mark::DropDownFieldmark& rFieldmark)
+    : MenuButton(pEditWin, WB_DIALOGCONTROL)
+    , m_rFieldmark(rFieldmark)
+{
+    assert(GetParent());
+    assert(dynamic_cast<SwEditWin*>(GetParent()));
+}
+
+DropDownFormFieldButton::~DropDownFormFieldButton() { disposeOnce(); }
+
+void DropDownFormFieldButton::dispose()
+{
+    m_pFieldPopup.disposeAndClear();
+    MenuButton::dispose();
+}
+
+void DropDownFormFieldButton::CalcPosAndSize(const SwRect& rPortionPaintArea)
+{
+    assert(GetParent());
+
+    Point aBoxPos = GetParent()->LogicToPixel(rPortionPaintArea.Pos());
+    Size aBoxSize = GetParent()->LogicToPixel(rPortionPaintArea.SSize());
+
+    // First calculate the size of the frame around the field
+    int nPadding = aBoxSize.Height() / 4;
+    aBoxPos.AdjustX(-nPadding);
+    aBoxPos.AdjustY(-nPadding);
+    aBoxSize.AdjustWidth(2 * nPadding);
+    aBoxSize.AdjustHeight(2 * nPadding);
+
+    m_aFieldFramePixel = tools::Rectangle(aBoxPos, aBoxSize);
+
+    // Then extend the size with the button area
+    aBoxSize.AdjustWidth(GetParent()->LogicToPixel(rPortionPaintArea.SSize()).Height());
+
+    SetPosSizePixel(aBoxPos, aBoxSize);
+}
+
+void DropDownFormFieldButton::MouseButtonUp(const MouseEvent&)
+{
+    assert(GetParent());
+
+    Point aPixPos = GetPosPixel();
+    aPixPos.AdjustY(GetSizePixel().Height());
+
+    m_pFieldPopup = VclPtr<SwFieldDialog>::Create(static_cast<SwEditWin*>(GetParent()),
+                                                  &m_rFieldmark, GetSizePixel().Width());
+    m_pFieldPopup->SetPopupModeEndHdl(LINK(this, DropDownFormFieldButton, FieldPopupModeEndHdl));
+
+    tools::Rectangle aRect(GetParent()->OutputToScreenPixel(aPixPos), Size(0, 0));
+    m_pFieldPopup->StartPopupMode(aRect, FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus);
+    Invalidate();
+}
+
+IMPL_LINK_NOARG(DropDownFormFieldButton, FieldPopupModeEndHdl, FloatingWindow*, void)
+{
+    m_pFieldPopup.disposeAndClear();
+    m_rFieldmark.Invalidate();
+    // Hide the button here and make it visible later, to make transparent background work with SAL_USE_VCLPLUGIN=gen
+    Show(false);
+    Invalidate();
+}
+
+static basegfx::BColor lcl_GetFillColor(const basegfx::BColor& rLineColor, double aLuminance)
+{
+    basegfx::BColor aHslLine = basegfx::utils::rgb2hsl(rLineColor);
+    aHslLine.setZ(aLuminance);
+    return basegfx::utils::hsl2rgb(aHslLine);
+}
+
+void DropDownFormFieldButton::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+    SetMapMode(MapMode(MapUnit::MapPixel));
+
+    //const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+    Color aLineColor = COL_BLACK;
+    Color aFillColor
+        = Color(lcl_GetFillColor(aLineColor.getBColor(), (m_pFieldPopup ? 0.5 : 0.75)));
+
+    // Draw the frame around the field
+    // GTK3 backend cuts down the frame's top and left border, to avoid that add a padding around the frame
+    int nPadding = 1;
+    Point aPos(nPadding, nPadding);
+    Size aSize(m_aFieldFramePixel.GetSize().Width() - nPadding,
+               m_aFieldFramePixel.GetSize().Height() - 2 * nPadding);
+    const tools::Rectangle aFrameRect(tools::Rectangle(aPos, aSize));
+    rRenderContext.SetLineColor(aLineColor);
+    rRenderContext.SetFillColor(COL_TRANSPARENT);
+    rRenderContext.DrawRect(aFrameRect);
+
+    // Draw the button next to the frame
+    Point aButtonPos(aFrameRect.TopLeft());
+    aButtonPos.AdjustX(aFrameRect.GetSize().getWidth() - 1);
+    Size aButtonSize(aFrameRect.GetSize());
+    aButtonSize.setWidth(GetSizePixel().getWidth() - aFrameRect.getWidth() - nPadding);
+    const tools::Rectangle aButtonRect(tools::Rectangle(aButtonPos, aButtonSize));
+
+    // Background & border
+    rRenderContext.SetLineColor(aLineColor);
+    rRenderContext.SetFillColor(aFillColor);
+    rRenderContext.DrawRect(aButtonRect);
+
+    // the arrowhead
+    rRenderContext.SetLineColor(aLineColor);
+    rRenderContext.SetFillColor(aLineColor);
+
+    Point aCenter(aButtonPos.X() + (aButtonSize.Width() / 2),
+                  aButtonPos.Y() + (aButtonSize.Height() / 2));
+    Size aArrowSize(aButtonSize.Width() / 4, aButtonSize.Height() / 10);
+
+    tools::Polygon aPoly(3);
+    aPoly.SetPoint(Point(aCenter.X() - aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 0);
+    aPoly.SetPoint(Point(aCenter.X() + aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 1);
+    aPoly.SetPoint(Point(aCenter.X(), aCenter.Y() + aArrowSize.Height()), 2);
+    rRenderContext.DrawPolygon(aPoly);
+}
+
+WindowHitTest DropDownFormFieldButton::ImplHitTest(const Point& rFramePos)
+{
+    // We need to check whether the position hits the button (the frame should be mouse transparent)
+    WindowHitTest aResult = MenuButton::ImplHitTest(rFramePos);
+    if (aResult != WindowHitTest::Inside)
+        return aResult;
+    else
+    {
+        return rFramePos.X() >= m_aFieldFramePixel.Right() ? WindowHitTest::Inside
+                                                           : WindowHitTest::Transparent;
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sw/source/core/crsr/bookmrk.cxx b/sw/source/core/crsr/bookmrk.cxx
index 4bb6d6780295..2e2a5417d0a0 100644
--- a/sw/source/core/crsr/bookmrk.cxx
+++ b/sw/source/core/crsr/bookmrk.cxx
@@ -37,6 +37,7 @@
 #include <comphelper/random.hxx>
 #include <comphelper/anytostring.hxx>
 #include <sal/log.hxx>
+#include <edtwin.hxx>
 
 using namespace ::sw::mark;
 using namespace ::com::sun::star;
@@ -481,11 +482,13 @@ namespace sw { namespace mark
 
     DropDownFieldmark::DropDownFieldmark(const SwPaM& rPaM)
         : Fieldmark(rPaM)
+        , m_pButton(nullptr)
     {
     }
 
     DropDownFieldmark::~DropDownFieldmark()
     {
+        m_pButton.disposeAndClear();
     }
 
     void DropDownFieldmark::InitDoc(SwDoc* const io_pDoc, sw::mark::InsertMode const eMode)
@@ -511,6 +514,44 @@ namespace sw { namespace mark
         lcl_RemoveFieldMarks(this, pDoc,
                 CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FORMELEMENT);
     }
+
+    void DropDownFieldmark::SetPortionPaintArea(const SwRect& rPortionPaintArea)
+    {
+        if(m_aPortionPaintArea == rPortionPaintArea &&
+           m_pButton && m_pButton->IsVisible())
+            return;
+
+        m_aPortionPaintArea = rPortionPaintArea;
+        if(m_pButton)
+        {
+            m_pButton->Show();
+            m_pButton->CalcPosAndSize(m_aPortionPaintArea);
+            m_pButton->Invalidate();
+        }
+    }
+
+    void DropDownFieldmark::ShowButton(SwEditWin* pEditWin)
+    {
+        if(pEditWin)
+        {
+            if(!m_pButton)
+                m_pButton = VclPtr<DropDownFormFieldButton>::Create(pEditWin, *this);
+            m_pButton->CalcPosAndSize(m_aPortionPaintArea);
+            m_pButton->Show();
+        }
+    }
+
+    void DropDownFieldmark::HideButton()
+    {
+        if(m_pButton)
+            m_pButton->Show(false);
+    }
+
+    void DropDownFieldmark::RemoveButton()
+    {
+        if(m_pButton)
+            m_pButton.disposeAndClear();
+    }
 }}
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx
index af7a56200564..f04c7a06e1f8 100644
--- a/sw/source/core/crsr/crsrsh.cxx
+++ b/sw/source/core/crsr/crsrsh.cxx
@@ -2009,6 +2009,8 @@ void SwCursorShell::UpdateCursor( sal_uInt16 eFlags, bool bIdleEnd )
 
     if( m_bSVCursorVis )
         m_pVisibleCursor->Show(); // show again
+
+    getIDocumentMarkAccess()->NotifyCursorUpdate(*this);
 }
 
 void SwCursorShell::RefreshBlockCursor()
diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx
index d34508e1b254..840462916484 100644
--- a/sw/source/core/doc/docbm.cxx
+++ b/sw/source/core/doc/docbm.cxx
@@ -54,6 +54,7 @@
 #include <viscrs.hxx>
 #include <edimp.hxx>
 #include <tools/datetimeutils.hxx>
+#include <view.hxx>
 
 using namespace ::sw::mark;
 
@@ -372,6 +373,7 @@ namespace sw { namespace mark
         , m_vFieldmarks()
         , m_vAnnotationMarks()
         , m_pDoc(&rDoc)
+        , m_pLastActiveFieldmark(nullptr)
     { }
 
     ::sw::mark::IMark* MarkManager::makeMark(const SwPaM& rPaM,
@@ -956,6 +958,9 @@ namespace sw { namespace mark
                     IDocumentMarkAccess::iterator_t ppFieldmark = lcl_FindMark(m_vFieldmarks, *ppMark);
                     if ( ppFieldmark != m_vFieldmarks.end() )
                     {
+                        if(m_pLastActiveFieldmark == ppFieldmark->get())
+                            ClearFieldActivation();
+
                         m_vFieldmarks.erase(ppFieldmark);
                         ret.reset(new LazyFieldmarkDeleter(*ppMark, m_pDoc));
                     }
@@ -1031,6 +1036,7 @@ namespace sw { namespace mark
 
     void MarkManager::clearAllMarks()
     {
+        ClearFieldActivation();
         m_vFieldmarks.clear();
         m_vBookmarks.clear();
 
@@ -1117,10 +1123,61 @@ namespace sw { namespace mark
         SwPaM aPaM(pFieldmark->GetMarkPos());
 
         // Remove the old fieldmark and create a new one with the new type
-        deleteFieldmarkAt(*aPaM.GetPoint());
-        return makeNoTextFieldBookmark(aPaM, sName, rNewType);
+        if(aPaM.GetPoint()->nContent > 0)
+        {
+            --aPaM.GetPoint()->nContent;
+            SwPosition aNewPos (aPaM.GetPoint()->nNode, aPaM.GetPoint()->nContent);
+            deleteFieldmarkAt(aNewPos);
+            return makeNoTextFieldBookmark(aPaM, sName, rNewType);
+        }
+        return nullptr;
+    }
+
+    void MarkManager::NotifyCursorUpdate(const SwCursorShell& rCursorShell)
+    {
+        SwView* pSwView = dynamic_cast<SwView *>(rCursorShell.GetSfxViewShell());
+        if(!pSwView)
+            return;
+
+        SwEditWin& rEditWin = pSwView->GetEditWin();
+        SwPosition aPos(*rCursorShell.GetCursor()->GetPoint());
+        IFieldmark* pFieldBM = getFieldmarkFor(aPos);
+        DropDownFieldmark* pNewActiveFieldmark = nullptr;
+        if ((!pFieldBM || pFieldBM->GetFieldname() != ODF_FORMDROPDOWN)
+            && aPos.nContent.GetIndex() > 0 )
+        {
+            --aPos.nContent;
+            pFieldBM = getFieldmarkFor(aPos);
+        }
+
+        if ( pFieldBM && pFieldBM->GetFieldname() == ODF_FORMDROPDOWN )
+        {
+            if (m_pLastActiveFieldmark != pFieldBM)
+            {
+                DropDownFieldmark* pDropDownFm = dynamic_cast<DropDownFieldmark*>(pFieldBM);
+                pDropDownFm->ShowButton(&rEditWin);
+                pNewActiveFieldmark = pDropDownFm;
+            }
+            else
+            {
+                pNewActiveFieldmark = m_pLastActiveFieldmark;
+            }
+        }
+
+        if(pNewActiveFieldmark != m_pLastActiveFieldmark)
+        {
+            ClearFieldActivation();
+            m_pLastActiveFieldmark = pNewActiveFieldmark;
+        }
     }
 
+    void MarkManager::ClearFieldActivation()
+    {
+        if(m_pLastActiveFieldmark)
+            m_pLastActiveFieldmark->RemoveButton();
+
+        m_pLastActiveFieldmark = nullptr;
+    }
 
     IFieldmark* MarkManager::getDropDownFor(const SwPosition& rPos) const
     {
diff --git a/sw/source/core/inc/DropDownFormFieldButton.hxx b/sw/source/core/inc/DropDownFormFieldButton.hxx
new file mode 100644
index 000000000000..e8b9153cb1a6
--- /dev/null
+++ b/sw/source/core/inc/DropDownFormFieldButton.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SW_SOURCE_CORE_TEXT_DROPDOWNFORMEFIELDBUTTO_HXX
+#define INCLUDED_SW_SOURCE_CORE_TEXT_DROPDOWNFORMEFIELDBUTTO_HXX
+
+#include <vcl/menubtn.hxx>
+#include <swrect.hxx>
+
+class SwFieldFormDropDownPortion;
+class SwEditWin;
+class FloatingWindow;
+namespace sw
+{
+namespace mark
+{
+class DropDownFieldmark;
+}
+}
+
+/**
+ * This button is shown when the cursor is in a drop-down form field.
+ * The user can select an item of the field using this button while filling in a form.
+ */
+class DropDownFormFieldButton : public MenuButton
+{
+public:
+    DropDownFormFieldButton(SwEditWin* pEditWin, sw::mark::DropDownFieldmark& rFieldMark);
+    virtual ~DropDownFormFieldButton() override;
+    virtual void dispose() override;
+
+    void CalcPosAndSize(const SwRect& rPortionPaintArea);
+
+    virtual void MouseButtonUp(const MouseEvent& rMEvt) override;
+    DECL_LINK(FieldPopupModeEndHdl, FloatingWindow*, void);
+
+    virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+    virtual WindowHitTest ImplHitTest(const Point& rFramePos) override;
+
+private:
+    tools::Rectangle m_aFieldFramePixel;
+    sw::mark::DropDownFieldmark& m_rFieldmark;
+    VclPtr<FloatingWindow> m_pFieldPopup;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx
index 71ad5c913d6c..11291f7b881a 100644
--- a/sw/source/core/inc/MarkManager.hxx
+++ b/sw/source/core/inc/MarkManager.hxx
@@ -24,11 +24,16 @@
 #include <IDocumentMarkAccess.hxx>
 #include <unordered_set>
 #include <unordered_map>
+#include <memory>
+
+class SwCursorShell;
 
 namespace sw {
     namespace mark {
     typedef std::unordered_map<OUString, sal_Int32> MarkBasenameMapUniqueOffset_t;
 
+    class DropDownFieldmark;
+
     class MarkManager
         : virtual public IDocumentMarkAccess
     {
@@ -88,6 +93,9 @@ namespace sw {
             virtual void deleteFieldmarkAt(const SwPosition& rPos) override;
             virtual ::sw::mark::IFieldmark* changeNonTextFieldmarkType(::sw::mark::IFieldmark* pFieldmark, const OUString& rNewType) override;
 
+            virtual void NotifyCursorUpdate(const SwCursorShell& rCursorShell) override;
+            virtual void ClearFieldActivation() override;
+
             void dumpAsXml(xmlTextWriterPtr pWriter) const;
 
             // Annotation Marks
@@ -125,6 +133,8 @@ namespace sw {
             container_t m_vAnnotationMarks;
 
             SwDoc * const m_pDoc;
+
+            sw::mark::DropDownFieldmark* m_pLastActiveFieldmark;
     };
     } // namespace mark
 }
diff --git a/sw/source/core/inc/bookmrk.hxx b/sw/source/core/inc/bookmrk.hxx
index 3bde575ab399..9f6c8af89f34 100644
--- a/sw/source/core/inc/bookmrk.hxx
+++ b/sw/source/core/inc/bookmrk.hxx
@@ -29,6 +29,8 @@
 #include <osl/diagnose.h>
 #include <IMark.hxx>
 #include <swserv.hxx>
+#include <swrect.hxx>
+#include "DropDownFormFieldButton.hxx"
 
 namespace com {
     namespace sun {
@@ -42,6 +44,7 @@ namespace com {
 
 struct SwPosition;  // fwd Decl. wg. UI
 class SwDoc;
+class SwEditWin;
 
 namespace sw {
     namespace mark {
@@ -267,6 +270,17 @@ namespace sw {
             virtual ~DropDownFieldmark() override;
             virtual void InitDoc(SwDoc* const io_pDoc, sw::mark::InsertMode eMode) override;
             virtual void ReleaseDoc(SwDoc* const pDoc) override;
+
+            // This method should be called only by the portion so we can now the portion's painting area
+            void SetPortionPaintArea(const SwRect& rPortionPaintArea);
+
+            void ShowButton(SwEditWin* pEditWin);
+            void HideButton();
+            void RemoveButton();
+
+        private:
+            SwRect m_aPortionPaintArea;
+            VclPtr<DropDownFormFieldButton> m_pButton;
         };
     }
 }
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index 2697f3022639..fa56ada86eba 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -908,7 +908,7 @@ SwTextPortion *SwTextFormatter::WhichTextPor( SwTextFormatInfo &rInf ) const
                     }
                     else if (pBM->GetFieldname( ) == ODF_FORMDROPDOWN)
                     {
-                        pPor = new SwFieldFormDropDownPortion(sw::mark::ExpandFieldmark(pBM));
+                        pPor = new SwFieldFormDropDownPortion(pBM, sw::mark::ExpandFieldmark(pBM));
                     }
                     /* we need to check for ODF_FORMTEXT for scenario having FormFields inside FORMTEXT.
                      * Otherwise file will crash on open.
diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx
index e2a482e870dc..2a52f9b539c7 100644
--- a/sw/source/core/text/porfld.cxx
+++ b/sw/source/core/text/porfld.cxx
@@ -43,6 +43,7 @@
 #include <accessibilityoptions.hxx>
 #include <editeng/lrspitem.hxx>
 #include <unicode/ubidi.h>
+#include <bookmrk.hxx>
 
 using namespace ::com::sun::star;
 
@@ -1310,7 +1311,20 @@ sal_uInt16 SwCombinedPortion::GetViewWidth( const SwTextSizeInfo &rInf ) const
 
 SwFieldPortion *SwFieldFormDropDownPortion::Clone(const OUString &rExpand) const
 {
-    return new SwFieldFormDropDownPortion(rExpand);
+    return new SwFieldFormDropDownPortion(m_pFieldMark, rExpand);
+}
+
+void SwFieldFormDropDownPortion::Paint( const SwTextPaintInfo &rInf ) const
+{
+    SwFieldPortion::Paint( rInf );
+
+    ::sw::mark::DropDownFieldmark* pDropDownField = dynamic_cast< ::sw::mark::DropDownFieldmark* >(m_pFieldMark);
+    if(pDropDownField)
+    {
+        SwRect aPaintArea;
+        rInf.CalcRect( *this, &aPaintArea );
+        pDropDownField->SetPortionPaintArea(aPaintArea);
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/porfld.hxx b/sw/source/core/text/porfld.hxx
index 4434f1e8c577..069ab3798060 100644
--- a/sw/source/core/text/porfld.hxx
+++ b/sw/source/core/text/porfld.hxx
@@ -217,12 +217,18 @@ namespace sw { namespace mark {
 class SwFieldFormDropDownPortion : public SwFieldPortion
 {
 public:
-    explicit SwFieldFormDropDownPortion(const OUString &rExpand)
+    explicit SwFieldFormDropDownPortion(sw::mark::IFieldmark *pFieldMark, const OUString &rExpand)
         : SwFieldPortion(rExpand)
+        , m_pFieldMark(pFieldMark)
     {
     }
     // Field cloner for SplitGlue
     virtual SwFieldPortion *Clone( const OUString &rExpand ) const override;
+
+    virtual void Paint( const SwTextPaintInfo &rInf ) const override;
+
+private:
+    sw::mark::IFieldmark* m_pFieldMark;
 };
 
 #endif
diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx
index 22458d77b710..85d24b1d61c5 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -4627,12 +4627,6 @@ void SwEditWin::MouseButtonUp(const MouseEvent& rMEvt)
                                         rCheckboxFm.SetChecked(!rCheckboxFm.IsChecked());
                                         rCheckboxFm.Invalidate();
                                         rSh.InvalidateWindows( m_rView.GetVisArea() );
-                                    } else if ( fieldBM->GetFieldname() == ODF_FORMDROPDOWN ) {
-                                        m_rView.ExecFieldPopup( aDocPt, fieldBM );
-                                        fieldBM->Invalidate();
-                                        rSh.InvalidateWindows( m_rView.GetVisArea() );
-                                    } else {
-                                        // unknown type..
                                     }
                                 }
                             }
diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx
index 65484c32e748..c70e84156b97 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -120,6 +120,8 @@
 #include <numrule.hxx>
 #include <memory>
 #include <xmloff/odffields.hxx>
+#include <swabstdlg.hxx>
+#include <bookmrk.hxx>
 
 using namespace ::com::sun::star;
 using namespace com::sun::star::beans;
@@ -1382,10 +1384,14 @@ void SwTextShell::Execute(SfxRequest &rReq)
         {
             SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
             ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateDropDownFormFieldDialog(rWrtSh.GetView().GetFrameWeld(), pFieldBM));
-            pDlg->Execute();
-            pFieldBM->Invalidate();
-            rWrtSh.InvalidateWindows( rWrtSh.GetView().GetVisArea() );
-            rWrtSh.UpdateCursor(); // cursor position might be invalid
+            if (pDlg->Execute() == RET_OK)
+            {
+                pFieldBM->Invalidate();
+                rWrtSh.InvalidateWindows( rWrtSh.GetView().GetVisArea() );
+                rWrtSh.UpdateCursor(); // cursor position might be invalid
+                // Hide the button here and make it visible later, to make transparent background work with SAL_USE_VCLPLUGIN=gen
+                dynamic_cast<::sw::mark::DropDownFieldmark*>(pFieldBM)->HideButton();
+            }
         }
         else
         {
diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx
index 63febf29b44a..59fc540e0d35 100644
--- a/sw/source/uibase/uiview/view.cxx
+++ b/sw/source/uibase/uiview/view.cxx
@@ -1067,6 +1067,9 @@ SwView::~SwView()
     SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "");
     SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY");
 
+    // Need to remove activated field's button before disposing EditWin.
+    GetWrtShell().getIDocumentMarkAccess()->ClearFieldActivation();
+
     GetViewFrame()->GetWindow().RemoveChildEventListener( LINK( this, SwView, WindowChildEventListener ) );
     m_pPostItMgr.reset();
 
diff --git a/sw/source/uibase/uiview/viewling.cxx b/sw/source/uibase/uiview/viewling.cxx
index 7d6aac2913d9..3ac2ebcadd3e 100644
--- a/sw/source/uibase/uiview/viewling.cxx
+++ b/sw/source/uibase/uiview/viewling.cxx
@@ -825,114 +825,4 @@ void SwView::ExecSmartTagPopup( const Point& rPt )
     m_pWrtShell->LockView( bOldViewLock );
 }
 
-class SwFieldDialog : public FloatingWindow
-{
-private:
-    VclPtr<ListBox> aListBox;
-    IFieldmark *pFieldmark;
-
-    DECL_LINK( MyListBoxHandler, ListBox&, void );
-
-public:
-    SwFieldDialog( SwEditWin* parent, IFieldmark *fieldBM );
-    virtual ~SwFieldDialog() override;
-    virtual void dispose() override;
-};
-
-SwFieldDialog::SwFieldDialog( SwEditWin* parent, IFieldmark *fieldBM ) :
-    FloatingWindow( parent, WB_BORDER | WB_SYSTEMWINDOW ),
-    aListBox(VclPtr<ListBox>::Create(this)),
-    pFieldmark( fieldBM )
-{
-    if ( fieldBM != nullptr )
-    {
-        const IFieldmark::parameter_map_t* const pParameters = fieldBM->GetParameters();
-
-        OUString sListKey = ODF_FORMDROPDOWN_LISTENTRY;
-        IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find( sListKey );
-        if(pListEntries != pParameters->end())
-        {
-            Sequence< OUString > vListEntries;
-            pListEntries->second >>= vListEntries;
-            for( OUString const & i : vListEntries)
-                aListBox->InsertEntry(i);
-        }
-
-        // Select the current one
-        OUString sResultKey = ODF_FORMDROPDOWN_RESULT;
-        IFieldmark::parameter_map_t::const_iterator pResult = pParameters->find( sResultKey );
-        if ( pResult != pParameters->end() )
-        {
-            sal_Int32 nSelection = -1;
-            pResult->second >>= nSelection;
-            aListBox->SelectEntryPos( nSelection );
-        }
-    }
-
-    Size lbSize(aListBox->GetOptimalSize());
-    lbSize.AdjustWidth(50 );
-    lbSize.AdjustHeight(20 );
-    aListBox->SetSizePixel(lbSize);
-    aListBox->SetSelectHdl( LINK( this, SwFieldDialog, MyListBoxHandler ) );
-    aListBox->Show();
-
-    SetSizePixel( lbSize );
-}
-
-SwFieldDialog::~SwFieldDialog()
-{
-    disposeOnce();
-}
-
-void SwFieldDialog::dispose()
-{
-    aListBox.disposeAndClear();
-    FloatingWindow::dispose();
-}
-
-IMPL_LINK( SwFieldDialog, MyListBoxHandler, ListBox&, rBox, void )
-{
-    if ( !rBox.IsTravelSelect() )
-    {
-        sal_Int32 selection = rBox.GetSelectedEntryPos();
-        if ( selection >= 0 )
-        {
-            OUString sKey = ODF_FORMDROPDOWN_RESULT;
-            (*pFieldmark->GetParameters())[ sKey ] <<= selection;
-            pFieldmark->Invalidate();
-            SwView& rView = static_cast<SwEditWin*>( GetParent() )->GetView();
-            rView.GetDocShell()->SetModified();
-        }
-
-        EndPopupMode();
-    }
-}
-
-IMPL_LINK_NOARG(SwView, FieldPopupModeEndHdl, FloatingWindow*, void)
-{
-    m_pFieldPopup.disposeAndClear();
-}
-
-void SwView::ExecFieldPopup( const Point& rPt, IFieldmark *fieldBM )
-{
-    // Don't show popup if there is no list item
-    auto pListEntries = fieldBM->GetParameters()->find( ODF_FORMDROPDOWN_LISTENTRY );
-    Sequence< OUString > vListEntries;
-    if(pListEntries != fieldBM->GetParameters()->end())
-    {
-        pListEntries->second >>= vListEntries;
-    }
-
-    if(vListEntries.getLength() == 0)
-        return;
-
-    const Point aPixPos = GetEditWin().LogicToPixel( rPt );
-
-    m_pFieldPopup = VclPtr<SwFieldDialog>::Create( m_pEditWin, fieldBM );
-    m_pFieldPopup->SetPopupModeEndHdl( LINK( this, SwView, FieldPopupModeEndHdl ) );
-
-    tools::Rectangle aRect( m_pEditWin->OutputToScreenPixel( aPixPos ), Size( 0, 0 ) );
-    m_pFieldPopup->StartPopupMode( aRect, FloatWinPopupFlags::Down|FloatWinPopupFlags::GrabFocus );
-}
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list