summaryrefslogtreecommitdiff
path: root/dbaccess/source
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2020-08-19 14:59:33 +0100
committerCaolán McNamara <caolanm@redhat.com>2020-08-26 17:14:31 +0200
commitfd2ea8e03510c6a99ec8be6228b7422f6c5b182b (patch)
tree0d79547d16857ce9f0f885fe11adb23189654833 /dbaccess/source
parent57666b8ba70f27c7250ef32f4cb9e7660e258521 (diff)
weld OApplicationSwapWindow
Change-Id: I71d24494b5fe7dd2949876944ab9aff41330ad50 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101027 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'dbaccess/source')
-rw-r--r--dbaccess/source/ui/app/AppIconControl.cxx174
-rw-r--r--dbaccess/source/ui/app/AppIconControl.hxx42
-rw-r--r--dbaccess/source/ui/app/AppSwapWindow.cxx89
-rw-r--r--dbaccess/source/ui/app/AppSwapWindow.hxx20
-rw-r--r--dbaccess/source/ui/app/AppView.cxx4
-rw-r--r--dbaccess/source/ui/inc/TableWindowListBox.hxx2
6 files changed, 215 insertions, 116 deletions
diff --git a/dbaccess/source/ui/app/AppIconControl.cxx b/dbaccess/source/ui/app/AppIconControl.cxx
index 514580014f79..84edc6a27f15 100644
--- a/dbaccess/source/ui/app/AppIconControl.cxx
+++ b/dbaccess/source/ui/app/AppIconControl.cxx
@@ -21,18 +21,53 @@
#include <core_resource.hxx>
#include <strings.hrc>
#include <bitmaps.hlst>
-#include <vcl/image.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/event.hxx>
+#include <vcl/i18nhelp.hxx>
+#include <vcl/mnemonic.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
#include <callbacks.hxx>
#include <AppElementType.hxx>
-using namespace ::dbaui;
-OApplicationIconControl::OApplicationIconControl(vcl::Window* _pParent)
- : SvtIconChoiceCtrl(_pParent,WB_ICON | WB_NOCOLUMNHEADER | WB_HIGHLIGHTFRAME | /*!WB_NOSELECTION |*/
- WB_TABSTOP | WB_CLIPCHILDREN | WB_NOVSCROLL | WB_SMART_ARRANGE | WB_NOHSCROLL | WB_CENTER)
- ,DropTargetHelper(this)
- ,m_pActionListener(nullptr)
+namespace dbaui
{
+class OApplicationIconControlDropTarget final : public DropTargetHelper
+{
+private:
+ OApplicationIconControl& m_rControl;
+
+public:
+ OApplicationIconControlDropTarget(OApplicationIconControl& rControl)
+ : DropTargetHelper(rControl.GetDrawingArea()->get_drop_target())
+ , m_rControl(rControl)
+ {
+ }
+
+ virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
+ {
+ return m_rControl.AcceptDrop(rEvt);
+ }
+
+ virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
+ {
+ return m_rControl.ExecuteDrop(rEvt);
+ }
+};
+
+OApplicationIconControl::OApplicationIconControl(std::unique_ptr<weld::ScrolledWindow> xScroll)
+ : SfxThumbnailView(std::move(xScroll), nullptr)
+ , m_pActionListener(nullptr)
+ , m_nMaxWidth(0)
+ , m_nMaxHeight(0)
+{
+ mnVItemSpace = 6; // row spacing
+ DrawMnemonics(true);
+}
+
+void OApplicationIconControl::Fill()
+{
static const struct CategoryDescriptor
{
const char* pLabelResId;
@@ -44,63 +79,128 @@ OApplicationIconControl::OApplicationIconControl(vcl::Window* _pParent)
{ RID_STR_FORMS_CONTAINER, E_FORM, BMP_FORMFOLDER_TREE_L },
{ RID_STR_REPORTS_CONTAINER, E_REPORT, BMP_REPORTFOLDER_TREE_L }
};
+
for (const CategoryDescriptor& aCategorie : aCategories)
{
- SvxIconChoiceCtrlEntry* pEntry = InsertEntry(
- DBA_RES(aCategorie.pLabelResId) ,
- Image(StockImage::Yes, OUString::createFromAscii(aCategorie.aImageResId)));
- if ( pEntry )
- pEntry->SetUserData( new ElementType( aCategorie.eType ) );
+ // E_TABLE is 0, but 0 means void so use id of enum + 1
+ std::unique_ptr<ThumbnailViewItem> xItem(new ThumbnailViewItem(*this, aCategorie.eType + 1));
+ xItem->mbBorder = false;
+ xItem->maPreview1 = BitmapEx(OUString::createFromAscii(aCategorie.aImageResId));
+ const Size& rSize = xItem->maPreview1.GetSizePixel();
+ m_nMaxWidth = std::max(m_nMaxWidth, rSize.Width());
+ m_nMaxHeight = std::max(m_nMaxHeight, rSize.Height());
+ xItem->maTitle = DBA_RES(aCategorie.pLabelResId);
+ m_nMaxWidth = std::max<long>(m_nMaxWidth, GetTextWidth(xItem->maTitle));
+ AppendItem(std::move(xItem));
}
- SetChoiceWithCursor();
- SetSelectionMode(SelectionMode::Single);
+ const int nMargin = 12;
+ const int nWidthRequest = m_nMaxWidth + 2 * nMargin;
+ set_size_request(nWidthRequest, -1);
+ // we expect a Resize at which point we'll set the item sizes based on our final size
}
-OApplicationIconControl::~OApplicationIconControl()
+ElementType OApplicationIconControl::GetSelectedItem() const
+{
+ for (const auto& rItem : mItemList)
+ {
+ if (!rItem->mbSelected)
+ continue;
+ return static_cast<ElementType>(rItem->mnId - 1);
+ }
+ return E_NONE;
+}
+
+void OApplicationIconControl::createIconAutoMnemonics(MnemonicGenerator& rMnemonics)
{
- disposeOnce();
+ for (const auto& rItem : mItemList)
+ rMnemonics.RegisterMnemonic(rItem->maTitle);
+
+ // exchange texts with generated mnemonics
+ for (auto& rItem : mItemList)
+ rItem->maTitle = rMnemonics.CreateMnemonic(rItem->maTitle);
}
-void OApplicationIconControl::dispose()
+void OApplicationIconControl::Resize()
{
- sal_Int32 nCount = GetEntryCount();
- for ( sal_Int32 i = 0; i < nCount; ++i )
+ // fill the full width of the allocated area and give two lines of space to
+ // center the title in
+ setItemDimensions(GetOutputSizePixel().Width(), m_nMaxHeight, GetTextHeight() * 2, 0);
+ SfxThumbnailView::Resize();
+}
+
+bool OApplicationIconControl::IsMnemonicChar(sal_Unicode cChar, ElementType& rType) const
+{
+ bool bRet = false;
+
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+ for (const auto& rItem : mItemList)
{
- SvxIconChoiceCtrlEntry* pEntry = GetEntry( i );
- if ( pEntry )
+ if (rI18nHelper.MatchMnemonic(rItem->maTitle, cChar))
{
- delete static_cast<ElementType*>(pEntry->GetUserData());
- pEntry->SetUserData(nullptr);
+ bRet = true;
+ rType = static_cast<ElementType>(rItem->mnId - 1);
+ break;
}
}
- DropTargetHelper::dispose();
- SvtIconChoiceCtrl::dispose();
+
+ return bRet;
}
-sal_Int8 OApplicationIconControl::AcceptDrop( const AcceptDropEvent& _rEvt )
+bool OApplicationIconControl::DoKeyShortCut(const KeyEvent& rKEvt)
{
- sal_Int8 nDropOption = DND_ACTION_NONE;
- if ( m_pActionListener )
+ bool bMod2 = rKEvt.GetKeyCode().IsMod2();
+ sal_Unicode cChar = rKEvt.GetCharCode();
+ ElementType eType(E_NONE);
+ if (bMod2 && cChar && IsMnemonicChar(cChar, eType))
{
+ // shortcut is clicked
+ deselectItems();
+ SelectItem(eType + 1);
+ return true;
+ }
+
+ return false;
+}
+
+bool OApplicationIconControl::KeyInput(const KeyEvent& rKEvt)
+{
+ return DoKeyShortCut(rKEvt) || SfxThumbnailView::KeyInput(rKEvt);
+}
+
+void OApplicationIconControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ SfxThumbnailView::SetDrawingArea(pDrawingArea);
+ m_xDropTarget.reset(new OApplicationIconControlDropTarget(*this));
+}
- SvxIconChoiceCtrlEntry* pEntry = GetEntry(_rEvt.maPosPixel);
- if ( pEntry )
+sal_Int8 OApplicationIconControl::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ sal_Int8 nDropOption = DND_ACTION_NONE;
+ if (m_pActionListener)
+ {
+ sal_uInt16 nEntry = GetItemId(rEvt.maPosPixel);
+ if (nEntry)
{
- SetCursor(pEntry);
- nDropOption = m_pActionListener->queryDrop( _rEvt, GetDataFlavorExVector() );
+ deselectItems();
+ SelectItem(nEntry);
+ nDropOption = m_pActionListener->queryDrop(rEvt, m_xDropTarget->GetDataFlavorExVector());
}
}
-
return nDropOption;
}
-sal_Int8 OApplicationIconControl::ExecuteDrop( const ExecuteDropEvent& _rEvt )
+sal_Int8 OApplicationIconControl::ExecuteDrop(const ExecuteDropEvent& rEvt)
{
- if ( m_pActionListener )
- return m_pActionListener->executeDrop( _rEvt );
-
+ if (m_pActionListener)
+ m_pActionListener->executeDrop(rEvt);
return DND_ACTION_NONE;
}
+OApplicationIconControl::~OApplicationIconControl()
+{
+}
+
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppIconControl.hxx b/dbaccess/source/ui/app/AppIconControl.hxx
index 38408af60687..7b29018c377b 100644
--- a/dbaccess/source/ui/app/AppIconControl.hxx
+++ b/dbaccess/source/ui/app/AppIconControl.hxx
@@ -19,28 +19,48 @@
#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPICONCONTROL_HXX
#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPICONCONTROL_HXX
-#include <vcl/ivctrl.hxx>
+#include <sfx2/thumbnailview.hxx>
+#include <sfx2/thumbnailviewitem.hxx>
#include <vcl/transfer.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/weld.hxx>
+#include <AppElementType.hxx>
+
+class MnemonicGenerator;
namespace dbaui
{
class IControlActionListener;
- class OApplicationIconControl :public SvtIconChoiceCtrl
- ,public DropTargetHelper
+ class IconControl;
+ class OApplicationIconControlDropTarget;
+
+ class OApplicationIconControl final : public SfxThumbnailView
{
- IControlActionListener* m_pActionListener;
+ std::unique_ptr<OApplicationIconControlDropTarget> m_xDropTarget;
+ IControlActionListener* m_pActionListener;
+
+ long m_nMaxWidth;
+ long m_nMaxHeight;
+
+ bool IsMnemonicChar(sal_Unicode cChar, ElementType& rType) const;
public:
- explicit OApplicationIconControl(vcl::Window* _pParent);
+ explicit OApplicationIconControl(std::unique_ptr<weld::ScrolledWindow> xScroll);
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ virtual void Resize() override;
+ bool DoKeyShortCut(const KeyEvent& rKEvt);
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
virtual ~OApplicationIconControl() override;
- virtual void dispose() override;
- void setControlActionListener( IControlActionListener* _pListener ) { m_pActionListener = _pListener; }
+ ElementType GetSelectedItem() const;
+
+ void setControlActionListener( IControlActionListener* _pListener ) { m_pActionListener = _pListener; }
+ void Fill();
+
+ void createIconAutoMnemonics(MnemonicGenerator& rMnemonics);
- protected:
- // DropTargetHelper overridables
- virtual sal_Int8 AcceptDrop( const AcceptDropEvent& _rEvt ) override;
- virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& _rEvt ) override;
+ sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt);
+ sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt);
};
}
#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPICONCONTROL_HXX
diff --git a/dbaccess/source/ui/app/AppSwapWindow.cxx b/dbaccess/source/ui/app/AppSwapWindow.cxx
index e291bdb8a6ac..9ab50e8a0b4c 100644
--- a/dbaccess/source/ui/app/AppSwapWindow.cxx
+++ b/dbaccess/source/ui/app/AppSwapWindow.cxx
@@ -31,18 +31,28 @@ using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::container;
-OApplicationSwapWindow::OApplicationSwapWindow( vcl::Window* _pParent, OAppBorderWindow& _rBorderWindow )
- :Window(_pParent,WB_DIALOGCONTROL )
- ,m_aIconControl(VclPtr<OApplicationIconControl>::Create(this))
- ,m_eLastType(E_NONE)
- ,m_rBorderWin( _rBorderWindow )
+OApplicationSwapWindow::OApplicationSwapWindow(vcl::Window* pParent, OAppBorderWindow& rBorderWindow)
+ : InterimItemWindow(pParent, "dbaccess/ui/appswapwindow.ui", "AppSwapWindow")
+ , m_xIconControl(new OApplicationIconControl(m_xBuilder->weld_scrolled_window("scroll")))
+ , m_xIconControlWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xIconControl))
+ , m_eLastType(E_NONE)
+ , m_rBorderWin(rBorderWindow)
{
+ m_xContainer->set_stack_background();
+
ImplInitSettings();
- m_aIconControl->SetClickHdl(LINK(this, OApplicationSwapWindow, OnContainerSelectHdl));
- m_aIconControl->setControlActionListener( &m_rBorderWin.getView()->getAppController() );
- m_aIconControl->SetHelpId(HID_APP_SWAP_ICONCONTROL);
- m_aIconControl->Show();
+ m_xIconControl->SetHelpId(HID_APP_SWAP_ICONCONTROL);
+ m_xIconControl->Fill();
+ m_xIconControl->setItemStateHdl(LINK(this, OApplicationSwapWindow, OnContainerSelectHdl));
+ m_xIconControl->setControlActionListener( &m_rBorderWin.getView()->getAppController() );
+}
+
+void OApplicationSwapWindow::GetFocus()
+{
+ if (m_xIconControl)
+ m_xIconControl->GrabFocus();
+ InterimItemWindow::GetFocus();
}
OApplicationSwapWindow::~OApplicationSwapWindow()
@@ -52,21 +62,9 @@ OApplicationSwapWindow::~OApplicationSwapWindow()
void OApplicationSwapWindow::dispose()
{
- m_aIconControl.disposeAndClear();
- vcl::Window::dispose();
-}
-
-void OApplicationSwapWindow::Resize()
-{
- Size aFLSize = LogicToPixel(Size(8, 0), MapMode(MapUnit::MapAppFont));
- long nX = 0;
- if ( m_aIconControl->GetEntryCount() != 0 )
- nX = m_aIconControl->GetBoundingBox( m_aIconControl->GetEntry(0) ).GetWidth() + aFLSize.Width();
-
- Size aOutputSize = GetOutputSize();
-
- m_aIconControl->SetPosSizePixel( Point(static_cast<long>((aOutputSize.Width() - nX)*0.5), 0) ,Size(nX,aOutputSize.Height()));
- m_aIconControl->ArrangeIcons();
+ m_xIconControlWin.reset();
+ m_xIconControl.reset();
+ InterimItemWindow::dispose();
}
void OApplicationSwapWindow::ImplInitSettings()
@@ -99,32 +97,27 @@ void OApplicationSwapWindow::DataChanged( const DataChangedEvent& rDCEvt )
void OApplicationSwapWindow::clearSelection()
{
- m_aIconControl->SetNoSelection();
- SvxIconChoiceCtrlEntry* pEntry = m_aIconControl->GetSelectedEntry();
- if ( pEntry )
- m_aIconControl->InvalidateEntry(pEntry);
- m_aIconControl->GetClickHdl().Call(m_aIconControl.get());
+ m_xIconControl->deselectItems();
+ onContainerSelected(E_NONE);
}
-void OApplicationSwapWindow::createIconAutoMnemonics( MnemonicGenerator& _rMnemonics )
+void OApplicationSwapWindow::createIconAutoMnemonics(MnemonicGenerator& rMnemonics)
{
- m_aIconControl->CreateAutoMnemonics( _rMnemonics );
+ m_xIconControl->createIconAutoMnemonics(rMnemonics);
}
bool OApplicationSwapWindow::interceptKeyInput( const KeyEvent& _rEvent )
{
const vcl::KeyCode& rKeyCode = _rEvent.GetKeyCode();
if ( rKeyCode.GetModifier() == KEY_MOD2 )
- return m_aIconControl->DoKeyInput( _rEvent );
-
+ return m_xIconControl->DoKeyShortCut( _rEvent );
// not handled
return false;
}
ElementType OApplicationSwapWindow::getElementType() const
{
- SvxIconChoiceCtrlEntry* pEntry = m_aIconControl->GetSelectedEntry();
- return pEntry ? *static_cast<ElementType*>(pEntry->GetUserData()) : E_NONE;
+ return m_xIconControl->GetSelectedItem();
}
bool OApplicationSwapWindow::onContainerSelected( ElementType _eType )
@@ -143,13 +136,11 @@ bool OApplicationSwapWindow::onContainerSelected( ElementType _eType )
return false;
}
-IMPL_LINK(OApplicationSwapWindow, OnContainerSelectHdl, SvtIconChoiceCtrl*, _pControl, void)
+IMPL_LINK(OApplicationSwapWindow, OnContainerSelectHdl, const ThumbnailViewItem*, pEntry, void)
{
- SvxIconChoiceCtrlEntry* pEntry = _pControl->GetSelectedEntry();
- ElementType eType = E_NONE;
- if ( pEntry )
+ if (pEntry->mbSelected)
{
- eType = *static_cast<ElementType*>(pEntry->GetUserData());
+ ElementType eType = static_cast<ElementType>(pEntry->mnId - 1);
onContainerSelected( eType ); // i87582
}
}
@@ -159,22 +150,10 @@ IMPL_LINK_NOARG(OApplicationSwapWindow, ChangeToLastSelected, void*, void)
selectContainer(m_eLastType);
}
-void OApplicationSwapWindow::selectContainer(ElementType _eType)
+void OApplicationSwapWindow::selectContainer(ElementType eType)
{
- sal_Int32 nCount = m_aIconControl->GetEntryCount();
- SvxIconChoiceCtrlEntry* pEntry = nullptr;
- for (sal_Int32 i=0; i < nCount; ++i)
- {
- pEntry = m_aIconControl->GetEntry(i);
- if ( pEntry && *static_cast<ElementType*>(pEntry->GetUserData()) == _eType )
- break;
- pEntry = nullptr;
- }
-
- if ( pEntry )
- m_aIconControl->SetCursor(pEntry); // this call also initiates a onContainerSelected call
- else
- onContainerSelected( _eType );
+ m_xIconControl->deselectItems();
+ m_xIconControl->SelectItem(eType + 1); // will trigger onContainerSelected
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppSwapWindow.hxx b/dbaccess/source/ui/app/AppSwapWindow.hxx
index 62f58c15248d..b63d563e496b 100644
--- a/dbaccess/source/ui/app/AppSwapWindow.hxx
+++ b/dbaccess/source/ui/app/AppSwapWindow.hxx
@@ -20,32 +20,36 @@
#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX
#include <IClipBoardTest.hxx>
+#include <vcl/InterimItemWindow.hxx>
#include <vcl/vclptr.hxx>
#include "AppIconControl.hxx"
#include <AppElementType.hxx>
+class MnemonicGenerator;
+
namespace dbaui
{
class OAppBorderWindow;
- class OApplicationSwapWindow : public vcl::Window,
- public IClipboardTest
+ class OApplicationSwapWindow : public InterimItemWindow
+ , public IClipboardTest
{
- VclPtr<OApplicationIconControl> m_aIconControl;
+ std::unique_ptr<OApplicationIconControl> m_xIconControl;
+ std::unique_ptr<weld::CustomWeld> m_xIconControlWin;
ElementType m_eLastType;
OAppBorderWindow& m_rBorderWin;
void ImplInitSettings();
- DECL_LINK( OnContainerSelectHdl, SvtIconChoiceCtrl*, void );
+ DECL_LINK( OnContainerSelectHdl, const ThumbnailViewItem*, void );
DECL_LINK( ChangeToLastSelected, void*, void );
protected:
virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
public:
- OApplicationSwapWindow( vcl::Window* _pParent, OAppBorderWindow& _rBorderWindow );
+ OApplicationSwapWindow(vcl::Window* pParent, OAppBorderWindow& rBorderWindow);
virtual ~OApplicationSwapWindow() override;
// Window overrides
virtual void dispose() override;
- virtual void Resize() override;
+ virtual void GetFocus() override;
bool isCutAllowed() override { return false; }
bool isCopyAllowed() override { return false; }
@@ -54,10 +58,6 @@ namespace dbaui
void cut() override { }
void paste() override { }
- sal_Int32 GetEntryCount() const { return m_aIconControl->GetEntryCount(); }
- SvxIconChoiceCtrlEntry* GetEntry( sal_uLong nPos ) const { return m_aIconControl->GetEntry(nPos); }
- tools::Rectangle GetBoundingBox( SvxIconChoiceCtrlEntry* pEntry ) const { return m_aIconControl->GetBoundingBox(pEntry); }
-
/** automatically creates mnemonics for the icon/texts in our left hand side panel
*/
void createIconAutoMnemonics( MnemonicGenerator& _rMnemonics );
diff --git a/dbaccess/source/ui/app/AppView.cxx b/dbaccess/source/ui/app/AppView.cxx
index b92917c4615b..c6770a1eafd9 100644
--- a/dbaccess/source/ui/app/AppView.cxx
+++ b/dbaccess/source/ui/app/AppView.cxx
@@ -100,8 +100,8 @@ void OAppBorderWindow::Resize()
if ( m_pPanel )
{
OApplicationSwapWindow* pSwap = getPanel();
- if ( pSwap && pSwap->GetEntryCount() != 0 )
- nX = pSwap->GetBoundingBox( pSwap->GetEntry(0) ).GetWidth() + aFLSize.Height();
+ if (pSwap)
+ nX = pSwap->get_preferred_size().Width();
nX = std::max(m_pPanel->GetWidthPixel() ,nX);
m_pPanel->SetPosSizePixel(Point(0,0),Size(nX,nOutputHeight));
}
diff --git a/dbaccess/source/ui/inc/TableWindowListBox.hxx b/dbaccess/source/ui/inc/TableWindowListBox.hxx
index 5ca01098266b..6d4ded28f97f 100644
--- a/dbaccess/source/ui/inc/TableWindowListBox.hxx
+++ b/dbaccess/source/ui/inc/TableWindowListBox.hxx
@@ -93,7 +93,7 @@ namespace dbaui
int GetEntryFromText( const OUString& rEntryText );
};
- class TableWindowListBoxHelper : public DropTargetHelper
+ class TableWindowListBoxHelper final : public DropTargetHelper
{
private:
OTableWindowListBox& m_rParent;