diff options
Diffstat (limited to '')
-rw-r--r-- | svx/source/gallery2/galbrws2.cxx | 1242 |
1 files changed, 1242 insertions, 0 deletions
diff --git a/svx/source/gallery2/galbrws2.cxx b/svx/source/gallery2/galbrws2.cxx new file mode 100644 index 000000000..27ba2634d --- /dev/null +++ b/svx/source/gallery2/galbrws2.cxx @@ -0,0 +1,1242 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <sot/formats.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/transfer.hxx> +#include <vcl/virdev.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/viewfrm.hxx> +#include <vcl/graphicfilter.hxx> +#include <helpids.h> +#include <svx/svxids.hrc> +#include <galobj.hxx> +#include <svx/gallery1.hxx> +#include <svx/galtheme.hxx> +#include <svx/galctrl.hxx> +#include <svx/galmisc.hxx> +#include <galbrws2.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <svx/svxdlg.hxx> +#include <svx/galleryitem.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/gallery/GalleryItemType.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/style/GraphicLocation.hpp> + +#include <cassert> +#include <map> +#include <memory> +#include <cppuhelper/implbase.hxx> +#include <osl/diagnose.h> +#include <o3tl/string_view.hxx> + +GalleryBrowserMode GalleryBrowser2::meInitMode = GALLERYBROWSERMODE_ICON; + +struct DispatchInfo +{ + css::util::URL TargetURL; + css::uno::Sequence< css::beans::PropertyValue > Arguments; + css::uno::Reference< css::frame::XDispatch > Dispatch; +}; + +IMPL_STATIC_LINK( GalleryBrowser2, AsyncDispatch_Impl, void*, p, void ) +{ + DispatchInfo* pDispatchInfo = static_cast<DispatchInfo*>(p); + if ( pDispatchInfo && pDispatchInfo->Dispatch.is() ) + { + try + { + pDispatchInfo->Dispatch->dispatch( pDispatchInfo->TargetURL, + pDispatchInfo->Arguments ); + } + catch ( const css::uno::Exception& ) + { + } + } + + delete pDispatchInfo; +} + +namespace +{ + +struct CommandInfo +{ + css::util::URL URL; + css::uno::Reference< css::frame::XDispatch > Dispatch; + + explicit CommandInfo( const OUString &rURL ) + { + URL.Complete = rURL; + } +}; + +class GalleryThemePopup : public ::cppu::WeakImplHelper< css::frame::XStatusListener > +{ +private: + const GalleryTheme* mpTheme; + sal_uInt32 mnObjectPos; + bool mbPreview; + std::unique_ptr<weld::Builder> mxBuilder; + std::unique_ptr<weld::Menu> mxPopupMenu; + std::unique_ptr<weld::Menu> mxBackgroundPopup; + GalleryBrowser2* mpBrowser; + + typedef std::map< int, CommandInfo > CommandInfoMap; + CommandInfoMap m_aCommandInfo; + + static void Execute( const CommandInfo &rCmdInfo, + const css::uno::Sequence< css::beans::PropertyValue > &rArguments ); + + void MenuSelectHdl(std::string_view rIdent); + void BackgroundMenuSelectHdl(sal_uInt16 nId); +public: + GalleryThemePopup(weld::Widget* pParent, + const GalleryTheme* pTheme, + sal_uInt32 nObjectPos, + bool bPreview, + GalleryBrowser2* pBrowser); + + void ExecutePopup(weld::Widget* pParent, const ::Point &rPos); + + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent &rEvent) override; + virtual void SAL_CALL disposing( const css::lang::EventObject &rSource) override; +}; + + +GalleryThemePopup::GalleryThemePopup( + weld::Widget* pParent, + const GalleryTheme* pTheme, + sal_uInt32 nObjectPos, + bool bPreview, + GalleryBrowser2* pBrowser ) + : mpTheme( pTheme ) + , mnObjectPos( nObjectPos ) + , mbPreview( bPreview ) + , mxBuilder(Application::CreateBuilder(pParent, "svx/ui/gallerymenu2.ui")) + , mxPopupMenu(mxBuilder->weld_menu("menu")) + , mxBackgroundPopup(mxBuilder->weld_menu("backgroundmenu")) + , mpBrowser( pBrowser ) +{ + // SID_GALLERY_ENABLE_ADDCOPY + m_aCommandInfo.emplace( + SID_GALLERY_ENABLE_ADDCOPY, + CommandInfo( ".uno:GalleryEnableAddCopy" )); + // SID_GALLERY_BG_BRUSH + m_aCommandInfo.emplace( + SID_GALLERY_BG_BRUSH, + CommandInfo( ".uno:BackgroundImage" )); + // SID_GALLERY_FORMATS + m_aCommandInfo.emplace( + SID_GALLERY_FORMATS, + CommandInfo( ".uno:InsertGalleryPic" )); + +} + +void SAL_CALL GalleryThemePopup::statusChanged( + const css::frame::FeatureStateEvent &rEvent ) +{ + const OUString &rURL = rEvent.FeatureURL.Complete; + if ( rURL == ".uno:GalleryEnableAddCopy" ) + { + if ( !rEvent.IsEnabled ) + { + mxPopupMenu->set_visible("add", false); + } + } + else if ( rURL == ".uno:BackgroundImage" ) + { + mxBackgroundPopup->clear(); + if ( rEvent.IsEnabled ) + { + OUString sItem; + css::uno::Sequence< OUString > sItems; + if ( ( rEvent.State >>= sItem ) && sItem.getLength() ) + { + mxBackgroundPopup->append(OUString::number(1), sItem); + } + else if ( ( rEvent.State >>= sItems ) && sItems.hasElements() ) + { + sal_uInt16 nId = 1; + for ( const OUString& rStr : std::as_const(sItems) ) + { + mxBackgroundPopup->append(OUString::number(nId), rStr); + nId++; + } + } + } + } +} + +void SAL_CALL GalleryThemePopup::disposing( + const css::lang::EventObject &/*rSource*/) +{ +} + +void GalleryThemePopup::Execute( + const CommandInfo &rCmdInfo, + const css::uno::Sequence< css::beans::PropertyValue > &rArguments ) +{ + if ( rCmdInfo.Dispatch.is() ) + { + std::unique_ptr<DispatchInfo> pInfo(new DispatchInfo); + pInfo->TargetURL = rCmdInfo.URL; + pInfo->Arguments = rArguments; + pInfo->Dispatch = rCmdInfo.Dispatch; + + if ( Application::PostUserEvent( + LINK( nullptr, GalleryBrowser2, AsyncDispatch_Impl), pInfo.get() ) ) + pInfo.release(); + } +} + +void GalleryThemePopup::ExecutePopup(weld::Widget* pParent, const ::Point &rPos) +{ + css::uno::Reference< css::frame::XStatusListener > xThis( this ); + + const SgaObjKind eObjKind = mpTheme->GetObjectKind( mnObjectPos ); + INetURLObject aURL; + + const_cast< GalleryTheme* >( mpTheme )->GetURL( mnObjectPos, aURL ); + const bool bValidURL = ( aURL.GetProtocol() != INetProtocol::NotValid ); + + mxPopupMenu->set_visible("add", bValidURL && SgaObjKind::Sound != eObjKind); + + mxPopupMenu->set_visible("preview", bValidURL); + mxPopupMenu->set_active("preview", mbPreview); + + if( mpTheme->IsReadOnly() || !mpTheme->GetObjectCount() ) + { + mxPopupMenu->set_visible("delete", false); + mxPopupMenu->set_visible("title", false); + if (mpTheme->IsReadOnly()) + mxPopupMenu->set_visible("paste", false); + + if (!mpTheme->GetObjectCount()) + mxPopupMenu->set_visible("copy", false); + } + else + { + mxPopupMenu->set_visible("delete", !mbPreview); + mxPopupMenu->set_visible("title", true); + mxPopupMenu->set_visible("copy", true); + mxPopupMenu->set_visible("paste", true); + } + + // update status + css::uno::Reference< css::frame::XDispatchProvider> xDispatchProvider( + GalleryBrowser2::GetFrame(), css::uno::UNO_QUERY ); + css::uno::Reference< css::util::XURLTransformer > xTransformer( + mpBrowser->GetURLTransformer() ); + for ( auto& rInfo : m_aCommandInfo ) + { + try + { + CommandInfo &rCmdInfo = rInfo.second; + if ( xTransformer.is() ) + xTransformer->parseStrict( rCmdInfo.URL ); + + if ( xDispatchProvider.is() ) + { + rCmdInfo.Dispatch = xDispatchProvider->queryDispatch( + rCmdInfo.URL, + "_self", + css::frame::FrameSearchFlag::SELF ); + } + + if ( rCmdInfo.Dispatch.is() ) + { + rCmdInfo.Dispatch->addStatusListener( this, rCmdInfo.URL ); + rCmdInfo.Dispatch->removeStatusListener( this, rCmdInfo.URL ); + } + } + catch ( ... ) + {} + } + + if( !mxBackgroundPopup->n_children() || ( eObjKind == SgaObjKind::SvDraw ) || ( eObjKind == SgaObjKind::Sound ) ) + mxPopupMenu->set_visible("background", false); + else + mxPopupMenu->set_visible("background", true); + + MenuSelectHdl(mxPopupMenu->popup_at_rect(pParent, tools::Rectangle(rPos, Size(1,1)))); +} + +void GalleryThemePopup::MenuSelectHdl(std::string_view rIdent) +{ + if (rIdent.empty()) + return; + + sal_uInt16 nSubMenuId = o3tl::toUInt32(rIdent); + if (nSubMenuId) + { + BackgroundMenuSelectHdl(nSubMenuId-1); + return; + } + + if (rIdent == "add") + { + const CommandInfoMap::const_iterator it = m_aCommandInfo.find( SID_GALLERY_FORMATS ); + if (it != m_aCommandInfo.end()) + mpBrowser->DispatchAdd(it->second.Dispatch, it->second.URL); + } + else + mpBrowser->Execute(rIdent); +} + +void GalleryThemePopup::BackgroundMenuSelectHdl(sal_uInt16 nPos) +{ + OUString aURL( mpBrowser->GetURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + OUString aFilterName( mpBrowser->GetFilterName() ); + + css::uno::Sequence< css::beans::PropertyValue > aArgs{ + comphelper::makePropertyValue("Background.Transparent", sal_Int32( 0 )), // 0 - 100 + comphelper::makePropertyValue("Background.BackColor", sal_Int32( - 1 )), + comphelper::makePropertyValue("Background.URL", aURL), + comphelper::makePropertyValue("Background.Filtername", aFilterName), // FIXME name should be FilterName + comphelper::makePropertyValue("Background.Position", css::style::GraphicLocation_TILED), + comphelper::makePropertyValue("Position", nPos) + }; + + const CommandInfoMap::const_iterator it = m_aCommandInfo.find( SID_GALLERY_BG_BRUSH ); + if ( it != m_aCommandInfo.end() ) + Execute( it->second, aArgs ); +} + +} // end anonymous namespace + +GalleryBrowser2::GalleryBrowser2(weld::Builder& rBuilder, Gallery* pGallery) + : mpGallery(pGallery) + , mpCurTheme(nullptr) + , mxIconView(new GalleryIconView(this, rBuilder.weld_scrolled_window("galleryscroll", true))) + , mxIconViewWin(new weld::CustomWeld(rBuilder, "gallery", *mxIconView)) + , mxListView(rBuilder.weld_tree_view("gallerylist")) + , mxPreview(new GalleryPreview(this, rBuilder.weld_scrolled_window("previewscroll"))) + , mxPreviewWin(new weld::CustomWeld(rBuilder, "preview", *mxPreview)) + , mxIconButton(rBuilder.weld_toggle_button("icon")) + , mxListButton(rBuilder.weld_toggle_button("list")) + , mxInfoBar(rBuilder.weld_label("label")) + , maPreviewSize(28, 28) + , mnCurActionPos ( 0xffffffff ) + , meMode ( GALLERYBROWSERMODE_NONE ) + , meLastMode ( GALLERYBROWSERMODE_NONE ) +{ + m_xContext.set( ::comphelper::getProcessComponentContext() ); + + int nHeight = mxListView->get_height_rows(10); + mxListView->set_size_request(-1, nHeight); + mxIconView->set_size_request(-1, nHeight); + + m_xTransformer.set( + m_xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.util.URLTransformer", m_xContext ), + css::uno::UNO_QUERY ); + + mxIconButton->set_help_id(HID_GALLERY_ICONVIEW); + mxListButton->set_help_id(HID_GALLERY_LISTVIEW); + + mxIconButton->connect_toggled( LINK( this, GalleryBrowser2, SelectTbxHdl ) ); + mxListButton->connect_toggled( LINK( this, GalleryBrowser2, SelectTbxHdl ) ); + + mxIconView->SetSelectHdl( LINK( this, GalleryBrowser2, SelectObjectValueSetHdl ) ); + mxListView->connect_visible_range_changed(LINK(this, GalleryBrowser2, VisRowsScrolledHdl)); + mxListView->connect_size_allocate(LINK(this, GalleryBrowser2, SizeAllocHdl)); + mxListView->connect_changed( LINK( this, GalleryBrowser2, SelectObjectHdl ) ); + mxListView->connect_popup_menu(LINK(this, GalleryBrowser2, PopupMenuHdl)); + mxListView->connect_key_press(LINK(this, GalleryBrowser2, KeyInputHdl)); + mxListView->connect_row_activated(LINK(this, GalleryBrowser2, RowActivatedHdl)); + mxDragDropTargetHelper.reset(new GalleryDragDrop(this, mxListView->get_drop_target())); + mxListView->connect_drag_begin(LINK(this, GalleryBrowser2, DragBeginHdl)); + + mxListView->set_help_id(HID_GALLERY_WINDOW); + + SetMode( ( GALLERYBROWSERMODE_PREVIEW != GalleryBrowser2::meInitMode ) ? GalleryBrowser2::meInitMode : GALLERYBROWSERMODE_ICON ); +} + +IMPL_LINK(GalleryBrowser2, PopupMenuHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + ShowContextMenu(rCEvt); + return true; +} + +IMPL_LINK(GalleryBrowser2, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + return KeyInput(rKEvt); +} + +IMPL_LINK_NOARG(GalleryBrowser2, RowActivatedHdl, weld::TreeView&, bool) +{ + TogglePreview(); + return true; +} + +GalleryBrowser2::~GalleryBrowser2() +{ + if (mpCurTheme) + mpGallery->ReleaseTheme( mpCurTheme, *this ); +} + +void GalleryBrowser2::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + const GalleryHint& rGalleryHint = static_cast<const GalleryHint&>(rHint); + + switch( rGalleryHint.GetType() ) + { + case GalleryHintType::THEME_UPDATEVIEW: + { + if( GALLERYBROWSERMODE_PREVIEW == GetMode() ) + SetMode( meLastMode ); + + ImplUpdateViews( reinterpret_cast<size_t>(rGalleryHint.GetData1()) + 1 ); + } + break; + + default: + break; + } +} + +sal_Int8 GalleryBrowser2::AcceptDrop( const DropTargetHelper& rTarget ) +{ + sal_Int8 nRet = DND_ACTION_NONE; + + if( mpCurTheme && !mpCurTheme->IsReadOnly() ) + { + if( !mpCurTheme->IsDragging() ) + { + if( rTarget.IsDropFormatSupported( SotClipboardFormatId::DRAWING ) || + rTarget.IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) || + rTarget.IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) || + rTarget.IsDropFormatSupported( SotClipboardFormatId::SVXB ) || + rTarget.IsDropFormatSupported( SotClipboardFormatId::GDIMETAFILE ) || + rTarget.IsDropFormatSupported( SotClipboardFormatId::BITMAP ) ) + { + nRet = DND_ACTION_COPY; + } + } + else + nRet = DND_ACTION_COPY; + } + + return nRet; +} + +sal_Int8 GalleryBrowser2::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + sal_Int8 nRet = DND_ACTION_NONE; + + if( mpCurTheme ) + { + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( &rEvt.maPosPixel, aSelPos ); + const sal_uInt32 nInsertPos = (nItemId ? (nItemId - 1) : mpCurTheme->GetObjectCount()); + + if( mpCurTheme->IsDragging() ) + mpCurTheme->ChangeObjectPos( mpCurTheme->GetDragPos(), nInsertPos ); + else + nRet = mpCurTheme->InsertTransferable( rEvt.maDropEvent.Transferable, nInsertPos ) ? 1 : 0; + } + + return nRet; +} + +bool GalleryBrowser2::StartDrag() +{ + if (!mpCurTheme) + return true; + return m_xHelper->StartDrag(); +} + +IMPL_LINK(GalleryBrowser2, DragBeginHdl, bool&, rUnsetDragIcon, bool) +{ + rUnsetDragIcon = false; + return StartDrag(); +} + +void GalleryBrowser2::TogglePreview() +{ + SetMode( ( GALLERYBROWSERMODE_PREVIEW != GetMode() ) ? GALLERYBROWSERMODE_PREVIEW : meLastMode ); + GetViewWindow()->grab_focus(); +} + +void GalleryBrowser2::ShowContextMenu(const CommandEvent& rCEvt) +{ + Point aMousePos = rCEvt.GetMousePosPixel(); + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( rCEvt.IsMouseEvent() ? &aMousePos : nullptr, aSelPos ); + + if( !(mpCurTheme && nItemId && ( nItemId <= mpCurTheme->GetObjectCount() )) ) + return; + + ImplSelectItemId( nItemId ); + + css::uno::Reference< css::frame::XFrame > xFrame( GetFrame() ); + if ( !xFrame.is() ) + return; + + weld::Widget* pParent = GetViewWindow(); + mnCurActionPos = nItemId - 1; + rtl::Reference< GalleryThemePopup > xPopup( + new GalleryThemePopup( + pParent, + mpCurTheme, + mnCurActionPos, + GALLERYBROWSERMODE_PREVIEW == GetMode(), + this ) ); + xPopup->ExecutePopup(pParent, aSelPos); +} + +bool GalleryBrowser2::ViewBoxHasFocus() const +{ + return mxIconButton->has_focus() || mxListButton->has_focus(); +} + +bool GalleryBrowser2::KeyInput(const KeyEvent& rKEvt) +{ + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos ); + bool bRet = false; + + if (!ViewBoxHasFocus() && nItemId && mpCurTheme) + { + OString sExecuteIdent; + INetURLObject aURL; + + mpCurTheme->GetURL( nItemId - 1, aURL ); + + const bool bValidURL = ( aURL.GetProtocol() != INetProtocol::NotValid ); + bool bPreview = bValidURL; + bool bDelete = false; + bool bTitle = false; + + if( !mpCurTheme->IsReadOnly() && mpCurTheme->GetObjectCount() ) + { + bDelete = ( GALLERYBROWSERMODE_PREVIEW != GetMode() ); + bTitle = true; + } + + switch( rKEvt.GetKeyCode().GetCode() ) + { + case KEY_SPACE: + case KEY_RETURN: + case KEY_P: + { + if( bPreview ) + { + TogglePreview(); + bRet = true; + } + } + break; + + case KEY_INSERT: + case KEY_I: + { + // Inserting a gallery item in the document must be dispatched + if( bValidURL ) + { + DispatchAdd(css::uno::Reference<css::frame::XDispatch>(), css::util::URL()); + return true; + } + } + break; + + case KEY_DELETE: + case KEY_D: + { + if( bDelete ) + sExecuteIdent = "delete"; + } + break; + + case KEY_T: + { + if( bTitle ) + sExecuteIdent = "title"; + } + break; + + default: + break; + } + + if (!sExecuteIdent.isEmpty()) + { + Execute(sExecuteIdent); + bRet = true; + } + } + + return bRet; +} + +void GalleryBrowser2::SelectTheme( std::u16string_view rThemeName ) +{ + if( mpCurTheme ) + mpGallery->ReleaseTheme( mpCurTheme, *this ); + + mpCurTheme = mpGallery->AcquireTheme( rThemeName, *this ); + + m_xHelper.set(new GalleryTransferable(mpCurTheme, 0, true)); + rtl::Reference<TransferDataContainer> xHelper(m_xHelper); + mxListView->enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK); + mxIconView->SetDragDataTransferrable(xHelper, DND_ACTION_COPY | DND_ACTION_LINK); + mxPreview->SetDragDataTransferrable(xHelper, DND_ACTION_COPY | DND_ACTION_LINK); + + mxIconView->SetTheme(mpCurTheme); + mxPreview->SetTheme(mpCurTheme); + + if( GALLERYBROWSERMODE_PREVIEW == GetMode() ) + meMode = meLastMode; + + ImplUpdateViews( 1 ); + + bool bIconMode = (GALLERYBROWSERMODE_ICON == GetMode()); + mxIconButton->set_sensitive(true); + mxListButton->set_sensitive(true); + mxIconButton->set_active(bIconMode); + mxListButton->set_active(!bIconMode); +} + +void GalleryBrowser2::SetMode( GalleryBrowserMode eMode ) +{ + if( GetMode() == eMode ) + return; + + meLastMode = GetMode(); + + switch( eMode ) + { + case GALLERYBROWSERMODE_ICON: + { + mxListView->hide(); + + mxPreview->Hide(); + mxPreview->SetGraphic( Graphic() ); + GalleryPreview::PreviewMedia( INetURLObject() ); + + mxIconView->Show(); + + mxIconButton->set_sensitive(true); + mxListButton->set_sensitive(true); + + mxIconButton->set_active(true); + mxListButton->set_active(false); + } + break; + + case GALLERYBROWSERMODE_LIST: + { + mxIconView->Hide(); + + mxPreview->Hide(); + mxPreview->SetGraphic( Graphic() ); + GalleryPreview::PreviewMedia( INetURLObject() ); + + mxListView->show(); + UpdateRows(true); + + mxIconButton->set_sensitive(true); + mxListButton->set_sensitive(true); + + mxIconButton->set_active(false); + mxListButton->set_active(true); + } + break; + + case GALLERYBROWSERMODE_PREVIEW: + { + Graphic aGraphic; + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos ); + + if( nItemId ) + { + const sal_uInt32 nPos = nItemId - 1; + + mxIconView->Hide(); + mxListView->hide(); + + if( mpCurTheme ) + mpCurTheme->GetGraphic( nPos, aGraphic ); + + mxPreview->SetGraphic( aGraphic ); + mxPreview->Show(); + + if( mpCurTheme && mpCurTheme->GetObjectKind( nPos ) == SgaObjKind::Sound ) + GalleryPreview::PreviewMedia( mpCurTheme->GetObjectURL( nPos ) ); + + mxIconButton->set_sensitive(false); + mxListButton->set_sensitive(false); + } + } + break; + + default: + break; + } + + GalleryBrowser2::meInitMode = meMode = eMode; +} + +weld::Widget* GalleryBrowser2::GetViewWindow() const +{ + weld::Widget* pRet; + + switch( GetMode() ) + { + case GALLERYBROWSERMODE_LIST: pRet = mxListView.get(); break; + case GALLERYBROWSERMODE_PREVIEW: pRet = mxPreview->GetDrawingArea(); break; + + default: + pRet = mxIconView->GetDrawingArea(); + break; + } + + return pRet; +} + +void GalleryBrowser2::Travel( GalleryBrowserTravel eTravel ) +{ + if( !mpCurTheme ) + return; + + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos ); + + if( !nItemId ) + return; + + sal_uInt32 nNewItemId = nItemId; + + switch( eTravel ) + { + case GalleryBrowserTravel::First: nNewItemId = 1; break; + case GalleryBrowserTravel::Last: nNewItemId = mpCurTheme->GetObjectCount(); break; + case GalleryBrowserTravel::Previous: nNewItemId--; break; + case GalleryBrowserTravel::Next: nNewItemId++; break; + default: + break; + } + + if( nNewItemId < 1 ) + nNewItemId = 1; + else if( nNewItemId > mpCurTheme->GetObjectCount() ) + nNewItemId = mpCurTheme->GetObjectCount(); + + if( nNewItemId == nItemId ) + return; + + ImplSelectItemId( nNewItemId ); + ImplUpdateInfoBar(); + + if( GALLERYBROWSERMODE_PREVIEW != GetMode() ) + return; + + Graphic aGraphic; + const sal_uInt32 nPos = nNewItemId - 1; + + mpCurTheme->GetGraphic( nPos, aGraphic ); + mxPreview->SetGraphic( aGraphic ); + + if( SgaObjKind::Sound == mpCurTheme->GetObjectKind( nPos ) ) + GalleryPreview::PreviewMedia( mpCurTheme->GetObjectURL( nPos ) ); + + mxPreview->Invalidate(); +} + +void GalleryBrowser2::ImplUpdateViews( sal_uInt16 nSelectionId ) +{ + mxIconView->Hide(); + mxListView->hide(); + mxPreview->Hide(); + + mxIconView->Clear(); + mxListView->clear(); + + if( mpCurTheme ) + { + const int nAlwaysUpToDate = 15; + + mxListView->freeze(); + + sal_uInt32 nCount = mpCurTheme->GetObjectCount(); + for (sal_uInt32 i = 0; i < nCount; ++i) + { + mxIconView->InsertItem(i + 1); // skip reserved id 0 + mxListView->append(OUString::number(i), ""); // create on-demand in VisRowsScrolledHdl + + if (i == nAlwaysUpToDate) // fill in the first block + UpdateRows(false); + } + + if (nCount < nAlwaysUpToDate) // if less than block size, fill in all of them + UpdateRows(false); + + mxListView->thaw(); + + ImplSelectItemId( std::min<sal_uInt16>( nSelectionId, mpCurTheme->GetObjectCount() ) ); + } + + switch( GetMode() ) + { + case GALLERYBROWSERMODE_ICON: mxIconView->Show(); break; + case GALLERYBROWSERMODE_LIST: + mxListView->show(); + UpdateRows(true); + break; + case GALLERYBROWSERMODE_PREVIEW: mxPreview->Show(); break; + + default: + break; + } + + ImplUpdateInfoBar(); +} + +void GalleryBrowser2::UpdateRows(bool bVisibleOnly) +{ + auto lambda = [this](weld::TreeIter& rEntry){ + // id is non-null if the preview is pending creation + OUString sId(mxListView->get_id(rEntry)); + if (sId.isEmpty()) + return false; + + // get the icon for the listview + BitmapEx aBitmapEx; + Size aPreparedSize; + + OUString sItemTextTitle; + OUString sItemTextPath; + + sal_Int32 i = sId.toUInt32(); + mpCurTheme->GetPreviewBitmapExAndStrings(i, aBitmapEx, aPreparedSize, sItemTextTitle, sItemTextPath); + + bool bNeedToCreate(aBitmapEx.IsEmpty()); + if (!bNeedToCreate && (sItemTextTitle.isEmpty() || aPreparedSize != maPreviewSize)) + bNeedToCreate = true; + + if (bNeedToCreate) + { + std::unique_ptr<SgaObject> xObj = mpCurTheme->AcquireObject(i); + if (xObj) + { + aBitmapEx = xObj->createPreviewBitmapEx(maPreviewSize); + sItemTextTitle = GalleryBrowser2::GetItemText(*xObj, GalleryItemFlags::Title); + sItemTextPath = GalleryBrowser2::GetItemText(*xObj, GalleryItemFlags::Path); + + mpCurTheme->SetPreviewBitmapExAndStrings(i, aBitmapEx, maPreviewSize, sItemTextTitle, sItemTextPath); + } + } + + ScopedVclPtr<VirtualDevice> xDev(mxListView->create_virtual_device()); + xDev->SetOutputSizePixel(maPreviewSize); + + if (!aBitmapEx.IsEmpty()) + { + const Size aBitmapExSizePixel(aBitmapEx.GetSizePixel()); + const Point aPos( + ((maPreviewSize.Width() - aBitmapExSizePixel.Width()) >> 1), + ((maPreviewSize.Height() - aBitmapExSizePixel.Height()) >> 1)); + + if (aBitmapEx.IsAlpha()) + { + // draw checkered background + GalleryIconView::drawTransparenceBackground(*xDev, aPos, aBitmapExSizePixel); + } + + xDev->DrawBitmapEx(aPos, aBitmapEx); + } + + mxListView->set_text(rEntry, sItemTextTitle); + mxListView->set_image(rEntry, *xDev); + mxListView->set_id(rEntry, OUString()); + + return false; + }; + + if (bVisibleOnly) + { + // ensure all visible entries are up to date + mxListView->visible_foreach(lambda); + // and ensure all selected entries are up to date + mxListView->selected_foreach(lambda); + return; + } + + mxListView->all_foreach(lambda); +} + +IMPL_LINK_NOARG(GalleryBrowser2, VisRowsScrolledHdl, weld::TreeView&, void) +{ + UpdateRows(true); +} + +IMPL_LINK_NOARG(GalleryBrowser2, SizeAllocHdl, const Size&, void) +{ + UpdateRows(true); +} + +void GalleryBrowser2::ImplUpdateInfoBar() +{ + if (!mpCurTheme) + return; + mxInfoBar->set_label( mpCurTheme->GetName() ); +} + +void GalleryBrowser2::ImplUpdateSelection() +{ + if (!mpCurTheme) + return; + auto nSelectedObject = (GALLERYBROWSERMODE_ICON == GetMode()) ? (mxIconView->GetSelectedItemId() - 1) : mxListView->get_selected_index(); + m_xHelper->SelectObject(nSelectedObject); +} + +sal_uInt32 GalleryBrowser2::ImplGetSelectedItemId( const Point* pSelPos, Point& rSelPos ) +{ + sal_uInt32 nRet = 0; + + if( GALLERYBROWSERMODE_PREVIEW == GetMode() ) + { + nRet = ( ( GALLERYBROWSERMODE_ICON == meLastMode ) ? mxIconView->GetSelectedItemId() : ( mxListView->get_selected_index() + 1 ) ); + + if( pSelPos ) + rSelPos = *pSelPos; + else + { + Size aOutputSizePixel(mxPreview->GetOutputSizePixel()); + rSelPos = Point( aOutputSizePixel.Width() >> 1, aOutputSizePixel.Height() >> 1 ); + } + } + else if (GALLERYBROWSERMODE_ICON == GetMode()) + { + if (pSelPos) + { + nRet = mxIconView->GetItemId( *pSelPos ); + rSelPos = *pSelPos; + } + else + { + nRet = mxIconView->GetSelectedItemId(); + rSelPos = mxIconView->GetItemRect(nRet).Center(); + } + } + else + { + std::unique_ptr<weld::TreeIter> xIter = mxListView->make_iterator(); + if( pSelPos ) + { + if (mxListView->get_dest_row_at_pos(*pSelPos, xIter.get(), false)) + nRet = mxListView->get_iter_index_in_parent(*xIter) + 1; + rSelPos = *pSelPos; + } + else + { + if (mxListView->get_selected(xIter.get())) + { + nRet = mxListView->get_iter_index_in_parent(*xIter) + 1; + rSelPos = mxListView->get_row_area(*xIter).Center(); + } + } + } + + if( nRet && ( !mpCurTheme || ( nRet > mpCurTheme->GetObjectCount() ) ) ) + { + nRet = 0; + } + + return nRet; +} + +void GalleryBrowser2::ImplSelectItemId(sal_uInt32 nItemId) +{ + if( nItemId ) + { + mxIconView->SelectItem(nItemId); + mxListView->select( nItemId - 1 ); + ImplUpdateSelection(); + } +} + +css::uno::Reference< css::frame::XFrame > +GalleryBrowser2::GetFrame() +{ + css::uno::Reference< css::frame::XFrame > xFrame; + SfxViewFrame* pCurrentViewFrame = SfxViewFrame::Current(); + if ( pCurrentViewFrame ) + { + SfxBindings& rBindings = pCurrentViewFrame->GetBindings(); + xFrame.set( rBindings.GetActiveFrame() ); + } + + return xFrame; +} + +void GalleryBrowser2::DispatchAdd( + const css::uno::Reference< css::frame::XDispatch > &rxDispatch, + const css::util::URL &rURL) +{ + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos ); + + if( !mpCurTheme || !nItemId ) + return; + + mnCurActionPos = nItemId - 1; + + css::uno::Reference< css::frame::XDispatch > xDispatch( rxDispatch ); + css::util::URL aURL = rURL; + + if ( !xDispatch.is() ) + { + css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( + GetFrame(), css::uno::UNO_QUERY ); + if ( !xDispatchProvider.is() || !m_xTransformer.is() ) + return; + + aURL.Complete = ".uno:InsertGalleryPic"; + m_xTransformer->parseStrict( aURL ); + xDispatch = xDispatchProvider->queryDispatch( + aURL, + "_self", + css::frame::FrameSearchFlag::SELF ); + } + + if ( !xDispatch.is() ) + return; + + sal_Int8 nType = 0; + OUString aFilterName; + css::uno::Reference< css::lang::XComponent > xDrawing; + css::uno::Reference< css::graphic::XGraphic > xGraphic; + + aFilterName = GetFilterName(); + + switch( mpCurTheme->GetObjectKind( mnCurActionPos ) ) + { + case SgaObjKind::Bitmap: + case SgaObjKind::Animation: + case SgaObjKind::Inet: + // TODO drawing objects are inserted as drawings only via drag&drop + case SgaObjKind::SvDraw: + nType = css::gallery::GalleryItemType::GRAPHIC; + break; + + case SgaObjKind::Sound : + nType = css::gallery::GalleryItemType::MEDIA; + break; + + default: + nType = css::gallery::GalleryItemType::EMPTY; + break; + } + + Graphic aGraphic; + bool bGraphic = mpCurTheme->GetGraphic( mnCurActionPos, aGraphic ); + if ( bGraphic && !aGraphic.IsNone() ) + xGraphic.set( aGraphic.GetXGraphic() ); + OSL_ENSURE( xGraphic.is(), "gallery item is graphic, but the reference is invalid!" ); + + css::uno::Sequence< css::beans::PropertyValue > aSeq{ + comphelper::makePropertyValue(SVXGALLERYITEM_TYPE, nType), + comphelper::makePropertyValue(SVXGALLERYITEM_URL, OUString()), + comphelper::makePropertyValue(SVXGALLERYITEM_FILTER, aFilterName), + comphelper::makePropertyValue(SVXGALLERYITEM_DRAWING, xDrawing), + comphelper::makePropertyValue(SVXGALLERYITEM_GRAPHIC, xGraphic) + }; + assert(aSeq.getLength() == SVXGALLERYITEM_PARAMS); + + css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue( + SVXGALLERYITEM_ARGNAME, aSeq) }; + + std::unique_ptr<DispatchInfo> pInfo(new DispatchInfo); + pInfo->TargetURL = aURL; + pInfo->Arguments = aArgs; + pInfo->Dispatch = xDispatch; + + if ( Application::PostUserEvent( + LINK( nullptr, GalleryBrowser2, AsyncDispatch_Impl), pInfo.get() ) ) + pInfo.release(); +} + +void GalleryBrowser2::Execute(std::string_view rIdent) +{ + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos ); + + if( !(mpCurTheme && nItemId) ) + return; + + mnCurActionPos = nItemId - 1; + + if (rIdent == "preview") + SetMode( ( GALLERYBROWSERMODE_PREVIEW != GetMode() ) ? GALLERYBROWSERMODE_PREVIEW : meLastMode ); + else if (rIdent == "delete") + { + if (!mpCurTheme->IsReadOnly()) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetViewWindow(), "svx/ui/querydeleteobjectdialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryDeleteObjectDialog")); + if (xQuery->run() == RET_YES) + { + mpCurTheme->RemoveObject( mnCurActionPos ); + } + } + } + else if (rIdent == "title") + { + std::unique_ptr<SgaObject> pObj = mpCurTheme->AcquireObject( mnCurActionPos ); + + if( pObj ) + { + const OUString aOldTitle( GetItemText( *pObj, GalleryItemFlags::Title ) ); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractTitleDialog> aDlg(pFact->CreateTitleDialog(GetViewWindow(), aOldTitle)); + if( aDlg->Execute() == RET_OK ) + { + OUString aNewTitle( aDlg->GetTitle() ); + + if( ( aNewTitle.isEmpty() && !pObj->GetTitle().isEmpty() ) || ( aNewTitle != aOldTitle ) ) + { + if( aNewTitle.isEmpty() ) + aNewTitle = "__<empty>__"; + + pObj->SetTitle( aNewTitle ); + mpCurTheme->InsertObject( *pObj ); + } + } + } + } + else if (rIdent == "copy") + { + mpCurTheme->CopyToClipboard(*GetViewWindow(), mnCurActionPos); + } + else if (rIdent == "paste") + { + if( !mpCurTheme->IsReadOnly() ) + { + weld::Widget* pParent = GetViewWindow(); + TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromClipboard(pParent->get_clipboard())); + mpCurTheme->InsertTransferable( aDataHelper.GetTransferable(), mnCurActionPos ); + } + } +} + +OUString GalleryBrowser2::GetItemText( const SgaObject& rObj, GalleryItemFlags nItemTextFlags ) +{ + OUString aRet; + + const INetURLObject& aURL(rObj.GetURL()); + + if( nItemTextFlags & GalleryItemFlags::Title ) + { + OUString aTitle( rObj.GetTitle() ); + + if( aTitle.isEmpty() ) + aTitle = aURL.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous ); + + if( aTitle.isEmpty() ) + { + aTitle = aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ); + aTitle = aTitle.copy( aTitle.lastIndexOf('/')+1 ); + } + + aRet += aTitle; + } + + if( nItemTextFlags & GalleryItemFlags::Path ) + { + const OUString aPath( aURL.getFSysPath( FSysStyle::Detect ) ); + + if( !aPath.isEmpty() && ( nItemTextFlags & GalleryItemFlags::Title ) ) + aRet += " ("; + + aRet += aURL.getFSysPath( FSysStyle::Detect ); + + if( !aPath.isEmpty() && ( nItemTextFlags & GalleryItemFlags::Title ) ) + aRet += ")"; + } + + return aRet; +} + +INetURLObject GalleryBrowser2::GetURL() const +{ + INetURLObject aURL; + + if( mpCurTheme && mnCurActionPos != 0xffffffff ) + aURL = mpCurTheme->GetObjectURL( mnCurActionPos ); + + return aURL; +} + +OUString GalleryBrowser2::GetFilterName() const +{ + OUString aFilterName; + + if( mpCurTheme && mnCurActionPos != 0xffffffff ) + { + const SgaObjKind eObjKind = mpCurTheme->GetObjectKind( mnCurActionPos ); + + if( ( SgaObjKind::Bitmap == eObjKind ) || ( SgaObjKind::Animation == eObjKind ) ) + { + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + INetURLObject aURL; + mpCurTheme->GetURL( mnCurActionPos, aURL ); + sal_uInt16 nFilter = rFilter.GetImportFormatNumberForShortName(aURL.GetFileExtension()); + + if( GRFILTER_FORMAT_DONTKNOW != nFilter ) + aFilterName = rFilter.GetImportFormatName( nFilter ); + } + } + + return aFilterName; +} + +IMPL_LINK_NOARG(GalleryBrowser2, SelectObjectValueSetHdl, ValueSet*, void) +{ + ImplUpdateSelection(); +} + +IMPL_LINK_NOARG(GalleryBrowser2, SelectObjectHdl, weld::TreeView&, void) +{ + ImplUpdateSelection(); +} + +IMPL_LINK(GalleryBrowser2, SelectTbxHdl, weld::Toggleable&, rBox, void) +{ + if (&rBox == mxIconButton.get()) + SetMode(rBox.get_active() ? GALLERYBROWSERMODE_ICON : GALLERYBROWSERMODE_LIST); + else if (&rBox == mxListButton.get()) + SetMode(rBox.get_active() ? GALLERYBROWSERMODE_LIST : GALLERYBROWSERMODE_ICON); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |