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.zol...@collabora.com> AuthorDate: Mon Mar 4 20:52:38 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@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.zol...@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: */ _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits