extras/source/glade/libreoffice-catalog.xml.in | 7 include/sfx2/emojiviewitem.hxx | 2 include/sfx2/inputdlg.hxx | 2 include/sfx2/recentdocsviewitem.hxx | 9 include/sfx2/templatedlg.hxx | 86 - include/sfx2/templatelocalview.hxx | 121 ++ include/sfx2/templateviewitem.hxx | 2 include/sfx2/thumbnailview.hxx | 184 +++ include/sfx2/thumbnailviewitem.hxx | 6 include/svx/SvxPresetListBox.hxx | 2 include/svx/charmap.hxx | 4 include/vcl/customweld.hxx | 8 include/vcl/layout.hxx | 6 include/vcl/weld.hxx | 22 sd/source/ui/app/sdmod1.cxx | 11 sfx2/source/appl/appopen.cxx | 6 sfx2/source/appl/appserv.cxx | 4 sfx2/source/control/emojiviewitem.cxx | 2 sfx2/source/control/recentdocsviewitem.cxx | 7 sfx2/source/control/templatelocalview.cxx | 888 ++++++++++++++++++ sfx2/source/control/templatesearchview.cxx | 143 +-- sfx2/source/control/templateviewitem.cxx | 2 sfx2/source/control/thumbnailview.cxx | 1176 ++++++++++++++++++++++++- sfx2/source/control/thumbnailviewacc.cxx | 560 +++++++++++ sfx2/source/control/thumbnailviewacc.hxx | 112 ++ sfx2/source/control/thumbnailviewitem.cxx | 2 sfx2/source/dialog/inputdlg.cxx | 2 sfx2/source/doc/templatedlg.cxx | 690 ++++++-------- sfx2/source/inc/templatesearchview.hxx | 13 sfx2/source/inc/templatesearchviewitem.hxx | 2 sfx2/uiconfig/ui/templatedlg.ui | 170 ++- solenv/bin/native-code.py | 2 svx/source/dialog/charmap.cxx | 4 svx/source/tbxctrls/SvxPresetListBox.cxx | 5 sw/source/uibase/uiview/view2.cxx | 4 vcl/source/app/customweld.cxx | 2 vcl/source/app/salvtables.cxx | 76 + vcl/unx/gtk3/gtk3gtkinst.cxx | 109 +- 38 files changed, 3785 insertions(+), 668 deletions(-)
New commits: commit 3e078e17ee2144fb976a7e6b9227152113cea0d4 Author: Caolán McNamara <[email protected]> AuthorDate: Tue Mar 26 16:27:17 2019 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Thu Mar 28 22:07:06 2019 +0100 weld SfxTemplateManagerDlg like expert configuration change the gear menu not to display a down indicator and use CommandEvent to distinguish mouse/non-mouse context menus Change-Id: I64bb660a9c7dacb5b90b240d9d76d29324c5fd9f Reviewed-on: https://gerrit.libreoffice.org/69893 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Caolán McNamara <[email protected]> diff --git a/extras/source/glade/libreoffice-catalog.xml.in b/extras/source/glade/libreoffice-catalog.xml.in index abeb0910a2dc..57106338489d 100644 --- a/extras/source/glade/libreoffice-catalog.xml.in +++ b/extras/source/glade/libreoffice-catalog.xml.in @@ -134,10 +134,6 @@ generic-name="Gamma Grid Widget" parent="GtkDrawingArea" icon-name="widget-gtk-drawingarea"/> - <glade-widget-class title="Template Local View" name="sfxlo-TemplateLocalView" - generic-name="Template Local View" parent="GtkDrawingArea" - icon-name="widget-gtk-drawingarea"/> - <glade-widget-class title="Mark Preview" name="swuilo-SwMarkPreview" generic-name="Mark Preview Window" parent="GtkDrawingArea" icon-name="widget-gtk-drawingarea"/> @@ -437,9 +433,6 @@ <glade-widget-class title="Template Thumbnail View" name="sfxlo-TemplateDefaultView" generic-name="Template Icon View" parent="GtkIconView" icon-name="widget-gtk-iconview"/> - <glade-widget-class title="Template Search View" name="sfxlo-TemplateSearchView" - generic-name="Template Icon View" parent="GtkIconView" - icon-name="widget-gtk-iconview"/> <glade-widget-class title="Driver List Control" name="cuilo-DriverListControl" generic-name="DriverListControl" parent="GtkEntry" diff --git a/include/sfx2/emojiviewitem.hxx b/include/sfx2/emojiviewitem.hxx index 0ca32e78238f..e0aa57675f9a 100644 --- a/include/sfx2/emojiviewitem.hxx +++ b/include/sfx2/emojiviewitem.hxx @@ -15,7 +15,7 @@ class EmojiViewItem : public ThumbnailViewItem { public: - EmojiViewItem (ThumbnailView &rView, sal_uInt16 nId); + EmojiViewItem (ThumbnailViewBase &rView, sal_uInt16 nId); virtual ~EmojiViewItem () override; diff --git a/include/sfx2/inputdlg.hxx b/include/sfx2/inputdlg.hxx index 6f50e012e997..bd54b6a5de02 100644 --- a/include/sfx2/inputdlg.hxx +++ b/include/sfx2/inputdlg.hxx @@ -21,7 +21,7 @@ private: std::unique_ptr<weld::Button> m_xHelp; public: - InputDialog(weld::Window* pParent, const OUString &rLabelText); + InputDialog(weld::Widget* pParent, const OUString &rLabelText); OUString GetEntryText() const; void SetEntryText(const OUString& rStr); void HideHelpBtn(); diff --git a/include/sfx2/recentdocsviewitem.hxx b/include/sfx2/recentdocsviewitem.hxx index 8320d4710d81..2ee90de19f03 100644 --- a/include/sfx2/recentdocsviewitem.hxx +++ b/include/sfx2/recentdocsviewitem.hxx @@ -12,10 +12,15 @@ #include <sfx2/thumbnailview.hxx> +namespace sfx2 +{ + class RecentDocsView; +} + class RecentDocsViewItem final : public ThumbnailViewItem { public: - RecentDocsViewItem(ThumbnailView &rView, const OUString &rURL, + RecentDocsViewItem(sfx2::RecentDocsView &rView, const OUString &rURL, const OUString &rTitle, const BitmapEx& rThumbnail, sal_uInt16 nId, long nThumbnailSize); /** Updates own highlight status based on the aPoint position. @@ -38,6 +43,8 @@ public: void OpenDocument(); private: + sfx2::RecentDocsView& mrParentView; + /// Return area where is the icon to remove document from the recent documents. tools::Rectangle getRemoveIconArea() const; diff --git a/include/sfx2/templatedlg.hxx b/include/sfx2/templatedlg.hxx index 7f730c50161d..5e8a12853419 100644 --- a/include/sfx2/templatedlg.hxx +++ b/include/sfx2/templatedlg.hxx @@ -38,18 +38,16 @@ namespace com { } } } } -class SFX2_DLLPUBLIC SfxTemplateManagerDlg : public ModalDialog +class SFX2_DLLPUBLIC SfxTemplateManagerDlg : public weld::GenericDialogController { typedef bool (*selection_cmp_fn)(const ThumbnailViewItem*,const ThumbnailViewItem*); public: - SfxTemplateManagerDlg(vcl::Window *parent = nullptr); + SfxTemplateManagerDlg(weld::Window *parent); virtual ~SfxTemplateManagerDlg() override; - virtual void dispose() override; - virtual short Execute() override; - virtual bool EventNotify( NotifyEvent& rNEvt ) override; + virtual short run() override; void setDocumentModel (const css::uno::Reference<css::frame::XModel> &rModel); @@ -63,21 +61,19 @@ protected: void fillFolderComboBox(); - DECL_LINK(TBXDropdownHdl, ToolBox*, void); + DECL_LINK(SelectApplicationHdl, weld::ComboBox&, void); + DECL_LINK(SelectRegionHdl, weld::ComboBox&, void); - DECL_LINK(SelectApplicationHdl, ListBox&, void); - DECL_LINK(SelectRegionHdl, ListBox&, void); - - DECL_LINK(OkClickHdl, Button*, void); - DECL_LINK(MoveClickHdl, Button*, void); - DECL_LINK(ExportClickHdl, Button*, void); - DECL_LINK(ImportClickHdl, Button*, void); - DECL_STATIC_LINK(SfxTemplateManagerDlg, LinkClickHdl, Button*, void); + DECL_LINK(OkClickHdl, weld::Button&, void); + DECL_LINK(MoveClickHdl, weld::Button&, void); + DECL_LINK(ExportClickHdl, weld::Button&, void); + DECL_LINK(ImportClickHdl, weld::Button&, void); + DECL_STATIC_LINK(SfxTemplateManagerDlg, LinkClickHdl, weld::Button&, void); DECL_LINK(TVItemStateHdl, const ThumbnailViewItem*, void); - DECL_LINK(MenuSelectHdl, Menu*, bool); - DECL_LINK(DefaultTemplateMenuSelectHdl, Menu*, bool); + DECL_LINK(MenuSelectHdl, const OString&, void); + void DefaultTemplateMenuSelectHdl(const OString& rIdent); DECL_LINK(OpenRegionHdl, void*, void); DECL_LINK(CreateContextMenuHdl, ThumbnailViewItem*, void); @@ -86,8 +82,13 @@ protected: DECL_LINK(DeleteTemplateHdl, ThumbnailViewItem*, void); DECL_LINK(DefaultTemplateHdl, ThumbnailViewItem*, void); - DECL_LINK(SearchUpdateHdl, Edit&, void); - DECL_LINK(GetFocusHdl, Control&, void); + void SearchUpdate(); + + DECL_LINK(SearchUpdateHdl, weld::Entry&, void); + DECL_LINK(GetFocusHdl, weld::Widget&, void); + DECL_LINK(LoseFocusHdl, weld::Widget&, void); + DECL_LINK(ImplUpdateDataHdl, Timer*, void); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); void OnTemplateImportCategory(const OUString& sCategory); static void OnTemplateLink (); @@ -122,27 +123,28 @@ protected: FILTER_APPLICATION getCurrentApplicationFilter(); protected: - - VclPtr<Edit> mpSearchFilter; - VclPtr<ListBox> mpCBApp; - VclPtr<ListBox> mpCBFolder; - - VclPtr<PushButton> mpOKButton; - VclPtr<PushButton> mpMoveButton; - VclPtr<PushButton> mpExportButton; - VclPtr<PushButton> mpImportButton; - VclPtr<PushButton> mpLinkButton; - VclPtr<CheckBox> mpCBXHideDlg; - VclPtr<ToolBox> mpActionBar; - VclPtr<TemplateSearchView> mpSearchView; - VclPtr<TemplateLocalView> mpLocalView; - VclPtr<PopupMenu> mpActionMenu; - VclPtr<PopupMenu> mpTemplateDefaultMenu; - std::set<const ThumbnailViewItem*,selection_cmp_fn> maSelTemplates; - css::uno::Reference< css::frame::XModel > m_xModel; css::uno::Reference< css::frame::XDesktop2 > mxDesktop; + + Timer m_aUpdateDataTimer; + + std::unique_ptr<weld::Entry> mxSearchFilter; + std::unique_ptr<weld::ComboBox> mxCBApp; + std::unique_ptr<weld::ComboBox> mxCBFolder; + + std::unique_ptr<weld::Button> mxOKButton; + std::unique_ptr<weld::Button> mxMoveButton; + std::unique_ptr<weld::Button> mxExportButton; + std::unique_ptr<weld::Button> mxImportButton; + std::unique_ptr<weld::Button> mxLinkButton; + std::unique_ptr<weld::CheckButton> mxCBXHideDlg; + std::unique_ptr<weld::MenuButton> mxActionBar; + std::unique_ptr<TemplateSearchView> mxSearchView; + std::unique_ptr<SfxTemplateLocalView> mxLocalView; + std::unique_ptr<weld::Menu> mxTemplateDefaultMenu; + std::unique_ptr<weld::CustomWeld> mxSearchViewWeld; + std::unique_ptr<weld::CustomWeld> mxLocalViewWeld; }; // class SfxTemplateCategoryDialog ------------------------------------------------------------------- @@ -192,23 +194,21 @@ public: class SFX2_DLLPUBLIC SfxTemplateSelectionDlg : public SfxTemplateManagerDlg { public: - SfxTemplateSelectionDlg(vcl::Window *parent); + SfxTemplateSelectionDlg(weld::Window *parent); virtual ~SfxTemplateSelectionDlg() override; - virtual void dispose() override; - virtual short Execute() override; + virtual short run() override; OUString const & getTemplatePath() const { return msTemplatePath; }; - bool IsStartWithTemplate() const { return mpCBXHideDlg->IsChecked(); }; + bool IsStartWithTemplate() const { return mxCBXHideDlg->get_active(); }; private: DECL_LINK(OpenTemplateHdl, ThumbnailViewItem*, void); - DECL_LINK(OkClickHdl, Button*, void); + DECL_LINK(OkClickHdl, weld::Button&, void); - OUString msTemplatePath; + OUString msTemplatePath; }; - #endif // INCLUDED_SFX2_INC_TEMPLATEDLG_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/sfx2/templatelocalview.hxx b/include/sfx2/templatelocalview.hxx index b739549580a8..93282b9ae9d0 100644 --- a/include/sfx2/templatelocalview.hxx +++ b/include/sfx2/templatelocalview.hxx @@ -193,6 +193,127 @@ protected: std::vector<TemplateItemProperties > maAllTemplates; }; +class SFX2_DLLPUBLIC SfxTemplateLocalView : public SfxThumbnailView +{ + typedef bool (*selection_cmp_fn)(const ThumbnailViewItem*,const ThumbnailViewItem*); + +public: + + SfxTemplateLocalView(std::unique_ptr<weld::ScrolledWindow> xWindow, + std::unique_ptr<weld::Menu> xMenu); + + virtual ~SfxTemplateLocalView () override; + + // Fill view with new item list + void insertItems (const std::vector<TemplateItemProperties> &rTemplates, bool isRegionSelected = true, bool bShowCategoryInTooltip = false); + + // Fill view with template folders thumbnails + void Populate (); + + virtual void reload (); + + virtual void showAllTemplates (); + + void showRegion (TemplateContainerItem const *pItem); + + void showRegion (const OUString &rName); + + void createContextMenu(const bool bIsDefault ); + + void ContextMenuSelectHdl(const OString& rIdent); + + TemplateContainerItem* getRegion(OUString const & sStr); + + sal_uInt16 getRegionId (size_t pos) const; + + sal_uInt16 getRegionId (OUString const & sRegionName) const; + + OUString getRegionName(const sal_uInt16 nRegionId) const; + + OUString getRegionItemName(const sal_uInt16 nItemId) const; + + std::vector<OUString> getFolderNames (); + + std::vector<TemplateItemProperties> + getFilteredItems (const std::function<bool (const TemplateItemProperties&) > &rFunc) const; + + sal_uInt16 createRegion (const OUString &rName); + + bool renameRegion(const OUString &rTitle, const OUString &rNewTitle); + + bool removeRegion (const sal_uInt16 nItemId); + + bool removeTemplate (const sal_uInt16 nItemId, const sal_uInt16 nSrcItemId); + + bool moveTemplate (const ThumbnailViewItem* pItem, const sal_uInt16 nSrcItem, + const sal_uInt16 nTargetItem); + + void moveTemplates (const std::set<const ThumbnailViewItem*,selection_cmp_fn> &rItems, const sal_uInt16 nTargetItem); + + bool copyFrom(TemplateContainerItem *pItem, const OUString &rPath); + + bool exportTo (const sal_uInt16 nItemId, const sal_uInt16 nRegionItemId, const OUString &rName); + + virtual bool renameItem(ThumbnailViewItem* pItem, const OUString& sNewTitle) override; + + virtual bool MouseButtonDown( const MouseEvent& rMEvt ) override; + + virtual bool ContextMenu(const CommandEvent& rPos) override; + + virtual bool KeyInput( const KeyEvent& rKEvt ) override; + + sal_uInt16 getCurRegionId () const { return mnCurRegionId;} + + void setOpenRegionHdl(const Link<void*,void> &rLink); + + void setCreateContextMenuHdl(const Link<ThumbnailViewItem*,void> &rLink); + + void setOpenTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink); + + void setEditTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink); + + void setDeleteTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink); + + void setDefaultTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink); + + void updateThumbnailDimensions(long itemMaxSize); + + void RemoveDefaultTemplateIcon( const OUString& rPath); + + static BitmapEx scaleImg (const BitmapEx &rImg, long width, long height); + + static BitmapEx getDefaultThumbnail( const OUString& rPath ); + + static BitmapEx fetchThumbnail (const OUString &msURL, long width, long height); + + static bool IsDefaultTemplate(const OUString& rPath); + +protected: + virtual void OnItemDblClicked(ThumbnailViewItem *pItem) override; + +protected: + sal_uInt16 mnCurRegionId; + + TemplateViewItem *maSelectedItem; + + long mnThumbnailWidth; + long mnThumbnailHeight; + + Point maPosition; //store the point of click event + + Link<void*,void> maOpenRegionHdl; + Link<ThumbnailViewItem*,void> maCreateContextMenuHdl; + Link<ThumbnailViewItem*,void> maOpenTemplateHdl; + Link<ThumbnailViewItem*,void> maEditTemplateHdl; + Link<ThumbnailViewItem*,void> maDeleteTemplateHdl; + Link<ThumbnailViewItem*,void> maDefaultTemplateHdl; + + std::unique_ptr<SfxDocumentTemplates> mpDocTemplates; + std::vector<std::unique_ptr<TemplateContainerItem> > maRegions; + std::vector<TemplateItemProperties > maAllTemplates; +}; + + #endif // INCLUDED_SFX2_TEMPLATELOCALVIEW_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/sfx2/templateviewitem.hxx b/include/sfx2/templateviewitem.hxx index e64b82ec23a2..21433157f796 100644 --- a/include/sfx2/templateviewitem.hxx +++ b/include/sfx2/templateviewitem.hxx @@ -16,7 +16,7 @@ class TemplateViewItem : public ThumbnailViewItem { public: - TemplateViewItem (ThumbnailView &rView, sal_uInt16 nId); + TemplateViewItem (ThumbnailViewBase &rView, sal_uInt16 nId); virtual ~TemplateViewItem () override; diff --git a/include/sfx2/thumbnailview.hxx b/include/sfx2/thumbnailview.hxx index 238004cdc67b..d1807f454583 100644 --- a/include/sfx2/thumbnailview.hxx +++ b/include/sfx2/thumbnailview.hxx @@ -18,6 +18,7 @@ #include <sfx2/thumbnailviewitem.hxx> #include <vcl/ctrl.hxx> +#include <vcl/customweld.hxx> #include <vcl/timer.hxx> #include <vcl/pngread.hxx> @@ -174,7 +175,26 @@ public: * **/ -class SFX2_DLLPUBLIC ThumbnailView : public Control +class SFX2_DLLPUBLIC ThumbnailViewBase +{ + friend class ThumbnailViewAcc; + friend class ThumbnailViewItemAcc; + + SFX2_DLLPRIVATE virtual sal_uInt16 ImplGetVisibleItemCount() const = 0; + SFX2_DLLPRIVATE virtual ThumbnailViewItem* ImplGetVisibleItem(sal_uInt16 nVisiblePos) = 0; + + virtual css::uno::Reference<css::accessibility::XAccessible> getAccessible() = 0; + +public: + /// Updates information in the view; used only in RecentDocsView ATM. + virtual void Reload() {} + + virtual bool renameItem(ThumbnailViewItem* pItem, const OUString& sNewTitle); + + virtual ~ThumbnailViewBase(); +}; + +class SFX2_DLLPUBLIC ThumbnailView : public Control, public ThumbnailViewBase { public: @@ -191,9 +211,6 @@ public: virtual void Clear(); - /// Updates information in the view; used only in RecentDocsView ATM. - virtual void Reload() {} - // Change current thumbnail item list with new one (invalidates all pointers to a thumbnail item) void updateItems(std::vector<std::unique_ptr<ThumbnailViewItem>> items); @@ -232,8 +249,6 @@ public: virtual void Resize() override; - virtual bool renameItem(ThumbnailViewItem* pItem, const OUString& sNewTitle); - static BitmapEx readThumbnail(const OUString &msURL); protected: @@ -256,6 +271,8 @@ protected: virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; + virtual css::uno::Reference<css::accessibility::XAccessible> getAccessible() override; + protected: // Drawing item related functions, override them to make your own custom ones. @@ -280,8 +297,8 @@ protected: SFX2_DLLPRIVATE void ImplDeleteItems(); SFX2_DLLPRIVATE size_t ImplGetItem( const Point& rPoint ) const; SFX2_DLLPRIVATE ThumbnailViewItem* ImplGetItem( size_t nPos ); - SFX2_DLLPRIVATE sal_uInt16 ImplGetVisibleItemCount() const; - SFX2_DLLPRIVATE ThumbnailViewItem* ImplGetVisibleItem( sal_uInt16 nVisiblePos ); + SFX2_DLLPRIVATE virtual sal_uInt16 ImplGetVisibleItemCount() const override; + SFX2_DLLPRIVATE virtual ThumbnailViewItem* ImplGetVisibleItem(sal_uInt16 nVisiblePos) override; SFX2_DLLPRIVATE void ImplFireAccessibleEvent( short nEventId, const css::uno::Any& rOldValue, const css::uno::Any& rNewValue ); SFX2_DLLPRIVATE bool ImplHasAccessibleListeners(); DECL_DLLPRIVATE_LINK( ImplScrollHdl, ScrollBar*, void ); @@ -320,6 +337,157 @@ protected: std::function<bool (const ThumbnailViewItem*)> maFilterFunc; }; +class SFX2_DLLPUBLIC SfxThumbnailView : public weld::CustomWidgetController, public ThumbnailViewBase +{ +public: + SfxThumbnailView(std::unique_ptr<weld::ScrolledWindow> xWindow, std::unique_ptr<weld::Menu> xMenu); + + virtual ~SfxThumbnailView() override; + + virtual bool MouseMove(const MouseEvent& rMEvt) override; + + void AppendItem(std::unique_ptr<ThumbnailViewItem> pItem); + + void RemoveItem(sal_uInt16 nItemId); + + virtual void Clear(); + + // Change current thumbnail item list with new one (invalidates all pointers to a thumbnail item) + void updateItems(std::vector<std::unique_ptr<ThumbnailViewItem>> items); + + size_t GetItemPos( sal_uInt16 nItemId ) const; + + sal_uInt16 GetItemId( size_t nPos ) const; + + sal_uInt16 GetItemId( const Point& rPos ) const; + + sal_uInt16 getNextItemId () const; + + void setItemMaxTextLength (sal_uInt32 nLength); + + void setItemDimensions (long ItemWidth, long ThumbnailHeight, + long DisplayHeight, int itemPadding); + + void SelectItem( sal_uInt16 nItemId ); + + bool IsItemSelected( sal_uInt16 nItemId ) const; + + /** + * + * @brief deselect all current selected items. + * + **/ + + void deselectItems (); + + void ShowTooltips( bool bShowTooltips ); + + void SetMultiSelectionEnabled( bool bIsMultiSelectionEnabled ); + + void filterItems (const std::function<bool (const ThumbnailViewItem*) > &func); + + void setItemStateHdl (const Link<const ThumbnailViewItem*,void> &aLink) { maItemStateHdl = aLink; } + + virtual void Resize() override; + + static BitmapEx readThumbnail(const OUString &msURL); + + virtual void Show() override + { + mxScrolledWindow->show(); + CustomWidgetController::Show(); + } + + virtual void Hide() override + { + mxScrolledWindow->hide(); + CustomWidgetController::Hide(); + } + + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + +protected: + + virtual bool KeyInput( const KeyEvent& rKEvt ) override; + + virtual bool MouseButtonDown( const MouseEvent& rMEvt ) override; + + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + + virtual void GetFocus() override; + + virtual void LoseFocus() override; + + virtual OUString RequestHelp(tools::Rectangle& rRect) override; + + virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; + + virtual css::uno::Reference<css::accessibility::XAccessible> getAccessible() override; + +protected: + + // Drawing item related functions, override them to make your own custom ones. + + void DrawItem (ThumbnailViewItem const *pItem); + + virtual void OnItemDblClicked (ThumbnailViewItem *pItem); + +protected: + + friend class SfxThumbnailViewAcc; + friend class ThumbnailViewItemAcc; + + void CalculateItemPositions (bool bScrollBarUsed = false); + void MakeItemVisible( sal_uInt16 nId ); + + SFX2_DLLPRIVATE void ImplInit(); + + SFX2_DLLPRIVATE void ImplDeleteItems(); + SFX2_DLLPRIVATE size_t ImplGetItem( const Point& rPoint ) const; + SFX2_DLLPRIVATE ThumbnailViewItem* ImplGetItem( size_t nPos ); + SFX2_DLLPRIVATE virtual sal_uInt16 ImplGetVisibleItemCount() const override; + SFX2_DLLPRIVATE virtual ThumbnailViewItem* ImplGetVisibleItem(sal_uInt16 nVisiblePos) override; + SFX2_DLLPRIVATE void ImplFireAccessibleEvent( short nEventId, const css::uno::Any& rOldValue, const css::uno::Any& rNewValue ); + SFX2_DLLPRIVATE bool ImplHasAccessibleListeners(); + DECL_DLLPRIVATE_LINK( ImplScrollHdl, weld::ScrolledWindow&, void ); + +protected: + + std::vector< std::unique_ptr<ThumbnailViewItem> > mItemList; + css::uno::Reference<css::accessibility::XAccessible> mxAccessible; + ThumbnailValueItemList mFilteredItemList; ///< Cache to store the filtered items + ThumbnailValueItemList::iterator mpStartSelRange; + long mnItemWidth; + long mnItemHeight; + long mnItemPadding; + long mnThumbnailHeight; // Maximum height of the thumbnail + long mnDisplayHeight; // Height of the data display box (name, etc) + long mnVisLines; + long mnLines; + + sal_uInt16 mnCols; + sal_uInt16 mnFirstLine; + bool mbScroll : 1; + bool mbHasVisibleItems : 1; + bool mbShowTooltips : 1; + bool mbIsMultiSelectionEnabled: 1; + Color maFillColor; ///< Background color of the thumbnail view widget. + Color maTextColor; ///< Text color. + Color maHighlightColor; ///< Color of the highlight (background) of the hovered item. + Color maHighlightTextColor; ///< Color of the text for the highlighted item. + Color maSelectHighlightColor; ///< Color of the highlight (background) of the selected and hovered item. + Color maSelectHighlightTextColor; ///< Color of the text of the selected and hovered item. + double mfHighlightTransparence; ///< Transparence of the highlight. + + Link<const ThumbnailViewItem*, void> maItemStateHdl; + std::unique_ptr<ThumbnailItemAttributes> mpItemAttrs; + std::unique_ptr<weld::ScrolledWindow> mxScrolledWindow; + std::unique_ptr<weld::Menu> mxContextMenu; + + std::function<bool (const ThumbnailViewItem*)> maFilterFunc; +}; + + #endif // INCLUDED_SFX2_THUMBNAILVIEW_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/sfx2/thumbnailviewitem.hxx b/include/sfx2/thumbnailviewitem.hxx index 3568da70d31b..26cb96966967 100644 --- a/include/sfx2/thumbnailviewitem.hxx +++ b/include/sfx2/thumbnailviewitem.hxx @@ -32,7 +32,7 @@ const int THUMBNAILVIEW_ITEM_CORNER = 5; -class ThumbnailView; +class ThumbnailViewBase; class MouseEvent; namespace basegfx { @@ -67,7 +67,7 @@ class SFX2_DLLPUBLIC ThumbnailViewItem { public: - ThumbnailView &mrParent; + ThumbnailViewBase &mrParent; sal_uInt16 const mnId; bool mbVisible; bool mbSelected; @@ -77,7 +77,7 @@ public: OUString maHelpText; css::uno::Reference< css::accessibility::XAccessible > mxAcc; - ThumbnailViewItem (ThumbnailView &rView, sal_uInt16 nId); + ThumbnailViewItem (ThumbnailViewBase &rView, sal_uInt16 nId); virtual ~ThumbnailViewItem (); diff --git a/include/svx/SvxPresetListBox.hxx b/include/svx/SvxPresetListBox.hxx index e8809eca0f61..f580ebac04fb 100644 --- a/include/svx/SvxPresetListBox.hxx +++ b/include/svx/SvxPresetListBox.hxx @@ -44,7 +44,7 @@ public: SvxPresetListBox(std::unique_ptr<weld::ScrolledWindow> pWindow); virtual void Resize() override; - virtual bool ContextMenu(const Point& rPos) override; + virtual bool ContextMenu(const CommandEvent& rEvent) override; static sal_uInt32 getColumnCount() { return nColCount; } Size const & GetIconSize() const { return aIconSize; } diff --git a/include/svx/charmap.hxx b/include/svx/charmap.hxx index 0551f2ad03c8..df6b29e1ef21 100644 --- a/include/svx/charmap.hxx +++ b/include/svx/charmap.hxx @@ -103,8 +103,8 @@ public: virtual sal_Int32 getMaxCharCount() const; - void Show() { mxScrollArea->show(); } - void Hide() { mxScrollArea->hide(); } + virtual void Show() override { mxScrollArea->show(); } + virtual void Hide() override { mxScrollArea->hide(); } uno::Reference<css::accessibility::XAccessible> getAccessibleParent() { return GetDrawingArea()->get_accessible_parent(); } diff --git a/include/vcl/customweld.hxx b/include/vcl/customweld.hxx index db60521a195d..e8bbb2129912 100644 --- a/include/vcl/customweld.hxx +++ b/include/vcl/customweld.hxx @@ -33,7 +33,7 @@ public: virtual void GetFocus() {} virtual void LoseFocus() {} virtual void StyleUpdated() { Invalidate(); } - virtual bool ContextMenu(const Point&) { return false; } + virtual bool ContextMenu(const CommandEvent&) { return false; } virtual bool KeyInput(const KeyEvent&) { return false; } virtual tools::Rectangle GetFocusRect() { return tools::Rectangle(); } virtual FactoryFunction GetUITestFactory() const { return nullptr; } @@ -49,8 +49,8 @@ public: m_pDrawingArea->queue_draw_area(rRect.Left(), rRect.Top(), rRect.GetWidth(), rRect.GetHeight()); } - void Show() { m_pDrawingArea->show(); } - void Hide() { m_pDrawingArea->hide(); } + virtual void Show() { m_pDrawingArea->show(); } + virtual void Hide() { m_pDrawingArea->hide(); } void GrabFocus() { m_pDrawingArea->grab_focus(); } bool HasFocus() const { return m_pDrawingArea->has_focus(); } bool IsVisible() const { return m_pDrawingArea->get_visible(); } @@ -101,7 +101,7 @@ private: DECL_LINK(DoLoseFocus, weld::Widget&, void); DECL_LINK(DoKeyPress, const KeyEvent&, bool); DECL_LINK(DoFocusRect, weld::Widget&, tools::Rectangle); - DECL_LINK(DoPopupMenu, const Point&, bool); + DECL_LINK(DoPopupMenu, const CommandEvent&, bool); DECL_LINK(DoStyleUpdated, weld::Widget&, void); DECL_LINK(DoRequestHelp, tools::Rectangle&, OUString); diff --git a/include/vcl/layout.hxx b/include/vcl/layout.hxx index 33a6db730a85..2ea881a31fd6 100644 --- a/include/vcl/layout.hxx +++ b/include/vcl/layout.hxx @@ -620,7 +620,7 @@ private: Link<const KeyEvent&, bool> m_aKeyPressHdl; Link<const KeyEvent&, bool> m_aKeyReleaseHdl; Link<VclDrawingArea&, void> m_aStyleUpdatedHdl; - Link<const Point&, bool> m_aPopupMenuHdl; + Link<const CommandEvent&, bool> m_aPopupMenuHdl; Link<tools::Rectangle&, OUString> m_aQueryTooltipHdl; virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override @@ -677,7 +677,7 @@ private: } virtual void Command(const CommandEvent& rEvent) override { - if (rEvent.GetCommand() == CommandEventId::ContextMenu && m_aPopupMenuHdl.Call(rEvent.GetMousePosPixel())) + if (rEvent.GetCommand() == CommandEventId::ContextMenu && m_aPopupMenuHdl.Call(rEvent)) return; Control::Command(rEvent); } @@ -755,7 +755,7 @@ public: { m_aStyleUpdatedHdl = rLink; } - void SetPopupMenuHdl(const Link<const Point&, bool>& rLink) + void SetPopupMenuHdl(const Link<const CommandEvent&, bool>& rLink) { m_aPopupMenuHdl = rLink; } diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index 91fc19f65a87..f258b83c2cd5 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -254,6 +254,8 @@ public: virtual int hadjustment_get_upper() const = 0; virtual void hadjustment_set_upper(int upper) = 0; virtual int hadjustment_get_page_size() const = 0; + virtual void hadjustment_set_page_size(int size) = 0; + virtual void hadjustment_set_page_increment(int size) = 0; virtual void set_hpolicy(VclPolicyType eHPolicy) = 0; virtual VclPolicyType get_hpolicy() const = 0; void connect_hadjustment_changed(const Link<ScrolledWindow&, void>& rLink) @@ -270,6 +272,8 @@ public: virtual int vadjustment_get_upper() const = 0; virtual void vadjustment_set_upper(int upper) = 0; virtual int vadjustment_get_page_size() const = 0; + virtual void vadjustment_set_page_size(int size) = 0; + virtual void vadjustment_set_page_increment(int size) = 0; virtual int vadjustment_get_lower() const = 0; virtual void vadjustment_set_lower(int upper) = 0; virtual void set_vpolicy(VclPolicyType eVPolicy) = 0; @@ -852,11 +856,14 @@ public: { insert_item(-1, rId, rStr, nullptr, &rImage, false); } + virtual void insert_separator(int pos, const OUString& rId) = 0; + void append_separator(const OUString& rId) { insert_separator(-1, rId); } virtual void remove_item(const OString& rId) = 0; virtual void set_item_sensitive(const OString& rIdent, bool bSensitive) = 0; virtual void set_item_active(const OString& rIdent, bool bActive) = 0; virtual void set_item_label(const OString& rIdent, const OUString& rLabel) = 0; virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) = 0; + virtual void set_item_visible(const OString& rIdent, bool bVisible) = 0; virtual OString get_item_help_id(const OString& rIdent) const = 0; virtual void set_popover(weld::Widget* pPopover) = 0; @@ -1474,7 +1481,7 @@ public: protected: Link<draw_args, void> m_aDrawHdl; Link<Widget&, void> m_aStyleUpdatedHdl; - Link<const Point&, bool> m_aPopupMenuHdl; + Link<const CommandEvent&, bool> m_aPopupMenuHdl; Link<Widget&, tools::Rectangle> m_aGetFocusRectHdl; Link<tools::Rectangle&, OUString> m_aQueryTooltipHdl; @@ -1486,7 +1493,10 @@ protected: public: void connect_draw(const Link<draw_args, void>& rLink) { m_aDrawHdl = rLink; } void connect_style_updated(const Link<Widget&, void>& rLink) { m_aStyleUpdatedHdl = rLink; } - void connect_popup_menu(const Link<const Point&, bool>& rLink) { m_aPopupMenuHdl = rLink; } + void connect_popup_menu(const Link<const CommandEvent&, bool>& rLink) + { + m_aPopupMenuHdl = rLink; + } void connect_focus_rect(const Link<Widget&, tools::Rectangle>& rLink) { m_aGetFocusRectHdl = rLink; @@ -1512,11 +1522,17 @@ public: virtual OString popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect) = 0; virtual void set_sensitive(const OString& rIdent, bool bSensitive) = 0; virtual void set_active(const OString& rIdent, bool bActive) = 0; - virtual void show(const OString& rIdent, bool bShow) = 0; + virtual void set_visible(const OString& rIdent, bool bVisible) = 0; virtual void insert(int pos, const OUString& rId, const OUString& rStr, const OUString* pIconName, VirtualDevice* pImageSufface, bool bCheck) = 0; + + virtual void clear() = 0; + + virtual void insert_separator(int pos, const OUString& rId) = 0; + void append_separator(const OUString& rId) { insert_separator(-1, rId); } + void append(const OUString& rId, const OUString& rStr) { insert(-1, rId, rStr, nullptr, nullptr, false); diff --git a/sd/source/ui/app/sdmod1.cxx b/sd/source/ui/app/sdmod1.cxx index 42bde350851f..f60e2ee4d0b8 100644 --- a/sd/source/ui/app/sdmod1.cxx +++ b/sd/source/ui/app/sdmod1.cxx @@ -475,15 +475,16 @@ SfxFrame* SdModule::ExecuteNewDocument( SfxRequest const & rReq ) if(bStartWithTemplate) { //Launch TemplateSelectionDialog - ScopedVclPtrInstance< SfxTemplateSelectionDlg > aTemplDlg( SfxGetpApp()->GetTopWindow()); - aTemplDlg->Execute(); + vcl::Window* pTopLevel = SfxGetpApp()->GetTopWindow(); + SfxTemplateSelectionDlg aTemplDlg(pTopLevel ? pTopLevel->GetFrameWeld() : nullptr); + aTemplDlg.run(); //check to disable the dialog - pOpt->SetStartWithTemplate( aTemplDlg->IsStartWithTemplate() ); + pOpt->SetStartWithTemplate( aTemplDlg.IsStartWithTemplate() ); //pFrame is loaded with the desired template - if(!aTemplDlg->getTemplatePath().isEmpty()) - pFrame = CreateFromTemplate(aTemplDlg->getTemplatePath(), xTargetFrame); + if (!aTemplDlg.getTemplatePath().isEmpty()) + pFrame = CreateFromTemplate(aTemplDlg.getTemplatePath(), xTargetFrame); } } diff --git a/sfx2/source/appl/appopen.cxx b/sfx2/source/appl/appopen.cxx index 4a655f940d4c..0c5288289098 100644 --- a/sfx2/source/appl/appopen.cxx +++ b/sfx2/source/appl/appopen.cxx @@ -448,12 +448,12 @@ void SfxApplication::NewDocExec_Impl( SfxRequest& rReq ) if(pCurrentShell) xModel = pCurrentShell->GetModel(); - ScopedVclPtrInstance< SfxTemplateManagerDlg > aTemplDlg; + SfxTemplateManagerDlg aTemplDlg(rReq.GetFrameWeld()); if (xModel.is()) - aTemplDlg->setDocumentModel(xModel); + aTemplDlg.setDocumentModel(xModel); - int nRet = aTemplDlg->Execute(); + int nRet = aTemplDlg.run(); if ( nRet == RET_OK ) { rReq.Done(); diff --git a/sfx2/source/appl/appserv.cxx b/sfx2/source/appl/appserv.cxx index d2ac03b9c2ac..bfe3fb24abc3 100644 --- a/sfx2/source/appl/appserv.cxx +++ b/sfx2/source/appl/appserv.cxx @@ -660,8 +660,8 @@ void SfxApplication::MiscExec_Impl( SfxRequest& rReq ) case SID_TEMPLATE_MANAGER: { - ScopedVclPtrInstance< SfxTemplateManagerDlg > dlg; - dlg->Execute(); + SfxTemplateManagerDlg aDialog(rReq.GetFrameWeld()); + aDialog.run(); bDone = true; break; } diff --git a/sfx2/source/control/emojiviewitem.cxx b/sfx2/source/control/emojiviewitem.cxx index e4f1e701363e..f393738d045f 100644 --- a/sfx2/source/control/emojiviewitem.cxx +++ b/sfx2/source/control/emojiviewitem.cxx @@ -27,7 +27,7 @@ using namespace basegfx::utils; using namespace drawinglayer::attribute; using namespace drawinglayer::primitive2d; -EmojiViewItem::EmojiViewItem (ThumbnailView &rView, sal_uInt16 nId) +EmojiViewItem::EmojiViewItem (ThumbnailViewBase &rView, sal_uInt16 nId) : ThumbnailViewItem(rView, nId) { } diff --git a/sfx2/source/control/recentdocsviewitem.cxx b/sfx2/source/control/recentdocsviewitem.cxx index f1992285e782..cddbe57ae500 100644 --- a/sfx2/source/control/recentdocsviewitem.cxx +++ b/sfx2/source/control/recentdocsviewitem.cxx @@ -32,9 +32,10 @@ using namespace com::sun::star::uno; using namespace drawinglayer::primitive2d; using namespace drawinglayer::processor2d; -RecentDocsViewItem::RecentDocsViewItem(ThumbnailView &rView, const OUString &rURL, +RecentDocsViewItem::RecentDocsViewItem(sfx2::RecentDocsView &rView, const OUString &rURL, const OUString &rTitle, const BitmapEx &rThumbnail, sal_uInt16 nId, long nThumbnailSize) : ThumbnailViewItem(rView, nId), + mrParentView(rView), maURL(rURL), m_bRemoveIconHighlighted(false), m_aRemoveRecentBitmap(BMP_RECENTDOC_REMOVE), @@ -178,7 +179,7 @@ void RecentDocsViewItem::MouseButtonUp(const MouseEvent& rMEvt) void RecentDocsViewItem::OpenDocument() { // show busy mouse pointer - mrParent.SetPointer(PointerStyle::Wait); + mrParentView.SetPointer(PointerStyle::Wait); Reference<frame::XDispatch> xDispatch; Reference<frame::XDispatchProvider> xDispatchProvider; @@ -216,7 +217,7 @@ void RecentDocsViewItem::OpenDocument() pLoadRecentFile->xDispatch = xDispatch; pLoadRecentFile->aTargetURL = aTargetURL; pLoadRecentFile->aArgSeq = aArgsList; - pLoadRecentFile->pView.set(&mrParent); + pLoadRecentFile->pView = &mrParentView; Application::PostUserEvent(LINK(nullptr, sfx2::RecentDocsView, ExecuteHdl_Impl), pLoadRecentFile, true); } diff --git a/sfx2/source/control/templatelocalview.cxx b/sfx2/source/control/templatelocalview.cxx index d15109f8943b..816448a3b298 100644 --- a/sfx2/source/control/templatelocalview.cxx +++ b/sfx2/source/control/templatelocalview.cxx @@ -96,8 +96,6 @@ TemplateLocalView::TemplateLocalView ( vcl::Window* pParent, WinBits nWinStyle) { } -VCL_BUILDER_FACTORY(TemplateLocalView) - TemplateLocalView::~TemplateLocalView() { disposeOnce(); @@ -1017,4 +1015,890 @@ void TemplateLocalView::OnItemDblClicked (ThumbnailViewItem *pItem) maOpenTemplateHdl.Call(pViewItem); } +SfxTemplateLocalView::SfxTemplateLocalView(std::unique_ptr<weld::ScrolledWindow> xWindow, + std::unique_ptr<weld::Menu> xMenu) + : SfxThumbnailView(std::move(xWindow), std::move(xMenu)) + , mnCurRegionId(0) + , maSelectedItem(nullptr) + , mnThumbnailWidth(TEMPLATE_THUMBNAIL_MAX_WIDTH) + , mnThumbnailHeight(TEMPLATE_THUMBNAIL_MAX_HEIGHT) + , maPosition(0,0) + , mpDocTemplates(new SfxDocumentTemplates) +{ +} + +SfxTemplateLocalView::~SfxTemplateLocalView() +{ +} + +void SfxTemplateLocalView::Populate() +{ + maRegions.clear(); + maAllTemplates.clear(); + + sal_uInt16 nCount = mpDocTemplates->GetRegionCount(); + for (sal_uInt16 i = 0; i < nCount; ++i) + { + OUString aRegionName(mpDocTemplates->GetFullRegionName(i)); + + std::unique_ptr<TemplateContainerItem> pItem(new TemplateContainerItem( i+1 )); + pItem->mnRegionId = i; + pItem->maTitle = aRegionName; + + sal_uInt16 nEntries = mpDocTemplates->GetCount(i); + + for (sal_uInt16 j = 0; j < nEntries; ++j) + { + OUString aName = mpDocTemplates->GetName(i,j); + OUString aURL = mpDocTemplates->GetPath(i,j); + + TemplateItemProperties aProperties; + aProperties.nId = j+1; + aProperties.nDocId = j; + aProperties.nRegionId = i; + aProperties.aName = aName; + aProperties.aPath = aURL; + aProperties.aRegionName = aRegionName; + aProperties.aThumbnail = TemplateLocalView::fetchThumbnail(aURL, + mnThumbnailWidth, + mnThumbnailHeight); + + pItem->maTemplates.push_back(aProperties); + maAllTemplates.push_back(aProperties); + } + + maRegions.push_back(std::move(pItem)); + } +} + +void SfxTemplateLocalView::reload() +{ + mpDocTemplates->Update(); + + Populate(); + + // Check if we are currently browsing a region or root folder + if (mnCurRegionId) + { + sal_uInt16 nRegionId = mnCurRegionId - 1; //Is offset by 1 + + for (auto const & pRegion : maRegions) + { + if (pRegion->mnRegionId == nRegionId) + { + showRegion(pRegion.get()); + break; + } + } + } + else + showAllTemplates(); + + //No items should be selected by default + deselectItems(); +} + +void SfxTemplateLocalView::showAllTemplates() +{ + mnCurRegionId = 0; + + insertItems(maAllTemplates, false, true); + + maOpenRegionHdl.Call(nullptr); +} + +void SfxTemplateLocalView::showRegion(TemplateContainerItem const *pItem) +{ + mnCurRegionId = pItem->mnRegionId+1; + + insertItems(pItem->maTemplates); + + maOpenRegionHdl.Call(nullptr); +} + +void SfxTemplateLocalView::showRegion(const OUString &rName) +{ + for (auto const & pRegion : maRegions) + { + if (pRegion->maTitle == rName) + { + showRegion(pRegion.get()); + break; + } + } +} + +TemplateContainerItem* SfxTemplateLocalView::getRegion(OUString const & rName) +{ + for (auto const & pRegion : maRegions) + if (pRegion->maTitle == rName) + return pRegion.get(); + + return nullptr; +} + +void SfxTemplateLocalView::createContextMenu(const bool bIsDefault) +{ + mxContextMenu->clear(); + mxContextMenu->append("open",SfxResId(STR_OPEN)); + mxContextMenu->append("edit",SfxResId(STR_EDIT_TEMPLATE)); + + if(!bIsDefault) + mxContextMenu->append("default",SfxResId(STR_DEFAULT_TEMPLATE)); + else + mxContextMenu->append("default",SfxResId(STR_RESET_DEFAULT)); + + mxContextMenu->append_separator("separator"); + mxContextMenu->append("rename",SfxResId(STR_RENAME)); + mxContextMenu->append("delete",SfxResId(STR_DELETE)); + deselectItems(); + maSelectedItem->setSelection(true); + maItemStateHdl.Call(maSelectedItem); + ContextMenuSelectHdl(mxContextMenu->popup_at_rect(GetDrawingArea(), tools::Rectangle(maPosition, Size(1,1)))); + Invalidate(); +} + +void SfxTemplateLocalView::ContextMenuSelectHdl(const OString& rIdent) +{ + if (rIdent == "open") + maOpenTemplateHdl.Call(maSelectedItem); + else if (rIdent == "edit") + maEditTemplateHdl.Call(maSelectedItem); + else if (rIdent == "rename") + { + InputDialog aTitleEditDlg(GetDrawingArea(), SfxResId(STR_RENAME_TEMPLATE)); + OUString sOldTitle = maSelectedItem->getTitle(); + aTitleEditDlg.SetEntryText(sOldTitle); + aTitleEditDlg.HideHelpBtn(); + + if (!aTitleEditDlg.run()) + return; + OUString sNewTitle = comphelper::string::strip(aTitleEditDlg.GetEntryText(), ' '); + + if ( !sNewTitle.isEmpty() && sNewTitle != sOldTitle ) + { + maSelectedItem->setTitle(sNewTitle); + } + } + else if (rIdent == "delete") + { + std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetDrawingArea(), VclMessageType::Question, VclButtonsType::YesNo, + SfxResId(STR_QMSG_SEL_TEMPLATE_DELETE))); + if (xQueryDlg->run() != RET_YES) + return; + + maDeleteTemplateHdl.Call(maSelectedItem); + reload(); + } + else if (rIdent == "default") + maDefaultTemplateHdl.Call(maSelectedItem); +} + +sal_uInt16 SfxTemplateLocalView::getRegionId(size_t pos) const +{ + assert(pos < maRegions.size()); + + return maRegions[pos]->mnId; +} + +sal_uInt16 SfxTemplateLocalView::getRegionId(OUString const & sRegion) const +{ + for (auto const & pRegion : maRegions) + { + if (pRegion->maTitle == sRegion) + return pRegion->mnId; + } + + return 0; +} + +OUString SfxTemplateLocalView::getRegionName(const sal_uInt16 nRegionId) const +{ + return mpDocTemplates->GetRegionName(nRegionId); +} + +OUString SfxTemplateLocalView::getRegionItemName(const sal_uInt16 nItemId) const +{ + for (auto const & pRegion : maRegions) + { + if (pRegion->mnId == nItemId) + return pRegion->maTitle; + } + + return OUString(); +} + +std::vector<OUString> SfxTemplateLocalView::getFolderNames() +{ + size_t n = maRegions.size(); + std::vector<OUString> ret(n); + + for (size_t i = 0; i < n; ++i) + ret[i] = maRegions[i]->maTitle; + + return ret; +} + +std::vector<TemplateItemProperties> +SfxTemplateLocalView::getFilteredItems(const std::function<bool (const TemplateItemProperties&)> &rFunc) const +{ + std::vector<TemplateItemProperties> aItems; + + if (mnCurRegionId) + { + TemplateContainerItem *pFolderItem = maRegions[mnCurRegionId-1].get(); + + for (TemplateItemProperties & rItemProps : pFolderItem->maTemplates) + { + if (rFunc(rItemProps)) + aItems.push_back(rItemProps); + } + } + else + { + for (auto const & pFolderItem : maRegions) + { + for (const TemplateItemProperties & rItemProps : pFolderItem->maTemplates) + { + if (rFunc(rItemProps)) + aItems.push_back(rItemProps); + } + } + } + + return aItems; +} + +sal_uInt16 SfxTemplateLocalView::createRegion(const OUString &rName) +{ + sal_uInt16 nRegionId = mpDocTemplates->GetRegionCount(); // Next regionId + sal_uInt16 nItemId = getNextItemId(); + + if (!mpDocTemplates->InsertDir(rName,nRegionId)) + return 0; + + // Insert to the region cache list and to the thumbnail item list + std::unique_ptr<TemplateContainerItem> pItem(new TemplateContainerItem( nItemId )); + pItem->mnRegionId = nRegionId; + pItem->maTitle = rName; + + maRegions.push_back(std::move(pItem)); + + return nItemId; +} + +bool SfxTemplateLocalView::renameRegion(const OUString &rTitle, const OUString &rNewTitle) +{ + TemplateContainerItem *pRegion = getRegion(rTitle); + + if(pRegion) + { + sal_uInt16 nRegionId = pRegion->mnRegionId; + return mpDocTemplates->SetName( rNewTitle, nRegionId, USHRT_MAX/*nDocId*/ ); + } + return false; +} + +bool SfxTemplateLocalView::removeRegion(const sal_uInt16 nItemId) +{ + sal_uInt16 nRegionId = USHRT_MAX; + + // Remove from the region cache list + for (auto pRegionIt = maRegions.begin(); pRegionIt != maRegions.end();) + { + if ( (*pRegionIt)->mnId == nItemId ) + { + if (!mpDocTemplates->Delete((*pRegionIt)->mnRegionId,USHRT_MAX)) + return false; + + nRegionId = (*pRegionIt)->mnRegionId; + + pRegionIt = maRegions.erase(pRegionIt); + } + else + { + // Synchronize regions cache ids with SfxDocumentTemplates + if (nRegionId != USHRT_MAX && (*pRegionIt)->mnRegionId > nRegionId) + --(*pRegionIt)->mnRegionId; + + ++pRegionIt; + } + } + + if (nRegionId == USHRT_MAX) + return false; + + // Synchronize view regions ids with SfxDocumentTemplates + for (auto const& region : maRegions) + { + if (region->mnRegionId > nRegionId) + --region->mnRegionId; + } + + return true; +} + +bool SfxTemplateLocalView::removeTemplate (const sal_uInt16 nItemId, const sal_uInt16 nSrcItemId) +{ + for (auto const & pRegion : maRegions) + { + if (pRegion->mnId == nSrcItemId) + { + TemplateContainerItem *pItem = pRegion.get(); + auto pIter = std::find_if(pItem->maTemplates.begin(), pItem->maTemplates.end(), + [nItemId](const TemplateItemProperties& rTemplate) { return rTemplate.nId == nItemId; }); + if (pIter != pItem->maTemplates.end()) + { + if (!mpDocTemplates->Delete(pItem->mnRegionId,pIter->nDocId)) + return false; + + pIter = pItem->maTemplates.erase(pIter); + + if (pRegion->mnRegionId == mnCurRegionId-1) + { + RemoveItem(nItemId); + Invalidate(); + } + + // Update Doc Idx for all templates that follow + for (; pIter != pItem->maTemplates.end(); ++pIter) + pIter->nDocId = pIter->nDocId - 1; + } + + CalculateItemPositions(); + break; + } + } + + return true; +} + +bool SfxTemplateLocalView::moveTemplate (const ThumbnailViewItem *pItem, const sal_uInt16 nSrcItem, + const sal_uInt16 nTargetItem) +{ + TemplateContainerItem *pTarget = nullptr; + TemplateContainerItem *pSrc = nullptr; + + for (auto const & pRegion : maRegions) + { + if (pRegion->mnId == nTargetItem) + pTarget = pRegion.get(); + else if (pRegion->mnId == nSrcItem) + pSrc = pRegion.get(); + } + + if (pTarget && pSrc) + { + sal_uInt16 nSrcRegionId = pSrc->mnRegionId; + sal_uInt16 nTargetRegion = pTarget->mnRegionId; + sal_uInt16 nTargetIdx = mpDocTemplates->GetCount(nTargetRegion); // Next Idx + + const TemplateViewItem *pViewItem = static_cast<const TemplateViewItem*>(pItem); + + bool bCopy = !mpDocTemplates->Move(nTargetRegion,nTargetIdx,nSrcRegionId,pViewItem->mnDocId); + + if (bCopy) + { + OUString sQuery = SfxResId(STR_MSG_QUERY_COPY).replaceFirst("$1", pViewItem->maTitle).replaceFirst("$2", + getRegionName(nTargetRegion)); + + std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetDrawingArea(), VclMessageType::Question, VclButtonsType::YesNo, sQuery)); + if (xQueryDlg->run() != RET_YES) + return false; + + if (!mpDocTemplates->Copy(nTargetRegion,nTargetIdx,nSrcRegionId,pViewItem->mnDocId)) + return false; + } + // move template to destination + + TemplateItemProperties aTemplateItem; + aTemplateItem.nId = nTargetIdx + 1; + aTemplateItem.nDocId = nTargetIdx; + aTemplateItem.nRegionId = nTargetRegion; + aTemplateItem.aName = pViewItem->maTitle; + aTemplateItem.aPath = mpDocTemplates->GetPath(nTargetRegion,nTargetIdx); + aTemplateItem.aRegionName = pViewItem->maHelpText; + aTemplateItem.aThumbnail = pViewItem->maPreview1; + + pTarget->maTemplates.push_back(aTemplateItem); + + if (!bCopy) + { + // remove template from region cached data + + std::vector<TemplateItemProperties>::iterator aIter; + for (aIter = pSrc->maTemplates.begin(); aIter != pSrc->maTemplates.end();) + { + if (aIter->nDocId == pViewItem->mnDocId) + { + aIter = pSrc->maTemplates.erase(aIter); + } + else + { + // Keep region document id synchronized with SfxDocumentTemplates + if (aIter->nDocId > pViewItem->mnDocId) + --aIter->nDocId; + + ++aIter; + } + } + + // Keep view document id synchronized with SfxDocumentTemplates + for (auto const& item : mItemList) + { + auto pTemplateViewItem = static_cast<TemplateViewItem*>(item.get()); + if (pTemplateViewItem->mnDocId > pViewItem->mnDocId) + --pTemplateViewItem->mnDocId; + } + } + + CalculateItemPositions(); + Invalidate(); + + return true; + } + + return false; +} + +void SfxTemplateLocalView::moveTemplates(const std::set<const ThumbnailViewItem*, selection_cmp_fn> &rItems, + const sal_uInt16 nTargetItem) +{ + TemplateContainerItem *pTarget = nullptr; + TemplateContainerItem *pSrc = nullptr; + + for (auto const & pRegion : maRegions) + { + if (pRegion->mnId == nTargetItem) + pTarget = pRegion.get(); + } + + if (!pTarget) + return; + + bool refresh = false; + + sal_uInt16 nTargetRegion = pTarget->mnRegionId; + sal_uInt16 nTargetIdx = mpDocTemplates->GetCount(nTargetRegion); // Next Idx + std::vector<sal_uInt16> aItemIds; // List of moved items ids (also prevents the invalidation of rItems iterators when we remove them as we go) + + std::set<const ThumbnailViewItem*,selection_cmp_fn>::const_iterator aSelIter; + for ( aSelIter = rItems.begin(); aSelIter != rItems.end(); ++aSelIter, ++nTargetIdx ) + { + const TemplateViewItem *pViewItem = static_cast<const TemplateViewItem*>(*aSelIter); + sal_uInt16 nSrcRegionId = pViewItem->mnRegionId; + + for (auto const & pRegion : maRegions) + { + if (pRegion->mnRegionId == nSrcRegionId) + pSrc = pRegion.get(); + } + + if(pSrc) + { + bool bCopy = !mpDocTemplates->Move(nTargetRegion,nTargetIdx,nSrcRegionId,pViewItem->mnDocId); + + if (bCopy) + { + OUString sQuery = SfxResId(STR_MSG_QUERY_COPY).replaceFirst("$1", pViewItem->maTitle).replaceFirst("$2", + getRegionName(nTargetRegion)); + std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetDrawingArea(), VclMessageType::Question, VclButtonsType::YesNo, sQuery)); + if (xQueryDlg->run() != RET_YES) + { + OUString sMsg(SfxResId(STR_MSG_ERROR_LOCAL_MOVE)); + sMsg = sMsg.replaceFirst("$1",getRegionName(nTargetRegion)); + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetDrawingArea(), + VclMessageType::Warning, VclButtonsType::Ok, sMsg.replaceFirst( "$2",pViewItem->maTitle))); + xBox->run(); + + return; //return if any single move operation fails + } + + if (!mpDocTemplates->Copy(nTargetRegion,nTargetIdx,nSrcRegionId,pViewItem->mnDocId)) + { + continue; + } + } + + // move template to destination + + TemplateItemProperties aTemplateItem; + aTemplateItem.nId = nTargetIdx + 1; + aTemplateItem.nDocId = nTargetIdx; + aTemplateItem.nRegionId = nTargetRegion; + aTemplateItem.aName = pViewItem->maTitle; + aTemplateItem.aPath = mpDocTemplates->GetPath(nTargetRegion,nTargetIdx); + aTemplateItem.aRegionName = pViewItem->maHelpText; + aTemplateItem.aThumbnail = pViewItem->maPreview1; + + pTarget->maTemplates.push_back(aTemplateItem); + + if (!bCopy) + { + // remove template from region cached data + + std::vector<TemplateItemProperties>::iterator pPropIter; + for (pPropIter = pSrc->maTemplates.begin(); pPropIter != pSrc->maTemplates.end();) + { + if (pPropIter->nDocId == pViewItem->mnDocId) + { + pPropIter = pSrc->maTemplates.erase(pPropIter); + aItemIds.push_back(pViewItem->mnDocId + 1);//mnid + } + else + { + // Keep region document id synchronized with SfxDocumentTemplates + if (pPropIter->nDocId > pViewItem->mnDocId) + --pPropIter->nDocId; + + ++pPropIter; + } + } + + // Keep view document id synchronized with SfxDocumentTemplates + for (auto const& item : mItemList) + { + auto pTemplateViewItem = static_cast<TemplateViewItem*>(item.get()); + if (pTemplateViewItem->mnDocId > pViewItem->mnDocId) + --pTemplateViewItem->mnDocId; + } + } + } + + refresh = true; + } + + // Remove items from the current view + for (auto const& itemId : aItemIds) + RemoveItem(itemId); + + if (refresh) + { + CalculateItemPositions(); + Invalidate(); + } +} + +bool SfxTemplateLocalView::copyFrom (TemplateContainerItem *pItem, const OUString &rPath) +{ + sal_uInt16 nId = 1; + sal_uInt16 nDocId = 0; + sal_uInt16 nRegionId = pItem->mnRegionId; + OUString aPath(rPath); + + if (!pItem->maTemplates.empty()) + { + nId = pItem->maTemplates.back().nId+1; + nDocId = pItem->maTemplates.back().nDocId+1; + } + + if (mpDocTemplates->CopyFrom(nRegionId,nDocId,aPath)) + { + TemplateItemProperties aTemplate; + aTemplate.nId = nId; + aTemplate.nDocId = nDocId; + aTemplate.nRegionId = nRegionId; + aTemplate.aName = aPath; + aTemplate.aThumbnail = SfxTemplateLocalView::fetchThumbnail(rPath, + TEMPLATE_THUMBNAIL_MAX_WIDTH, + TEMPLATE_THUMBNAIL_MAX_HEIGHT); + aTemplate.aPath = rPath; + aTemplate.aRegionName = getRegionName(nRegionId); + + pItem->maTemplates.push_back(aTemplate); + + CalculateItemPositions(); + + return true; + } + + return false; +} + +bool SfxTemplateLocalView::exportTo(const sal_uInt16 nItemId, const sal_uInt16 nRegionItemId, const OUString &rName) +{ + for (auto const & pRegItem : maRegions) + { + if (pRegItem->mnId == nRegionItemId) + { + for (auto const& elem : pRegItem->maTemplates) + { + if (elem.nId == nItemId) + { + return mpDocTemplates->CopyTo(pRegItem->mnRegionId,elem.nDocId,rName); + } + } + + break; + } + } + + return false; +} + +bool SfxTemplateLocalView::renameItem(ThumbnailViewItem* pItem, const OUString& sNewTitle) +{ + sal_uInt16 nRegionId = 0; + sal_uInt16 nDocId = USHRT_MAX; + TemplateViewItem* pDocItem = dynamic_cast<TemplateViewItem*>( pItem ); + + if ( pDocItem ) + { + nRegionId = pDocItem->mnRegionId; + nDocId = pDocItem->mnDocId; + } + + return mpDocTemplates->SetName( sNewTitle, nRegionId, nDocId ); +} + +void SfxTemplateLocalView::insertItems(const std::vector<TemplateItemProperties> &rTemplates, bool isRegionSelected, bool bShowCategoryInTooltip) +{ + std::vector<std::unique_ptr<ThumbnailViewItem>> aItems(rTemplates.size()); + for (size_t i = 0, n = rTemplates.size(); i < n; ++i ) + { + const TemplateItemProperties *pCur = &rTemplates[i]; + + std::unique_ptr<TemplateViewItem> pChild; + if(isRegionSelected) + pChild.reset(new TemplateViewItem(*this, pCur->nId)); + else + pChild.reset(new TemplateViewItem(*this, i+1)); + + pChild->mnDocId = pCur->nDocId; + pChild->mnRegionId = pCur->nRegionId; + pChild->maTitle = pCur->aName; + pChild->setPath(pCur->aPath); + + if(!bShowCategoryInTooltip) + pChild->setHelpText(pCur->aName); + else + { + OUString sHelpText = SfxResId(STR_TEMPLATE_TOOLTIP); + sHelpText = (sHelpText.replaceFirst("$1", pCur->aName)).replaceFirst("$2", pCur->aRegionName); + pChild->setHelpText(sHelpText); + } + + pChild->maPreview1 = pCur->aThumbnail; + + if(IsDefaultTemplate(pCur->aPath)) + pChild->showDefaultIcon(true); + + if ( pCur->aThumbnail.IsEmpty() ) + { + // Use the default thumbnail if we have nothing else + pChild->maPreview1 = SfxTemplateLocalView::getDefaultThumbnail(pCur->aPath); + } + + aItems[i] = std::move(pChild); + } + + updateItems(std::move(aItems)); +} + +void SfxTemplateLocalView::updateThumbnailDimensions(long itemMaxSize) +{ + mnThumbnailWidth = itemMaxSize; + mnThumbnailHeight = itemMaxSize; +} + +bool SfxTemplateLocalView::MouseButtonDown( const MouseEvent& rMEvt ) +{ + GrabFocus(); + return SfxThumbnailView::MouseButtonDown(rMEvt); +} + +bool SfxTemplateLocalView::ContextMenu(const CommandEvent& rCEvt) +{ + if (rCEvt.IsMouseEvent()) + { + deselectItems(); + size_t nPos = ImplGetItem(rCEvt.GetMousePosPixel()); + Point aPosition(rCEvt.GetMousePosPixel()); + maPosition = aPosition; + ThumbnailViewItem* pItem = ImplGetItem(nPos); + const TemplateViewItem *pViewItem = dynamic_cast<const TemplateViewItem*>(pItem); + + if(pViewItem) + { + maSelectedItem = dynamic_cast<TemplateViewItem*>(pItem); + maCreateContextMenuHdl.Call(pItem); + } + } + else + { + for (ThumbnailViewItem* pItem : mFilteredItemList) + { + //create context menu for the first selected item + if (pItem->isSelected()) + { + deselectItems(); + pItem->setSelection(true); + maItemStateHdl.Call(pItem); + tools::Rectangle aRect = pItem->getDrawArea(); + maPosition = aRect.Center(); + maSelectedItem = dynamic_cast<TemplateViewItem*>(pItem); + maCreateContextMenuHdl.Call(pItem); + break; + } + } + } + return true; +} + +bool SfxTemplateLocalView::KeyInput( const KeyEvent& rKEvt ) +{ + vcl::KeyCode aKeyCode = rKEvt.GetKeyCode(); + + if(aKeyCode == ( KEY_MOD1 | KEY_A ) ) + { + for (ThumbnailViewItem* pItem : mFilteredItemList) + { + if (!pItem->isSelected()) + { + pItem->setSelection(true); + maItemStateHdl.Call(pItem); + } + } + + if (IsReallyVisible() && IsUpdateMode()) + Invalidate(); + return true; + } + else if( aKeyCode == KEY_DELETE && !mFilteredItemList.empty()) + { + std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetDrawingArea(), VclMessageType::Question, VclButtonsType::YesNo, + SfxResId(STR_QMSG_SEL_TEMPLATE_DELETE))); + if (xQueryDlg->run() != RET_YES) + return true; + + //copy to avoid changing filtered item list during deletion + ThumbnailValueItemList mFilteredItemListCopy = mFilteredItemList; + + for (ThumbnailViewItem* pItem : mFilteredItemListCopy) + { + if (pItem->isSelected()) + { + maDeleteTemplateHdl.Call(pItem); + } + } + reload(); + } + + return SfxThumbnailView::KeyInput(rKEvt); +} + +void SfxTemplateLocalView::setOpenRegionHdl(const Link<void*,void> &rLink) +{ + maOpenRegionHdl = rLink; +} + +void SfxTemplateLocalView::setCreateContextMenuHdl(const Link<ThumbnailViewItem*,void> &rLink) +{ + maCreateContextMenuHdl = rLink; +} + +void SfxTemplateLocalView::setOpenTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink) +{ + maOpenTemplateHdl = rLink; +} + +void SfxTemplateLocalView::setEditTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink) +{ + maEditTemplateHdl = rLink; +} + +void SfxTemplateLocalView::setDeleteTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink) +{ + maDeleteTemplateHdl = rLink; +} + +void SfxTemplateLocalView::setDefaultTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink) +{ + maDefaultTemplateHdl = rLink; +} + +BitmapEx SfxTemplateLocalView::scaleImg (const BitmapEx &rImg, long width, long height) +{ + BitmapEx aImg = rImg; + + if (!rImg.IsEmpty()) + { + Size aSize = rImg.GetSizePixel(); + + if (aSize.Width() == 0) + aSize.setWidth( 1 ); + + if (aSize.Height() == 0) + aSize.setHeight( 1 ); + + // make the picture fit the given width/height constraints + double nRatio = std::min(double(width)/double(aSize.Width()), double(height)/double(aSize.Height())); + + aImg.Scale(Size(aSize.Width() * nRatio, aSize.Height() * nRatio)); + } + + return aImg; +} + +bool SfxTemplateLocalView::IsDefaultTemplate(const OUString& rPath) +{ + SvtModuleOptions aModOpt; + const css::uno::Sequence<OUString> &aServiceNames = aModOpt.GetAllServiceNames(); + + for( sal_Int32 i=0, nCount = aServiceNames.getLength(); i < nCount; ++i ) + { + const OUString defaultPath = SfxObjectFactory::GetStandardTemplate( aServiceNames[i] ); + if(defaultPath.match(rPath)) + return true; + } + + return false; +} + +void SfxTemplateLocalView::RemoveDefaultTemplateIcon(const OUString& rPath) +{ + for (std::unique_ptr<ThumbnailViewItem>& pItem : mItemList) + { + TemplateViewItem* pViewItem = dynamic_cast<TemplateViewItem*>(pItem.get()); + if (pViewItem && pViewItem->getPath().match(rPath)) + { + pViewItem->showDefaultIcon(false); + Invalidate(); + return; + } + } +} + +BitmapEx SfxTemplateLocalView::getDefaultThumbnail( const OUString& rPath ) +{ + BitmapEx aImg; + INetURLObject aUrl(rPath); + OUString aExt = aUrl.getExtension(); + + if ( ViewFilter_Application::isFilteredExtension( FILTER_APPLICATION::WRITER, aExt) ) + aImg = BitmapEx(SFX_THUMBNAIL_TEXT); + else if ( ViewFilter_Application::isFilteredExtension( FILTER_APPLICATION::CALC, aExt) ) + aImg = BitmapEx(SFX_THUMBNAIL_SHEET); + else if ( ViewFilter_Application::isFilteredExtension( FILTER_APPLICATION::IMPRESS, aExt) ) + aImg = BitmapEx(SFX_THUMBNAIL_PRESENTATION); + else if ( ViewFilter_Application::isFilteredExtension( FILTER_APPLICATION::DRAW, aExt) ) + aImg = BitmapEx(SFX_THUMBNAIL_DRAWING); + + return aImg; +} + +BitmapEx SfxTemplateLocalView::fetchThumbnail (const OUString &msURL, long width, long height) +{ + return SfxTemplateLocalView::scaleImg(ThumbnailView::readThumbnail(msURL), width, height); +} + +void SfxTemplateLocalView::OnItemDblClicked (ThumbnailViewItem *pItem) +{ + TemplateViewItem* pViewItem = dynamic_cast<TemplateViewItem*>(pItem); + + if( pViewItem ) + maOpenTemplateHdl.Call(pViewItem); +} + + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sfx2/source/control/templatesearchview.cxx b/sfx2/source/control/templatesearchview.cxx index 279b8bc596ad..97848d65e28a 100644 --- a/sfx2/source/control/templatesearchview.cxx +++ b/sfx2/source/control/templatesearchview.cxx @@ -22,27 +22,26 @@ #include <vcl/builderfactory.hxx> -#define MNI_OPEN 1 -#define MNI_EDIT 2 -#define MNI_DEFAULT_TEMPLATE 3 -#define MNI_DELETE 4 - -TemplateSearchView::TemplateSearchView (vcl::Window *pParent) - : ThumbnailView(pParent,WB_TABSTOP | WB_VSCROLL | WB_BORDER), - maSelectedItem(nullptr), - maPosition(0,0) +#define MNI_OPEN "open" +#define MNI_EDIT "edit" +#define MNI_DEFAULT_TEMPLATE "default" +#define MNI_DELETE "delete" + +TemplateSearchView::TemplateSearchView(std::unique_ptr<weld::ScrolledWindow> xWindow, + std::unique_ptr<weld::Menu> xMenu) + : SfxThumbnailView(std::move(xWindow), std::move(xMenu)) + , maSelectedItem(nullptr) + , maPosition(0,0) { } -VCL_BUILDER_FACTORY(TemplateSearchView) - -void TemplateSearchView::MouseButtonDown( const MouseEvent& rMEvt ) +bool TemplateSearchView::MouseButtonDown( const MouseEvent& rMEvt ) { GrabFocus(); - ThumbnailView::MouseButtonDown(rMEvt); + return SfxThumbnailView::MouseButtonDown(rMEvt); } -void TemplateSearchView::KeyInput( const KeyEvent& rKEvt ) +bool TemplateSearchView::KeyInput( const KeyEvent& rKEvt ) { vcl::KeyCode aKeyCode = rKEvt.GetKeyCode(); @@ -59,14 +58,14 @@ void TemplateSearchView::KeyInput( const KeyEvent& rKEvt ) if (IsReallyVisible() && IsUpdateMode()) Invalidate(); - return; + return true; } else if( aKeyCode == KEY_DELETE && !mFilteredItemList.empty()) { - std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetFrameWeld(), VclMessageType::Question, VclButtonsType::YesNo, + std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetDrawingArea(), VclMessageType::Question, VclButtonsType::YesNo, SfxResId(STR_QMSG_SEL_TEMPLATE_DELETE))); if (xQueryDlg->run() != RET_YES) - return; + return true; //copy to avoid changing filtered item list during deletion ThumbnailValueItemList mFilteredItemListCopy = mFilteredItemList; @@ -83,104 +82,86 @@ void TemplateSearchView::KeyInput( const KeyEvent& rKEvt ) } } - ThumbnailView::KeyInput(rKEvt); + return SfxThumbnailView::KeyInput(rKEvt); } -void TemplateSearchView::Command( const CommandEvent& rCEvt ) +bool TemplateSearchView::ContextMenu(const CommandEvent& rCEvt) { - if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) + if (rCEvt.IsMouseEvent()) { - if(rCEvt.IsMouseEvent()) + deselectItems(); + size_t nPos = ImplGetItem(rCEvt.GetMousePosPixel()); + Point aPosition(rCEvt.GetMousePosPixel()); + maPosition = aPosition; + ThumbnailViewItem* pItem = ImplGetItem(nPos); + const TemplateViewItem *pViewItem = dynamic_cast<const TemplateViewItem*>(pItem); + + if(pViewItem) { - deselectItems(); - size_t nPos = ImplGetItem(rCEvt.GetMousePosPixel()); - Point aPosition (rCEvt.GetMousePosPixel()); - maPosition = aPosition; - ThumbnailViewItem* pItem = ImplGetItem(nPos); - const TemplateViewItem *pViewItem = dynamic_cast<const TemplateViewItem*>(pItem); - - if(pViewItem) - { - maSelectedItem = dynamic_cast<TemplateViewItem*>(pItem); - maCreateContextMenuHdl.Call(pItem); - } + maSelectedItem = dynamic_cast<TemplateViewItem*>(pItem); + maCreateContextMenuHdl.Call(pItem); } - else + } + else + { + for (ThumbnailViewItem* pItem : mFilteredItemList) { - for (ThumbnailViewItem* pItem : mFilteredItemList) + //create context menu for the first selected item + if (pItem->isSelected()) { - //create context menu for the first selected item - if (pItem->isSelected()) - { - deselectItems(); - pItem->setSelection(true); - maItemStateHdl.Call(pItem); - tools::Rectangle aRect = pItem->getDrawArea(); - maPosition = aRect.Center(); - maSelectedItem = dynamic_cast<TemplateViewItem*>(pItem); - maCreateContextMenuHdl.Call(pItem); - break; - } + deselectItems(); + pItem->setSelection(true); + maItemStateHdl.Call(pItem); + tools::Rectangle aRect = pItem->getDrawArea(); + maPosition = aRect.Center(); + maSelectedItem = dynamic_cast<TemplateViewItem*>(pItem); + maCreateContextMenuHdl.Call(pItem); + break; } } } - - ThumbnailView::Command(rCEvt); + return true; } -void TemplateSearchView::createContextMenu( const bool bIsDefault) +void TemplateSearchView::createContextMenu(const bool bIsDefault) { - ScopedVclPtrInstance<PopupMenu> pItemMenu; - pItemMenu->InsertItem(MNI_OPEN,SfxResId(STR_OPEN)); - pItemMenu->InsertItem(MNI_EDIT,SfxResId(STR_EDIT_TEMPLATE)); + mxContextMenu->clear(); + mxContextMenu->append(MNI_OPEN,SfxResId(STR_OPEN)); + mxContextMenu->append(MNI_EDIT,SfxResId(STR_EDIT_TEMPLATE)); - if(!bIsDefault) - pItemMenu->InsertItem(MNI_DEFAULT_TEMPLATE,SfxResId(STR_DEFAULT_TEMPLATE)); + if (!bIsDefault) + mxContextMenu->append(MNI_DEFAULT_TEMPLATE,SfxResId(STR_DEFAULT_TEMPLATE)); else - pItemMenu->InsertItem(MNI_DEFAULT_TEMPLATE,SfxResId(STR_RESET_DEFAULT)); + mxContextMenu->append(MNI_DEFAULT_TEMPLATE,SfxResId(STR_RESET_DEFAULT)); - pItemMenu->InsertSeparator(); - pItemMenu->InsertItem(MNI_DELETE,SfxResId(STR_DELETE)); + mxContextMenu->append_separator("separator"); + mxContextMenu->append(MNI_DELETE,SfxResId(STR_DELETE)); maSelectedItem->setSelection(true); maItemStateHdl.Call(maSelectedItem); - pItemMenu->SetSelectHdl(LINK(this, TemplateSearchView, ContextMenuSelectHdl)); - pItemMenu->Execute(this, tools::Rectangle(maPosition,Size(1,1)), PopupMenuFlags::ExecuteDown); + ContextMenuSelectHdl(mxContextMenu->popup_at_rect(GetDrawingArea(), tools::Rectangle(maPosition, Size(1,1)))); Invalidate(); } -IMPL_LINK(TemplateSearchView, ContextMenuSelectHdl, Menu*, pMenu, bool) +void TemplateSearchView::ContextMenuSelectHdl(const OString& rIdent) { - sal_uInt16 nMenuId = pMenu->GetCurItemId(); - - switch(nMenuId) - { - case MNI_OPEN: + if (rIdent == MNI_OPEN) maOpenTemplateHdl.Call(maSelectedItem); - break; - case MNI_EDIT: + else if (rIdent == MNI_EDIT) maEditTemplateHdl.Call(maSelectedItem); - break; - case MNI_DELETE: + else if (rIdent == MNI_DELETE) { - std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetFrameWeld(), VclMessageType::Question, VclButtonsType::YesNo, + std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetDrawingArea(), VclMessageType::Question, VclButtonsType::YesNo, SfxResId(STR_QMSG_SEL_TEMPLATE_DELETE))); if (xQueryDlg->run() != RET_YES) - break; + return; maDeleteTemplateHdl.Call(maSelectedItem); RemoveItem(maSelectedItem->mnId); CalculateItemPositions(); } - break; - case MNI_DEFAULT_TEMPLATE: + else if (rIdent == MNI_DEFAULT_TEMPLATE) maDefaultTemplateHdl.Call(maSelectedItem); - break; - default: - break; - } - - return false; } void TemplateSearchView::setCreateContextMenuHdl(const Link<ThumbnailViewItem*,void> &rLink) @@ -235,7 +216,7 @@ void TemplateSearchView::AppendItem(sal_uInt16 nAssocItemId, sal_uInt16 nRegionI if(TemplateLocalView::IsDefaultTemplate(rPath)) pItem->showDefaultIcon(true); - ThumbnailView::AppendItem(std::move(pItem)); + SfxThumbnailView::AppendItem(std::move(pItem)); CalculateItemPositions(); } diff --git a/sfx2/source/control/templateviewitem.cxx b/sfx2/source/control/templateviewitem.cxx index 6d6207554382..b6918de9445b 100644 --- a/sfx2/source/control/templateviewitem.cxx +++ b/sfx2/source/control/templateviewitem.cxx @@ -29,7 +29,7 @@ using namespace basegfx::utils; using namespace drawinglayer::attribute; using namespace drawinglayer::primitive2d; -TemplateViewItem::TemplateViewItem (ThumbnailView &rView, sal_uInt16 nId) +TemplateViewItem::TemplateViewItem (ThumbnailViewBase &rView, sal_uInt16 nId) : ThumbnailViewItem(rView, nId), mnRegionId(USHRT_MAX), mnDocId(USHRT_MAX), diff --git a/sfx2/source/control/thumbnailview.cxx b/sfx2/source/control/thumbnailview.cxx index 04c47f81ffc0..9c4986a16220 100644 --- a/sfx2/source/control/thumbnailview.cxx +++ b/sfx2/source/control/thumbnailview.cxx @@ -229,6 +229,11 @@ css::uno::Reference< css::accessibility::XAccessible > ThumbnailView::CreateAcce return new ThumbnailViewAcc( this ); } +css::uno::Reference< css::accessibility::XAccessible > ThumbnailView::getAccessible() +{ + return GetAccessible(); +} + void ThumbnailView::CalculateItemPositions (bool bScrollBarUsed) { if (!mnItemHeight || !mnItemWidth) @@ -1206,12 +1211,16 @@ void ThumbnailView::filterItems(const std::function<bool (const ThumbnailViewIte Invalidate(); } -bool ThumbnailView::renameItem(ThumbnailViewItem*, const OUString&) +bool ThumbnailViewBase::renameItem(ThumbnailViewItem*, const OUString&) { // Do nothing by default return false; } +ThumbnailViewBase::~ThumbnailViewBase() +{ +} + BitmapEx ThumbnailView::readThumbnail(const OUString &msURL) { using namespace ::com::sun::star; @@ -1306,4 +1315,1169 @@ BitmapEx ThumbnailView::readThumbnail(const OUString &msURL) return aThumbnail; } +SfxThumbnailView::SfxThumbnailView(std::unique_ptr<weld::ScrolledWindow> xWindow, std::unique_ptr<weld::Menu> xMenu) + : mpItemAttrs(new ThumbnailItemAttributes) + , mxScrolledWindow(std::move(xWindow)) + , mxContextMenu(std::move(xMenu)) +{ + mxScrolledWindow->set_user_managed_scrolling(); + ImplInit(); + mxScrolledWindow->connect_vadjustment_changed(LINK(this, SfxThumbnailView, ImplScrollHdl)); +} + +SfxThumbnailView::~SfxThumbnailView() +{ + css::uno::Reference< css::lang::XComponent> xComponent(mxAccessible, css::uno::UNO_QUERY); + + if (xComponent.is()) + xComponent->dispose(); + + mpItemAttrs.reset(); + + ImplDeleteItems(); +} + +bool SfxThumbnailView::MouseMove(const MouseEvent& rMEvt) +{ + size_t nItemCount = mFilteredItemList.size(); + Point aPoint = rMEvt.GetPosPixel(); + + for (size_t i = 0; i < nItemCount; i++) + { + ThumbnailViewItem *pItem = mFilteredItemList[i]; + ::tools::Rectangle aToInvalidate(pItem->updateHighlight(pItem->mbVisible && !rMEvt.IsLeaveWindow(), aPoint)); + if (!aToInvalidate.IsEmpty() && IsReallyVisible() && IsUpdateMode()) + Invalidate(aToInvalidate); + } + + return true; +} + +OUString SfxThumbnailView::RequestHelp(tools::Rectangle& rHelpRect) +{ + if (!mbShowTooltips) + return OUString(); + + Point aPos = rHelpRect.TopLeft(); + size_t nItemCount = mFilteredItemList.size(); + for (size_t i = 0; i < nItemCount; i++) + { + ThumbnailViewItem *pItem = mFilteredItemList[i]; + if (!pItem->mbVisible) + continue; + const tools::Rectangle& rDrawArea = pItem->getDrawArea(); + if (pItem->mbVisible && rDrawArea.IsInside(aPos)) + { + rHelpRect = rDrawArea; + return pItem->getHelpText(); + } + } + + return OUString(); +} + +void SfxThumbnailView::AppendItem(std::unique_ptr<ThumbnailViewItem> pItem) +{ + if (maFilterFunc(pItem.get())) + { + // Save current start,end range, iterator might get invalidated + size_t nSelStartPos = 0; + ThumbnailViewItem *pSelStartItem = nullptr; + + if (mpStartSelRange != mFilteredItemList.end()) + { + pSelStartItem = *mpStartSelRange; + nSelStartPos = mpStartSelRange - mFilteredItemList.begin(); + } + + mFilteredItemList.push_back(pItem.get()); + mpStartSelRange = pSelStartItem != nullptr ? mFilteredItemList.begin() + nSelStartPos : mFilteredItemList.end(); + } + + mItemList.push_back(std::move(pItem)); +} + +void SfxThumbnailView::ImplInit() +{ + mnItemWidth = 0; + mnItemHeight = 0; + mnItemPadding = 0; + mnVisLines = 0; + mnLines = 0; + mnFirstLine = 0; + mnCols = 0; + mbScroll = false; + mbHasVisibleItems = false; + mbShowTooltips = false; + mbIsMultiSelectionEnabled = true; + maFilterFunc = ViewFilterAll(); + + const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); + maFillColor = rSettings.GetFieldColor(); + maTextColor = rSettings.GetWindowTextColor(); + maHighlightColor = rSettings.GetHighlightColor(); + maHighlightTextColor = rSettings.GetWindowTextColor(); + maSelectHighlightColor = rSettings.GetActiveColor(); + maSelectHighlightTextColor = rSettings.GetActiveTextColor(); + + const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer; + mfHighlightTransparence = aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01; + + mpStartSelRange = mFilteredItemList.end(); + + mpItemAttrs->aFillColor = maFillColor.getBColor(); + mpItemAttrs->aTextColor = maTextColor.getBColor(); + mpItemAttrs->aHighlightColor = maHighlightColor.getBColor(); + mpItemAttrs->aHighlightTextColor = maHighlightTextColor.getBColor(); + mpItemAttrs->aSelectHighlightColor = maSelectHighlightColor.getBColor(); + mpItemAttrs->aSelectHighlightTextColor = maSelectHighlightTextColor.getBColor(); + mpItemAttrs->fHighlightTransparence = mfHighlightTransparence; + + mpItemAttrs->nMaxTextLength = 0; +} + +void SfxThumbnailView::ImplDeleteItems() +{ + const size_t n = mItemList.size(); + + for ( size_t i = 0; i < n; ++i ) + { + ThumbnailViewItem *const pItem = mItemList[i].get(); + + // deselect all current selected items and fire events + if (pItem->isSelected()) + { + pItem->setSelection(false); + maItemStateHdl.Call(pItem); + + // fire accessible event??? + } + + if ( pItem->isVisible() && ImplHasAccessibleListeners() ) + { + css::uno::Any aOldAny, aNewAny; + + aOldAny <<= pItem->GetAccessible( false ); + ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny ); + } + + mItemList[i].reset(); + } + + mItemList.clear(); + mFilteredItemList.clear(); + + mpStartSelRange = mFilteredItemList.end(); +} + +void SfxThumbnailView::DrawItem(ThumbnailViewItem const *pItem) +{ + if (pItem->isVisible()) + { + ::tools::Rectangle aRect = pItem->getDrawArea(); + + if ((aRect.GetHeight() > 0) && (aRect.GetWidth() > 0)) + Invalidate(aRect); + } +} + +void SfxThumbnailView::OnItemDblClicked (ThumbnailViewItem*) +{ +} + +css::uno::Reference< css::accessibility::XAccessible > SfxThumbnailView::CreateAccessible() +{ + mxAccessible.set(new SfxThumbnailViewAcc(this)); + return mxAccessible; +} + +css::uno::Reference< css::accessibility::XAccessible > SfxThumbnailView::getAccessible() +{ + return mxAccessible; +} + +void SfxThumbnailView::CalculateItemPositions(bool bScrollBarUsed) +{ + if (!mnItemHeight || !mnItemWidth) + return; + + Size aWinSize = GetOutputSizePixel(); + size_t nItemCount = mFilteredItemList.size(); + + // calculate window scroll ratio + float nScrollRatio; + if (bScrollBarUsed) + nScrollRatio = static_cast<float>(mxScrolledWindow->vadjustment_get_value()) / + static_cast<float>(mxScrolledWindow->vadjustment_get_upper()-2); + else + nScrollRatio = 0; + + // calculate ScrollBar width + long nScrBarWidth = mxScrolledWindow->get_vscroll_width(); + + // calculate maximum number of visible columns + mnCols = static_cast<sal_uInt16>((aWinSize.Width()-nScrBarWidth) / mnItemWidth); + + if (!mnCols) + mnCols = 1; + + // calculate maximum number of visible rows + mnVisLines = static_cast<sal_uInt16>(aWinSize.Height() / mnItemHeight); + + // calculate empty space + long nHSpace = aWinSize.Width()-nScrBarWidth - mnCols*mnItemWidth; + long nVSpace = aWinSize.Height() - mnVisLines*mnItemHeight; + long nHItemSpace = nHSpace / (mnCols+1); + long nVItemSpace = nVSpace / (mnVisLines+1); + + // calculate maximum number of rows + // Floor( (M+N-1)/N )==Ceiling( M/N ) + mnLines = (static_cast<long>(nItemCount)+mnCols-1) / mnCols; + + if ( !mnLines ) + mnLines = 1; + + if ( mnLines <= mnVisLines ) + mnFirstLine = 0; + else if ( mnFirstLine > static_cast<sal_uInt16>(mnLines-mnVisLines) ) + mnFirstLine = static_cast<sal_uInt16>(mnLines-mnVisLines); + + mbHasVisibleItems = true; + + long nItemHeightOffset = mnItemHeight + nVItemSpace; + long nHiddenLines = (static_cast<long>( + ( mnLines - 1 ) * nItemHeightOffset * nScrollRatio ) - + nVItemSpace ) / + nItemHeightOffset; + + // calculate offsets + long nStartX = nHItemSpace; + long nStartY = nVItemSpace; + + // calculate and draw items + long x = nStartX; + long y = nStartY - ( mnLines - 1 ) * nItemHeightOffset * nScrollRatio + + nHiddenLines * nItemHeightOffset; + + // draw items + // Unless we are scrolling (via scrollbar) we just use the precalculated + // mnFirstLine -- our nHiddenLines calculation takes into account only + // what the user has done with the scrollbar but not any changes of selection + // using the keyboard, meaning we could accidentally hide the selected item + // if we believe the scrollbar (fdo#72287). + size_t nFirstItem = (bScrollBarUsed ? nHiddenLines : mnFirstLine) * mnCols; + size_t nLastItem = nFirstItem + (mnVisLines + 1) * mnCols; + + // If want also draw parts of items in the last line, + // then we add one more line if parts of these line are + // visible + + size_t nCurCount = 0; + for ( size_t i = 0; i < nItemCount; i++ ) + { + ThumbnailViewItem *const pItem = mFilteredItemList[i]; + + if ((nCurCount >= nFirstItem) && (nCurCount < nLastItem)) + { + if( !pItem->isVisible()) + { + if ( ImplHasAccessibleListeners() ) + { + css::uno::Any aOldAny, aNewAny; + + aNewAny <<= pItem->GetAccessible( false ); + ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny ); + } + + pItem->show(true); + + maItemStateHdl.Call(pItem); + } + + pItem->setDrawArea(::tools::Rectangle( Point(x,y), Size(mnItemWidth, mnItemHeight) )); + pItem->calculateItemsPosition(mnThumbnailHeight,mnDisplayHeight,mnItemPadding,mpItemAttrs->nMaxTextLength,mpItemAttrs.get()); + + if ( !((nCurCount+1) % mnCols) ) + { + x = nStartX; + y += mnItemHeight+nVItemSpace; + } + else + x += mnItemWidth+nHItemSpace; + } + else + { + if( pItem->isVisible()) + { + if ( ImplHasAccessibleListeners() ) + { + css::uno::Any aOldAny, aNewAny; + + aOldAny <<= pItem->GetAccessible( false ); + ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny ); + } + + pItem->show(false); + + maItemStateHdl.Call(pItem); + } + + } + + ++nCurCount; + } + + // arrange ScrollBar, set values and show it + mnLines = (nCurCount+mnCols-1)/mnCols; + + // check if scroll is needed + mbScroll = mnLines > mnVisLines; + + mxScrolledWindow->vadjustment_set_upper((nCurCount+mnCols-1)*gnFineness/mnCols); + mxScrolledWindow->vadjustment_set_page_size(mnVisLines); + if (!bScrollBarUsed) + mxScrolledWindow->vadjustment_set_value(static_cast<long>(mnFirstLine)*gnFineness); + long nPageSize = mnVisLines; + if ( nPageSize < 1 ) + nPageSize = 1; + mxScrolledWindow->vadjustment_set_page_increment(nPageSize); + mxScrolledWindow->set_vpolicy(mbScroll ? VclPolicyType::ALWAYS : VclPolicyType::NEVER); +} + +size_t SfxThumbnailView::ImplGetItem( const Point& rPos ) const +{ + if ( !mbHasVisibleItems ) + { + return THUMBNAILVIEW_ITEM_NOTFOUND; + } + + for (size_t i = 0; i < mFilteredItemList.size(); ++i) + { + if (mFilteredItemList[i]->isVisible() && mFilteredItemList[i]->getDrawArea().IsInside(rPos)) + return i; + } + + return THUMBNAILVIEW_ITEM_NOTFOUND; +} + +ThumbnailViewItem* SfxThumbnailView::ImplGetItem( size_t nPos ) +{ + return ( nPos < mFilteredItemList.size() ) ? mFilteredItemList[nPos] : nullptr; +} + +sal_uInt16 SfxThumbnailView::ImplGetVisibleItemCount() const +{ + sal_uInt16 nRet = 0; + const size_t nItemCount = mItemList.size(); + + for ( size_t n = 0; n < nItemCount; ++n ) + { + if ( mItemList[n]->isVisible() ) + ++nRet; + } + + return nRet; +} + +ThumbnailViewItem* SfxThumbnailView::ImplGetVisibleItem( sal_uInt16 nVisiblePos ) +{ + const size_t nItemCount = mItemList.size(); + + for ( size_t n = 0; n < nItemCount; ++n ) + { + ThumbnailViewItem *const pItem = mItemList[n].get(); + + if ( pItem->isVisible() && !nVisiblePos-- ) + return pItem; + } + + return nullptr; +} + +void SfxThumbnailView::ImplFireAccessibleEvent( short nEventId, const css::uno::Any& rOldValue, const css::uno::Any& rNewValue ) +{ + ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation(mxAccessible); + + if( pAcc ) + pAcc->FireAccessibleEvent( nEventId, rOldValue, rNewValue ); +} + +bool SfxThumbnailView::ImplHasAccessibleListeners() +{ + ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation(mxAccessible); + return( pAcc && pAcc->HasAccessibleListeners() ); +} + +IMPL_LINK_NOARG(SfxThumbnailView, ImplScrollHdl, weld::ScrolledWindow&, void) +{ + CalculateItemPositions(true); + if (IsReallyVisible() && IsUpdateMode()) + Invalidate(); +} + +bool SfxThumbnailView::KeyInput( const KeyEvent& rKEvt ) +{ + bool bHandled = true; + + // Get the last selected item in the list + size_t nLastPos = 0; + bool bFoundLast = false; + for ( long i = mFilteredItemList.size() - 1; !bFoundLast && i >= 0; --i ) + { + ThumbnailViewItem* pItem = mFilteredItemList[i]; + if ( pItem->isSelected() ) + { + nLastPos = i; + bFoundLast = true; + } + } + + bool bValidRange = false; + bool bHasSelRange = mpStartSelRange != mFilteredItemList.end(); + size_t nNextPos = nLastPos; + vcl::KeyCode aKeyCode = rKEvt.GetKeyCode(); + ThumbnailViewItem* pNext = nullptr; + + if (aKeyCode.IsShift() && bHasSelRange) + { + //If the last element selected is the start range position + //search for the first selected item + size_t nSelPos = mpStartSelRange - mFilteredItemList.begin(); + + if (nLastPos == nSelPos) + { + while (nLastPos && mFilteredItemList[nLastPos-1]->isSelected()) + --nLastPos; + } + } + + switch ( aKeyCode.GetCode() ) + { + case KEY_RIGHT: + if (!mFilteredItemList.empty()) + { + if ( bFoundLast && nLastPos + 1 < mFilteredItemList.size() ) + { + bValidRange = true; + nNextPos = nLastPos + 1; + } + + pNext = mFilteredItemList[nNextPos]; + } + break; + case KEY_LEFT: + if (!mFilteredItemList.empty()) + { + if ( nLastPos > 0 ) + { + bValidRange = true; + nNextPos = nLastPos - 1; + } + + pNext = mFilteredItemList[nNextPos]; + } + break; + case KEY_DOWN: + if (!mFilteredItemList.empty()) + { + if ( bFoundLast ) + { + //If we are in the second last row just go the one in + //the row below, if there's not row below just go to the + //last item but for the last row don't do anything. + if ( nLastPos + mnCols < mFilteredItemList.size( ) ) + { + bValidRange = true; + nNextPos = nLastPos + mnCols; + } + else + { + int curRow = nLastPos/mnCols; + + if (curRow < mnLines-1) + nNextPos = mFilteredItemList.size()-1; + } + } + + pNext = mFilteredItemList[nNextPos]; + } + break; + case KEY_UP: + if (!mFilteredItemList.empty()) + { + if ( nLastPos >= mnCols ) + { + bValidRange = true; + nNextPos = nLastPos - mnCols; + } + + pNext = mFilteredItemList[nNextPos]; + } + break; + case KEY_RETURN: + { + if ( bFoundLast ) + OnItemDblClicked( mFilteredItemList[nLastPos] ); + } + [[fallthrough]]; + default: + bHandled = CustomWidgetController::KeyInput(rKEvt); + } + + if ( pNext && mbIsMultiSelectionEnabled) + { + if (aKeyCode.IsShift() && bValidRange) + { + std::pair<size_t,size_t> aRange; + size_t nSelPos = mpStartSelRange - mFilteredItemList.begin(); + + if (nLastPos < nSelPos) + { + if (nNextPos > nLastPos) + { + if ( nNextPos > nSelPos) + aRange = std::make_pair(nLastPos,nNextPos); + else + aRange = std::make_pair(nLastPos,nNextPos-1); + } + else + aRange = std::make_pair(nNextPos,nLastPos-1); + } + else if (nLastPos == nSelPos) + { + if (nNextPos > nLastPos) + aRange = std::make_pair(nLastPos+1,nNextPos); + else + aRange = std::make_pair(nNextPos,nLastPos-1); + } + else + { + if (nNextPos > nLastPos) + aRange = std::make_pair(nLastPos+1,nNextPos); + else + { + if ( nNextPos < nSelPos) + aRange = std::make_pair(nNextPos,nLastPos); + else + aRange = std::make_pair(nNextPos+1,nLastPos); + } + } + + for (size_t i = aRange.first; i <= aRange.second; ++i) + { + if (i != nSelPos) + { + ThumbnailViewItem *pCurItem = mFilteredItemList[i]; + + pCurItem->setSelection(!pCurItem->isSelected()); + + if (pCurItem->isVisible()) + DrawItem(pCurItem); + + maItemStateHdl.Call(pCurItem); + } + } + } + else if (!aKeyCode.IsShift()) + { + deselectItems(); + SelectItem(pNext->mnId); + + //Mark it as the selection range start position + mpStartSelRange = mFilteredItemList.begin() + nNextPos; + } + + MakeItemVisible(pNext->mnId); + } + else if(pNext && !mbIsMultiSelectionEnabled) + { + deselectItems(); + SelectItem(pNext->mnId); + MakeItemVisible(pNext->mnId); + } + return bHandled; +} + +void SfxThumbnailView::MakeItemVisible( sal_uInt16 nItemId ) +{ + // Get the item row + size_t nPos = 0; + bool bFound = false; + for ( size_t i = 0; !bFound && i < mFilteredItemList.size(); ++i ) + { + ThumbnailViewItem* pItem = mFilteredItemList[i]; + if ( pItem->mnId == nItemId ) + { + nPos = i; + bFound = true; + } + } + sal_uInt16 nRow = mnCols ? nPos / mnCols : 0; + + // Move the visible rows as little as possible to include that one + if ( nRow < mnFirstLine ) + mnFirstLine = nRow; + else if ( nRow > mnFirstLine + mnVisLines ) + mnFirstLine = nRow - mnVisLines; + + CalculateItemPositions(); + Invalidate(); +} + +bool SfxThumbnailView::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if (!rMEvt.IsLeft()) + { + return CustomWidgetController::MouseButtonDown( rMEvt ); + } + + size_t nPos = ImplGetItem(rMEvt.GetPosPixel()); + ThumbnailViewItem* pItem = ImplGetItem(nPos); + + if ( !pItem ) + { + deselectItems(); + return CustomWidgetController::MouseButtonDown( rMEvt ); + } + + if ( rMEvt.GetClicks() == 2 ) + { + OnItemDblClicked(pItem); + return true; + } + + if ( rMEvt.GetClicks() == 1 && !mbIsMultiSelectionEnabled ) + { + deselectItems(); + pItem->setSelection(!pItem->isSelected()); + + if (!pItem->isHighlighted()) + DrawItem(pItem); + + maItemStateHdl.Call(pItem); + } + else if(rMEvt.GetClicks() == 1) + { + if (rMEvt.IsMod1()) + { + //Keep selected item group state and just invert current desired one state + pItem->setSelection(!pItem->isSelected()); + + //This one becomes the selection range start position if it changes its state to selected otherwise resets it + mpStartSelRange = pItem->isSelected() ? mFilteredItemList.begin() + nPos : mFilteredItemList.end(); + } + else if (rMEvt.IsShift() && mpStartSelRange != mFilteredItemList.end()) + { + std::pair<size_t,size_t> aNewRange; + aNewRange.first = mpStartSelRange - mFilteredItemList.begin(); + aNewRange.second = nPos; + + if (aNewRange.first > aNewRange.second) + std::swap(aNewRange.first,aNewRange.second); + + //Deselect the ones outside of it + for (size_t i = 0, n = mFilteredItemList.size(); i < n; ++i) + { + ThumbnailViewItem *pCurItem = mFilteredItemList[i]; + + if (pCurItem->isSelected() && (i < aNewRange.first || i > aNewRange.second)) + { + pCurItem->setSelection(false); + + if (pCurItem->isVisible()) + DrawItem(pCurItem); + + maItemStateHdl.Call(pCurItem); + } + } + + size_t nSelPos = mpStartSelRange - mFilteredItemList.begin(); + + //Select the items between start range and the selected item + if (nSelPos != nPos) + { + int dir = nSelPos < nPos ? 1 : -1; + size_t nCurPos = nSelPos + dir; + + while (nCurPos != nPos) + { + ThumbnailViewItem *pCurItem = mFilteredItemList[nCurPos]; + + if (!pCurItem->isSelected()) + { + pCurItem->setSelection(true); + + if (pCurItem->isVisible()) + DrawItem(pCurItem); + + maItemStateHdl.Call(pCurItem); + } + + nCurPos += dir; + } + } + + pItem->setSelection(true); + } + else + { + //If we got a group of selected items deselect the rest and only keep the desired one + //mark items as not selected to not fire unnecessary change state events. + pItem->setSelection(false); + deselectItems(); + pItem->setSelection(true); + + //Mark as initial selection range position and reset end one + mpStartSelRange = mFilteredItemList.begin() + nPos; + } + + if (!pItem->isHighlighted()) + DrawItem(pItem); + + maItemStateHdl.Call(pItem); + + //fire accessible event?? + } + return true; +} + +void SfxThumbnailView::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + CustomWidgetController::SetDrawingArea(pDrawingArea); + + if (vcl::Window* pDefaultDevice = dynamic_cast<vcl::Window*>(Application::GetDefaultDevice())) + { + OutputDevice& rDevice = pDrawingArea->get_ref_device(); + pDefaultDevice->SetPointFont(rDevice, pDrawingArea->get_font()); + mpItemAttrs->aFontAttr = getFontAttributeFromVclFont(mpItemAttrs->aFontSize, rDevice.GetFont(), false, true); + } + + SetOutputSizePixel(pDrawingArea->get_preferred_size()); +} + +void SfxThumbnailView::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& /*rRect*/) +{ ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
