summaryrefslogtreecommitdiffstats
path: root/svx/source/gallery2
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /svx/source/gallery2
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'svx/source/gallery2')
-rw-r--r--svx/source/gallery2/GalleryControl.cxx47
-rw-r--r--svx/source/gallery2/codec.cxx148
-rw-r--r--svx/source/gallery2/codec.hxx40
-rw-r--r--svx/source/gallery2/galbrws1.cxx485
-rw-r--r--svx/source/gallery2/galbrws1.hxx91
-rw-r--r--svx/source/gallery2/galbrws2.cxx1242
-rw-r--r--svx/source/gallery2/galctrl.cxx408
-rw-r--r--svx/source/gallery2/galexpl.cxx299
-rw-r--r--svx/source/gallery2/galini.cxx95
-rw-r--r--svx/source/gallery2/gallery1.cxx724
-rw-r--r--svx/source/gallery2/gallerybinaryengine.cxx810
-rw-r--r--svx/source/gallery2/gallerybinaryengineentry.cxx180
-rw-r--r--svx/source/gallery2/gallerybinarystoragelocations.cxx75
-rw-r--r--svx/source/gallery2/gallerydrawmodel.hxx39
-rw-r--r--svx/source/gallery2/galleryfilestorage.cxx24
-rw-r--r--svx/source/gallery2/galleryfilestorageentry.cxx24
-rw-r--r--svx/source/gallery2/galleryobjectbinarystorage.cxx25
-rw-r--r--svx/source/gallery2/galleryobjectcollection.cxx60
-rw-r--r--svx/source/gallery2/galleryobjectstorage.cxx24
-rw-r--r--svx/source/gallery2/galleryobjectxmlstorage.cxx25
-rw-r--r--svx/source/gallery2/gallerystoragelocations.cxx24
-rw-r--r--svx/source/gallery2/galmisc.cxx563
-rw-r--r--svx/source/gallery2/galobj.cxx493
-rw-r--r--svx/source/gallery2/galtheme.cxx780
24 files changed, 6725 insertions, 0 deletions
diff --git a/svx/source/gallery2/GalleryControl.cxx b/svx/source/gallery2/GalleryControl.cxx
new file mode 100644
index 000000000..d7b2a9693
--- /dev/null
+++ b/svx/source/gallery2/GalleryControl.cxx
@@ -0,0 +1,47 @@
+/* -*- 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 <GalleryControl.hxx>
+
+#include <svx/gallery1.hxx>
+#include "galbrws1.hxx"
+#include <galbrws2.hxx>
+
+namespace svx::sidebar {
+
+GalleryControl::GalleryControl(weld::Widget* pParent)
+ : PanelLayout(pParent, "GalleryPanel", "svx/ui/sidebargallery.ui")
+ , mpGallery(Gallery::GetGalleryInstance())
+ , mxBrowser1(new GalleryBrowser1(
+ *m_xBuilder,
+ mpGallery,
+ [this] ()
+ { return mxBrowser2->SelectTheme(mxBrowser1->GetSelectedTheme()); }))
+ , mxBrowser2(new GalleryBrowser2(*m_xBuilder, mpGallery))
+{
+ mxBrowser1->SelectTheme(0);
+}
+
+GalleryControl::~GalleryControl()
+{
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/codec.cxx b/svx/source/gallery2/codec.cxx
new file mode 100644
index 000000000..062c60dbe
--- /dev/null
+++ b/svx/source/gallery2/codec.cxx
@@ -0,0 +1,148 @@
+/* -*- 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 <tools/stream.hxx>
+#include <tools/zcodec.hxx>
+#include "codec.hxx"
+#include <memory>
+
+
+GalleryCodec::GalleryCodec( SvStream& rIOStm ) :
+ rStm( rIOStm )
+{
+}
+
+bool GalleryCodec::IsCoded( SvStream& rStm, sal_uInt32& rVersion )
+{
+ const sal_uInt64 nPos = rStm.Tell();
+ bool bRet;
+ sal_uInt8 cByte1, cByte2, cByte3, cByte4, cByte5, cByte6;
+
+ rStm.ReadUChar( cByte1 ).ReadUChar( cByte2 ).ReadUChar( cByte3 ).ReadUChar( cByte4 ).ReadUChar( cByte5 ).ReadUChar( cByte6 );
+
+ if ( cByte1 == 'S' && cByte2 == 'V' && cByte3 == 'R' && cByte4 == 'L' && cByte5 == 'E' && ( cByte6 == '1' || cByte6 == '2' ) )
+ {
+ rVersion = ( ( cByte6 == '1' ) ? 1 : 2 );
+ bRet = true;
+ }
+ else
+ {
+ rVersion = 0;
+ bRet = false;
+ }
+
+ rStm.Seek( nPos );
+
+ return bRet;
+}
+
+void GalleryCodec::Write( SvStream& rStmToWrite )
+{
+ sal_uInt32 nPos, nCompSize;
+
+ const sal_uInt32 nSize = rStmToWrite.TellEnd();
+ rStmToWrite.Seek( 0 );
+
+ rStm.WriteChar( 'S' ).WriteChar( 'V' ).WriteChar( 'R' ).WriteChar( 'L' ).WriteChar( 'E' ).WriteChar( '2' );
+ rStm.WriteUInt32( nSize );
+
+ nPos = rStm.Tell();
+ rStm.SeekRel( 4 );
+
+ ZCodec aCodec;
+ aCodec.BeginCompression();
+ aCodec.Compress( rStmToWrite, rStm );
+ aCodec.EndCompression();
+
+ nCompSize = rStm.Tell() - nPos - 4;
+ rStm.Seek( nPos );
+ rStm.WriteUInt32( nCompSize );
+ rStm.Seek( STREAM_SEEK_TO_END );
+}
+
+void GalleryCodec::Read( SvStream& rStmToRead )
+{
+ sal_uInt32 nVersion = 0;
+
+ if( !IsCoded( rStm, nVersion ) )
+ return;
+
+ sal_uInt32 nCompressedSize, nUnCompressedSize;
+
+ rStm.SeekRel( 6 );
+ rStm.ReadUInt32( nUnCompressedSize ).ReadUInt32( nCompressedSize );
+
+ // decompress
+ if( 1 == nVersion )
+ {
+ std::unique_ptr<sal_uInt8[]> pCompressedBuffer(new sal_uInt8[ nCompressedSize ]);
+ rStm.ReadBytes(pCompressedBuffer.get(), nCompressedSize);
+ sal_uInt8* pInBuf = pCompressedBuffer.get();
+ std::unique_ptr<sal_uInt8[]> pOutBuf(new sal_uInt8[ nUnCompressedSize ]);
+ sal_uInt8* pTmpBuf = pOutBuf.get();
+ sal_uInt8* pLast = pOutBuf.get() + nUnCompressedSize - 1;
+ sal_uIntPtr nIndex = 0, nCountByte, nRunByte;
+ bool bEndDecoding = false;
+
+ do
+ {
+ nCountByte = *pInBuf++;
+
+ if ( !nCountByte )
+ {
+ nRunByte = *pInBuf++;
+
+ if ( nRunByte > 2 )
+ {
+ // filling absolutely
+ memcpy( &pTmpBuf[ nIndex ], pInBuf, nRunByte );
+ pInBuf += nRunByte;
+ nIndex += nRunByte;
+
+ // note WORD alignment
+ if ( nRunByte & 1 )
+ pInBuf++;
+ }
+ else if ( nRunByte == 1 ) // End of the image
+ bEndDecoding = true;
+ }
+ else
+ {
+ const sal_uInt8 cVal = *pInBuf++;
+
+ memset( &pTmpBuf[ nIndex ], cVal, nCountByte );
+ nIndex += nCountByte;
+ }
+ }
+ while ( !bEndDecoding && ( pTmpBuf <= pLast ) );
+
+ rStmToRead.WriteBytes(pOutBuf.get(), nUnCompressedSize);
+ }
+ else if( 2 == nVersion )
+ {
+ ZCodec aCodec;
+
+ aCodec.BeginCompression();
+ aCodec.Decompress( rStm, rStmToRead );
+ aCodec.EndCompression();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/codec.hxx b/svx/source/gallery2/codec.hxx
new file mode 100644
index 000000000..726b80157
--- /dev/null
+++ b/svx/source/gallery2/codec.hxx
@@ -0,0 +1,40 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+class SvStream;
+
+class GalleryCodec
+{
+private:
+ SvStream& rStm;
+
+public:
+ explicit GalleryCodec(SvStream& rIOStm);
+
+ void Write(SvStream& rStmToWrite);
+ void Read(SvStream& rStmToRead);
+
+ static bool IsCoded(SvStream& rStm, sal_uInt32& rVersion);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galbrws1.cxx b/svx/source/gallery2/galbrws1.cxx
new file mode 100644
index 000000000..e33e16974
--- /dev/null
+++ b/svx/source/gallery2/galbrws1.cxx
@@ -0,0 +1,485 @@
+/* -*- 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 <sal/config.h>
+
+#include <tools/datetime.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <sfx2/app.hxx>
+#include <helpids.h>
+#include <svx/gallery1.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/galmisc.hxx>
+#include "galbrws1.hxx"
+#include <svx/strings.hrc>
+#include <algorithm>
+#include <svx/dialmgr.hxx>
+#include <comphelper/dispatchcommand.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <svx/svxdlg.hxx>
+#include <memory>
+#include <bitmaps.hlst>
+
+using namespace ::com::sun::star;
+
+GalleryBrowser1::GalleryBrowser1(
+ weld::Builder& rBuilder,
+ Gallery* pGallery,
+ const std::function<void ()>& rThemeSelectionHandler)
+ :
+ mxNewTheme(rBuilder.weld_button("insert")),
+ mxThemes(rBuilder.weld_tree_view("themelist")),
+ mxMoreGalleries(rBuilder.weld_button("btnMoreGalleries")),
+ mpGallery ( pGallery ),
+ mpExchangeData ( new ExchangeData ),
+ aImgNormal ( RID_SVXBMP_THEME_NORMAL ),
+ aImgDefault ( RID_SVXBMP_THEME_DEFAULT ),
+ aImgReadOnly ( RID_SVXBMP_THEME_READONLY ),
+ maThemeSelectionHandler(rThemeSelectionHandler)
+{
+ mxNewTheme->set_help_id(HID_GALLERY_NEWTHEME);
+ mxNewTheme->connect_clicked( LINK( this, GalleryBrowser1, ClickNewThemeHdl ) );
+
+ mxThemes->make_sorted();
+ mxThemes->set_help_id( HID_GALLERY_THEMELIST );
+ mxThemes->connect_changed( LINK( this, GalleryBrowser1, SelectThemeHdl ) );
+ mxThemes->connect_popup_menu(LINK(this, GalleryBrowser1, PopupMenuHdl));
+ mxThemes->connect_key_press(LINK(this, GalleryBrowser1, KeyInputHdl));
+ mxThemes->set_size_request(-1, mxThemes->get_height_rows(6));
+
+ mxMoreGalleries->set_from_icon_name("cmd/sc_additionsdialog.png");
+ mxMoreGalleries->connect_clicked(LINK(this, GalleryBrowser1, OnMoreGalleriesClick));
+
+ // disable creation of new themes if a writable directory is not available
+ if( mpGallery->GetUserURL().GetProtocol() == INetProtocol::NotValid )
+ mxNewTheme->set_sensitive(false);
+
+ StartListening( *mpGallery );
+
+ for (size_t i = 0, nCount = mpGallery->GetThemeCount(); i < nCount; ++i)
+ ImplInsertThemeEntry( mpGallery->GetThemeInfo( i ) );
+}
+
+GalleryBrowser1::~GalleryBrowser1()
+{
+ EndListening( *mpGallery );
+ mpExchangeData.reset();
+}
+
+void GalleryBrowser1::ImplInsertThemeEntry( const GalleryThemeEntry* pEntry )
+{
+ static const bool bShowHiddenThemes = ( getenv( "GALLERY_SHOW_HIDDEN_THEMES" ) != nullptr );
+
+ if( !(pEntry && ( !pEntry->IsHidden() || bShowHiddenThemes )) )
+ return;
+
+ const OUString* pImage;
+
+ if( pEntry->IsReadOnly() )
+ pImage = &aImgReadOnly;
+ else if( pEntry->IsDefault() )
+ pImage = &aImgDefault;
+ else
+ pImage = &aImgNormal;
+
+ mxThemes->append("", pEntry->GetThemeName(), *pImage);
+}
+
+void GalleryBrowser1::ImplFillExchangeData( const GalleryTheme* pThm, ExchangeData& rData )
+{
+ rData.pTheme = const_cast<GalleryTheme*>(pThm);
+ rData.aEditedTitle = pThm->GetName();
+
+ try
+ {
+ DateTime aDateTime(pThm->getModificationDate());
+
+ rData.aThemeChangeDate = aDateTime;
+ rData.aThemeChangeTime = aDateTime;
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+void GalleryBrowser1::ImplGetExecuteVector(std::vector<OString>& o_aExec)
+{
+ GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this );
+
+ if( !pTheme )
+ return;
+
+ bool bUpdateAllowed, bRenameAllowed, bRemoveAllowed;
+ static const bool bIdDialog = ( getenv( "GALLERY_ENABLE_ID_DIALOG" ) != nullptr );
+
+ if( pTheme->IsReadOnly() )
+ bUpdateAllowed = bRenameAllowed = bRemoveAllowed = false;
+ else if( pTheme->IsDefault() )
+ {
+ bUpdateAllowed = bRenameAllowed = true;
+ bRemoveAllowed = false;
+ }
+ else
+ bUpdateAllowed = bRenameAllowed = bRemoveAllowed = true;
+
+ if( bUpdateAllowed && pTheme->GetObjectCount() )
+ o_aExec.emplace_back("update");
+
+ if( bRenameAllowed )
+ o_aExec.emplace_back("rename");
+
+ if( bRemoveAllowed )
+ o_aExec.emplace_back("delete");
+
+ if( bIdDialog && !pTheme->IsReadOnly() )
+ o_aExec.emplace_back("assign");
+
+ o_aExec.emplace_back("properties");
+
+ mpGallery->ReleaseTheme( pTheme, *this );
+}
+
+void GalleryBrowser1::ImplGalleryThemeProperties( std::u16string_view rThemeName, bool bCreateNew )
+{
+ DBG_ASSERT(!mpThemePropsDlgItemSet, "mpThemePropsDlgItemSet already set!");
+ mpThemePropsDlgItemSet.reset(new SfxItemSet( SfxGetpApp()->GetPool() ));
+ GalleryTheme* pTheme = mpGallery->AcquireTheme( rThemeName, *this );
+
+ ImplFillExchangeData( pTheme, *mpExchangeData );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ VclPtr<VclAbstractDialog> xThemePropertiesDialog = pFact->CreateGalleryThemePropertiesDialog(mxThemes.get(), mpExchangeData.get(), mpThemePropsDlgItemSet.get());
+
+ if ( bCreateNew )
+ {
+ xThemePropertiesDialog->StartExecuteAsync([xThemePropertiesDialog, this](sal_Int32 nResult){
+ EndNewThemePropertiesDlgHdl(nResult);
+ xThemePropertiesDialog->disposeOnce();
+ });
+ }
+ else
+ {
+ xThemePropertiesDialog->StartExecuteAsync([xThemePropertiesDialog, this](sal_Int32 nResult){
+ EndThemePropertiesDlgHdl(nResult);
+ xThemePropertiesDialog->disposeOnce();
+ });
+ }
+}
+
+void GalleryBrowser1::ImplEndGalleryThemeProperties(bool bCreateNew, sal_Int32 nRet)
+{
+ if( nRet == RET_OK )
+ {
+ OUString aName( mpExchangeData->pTheme->GetName() );
+
+ if( !mpExchangeData->aEditedTitle.isEmpty() && aName != mpExchangeData->aEditedTitle )
+ {
+ OUString aTitle( mpExchangeData->aEditedTitle );
+ sal_uInt16 nCount = 0;
+
+ while( mpGallery->HasTheme( aTitle ) && ( nCount++ < 16000 ) )
+ {
+ aTitle = mpExchangeData->aEditedTitle + " " + OUString::number( nCount );
+ }
+
+ mpGallery->RenameTheme( aName, aTitle );
+ }
+
+ if ( bCreateNew )
+ {
+ mxThemes->select_text( mpExchangeData->pTheme->GetName() );
+ SelectThemeHdl( *mxThemes );
+ }
+ }
+
+ OUString aThemeName( mpExchangeData->pTheme->GetName() );
+ mpGallery->ReleaseTheme( mpExchangeData->pTheme, *this );
+
+ if ( bCreateNew && ( nRet != RET_OK ) )
+ {
+ mpGallery->RemoveTheme( aThemeName );
+ }
+}
+
+void GalleryBrowser1::EndNewThemePropertiesDlgHdl(sal_Int32 nResult)
+{
+ ImplEndGalleryThemeProperties(true, nResult);
+}
+
+void GalleryBrowser1::EndThemePropertiesDlgHdl(sal_Int32 nResult)
+{
+ ImplEndGalleryThemeProperties(false, nResult);
+}
+
+void GalleryBrowser1::ImplExecute(std::string_view rIdent)
+{
+ if (rIdent == "update")
+ {
+ GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> aActualizeProgress(pFact->CreateActualizeProgressDialog(mxThemes.get(), pTheme));
+
+ aActualizeProgress->Execute();
+ mpGallery->ReleaseTheme( pTheme, *this );
+ }
+ else if (rIdent == "delete")
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxThemes.get(), "svx/ui/querydeletethemedialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryDeleteThemeDialog"));
+ if (xQuery->run() == RET_YES)
+ mpGallery->RemoveTheme( mxThemes->get_selected_text() );
+ }
+ else if (rIdent == "rename")
+ {
+ GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this );
+ const OUString aOldName( pTheme->GetName() );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractTitleDialog> aDlg(pFact->CreateTitleDialog(mxThemes.get(), aOldName));
+
+ if( aDlg->Execute() == RET_OK )
+ {
+ const OUString aNewName( aDlg->GetTitle() );
+
+ if( !aNewName.isEmpty() && ( aNewName != aOldName ) )
+ {
+ OUString aName( aNewName );
+ sal_uInt16 nCount = 0;
+
+ while( mpGallery->HasTheme( aName ) && ( nCount++ < 16000 ) )
+ {
+ aName = aNewName + " " + OUString::number( nCount );
+ }
+
+ mpGallery->RenameTheme( aOldName, aName );
+ }
+ }
+ mpGallery->ReleaseTheme( pTheme, *this );
+ }
+ else if (rIdent == "assign")
+ {
+ GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this );
+
+ if (pTheme && !pTheme->IsReadOnly())
+ {
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGalleryIdDialog> aDlg(pFact->CreateGalleryIdDialog(mxThemes.get(), pTheme));
+ if( aDlg->Execute() == RET_OK )
+ pTheme->SetId( aDlg->GetId(), true );
+ }
+
+ mpGallery->ReleaseTheme( pTheme, *this );
+ }
+ else if (rIdent == "properties")
+ {
+ ImplGalleryThemeProperties( GetSelectedTheme(), false );
+ }
+}
+
+void GalleryBrowser1::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const GalleryHint& rGalleryHint = static_cast<const GalleryHint&>(rHint);
+
+ switch( rGalleryHint.GetType() )
+ {
+ case GalleryHintType::THEME_CREATED:
+ ImplInsertThemeEntry( mpGallery->GetThemeInfo( rGalleryHint.GetThemeName() ) );
+ break;
+
+ case GalleryHintType::THEME_RENAMED:
+ {
+ const sal_Int32 nCurSelectPos = mxThemes->get_selected_index();
+ const sal_Int32 nRenameEntryPos = mxThemes->find_text( rGalleryHint.GetThemeName() );
+
+ mxThemes->remove_text( rGalleryHint.GetThemeName() );
+ ImplInsertThemeEntry( mpGallery->GetThemeInfo( rGalleryHint.GetStringData() ) );
+
+ if( nCurSelectPos == nRenameEntryPos )
+ {
+ mxThemes->select_text( rGalleryHint.GetStringData() );
+ SelectThemeHdl( *mxThemes );
+ }
+ }
+ break;
+
+ case GalleryHintType::THEME_REMOVED:
+ {
+ mxThemes->remove_text( rGalleryHint.GetThemeName() );
+ }
+ break;
+
+ case GalleryHintType::CLOSE_THEME:
+ {
+ const sal_Int32 nCurSelectPos = mxThemes->get_selected_index();
+ const sal_Int32 nCloseEntryPos = mxThemes->find_text( rGalleryHint.GetThemeName() );
+
+ if( nCurSelectPos == nCloseEntryPos )
+ {
+ if( nCurSelectPos < ( mxThemes->n_children() - 1 ) )
+ mxThemes->select( nCurSelectPos + 1 );
+ else if( nCurSelectPos )
+ mxThemes->select( nCurSelectPos - 1 );
+ else
+ mxThemes->select(-1);
+
+ SelectThemeHdl( *mxThemes );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+IMPL_STATIC_LINK_NOARG( GalleryBrowser1, OnMoreGalleriesClick, weld::Button&, void)
+{
+ css::uno::Sequence<css::beans::PropertyValue> aArgs{
+ comphelper::makePropertyValue("AdditionsTag", OUString("Gallery"))
+ };
+ comphelper::dispatchCommand(".uno:AdditionsDialog", aArgs);
+}
+
+IMPL_LINK(GalleryBrowser1, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bRet = false;
+
+ std::vector<OString> aExecVector;
+ ImplGetExecuteVector(aExecVector);
+ OString sExecuteIdent;
+ bool bMod1 = rKEvt.GetKeyCode().IsMod1();
+
+ switch( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_INSERT:
+ ClickNewThemeHdl(*mxNewTheme);
+ break;
+
+ case KEY_I:
+ {
+ if( bMod1 )
+ ClickNewThemeHdl(*mxNewTheme);
+ }
+ break;
+
+ case KEY_U:
+ {
+ if( bMod1 )
+ sExecuteIdent = "update";
+ }
+ break;
+
+ case KEY_DELETE:
+ sExecuteIdent = "delete";
+ break;
+
+ case KEY_D:
+ {
+ if( bMod1 )
+ sExecuteIdent = "delete";
+ }
+ break;
+
+ case KEY_R:
+ {
+ if( bMod1 )
+ sExecuteIdent = "rename";
+ }
+ break;
+
+ case KEY_RETURN:
+ {
+ if( bMod1 )
+ sExecuteIdent = "properties";
+ }
+ break;
+ }
+
+ if (!sExecuteIdent.isEmpty() && (std::find( aExecVector.begin(), aExecVector.end(), sExecuteIdent) != aExecVector.end()))
+ {
+ ImplExecute(sExecuteIdent);
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+IMPL_LINK(GalleryBrowser1, PopupMenuHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ std::vector<OString> aExecVector;
+ ImplGetExecuteVector(aExecVector);
+
+ if (aExecVector.empty())
+ return true;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxThemes.get(), "svx/ui/gallerymenu1.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+
+ xMenu->set_visible("update", std::find( aExecVector.begin(), aExecVector.end(), "update" ) != aExecVector.end());
+ xMenu->set_visible("rename", std::find( aExecVector.begin(), aExecVector.end(), "rename" ) != aExecVector.end());
+ xMenu->set_visible("delete", std::find( aExecVector.begin(), aExecVector.end(), "delete" ) != aExecVector.end());
+ xMenu->set_visible("assign", std::find( aExecVector.begin(), aExecVector.end(), "assign" ) != aExecVector.end());
+ xMenu->set_visible("properties", std::find( aExecVector.begin(), aExecVector.end(), "properties" ) != aExecVector.end());
+
+ OString sCommand(xMenu->popup_at_rect(mxThemes.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
+ ImplExecute(sCommand);
+
+ return true;
+}
+
+IMPL_LINK_NOARG(GalleryBrowser1, SelectThemeHdl, weld::TreeView&, void)
+{
+ if (maThemeSelectionHandler)
+ maThemeSelectionHandler();
+}
+
+IMPL_LINK_NOARG(GalleryBrowser1, ClickNewThemeHdl, weld::Button&, void)
+{
+ OUString aNewTheme( SvxResId(RID_SVXSTR_GALLERY_NEWTHEME) );
+ OUString aName( aNewTheme );
+ sal_uInt16 nCount = 0;
+
+ while( mpGallery->HasTheme( aName ) && ( nCount++ < 16000 ) )
+ {
+ aName = aNewTheme + " " + OUString::number( nCount );
+ }
+
+ if( !mpGallery->HasTheme( aName ) && mpGallery->CreateTheme( aName ) )
+ {
+ ImplGalleryThemeProperties( aName, true );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galbrws1.hxx b/svx/source/gallery2/galbrws1.hxx
new file mode 100644
index 000000000..ccbc7f24f
--- /dev/null
+++ b/svx/source/gallery2/galbrws1.hxx
@@ -0,0 +1,91 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <svl/lstner.hxx>
+#include <vcl/weld.hxx>
+#include <vector>
+
+#include <functional>
+
+class GalleryBrowser1;
+
+
+class Gallery;
+class GalleryThemeEntry;
+class GalleryTheme;
+class VclAbstractDialog;
+struct ExchangeData;
+class SfxItemSet;
+
+namespace svx::sidebar { class GalleryControl; }
+
+class GalleryBrowser1 final : public SfxListener
+{
+ friend class GalleryBrowser;
+ friend class svx::sidebar::GalleryControl;
+
+private:
+
+ std::unique_ptr<weld::Button> mxNewTheme;
+ std::unique_ptr<weld::TreeView> mxThemes;
+ std::unique_ptr<weld::Button> mxMoreGalleries;
+ Gallery* mpGallery;
+ std::unique_ptr<ExchangeData> mpExchangeData;
+ std::unique_ptr<SfxItemSet> mpThemePropsDlgItemSet;
+
+ OUString aImgNormal;
+ OUString aImgDefault;
+ OUString aImgReadOnly;
+
+ ::std::function<void ()> maThemeSelectionHandler;
+
+ void ImplInsertThemeEntry( const GalleryThemeEntry* pEntry );
+ static void ImplFillExchangeData( const GalleryTheme* pThm, ExchangeData& rData );
+ void ImplGetExecuteVector(std::vector<OString>& o_aExec);
+ void ImplExecute(std::string_view rIdent);
+ void ImplGalleryThemeProperties( std::u16string_view rThemeName, bool bCreateNew );
+ void EndNewThemePropertiesDlgHdl(sal_Int32 nResult);
+ void EndThemePropertiesDlgHdl(sal_Int32 nResult);
+ void ImplEndGalleryThemeProperties(bool bCreateNew, sal_Int32 nResult);
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ DECL_LINK( ClickNewThemeHdl, weld::Button&, void );
+ DECL_LINK( SelectThemeHdl, weld::TreeView&, void );
+ DECL_LINK( PopupMenuHdl, const CommandEvent&, bool );
+ DECL_LINK( KeyInputHdl, const KeyEvent&, bool );
+ DECL_STATIC_LINK( GalleryBrowser1, OnMoreGalleriesClick, weld::Button&, void );
+
+public:
+
+ GalleryBrowser1(
+ weld::Builder& rBuilder,
+ Gallery* pGallery,
+ const ::std::function<void ()>& rThemeSelectionHandler);
+
+ ~GalleryBrowser1();
+
+ void SelectTheme( sal_uInt16 nThemePos ) { mxThemes->select( nThemePos ); SelectThemeHdl( *mxThemes ); }
+ OUString GetSelectedTheme() const { return mxThemes->get_selected_text(); }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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: */
diff --git a/svx/source/gallery2/galctrl.cxx b/svx/source/gallery2/galctrl.cxx
new file mode 100644
index 000000000..ae9de1ce7
--- /dev/null
+++ b/svx/source/gallery2/galctrl.cxx
@@ -0,0 +1,408 @@
+/* -*- 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 <config_features.h>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <avmedia/mediaplayer.hxx>
+#include <helpids.h>
+#include <galbrws2.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/galctrl.hxx>
+#include <galobj.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <vcl/event.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <bitmaps.hlst>
+
+GalleryPreview::GalleryPreview(GalleryBrowser2* pParent, std::unique_ptr<weld::ScrolledWindow> xScrolledWindow)
+ : mxScrolledWindow(std::move(xScrolledWindow))
+ , mpParent(pParent)
+ , mpTheme(nullptr)
+{
+}
+
+void GalleryPreview::Show()
+{
+ mxScrolledWindow->show();
+ weld::CustomWidgetController::Show();
+}
+
+void GalleryPreview::Hide()
+{
+ weld::CustomWidgetController::Hide();
+ mxScrolledWindow->hide();
+}
+
+GalleryPreview::~GalleryPreview()
+{
+}
+
+void GalleryPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize = pDrawingArea->get_ref_device().LogicToPixel(Size(70, 88), MapMode(MapUnit::MapAppFont));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+
+ pDrawingArea->set_help_id(HID_GALLERY_WINDOW);
+
+ mxDragDropTargetHelper.reset(new GalleryDragDrop(mpParent, pDrawingArea->get_drop_target()));
+}
+
+namespace
+{
+ bool ImplGetGraphicCenterRect(const weld::CustomWidgetController& rWidget, const Graphic& rGraphic, tools::Rectangle& rResultRect)
+ {
+ const Size aWinSize(rWidget.GetOutputSizePixel());
+ Size aNewSize(rWidget.GetDrawingArea()->get_ref_device().LogicToPixel(rGraphic.GetPrefSize(), rGraphic.GetPrefMapMode()));
+ bool bRet = false;
+
+ if( aNewSize.Width() && aNewSize.Height() )
+ {
+ // scale to fit window
+ const double fGrfWH = static_cast<double>(aNewSize.Width()) / aNewSize.Height();
+ const double fWinWH = static_cast<double>(aWinSize.Width()) / aWinSize.Height();
+
+ if ( fGrfWH < fWinWH )
+ {
+ aNewSize.setWidth( static_cast<tools::Long>( aWinSize.Height() * fGrfWH ) );
+ aNewSize.setHeight( aWinSize.Height() );
+ }
+ else
+ {
+ aNewSize.setWidth( aWinSize.Width() );
+ aNewSize.setHeight( static_cast<tools::Long>( aWinSize.Width() / fGrfWH) );
+ }
+
+ const Point aNewPos( ( aWinSize.Width() - aNewSize.Width() ) >> 1,
+ ( aWinSize.Height() - aNewSize.Height() ) >> 1 );
+
+ rResultRect = tools::Rectangle( aNewPos, aNewSize );
+ bRet = true;
+ }
+
+ return bRet;
+ }
+}
+
+bool GalleryPreview::ImplGetGraphicCenterRect( const Graphic& rGraphic, tools::Rectangle& rResultRect ) const
+{
+ return ::ImplGetGraphicCenterRect(*this, rGraphic, rResultRect);
+}
+
+void GalleryPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
+{
+ rRenderContext.SetBackground(Wallpaper(GALLERY_BG_COLOR));
+ rRenderContext.Erase();
+
+ if (ImplGetGraphicCenterRect(aGraphicObj.GetGraphic(), aPreviewRect))
+ {
+ const Point aPos( aPreviewRect.TopLeft() );
+ const Size aSize( aPreviewRect.GetSize() );
+
+ if( aGraphicObj.IsAnimated() )
+ aGraphicObj.StartAnimation(rRenderContext, aPos, aSize);
+ else
+ aGraphicObj.Draw(rRenderContext, aPos, aSize);
+ }
+}
+
+bool GalleryPreview::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if (mpTheme && (rMEvt.GetClicks() == 2))
+ mpParent->TogglePreview();
+ return true;
+}
+
+bool GalleryPreview::Command(const CommandEvent& rCEvt)
+{
+ if (mpTheme && (rCEvt.GetCommand() == CommandEventId::ContextMenu))
+ {
+ mpParent->ShowContextMenu(rCEvt);
+ return true;
+ }
+ return false;
+}
+
+bool GalleryPreview::KeyInput(const KeyEvent& rKEvt)
+{
+ if(mpTheme)
+ {
+ GalleryBrowser2* pBrowser = mpParent;
+
+ switch( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_BACKSPACE:
+ pBrowser->TogglePreview();
+ break;
+
+ case KEY_HOME:
+ pBrowser->Travel( GalleryBrowserTravel::First );
+ break;
+
+ case KEY_END:
+ pBrowser->Travel( GalleryBrowserTravel::Last );
+ break;
+
+ case KEY_LEFT:
+ case KEY_UP:
+ pBrowser->Travel( GalleryBrowserTravel::Previous );
+ break;
+
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ pBrowser->Travel( GalleryBrowserTravel::Next );
+ break;
+
+ default:
+ {
+ if (!pBrowser->KeyInput(rKEvt))
+ return false;
+ }
+ break;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool GalleryPreview::StartDrag()
+{
+ if (mpTheme)
+ return mpParent->StartDrag();
+ return true;
+}
+
+void GalleryPreview::PreviewMedia( const INetURLObject& rURL )
+{
+#if HAVE_FEATURE_AVMEDIA
+ if (rURL.GetProtocol() == INetProtocol::NotValid)
+ return;
+
+ ::avmedia::MediaFloater* pFloater = avmedia::getMediaFloater();
+
+ if (!pFloater)
+ {
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ pViewFrm->GetBindings().GetDispatcher()->Execute( SID_AVMEDIA_PLAYER, SfxCallMode::SYNCHRON );
+ pFloater = avmedia::getMediaFloater();
+ }
+
+ if (pFloater)
+ pFloater->setURL( rURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ), "", true );
+#else
+ (void) rURL;
+#endif
+}
+
+DialogGalleryPreview::DialogGalleryPreview()
+{
+}
+
+void DialogGalleryPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(70, 88), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ pDrawingArea->set_help_id(HID_GALLERY_WINDOW);
+}
+
+bool DialogGalleryPreview::SetGraphic( const INetURLObject& _aURL )
+{
+ bool bRet = true;
+ Graphic aGraphic;
+#if HAVE_FEATURE_AVMEDIA
+ if( ::avmedia::MediaWindow::isMediaURL( _aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ), "" ) )
+ {
+ aGraphic = BitmapEx(RID_SVXBMP_GALLERY_MEDIA);
+ }
+ else
+#endif
+ {
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ GalleryProgress aProgress( &rFilter );
+ if( rFilter.ImportGraphic( aGraphic, _aURL ) )
+ bRet = false;
+ }
+
+ SetGraphic( aGraphic );
+ Invalidate();
+ return bRet;
+}
+
+bool DialogGalleryPreview::ImplGetGraphicCenterRect( const Graphic& rGraphic, tools::Rectangle& rResultRect ) const
+{
+ return ::ImplGetGraphicCenterRect(*this, rGraphic, rResultRect);
+}
+
+void DialogGalleryPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.SetBackground(Wallpaper(GALLERY_BG_COLOR));
+
+ if (ImplGetGraphicCenterRect(aGraphicObj.GetGraphic(), aPreviewRect))
+ {
+ const Point aPos( aPreviewRect.TopLeft() );
+ const Size aSize( aPreviewRect.GetSize() );
+
+ if( aGraphicObj.IsAnimated() )
+ aGraphicObj.StartAnimation(rRenderContext, aPos, aSize);
+ else
+ aGraphicObj.Draw(rRenderContext, aPos, aSize);
+ }
+}
+
+void GalleryIconView::drawTransparenceBackground(vcl::RenderContext& rOut, const Point& rPos, const Size& rSize)
+{
+ // draw checkered background
+ static const sal_uInt32 nLen(8);
+ static const Color aW(COL_WHITE);
+ static const Color aG(0xef, 0xef, 0xef);
+
+ rOut.DrawCheckered(rPos, rSize, nLen, aW, aG);
+}
+
+GalleryIconView::GalleryIconView(GalleryBrowser2* pParent, std::unique_ptr<weld::ScrolledWindow> xScrolledWindow)
+ : ValueSet(std::move(xScrolledWindow))
+ , mpParent(pParent)
+ , mpTheme(nullptr)
+{
+}
+
+GalleryIconView::~GalleryIconView()
+{
+}
+
+void GalleryIconView::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ ValueSet::SetDrawingArea(pDrawingArea);
+
+ SetStyle(GetStyle() | WB_TABSTOP | WB_3DLOOK | WB_BORDER | WB_ITEMBORDER | WB_DOUBLEBORDER | WB_VSCROLL | WB_FLATVALUESET);
+ EnableFullItemMode( false );
+
+ SetHelpId( HID_GALLERY_WINDOW );
+ SetExtraSpacing( 2 );
+ SetItemWidth( S_THUMB + 6 );
+ SetItemHeight( S_THUMB + 6 );
+
+ mxDragDropTargetHelper.reset(new GalleryDragDrop(mpParent, pDrawingArea->get_drop_target()));
+}
+
+void GalleryIconView::UserDraw(const UserDrawEvent& rUDEvt)
+{
+ const sal_uInt16 nId = rUDEvt.GetItemId();
+
+ if (!nId || !mpTheme)
+ return;
+
+ const tools::Rectangle& rRect = rUDEvt.GetRect();
+ const Size aSize(rRect.GetWidth(), rRect.GetHeight());
+ BitmapEx aBitmapEx;
+ Size aPreparedSize;
+ OUString aItemTextTitle;
+ OUString aItemTextPath;
+
+ mpTheme->GetPreviewBitmapExAndStrings(nId - 1, aBitmapEx, aPreparedSize, aItemTextTitle, aItemTextPath);
+
+ bool bNeedToCreate(aBitmapEx.IsEmpty());
+
+ if (!bNeedToCreate && aItemTextTitle.isEmpty())
+ {
+ bNeedToCreate = true;
+ }
+
+ if (!bNeedToCreate && aPreparedSize != aSize)
+ {
+ bNeedToCreate = true;
+ }
+
+ if (bNeedToCreate)
+ {
+ std::unique_ptr<SgaObject> pObj = mpTheme->AcquireObject(nId - 1);
+
+ if(pObj)
+ {
+ aBitmapEx = pObj->createPreviewBitmapEx(aSize);
+ aItemTextTitle = GalleryBrowser2::GetItemText(*pObj, GalleryItemFlags::Title);
+
+ mpTheme->SetPreviewBitmapExAndStrings(nId - 1, aBitmapEx, aSize, aItemTextTitle, aItemTextPath);
+ }
+ }
+
+ if (!aBitmapEx.IsEmpty())
+ {
+ const Size aBitmapExSizePixel(aBitmapEx.GetSizePixel());
+ const Point aPos(
+ ((aSize.Width() - aBitmapExSizePixel.Width()) >> 1) + rRect.Left(),
+ ((aSize.Height() - aBitmapExSizePixel.Height()) >> 1) + rRect.Top());
+ OutputDevice* pDev = rUDEvt.GetRenderContext();
+
+ if(aBitmapEx.IsAlpha())
+ {
+ // draw checkered background for full rectangle.
+ GalleryIconView::drawTransparenceBackground(*pDev, rRect.TopLeft(), rRect.GetSize());
+ }
+
+ pDev->DrawBitmapEx(aPos, aBitmapEx);
+ }
+
+ SetItemText(nId, aItemTextTitle);
+}
+
+bool GalleryIconView::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bRet = ValueSet::MouseButtonDown(rMEvt);
+
+ if (rMEvt.GetClicks() == 2)
+ mpParent->TogglePreview();
+
+ return bRet;
+}
+
+bool GalleryIconView::Command(const CommandEvent& rCEvt)
+{
+ bool bRet = ValueSet::Command(rCEvt);
+
+ if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
+ {
+ mpParent->ShowContextMenu(rCEvt);
+ }
+
+ return bRet;
+}
+
+bool GalleryIconView::KeyInput(const KeyEvent& rKEvt)
+{
+ if (!mpTheme || !mpParent->KeyInput(rKEvt))
+ return ValueSet::KeyInput(rKEvt);
+ return true;
+}
+
+bool GalleryIconView::StartDrag()
+{
+ Select();
+ return mpParent->StartDrag();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galexpl.cxx b/svx/source/gallery2/galexpl.cxx
new file mode 100644
index 000000000..b1e70919c
--- /dev/null
+++ b/svx/source/gallery2/galexpl.cxx
@@ -0,0 +1,299 @@
+/* -*- 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 <svx/gallery1.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/gallery.hxx>
+#include <galobj.hxx>
+
+namespace
+{
+ SfxListener& theLockListener()
+ {
+ static SfxListener SINGLETON;
+ return SINGLETON;
+ }
+}
+
+
+bool GalleryExplorer::FillThemeList( std::vector<OUString>& rThemeList )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+
+ if( pGal )
+ {
+ for( sal_uInt32 i = 0, nCount = pGal->GetThemeCount(); i < nCount; i++ )
+ {
+ const GalleryThemeEntry* pEntry = pGal->GetThemeInfo( i );
+
+ if( pEntry && !pEntry->IsReadOnly() && !pEntry->IsHidden() )
+ rThemeList.push_back(pEntry->GetThemeName());
+ }
+ }
+
+ return !rThemeList.empty();
+}
+
+bool GalleryExplorer::FillObjList( std::u16string_view rThemeName, std::vector<OUString> &rObjList )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ for( sal_uInt32 i = 0, nCount = pTheme->GetObjectCount(); i < nCount; i++ )
+ rObjList.push_back( pTheme->GetObjectURL( i ).GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+
+ return !rObjList.empty();
+}
+
+bool GalleryExplorer::FillObjList( const sal_uInt32 nThemeId, std::vector<OUString> &rObjList )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+
+ if (!pGal)
+ return false;
+
+ return FillObjList( pGal->GetThemeName( nThemeId ), rObjList );
+}
+
+bool GalleryExplorer::FillObjListTitle( const sal_uInt32 nThemeId, std::vector< OUString >& rList )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( pGal->GetThemeName( nThemeId ), aListener );
+
+ if( pTheme )
+ {
+ for( sal_uInt32 i = 0, nCount = pTheme->GetObjectCount(); i < nCount; i++ )
+ {
+ std::unique_ptr<SgaObject> pObj = pTheme->AcquireObject( i );
+ if ( pObj )
+ {
+ OUString aTitle( pObj->GetTitle() );
+ rList.push_back( aTitle );
+ }
+ }
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+ return !rList.empty();
+}
+
+bool GalleryExplorer::InsertURL( std::u16string_view rThemeName, std::u16string_view rURL )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ bool bRet = false;
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ INetURLObject aURL( rURL );
+ DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+ bRet = pTheme->InsertURL( aURL );
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryExplorer::InsertURL( sal_uInt32 nThemeId, std::u16string_view rURL )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return pGal && InsertURL( pGal->GetThemeName( nThemeId ), rURL );
+}
+
+bool GalleryExplorer::GetGraphicObj( std::u16string_view rThemeName, sal_uInt32 nPos,
+ Graphic* pGraphic )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ bool bRet = false;
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ if( pGraphic )
+ bRet = bRet || pTheme->GetGraphic( nPos, *pGraphic );
+
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryExplorer::GetGraphicObj( sal_uInt32 nThemeId, sal_uInt32 nPos,
+ Graphic* pGraphic )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return pGal && GetGraphicObj( pGal->GetThemeName( nThemeId ), nPos, pGraphic );
+}
+
+sal_uInt32 GalleryExplorer::GetSdrObjCount( std::u16string_view rThemeName )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ sal_uInt32 nRet = 0;
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ for( sal_uInt32 i = 0, nCount = pTheme->GetObjectCount(); i < nCount; i++ )
+ if( SgaObjKind::SvDraw == pTheme->GetObjectKind( i ) )
+ nRet++;
+
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+
+ return nRet;
+}
+
+sal_uInt32 GalleryExplorer::GetSdrObjCount( sal_uInt32 nThemeId )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return( pGal ? GetSdrObjCount( pGal->GetThemeName( nThemeId ) ) : 0 );
+}
+
+bool GalleryExplorer::GetSdrObj( std::u16string_view rThemeName, sal_uInt32 nSdrModelPos,
+ SdrModel* pModel, BitmapEx* pThumb )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ bool bRet = false;
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ for( sal_uInt32 i = 0, nCount = pTheme->GetObjectCount(), nActPos = 0; ( i < nCount ) && !bRet; i++ )
+ {
+ if( SgaObjKind::SvDraw == pTheme->GetObjectKind( i ) )
+ {
+ if( nActPos++ == nSdrModelPos )
+ {
+ if( pModel )
+ bRet = pTheme->GetModel(i, *pModel);
+
+ if( pThumb )
+ bRet = bRet || pTheme->GetThumb( i, *pThumb );
+ }
+ }
+ }
+
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryExplorer::GetSdrObj( sal_uInt32 nThemeId, sal_uInt32 nSdrModelPos,
+ SdrModel* pModel, BitmapEx* pThumb )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return pGal && GetSdrObj( pGal->GetThemeName( nThemeId ), nSdrModelPos, pModel, pThumb );
+}
+
+bool GalleryExplorer::BeginLocking( std::u16string_view rThemeName )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ bool bRet = false;
+
+ if( pGal )
+ {
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, theLockListener() );
+
+ if( pTheme )
+ {
+ pTheme->LockTheme();
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryExplorer::BeginLocking( sal_uInt32 nThemeId )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return pGal && BeginLocking( pGal->GetThemeName( nThemeId ) );
+}
+
+bool GalleryExplorer::EndLocking( std::u16string_view rThemeName )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ bool bRet = false;
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ const bool bReleaseLockedTheme = pTheme->UnlockTheme();
+
+ // release acquired theme
+ pGal->ReleaseTheme( pTheme, aListener );
+
+ if( bReleaseLockedTheme )
+ {
+ // release locked theme
+ pGal->ReleaseTheme( pTheme, theLockListener() );
+ bRet = true;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryExplorer::EndLocking( sal_uInt32 nThemeId )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return pGal && EndLocking( pGal->GetThemeName( nThemeId ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galini.cxx b/svx/source/gallery2/galini.cxx
new file mode 100644
index 000000000..8cdfb23ae
--- /dev/null
+++ b/svx/source/gallery2/galini.cxx
@@ -0,0 +1,95 @@
+/* -*- 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/.
+ */
+
+/*
+ * The world's quickest and lamest .desktop / .ini file parser.
+ * Ideally the .thm file would move to a .desktop file in
+ * future.
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <unotools/ucbstreamhelper.hxx>
+#include <svx/gallerybinaryengineentry.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <o3tl/string_view.hxx>
+#include <memory>
+
+OUString GalleryBinaryEngineEntry::ReadStrFromIni(std::u16string_view aKeyName ) const
+{
+ std::unique_ptr<SvStream> pStrm(::utl::UcbStreamHelper::CreateStream(
+ GetStrURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ StreamMode::READ ));
+
+ const LanguageTag &rLangTag = Application::GetSettings().GetUILanguageTag();
+
+ ::std::vector< OUString > aFallbacks = rLangTag.getFallbackStrings( true);
+
+ OUString aResult;
+ sal_Int32 nRank = 42;
+
+ if( pStrm )
+ {
+ OString aLine;
+ while( pStrm->ReadLine( aLine ) )
+ {
+ OUString aKey;
+ OUString aLocale;
+ OUString aValue;
+ sal_Int32 n;
+
+ // comments
+ if( aLine.startsWith( "#" ) )
+ continue;
+
+ // a[en_US] = Bob
+ if( ( n = aLine.indexOf( '=' ) ) >= 1)
+ {
+ aKey = OStringToOUString(
+ o3tl::trim(aLine.subView( 0, n )), RTL_TEXTENCODING_ASCII_US );
+ aValue = OStringToOUString(
+ o3tl::trim(aLine.subView( n + 1 )), RTL_TEXTENCODING_UTF8 );
+
+ if( ( n = aKey.indexOf( '[' ) ) >= 1 )
+ {
+ aLocale = o3tl::trim(aKey.subView( n + 1 ));
+ aKey = o3tl::trim(aKey.subView( 0, n ));
+ if( (n = aLocale.indexOf( ']' ) ) >= 1 )
+ aLocale = o3tl::trim(aLocale.subView( 0, n ));
+ }
+ }
+ SAL_INFO("svx", "ini file has '" << aKey << "' [ '" << aLocale << "' ] = '" << aValue << "'");
+
+ // grisly language matching, is this not available somewhere else?
+ if( aKey == aKeyName )
+ {
+ /* FIXME-BCP47: what is this supposed to do? */
+ n = 0;
+ OUString aLang = aLocale.replace('_','-');
+ for( const auto& rFallback : aFallbacks )
+ {
+ SAL_INFO( "svx", "compare '" << aLang << "' with '" << rFallback << "' rank " << nRank << " vs. " << n );
+ if( rFallback == aLang && n < nRank ) {
+ nRank = n; // try to get the most accurate match
+ aResult = aValue;
+ }
+ ++n;
+ }
+ }
+ }
+ }
+
+ SAL_INFO( "svx", "readStrFromIni returns '" << aResult << "'");
+ return aResult;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallery1.cxx b/svx/source/gallery2/gallery1.cxx
new file mode 100644
index 000000000..3d412eacb
--- /dev/null
+++ b/svx/source/gallery2/gallery1.cxx
@@ -0,0 +1,724 @@
+/* -*- 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 <config_features.h>
+
+#if defined(MACOSX) && HAVE_FEATURE_READONLY_INSTALLSET
+#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
+#include <premac.h>
+#include <Foundation/Foundation.h>
+#include <postmac.h>
+#endif
+
+#include <sal/config.h>
+
+#include <comphelper/processfactory.hxx>
+#include <ucbhelper/content.hxx>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <o3tl/string_view.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/pathoptions.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/gallery.hxx>
+#include <svx/galleryobjectcollection.hxx>
+#include <svx/strings.hrc>
+#include <strings.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/gallery1.hxx>
+#include <svx/gallerybinaryengineentry.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+#include <memory>
+
+
+using namespace ::com::sun::star;
+
+
+const std::pair<sal_uInt16, rtl::OUStringConstExpr> aUnlocalized[] =
+{
+ { GALLERY_THEME_HOMEPAGE, RID_GALLERYSTR_THEME_HTMLBUTTONS },
+ { GALLERY_THEME_POWERPOINT, RID_GALLERYSTR_THEME_POWERPOINT },
+ { GALLERY_THEME_USERSOUNDS, RID_GALLERYSTR_THEME_USERSOUNDS },
+ { GALLERY_THEME_DUMMY5, RID_GALLERYSTR_THEME_DUMMY5 },
+ { GALLERY_THEME_RULERS, RID_GALLERYSTR_THEME_RULERS },
+ { GALLERY_THEME_FONTWORK, RID_GALLERYSTR_THEME_FONTWORK },
+ { GALLERY_THEME_FONTWORK_VERTICAL, RID_GALLERYSTR_THEME_FONTWORK_VERTICAL }
+};
+
+const std::pair<sal_uInt16, TranslateId> aLocalized[] =
+{
+ { RID_GALLERY_THEME_3D, RID_GALLERYSTR_THEME_3D },
+ { RID_GALLERY_THEME_ANIMATIONS, RID_GALLERYSTR_THEME_ANIMATIONS },
+ { RID_GALLERY_THEME_BULLETS, RID_GALLERYSTR_THEME_BULLETS },
+ { RID_GALLERY_THEME_OFFICE, RID_GALLERYSTR_THEME_OFFICE },
+ { RID_GALLERY_THEME_FLAGS, RID_GALLERYSTR_THEME_FLAGS },
+ { RID_GALLERY_THEME_FLOWCHARTS, RID_GALLERYSTR_THEME_FLOWCHARTS },
+ { RID_GALLERY_THEME_EMOTICONS, RID_GALLERYSTR_THEME_EMOTICONS },
+ { RID_GALLERY_THEME_PHOTOS, RID_GALLERYSTR_THEME_PHOTOS },
+ { RID_GALLERY_THEME_BACKGROUNDS, RID_GALLERYSTR_THEME_BACKGROUNDS },
+ { RID_GALLERY_THEME_HOMEPAGE, RID_GALLERYSTR_THEME_HOMEPAGE },
+ { RID_GALLERY_THEME_INTERACTION, RID_GALLERYSTR_THEME_INTERACTION },
+ { RID_GALLERY_THEME_MAPS, RID_GALLERYSTR_THEME_MAPS },
+ { RID_GALLERY_THEME_PEOPLE, RID_GALLERYSTR_THEME_PEOPLE },
+ { RID_GALLERY_THEME_SURFACES, RID_GALLERYSTR_THEME_SURFACES },
+ { RID_GALLERY_THEME_SOUNDS, RID_GALLERYSTR_THEME_SOUNDS },
+ { RID_GALLERY_THEME_SYMBOLS, RID_GALLERYSTR_THEME_SYMBOLS },
+ { RID_GALLERY_THEME_MYTHEME, RID_GALLERYSTR_THEME_MYTHEME },
+
+ { RID_GALLERY_THEME_ARROWS, RID_GALLERYSTR_THEME_ARROWS },
+ { RID_GALLERY_THEME_BALLOONS, RID_GALLERYSTR_THEME_BALLOONS },
+ { RID_GALLERY_THEME_KEYBOARD, RID_GALLERYSTR_THEME_KEYBOARD },
+ { RID_GALLERY_THEME_TIME, RID_GALLERYSTR_THEME_TIME },
+ { RID_GALLERY_THEME_PRESENTATION, RID_GALLERYSTR_THEME_PRESENTATION },
+ { RID_GALLERY_THEME_CALENDAR, RID_GALLERYSTR_THEME_CALENDAR },
+ { RID_GALLERY_THEME_NAVIGATION, RID_GALLERYSTR_THEME_NAVIGATION },
+ { RID_GALLERY_THEME_COMMUNICATION, RID_GALLERYSTR_THEME_COMMUNICATION },
+ { RID_GALLERY_THEME_FINANCES, RID_GALLERYSTR_THEME_FINANCES },
+ { RID_GALLERY_THEME_COMPUTER, RID_GALLERYSTR_THEME_COMPUTER },
+
+ { RID_GALLERY_THEME_CLIMA, RID_GALLERYSTR_THEME_CLIMA },
+ { RID_GALLERY_THEME_EDUCATION, RID_GALLERYSTR_THEME_EDUCATION },
+ { RID_GALLERY_THEME_TROUBLE, RID_GALLERYSTR_THEME_TROUBLE },
+ { RID_GALLERY_THEME_SCREENBEANS, RID_GALLERYSTR_THEME_SCREENBEANS },
+
+ { RID_GALLERY_THEME_COMPUTERS, RID_GALLERYSTR_THEME_COMPUTERS },
+ { RID_GALLERY_THEME_DIAGRAMS, RID_GALLERYSTR_THEME_DIAGRAMS },
+ { RID_GALLERY_THEME_ENVIRONMENT, RID_GALLERYSTR_THEME_ENVIRONMENT },
+ { RID_GALLERY_THEME_FINANCE, RID_GALLERYSTR_THEME_FINANCE },
+ { RID_GALLERY_THEME_TRANSPORT, RID_GALLERYSTR_THEME_TRANSPORT },
+ { RID_GALLERY_THEME_TXTSHAPES, RID_GALLERYSTR_THEME_TXTSHAPES }
+};
+
+GalleryThemeEntry::GalleryThemeEntry( bool bCreateUniqueURL,
+ const INetURLObject& rBaseURL, const OUString& rName,
+ bool _bReadOnly, bool _bNewFile,
+ sal_uInt32 _nId, bool _bThemeNameFromResource ) :
+ nId ( _nId ),
+ bReadOnly ( _bReadOnly ),
+ bThemeNameFromResource ( _bThemeNameFromResource )
+{
+ INetURLObject aURL( rBaseURL );
+ DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+
+ if (bCreateUniqueURL)
+ {
+ GalleryBinaryEngineEntry::CreateUniqueURL(rBaseURL,aURL);
+ }
+
+ mpGalleryStorageEngineEntry = std::make_unique<GalleryBinaryEngineEntry>();
+ setStorageLocations(aURL);
+
+ SetModified( _bNewFile );
+
+ aName = mpGalleryStorageEngineEntry->ReadStrFromIni( u"name" );
+
+ // This is awful - we shouldn't use these resources if we
+ // possibly can avoid them
+ if( aName.isEmpty() && nId && bThemeNameFromResource )
+ {
+ //some of these are supposed to *not* be localized
+ //so catch them before looking up the resource
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aUnlocalized); ++i)
+ {
+ if (aUnlocalized[i].first == nId)
+ {
+ aName = aUnlocalized[i].second;
+ break;
+ }
+ }
+ //look up the rest of the ids in string resources
+ if (aName.isEmpty())
+ {
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aLocalized); ++i)
+ {
+ if (aLocalized[i].first == nId)
+ {
+ aName = SvxResId(aLocalized[i].second);
+ break;
+ }
+ }
+ }
+ }
+
+ if( aName.isEmpty() )
+ aName = rName;
+}
+
+void GalleryThemeEntry::setStorageLocations(INetURLObject & rURL)
+{
+ mpGalleryStorageEngineEntry->setStorageLocations(rURL);
+}
+
+GalleryTheme* GalleryThemeEntry::createGalleryTheme(Gallery* pGallery)
+{
+ return new GalleryTheme(pGallery,this);
+}
+
+std::unique_ptr<GalleryBinaryEngine> GalleryThemeEntry::createGalleryStorageEngine(GalleryObjectCollection& mrGalleryObjectCollection)
+{
+ return mpGalleryStorageEngineEntry->createGalleryStorageEngine(mrGalleryObjectCollection, bReadOnly);
+}
+
+void GalleryTheme::InsertAllThemes(weld::ComboBox& rListBox)
+{
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aUnlocalized); ++i)
+ rListBox.append_text(aUnlocalized[i].second);
+
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aLocalized); ++i)
+ rListBox.append_text(SvxResId(aLocalized[i].second));
+}
+
+void GalleryThemeEntry::SetName( const OUString& rNewName )
+{
+ if( aName != rNewName )
+ {
+ aName = rNewName;
+ SetModified( true );
+ bThemeNameFromResource = false;
+ }
+}
+
+void GalleryThemeEntry::SetId( sal_uInt32 nNewId, bool bResetThemeName )
+{
+ nId = nNewId;
+ SetModified( true );
+ bThemeNameFromResource = ( nId && bResetThemeName );
+}
+
+void GalleryThemeEntry::removeTheme()
+{
+ mpGalleryStorageEngineEntry->removeTheme();
+}
+
+class GalleryThemeCacheEntry
+{
+private:
+
+ const GalleryThemeEntry* mpThemeEntry;
+ std::unique_ptr<GalleryTheme> mpTheme;
+
+public:
+
+ GalleryThemeCacheEntry( const GalleryThemeEntry* pThemeEntry, std::unique_ptr<GalleryTheme> pTheme ) :
+ mpThemeEntry( pThemeEntry ), mpTheme( std::move(pTheme) ) {}
+
+ const GalleryThemeEntry* GetThemeEntry() const { return mpThemeEntry; }
+ GalleryTheme* GetTheme() const { return mpTheme.get(); }
+};
+
+
+Gallery::Gallery( std::u16string_view rMultiPath )
+: bMultiPath ( false )
+{
+ ImplLoad( rMultiPath );
+}
+
+Gallery::~Gallery()
+{
+}
+
+Gallery* Gallery::GetGalleryInstance()
+{
+ // note: this would deadlock if it used osl::Mutex::getGlobalMutex()
+ static Gallery *const s_pGallery(
+ utl::ConfigManager::IsFuzzing() ? nullptr :
+ new Gallery(SvtPathOptions().GetGalleryPath()));
+
+ return s_pGallery;
+}
+
+void Gallery::ImplLoad( std::u16string_view rMultiPath )
+{
+ bool bIsReadOnlyDir {false};
+
+ bMultiPath = !rMultiPath.empty();
+
+ INetURLObject aCurURL(SvtPathOptions().GetConfigPath());
+ ImplLoadSubDirs( aCurURL, bIsReadOnlyDir );
+
+ if( !bIsReadOnlyDir )
+ aUserURL = aCurURL;
+
+ if( bMultiPath )
+ {
+ bool bIsRelURL {true};
+ sal_Int32 nIdx {0};
+ do
+ {
+ aCurURL = INetURLObject(o3tl::getToken(rMultiPath, 0, ';', nIdx));
+ if (bIsRelURL)
+ {
+ aRelURL = aCurURL;
+ bIsRelURL = false;
+ }
+
+ ImplLoadSubDirs( aCurURL, bIsReadOnlyDir );
+
+ if( !bIsReadOnlyDir )
+ aUserURL = aCurURL;
+ }
+ while (nIdx>0);
+ }
+ else
+ aRelURL = INetURLObject( rMultiPath );
+
+ DBG_ASSERT( aUserURL.GetProtocol() != INetProtocol::NotValid, "no writable Gallery user directory available" );
+ DBG_ASSERT( aRelURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+}
+
+void Gallery::ImplLoadSubDirs( const INetURLObject& rBaseURL, bool& rbDirIsReadOnly )
+{
+ rbDirIsReadOnly = false;
+
+ try
+ {
+ uno::Reference< ucb::XCommandEnvironment > xEnv;
+ ::ucbhelper::Content aCnt( rBaseURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext() );
+
+ uno::Sequence<OUString> aProps { "Url" };
+
+ uno::Reference< sdbc::XResultSet > xResultSet( aCnt.createCursor( aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ) );
+
+#if defined(MACOSX) && HAVE_FEATURE_READONLY_INSTALLSET
+ if( rBaseURL.GetProtocol() == INetProtocol::File )
+ {
+ const char *appBundle = [[[NSBundle mainBundle] bundlePath] UTF8String];
+ OUString path = rBaseURL.GetURLPath();
+ if( path.startsWith( OUStringConcatenation(OUString( appBundle, strlen( appBundle ), RTL_TEXTENCODING_UTF8 ) + "/") ) )
+ rbDirIsReadOnly = true;
+ }
+#else
+ try
+ {
+ // check readonlyness the very hard way
+ INetURLObject aTestURL( rBaseURL );
+
+ aTestURL.Append( u"cdefghij.klm" );
+ std::unique_ptr<SvStream> pTestStm(::utl::UcbStreamHelper::CreateStream( aTestURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE ));
+
+ if( pTestStm )
+ {
+ pTestStm->WriteInt32( sal_Int32(1) );
+
+ if( pTestStm->GetError() )
+ rbDirIsReadOnly = true;
+
+ pTestStm.reset();
+ KillFile( aTestURL );
+ }
+ else
+ rbDirIsReadOnly = true;
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+#endif
+ if( xResultSet.is() )
+ {
+ uno::Reference< ucb::XContentAccess > xContentAccess( xResultSet, uno::UNO_QUERY );
+
+ if( xContentAccess.is() )
+ {
+ static constexpr OUStringLiteral s_sTitle = u"Title";
+ static constexpr OUStringLiteral s_sIsReadOnly = u"IsReadOnly";
+
+ while( xResultSet->next() )
+ {
+ INetURLObject aThmURL( xContentAccess->queryContentIdentifierString() );
+
+ if (aThmURL.GetFileExtension().equalsIgnoreAsciiCase("thm"))
+ {
+ INetURLObject aSdgURL( aThmURL); aSdgURL.SetExtension( u"sdg" );
+ INetURLObject aSdvURL( aThmURL ); aSdvURL.SetExtension( u"sdv" );
+
+ try
+ {
+ ::ucbhelper::Content aThmCnt( aThmURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext() );
+ ::ucbhelper::Content aSdgCnt( aSdgURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext() );
+ ::ucbhelper::Content aSdvCnt( aSdvURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext() );
+
+ OUString aTitle;
+ try
+ {
+ aThmCnt.getPropertyValue( s_sTitle ) >>= aTitle;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ if( !aTitle.isEmpty() )
+ {
+ bool bReadOnly = false;
+
+ try
+ {
+ aThmCnt.getPropertyValue( s_sIsReadOnly ) >>= bReadOnly;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ if( !bReadOnly )
+ {
+ try
+ {
+ aSdgCnt.getPropertyValue( s_sTitle ) >>= aTitle;
+ }
+ catch( const css::uno::RuntimeException& )
+ {
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+
+ if( !aTitle.isEmpty() )
+ {
+ try
+ {
+ aSdgCnt.getPropertyValue( s_sIsReadOnly ) >>= bReadOnly;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ }
+
+ if( !bReadOnly )
+ {
+ try
+ {
+ aSdvCnt.getPropertyValue( s_sTitle ) >>= aTitle;
+ }
+ catch( const css::uno::RuntimeException& )
+ {
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+
+ if( !aTitle.isEmpty() )
+ {
+ try
+ {
+ aSdvCnt.getPropertyValue( s_sIsReadOnly ) >>= bReadOnly;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ }
+
+ GalleryThemeEntry* pEntry = GalleryBinaryEngineEntry::CreateThemeEntry( aThmURL, rbDirIsReadOnly || bReadOnly );
+
+ if( pEntry )
+ aThemeList.emplace_back( pEntry );
+ }
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+GalleryThemeEntry* Gallery::ImplGetThemeEntry( std::u16string_view rThemeName )
+{
+ if( !rThemeName.empty() )
+ {
+ for ( size_t i = 0, n = aThemeList.size(); i < n; ++i )
+ if( rThemeName == aThemeList[ i ]->GetThemeName() )
+ return aThemeList[ i ].get();
+ }
+
+ return nullptr;
+}
+
+OUString Gallery::GetThemeName( sal_uInt32 nThemeId ) const
+{
+ GalleryThemeEntry* pFound = nullptr;
+
+ for ( size_t i = 0, n = aThemeList.size(); i < n && !pFound; ++i )
+ {
+ GalleryThemeEntry* pEntry = aThemeList[ i ].get();
+ if( nThemeId == pEntry->GetId() )
+ pFound = pEntry;
+ }
+
+ // try fallback, if no entry was found
+ if( !pFound )
+ {
+ OUString aFallback;
+
+ switch( nThemeId )
+ {
+ case GALLERY_THEME_3D:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_3D);
+ break;
+ case GALLERY_THEME_BULLETS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_BULLETS);
+ break;
+ case GALLERY_THEME_HOMEPAGE:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_HOMEPAGE);
+ break;
+ case GALLERY_THEME_POWERPOINT:
+ aFallback = RID_GALLERYSTR_THEME_POWERPOINT;
+ break;
+ case GALLERY_THEME_FONTWORK:
+ aFallback = RID_GALLERYSTR_THEME_FONTWORK;
+ break;
+ case GALLERY_THEME_FONTWORK_VERTICAL:
+ aFallback = RID_GALLERYSTR_THEME_FONTWORK_VERTICAL;
+ break;
+ case GALLERY_THEME_SOUNDS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_SOUNDS);
+ break;
+ case RID_GALLERY_THEME_ARROWS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_ARROWS);
+ break;
+ case RID_GALLERY_THEME_COMPUTERS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_COMPUTERS);
+ break;
+ case RID_GALLERY_THEME_DIAGRAMS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_DIAGRAMS);
+ break;
+ case RID_GALLERY_THEME_EDUCATION:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_EDUCATION);
+ break;
+ case RID_GALLERY_THEME_ENVIRONMENT:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_ENVIRONMENT);
+ break;
+ case RID_GALLERY_THEME_FINANCE:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_FINANCE);
+ break;
+ case RID_GALLERY_THEME_PEOPLE:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_PEOPLE);
+ break;
+ case RID_GALLERY_THEME_SYMBOLS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_SYMBOLS);
+ break;
+ case RID_GALLERY_THEME_TRANSPORT:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_TRANSPORT);
+ break;
+ case RID_GALLERY_THEME_TXTSHAPES:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_TXTSHAPES);
+ break;
+ default:
+ break;
+ }
+
+ pFound = const_cast<Gallery*>(this)->ImplGetThemeEntry(aFallback);
+ }
+
+ return( pFound ? pFound->GetThemeName() : OUString() );
+}
+
+bool Gallery::HasTheme( std::u16string_view rThemeName )
+{
+ return( ImplGetThemeEntry( rThemeName ) != nullptr );
+}
+
+bool Gallery::CreateTheme( const OUString& rThemeName )
+{
+ bool bRet = false;
+
+ if( !HasTheme( rThemeName ) && ( GetUserURL().GetProtocol() != INetProtocol::NotValid ) )
+ {
+ INetURLObject aURL( GetUserURL() );
+ aURL.Append( rThemeName );
+ GalleryThemeEntry* pNewEntry = new GalleryThemeEntry(
+ true, aURL, rThemeName,
+ false, true, 0, false );
+
+ aThemeList.emplace_back( pNewEntry );
+ delete pNewEntry->createGalleryTheme( this );
+ Broadcast( GalleryHint( GalleryHintType::THEME_CREATED, rThemeName ) );
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+void Gallery::RenameTheme( const OUString& rOldName, const OUString& rNewName )
+{
+ GalleryThemeEntry* pThemeEntry = ImplGetThemeEntry( rOldName );
+
+ // check if the new theme name is already present
+ if( !pThemeEntry || HasTheme( rNewName ) || pThemeEntry->IsReadOnly() )
+ return;
+
+ SfxListener aListener;
+ GalleryTheme* pThm = AcquireTheme( rOldName, aListener );
+
+ if( pThm )
+ {
+ pThemeEntry->SetName( rNewName );
+ if (pThm->pThm->IsModified())
+ if (!pThm->mpGalleryStorageEngine->implWrite(*pThm, pThm->pThm))
+ pThm->ImplSetModified(false);
+
+ Broadcast( GalleryHint( GalleryHintType::THEME_RENAMED, rOldName, pThm->GetName() ) );
+ ReleaseTheme( pThm, aListener );
+ }
+}
+
+bool Gallery::RemoveTheme( const OUString& rThemeName )
+{
+ GalleryThemeEntry* pThemeEntry = ImplGetThemeEntry( rThemeName );
+ bool bRet = false;
+
+ if( pThemeEntry && !pThemeEntry->IsReadOnly() )
+ {
+ Broadcast( GalleryHint( GalleryHintType::CLOSE_THEME, rThemeName ) );
+
+ SfxListener aListener;
+ GalleryTheme* pThm = AcquireTheme( rThemeName, aListener );
+
+ if( pThm )
+ {
+ ReleaseTheme(pThm, aListener);
+ pThemeEntry->removeTheme();
+ }
+
+ auto it = std::find_if(aThemeList.begin(), aThemeList.end(),
+ [&pThemeEntry](const std::unique_ptr<GalleryThemeEntry>& rpEntry) { return pThemeEntry == rpEntry.get(); });
+ if (it != aThemeList.end())
+ aThemeList.erase( it );
+
+ Broadcast( GalleryHint( GalleryHintType::THEME_REMOVED, rThemeName ) );
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+std::unique_ptr<GalleryTheme> GalleryThemeEntry::getCachedTheme(Gallery* pGallery)
+{
+ std::unique_ptr<GalleryTheme> pNewTheme;
+ pNewTheme.reset(createGalleryTheme(pGallery));
+ mpGalleryStorageEngineEntry->getCachedTheme(pNewTheme);
+ return pNewTheme;
+}
+
+GalleryTheme* Gallery::ImplGetCachedTheme(GalleryThemeEntry* pThemeEntry)
+{
+ GalleryTheme* pTheme = nullptr;
+
+ if( pThemeEntry )
+ {
+ auto it = std::find_if(aThemeCache.begin(), aThemeCache.end(),
+ [&pThemeEntry](const GalleryThemeCacheEntry* pEntry) { return pThemeEntry == pEntry->GetThemeEntry(); });
+ if (it != aThemeCache.end())
+ pTheme = (*it)->GetTheme();
+
+ if( !pTheme )
+ {
+ std::unique_ptr<GalleryTheme> pNewTheme = pThemeEntry->getCachedTheme(this);
+ if (pNewTheme)
+ {
+ aThemeCache.push_back( new GalleryThemeCacheEntry( pThemeEntry, std::move(pNewTheme) ));
+ pTheme = aThemeCache.back()->GetTheme();
+ }
+ }
+ }
+
+ return pTheme;
+}
+
+void Gallery::ImplDeleteCachedTheme( GalleryTheme const * pTheme )
+{
+ auto it = std::find_if(aThemeCache.begin(), aThemeCache.end(),
+ [&pTheme](const GalleryThemeCacheEntry* pEntry) { return pTheme == pEntry->GetTheme(); });
+ if (it != aThemeCache.end())
+ {
+ delete *it;
+ aThemeCache.erase(it);
+ }
+}
+
+GalleryTheme* Gallery::AcquireTheme( std::u16string_view rThemeName, SfxListener& rListener )
+{
+ GalleryTheme* pTheme = nullptr;
+ GalleryThemeEntry* pThemeEntry = ImplGetThemeEntry( rThemeName );
+
+ if( pThemeEntry )
+ {
+ pTheme = ImplGetCachedTheme( pThemeEntry );
+ if (pTheme)
+ rListener.StartListening(*pTheme, DuplicateHandling::Prevent);
+ }
+ return pTheme;
+}
+
+void Gallery::ReleaseTheme( GalleryTheme* pTheme, SfxListener& rListener )
+{
+ if( pTheme )
+ {
+ rListener.EndListening( *pTheme );
+
+ if( !pTheme->HasListeners() )
+ ImplDeleteCachedTheme( pTheme );
+ }
+}
+
+bool GalleryThemeEntry::IsDefault() const
+{
+ return nId > 0 && nId != GALLERY_THEME_MYTHEME;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallerybinaryengine.cxx b/svx/source/gallery2/gallerybinaryengine.cxx
new file mode 100644
index 000000000..c86ffa6f5
--- /dev/null
+++ b/svx/source/gallery2/gallerybinaryengine.cxx
@@ -0,0 +1,810 @@
+/* -*- 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 <svx/unomodel.hxx>
+#include <svx/fmmodel.hxx>
+#include <galobj.hxx>
+#include <svx/gallerybinaryengine.hxx>
+#include <svx/galleryobjectcollection.hxx>
+#include <svx/gallery1.hxx>
+#include <galleryobjectbinarystorage.hxx>
+#include <osl/thread.hxx>
+#include "codec.hxx"
+#include "gallerydrawmodel.hxx"
+#include <vcl/cvtgrf.hxx>
+#include <vcl/filter/SvmWriter.hxx>
+
+#include <sal/log.hxx>
+
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+#include <comphelper/fileformat.h>
+#include <comphelper/graphicmimetype.hxx>
+#include <comphelper/processfactory.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/datetime.hxx>
+#include <unotools/datetime.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/tempfile.hxx>
+#include <ucbhelper/content.hxx>
+#include <tools/vcompat.hxx>
+
+using namespace ::com::sun::star;
+
+GalleryBinaryEngine::GalleryBinaryEngine(
+ const GalleryBinaryStorageLocations& rGalleryBinaryStorageLocations,
+ GalleryObjectCollection& rGalleryObjectCollection, bool bReadOnly)
+ : maGalleryStorageLocations(rGalleryBinaryStorageLocations)
+ , mrGalleryObjectCollection(rGalleryObjectCollection)
+ , mbReadOnly(bReadOnly)
+ , m_bDestDirRelative(false)
+{
+ ImplCreateSvDrawStorage();
+}
+
+GalleryBinaryEngine::~GalleryBinaryEngine() { clearSotStorage(); }
+
+void GalleryBinaryEngine::setDestDir(const OUString& rDestDir, bool bRelative)
+{
+ m_aDestDir = rDestDir;
+ m_bDestDirRelative = bRelative;
+}
+
+void GalleryBinaryEngine::clearSotStorage() { m_aSvDrawStorageRef.clear(); }
+
+void GalleryBinaryEngine::ImplCreateSvDrawStorage()
+{
+ try
+ {
+ m_aSvDrawStorageRef
+ = new SotStorage(false, GetSdvURL().GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ mbReadOnly ? StreamMode::READ : StreamMode::STD_READWRITE);
+ // #i50423# ReadOnly may not been set though the file can't be written (because of security reasons)
+ if ((m_aSvDrawStorageRef->GetError() != ERRCODE_NONE) && !mbReadOnly)
+ m_aSvDrawStorageRef = new SotStorage(
+ false, GetSdvURL().GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::READ);
+ }
+ catch (const css::ucb::ContentCreationException&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "failed to open: " << GetSdvURL().GetMainURL(
+ INetURLObject::DecodeMechanism::NONE)
+ << "due to");
+ }
+}
+
+const tools::SvRef<SotStorage>& GalleryBinaryEngine::GetSvDrawStorage() const
+{
+ return m_aSvDrawStorageRef;
+}
+
+bool GalleryBinaryEngine::implWrite(const GalleryTheme& rTheme, const GalleryThemeEntry* pThm)
+{
+ INetURLObject aPathURL(GetThmURL());
+
+ aPathURL.removeSegment();
+ aPathURL.removeFinalSlash();
+
+ DBG_ASSERT(aPathURL.GetProtocol() != INetProtocol::NotValid, "invalid URL");
+
+ if (FileExists(aPathURL) || CreateDir(aPathURL))
+ {
+#ifdef UNX
+ std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream(
+ GetThmURL().GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::WRITE | StreamMode::COPY_ON_SYMLINK | StreamMode::TRUNC));
+#else
+ std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream(
+ GetThmURL().GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::WRITE | StreamMode::TRUNC));
+#endif
+
+ if (pOStm)
+ {
+ writeGalleryTheme(*pOStm, rTheme, pThm);
+ pOStm.reset();
+ return true;
+ }
+
+ return false;
+ }
+ return true;
+}
+
+void GalleryBinaryEngine::insertObject(const SgaObject& rObj, GalleryObject* pFoundEntry,
+ sal_uInt32 nInsertPos)
+{
+ if (pFoundEntry)
+ {
+ GalleryObject aNewEntry;
+
+ // update title of new object if necessary
+ if (rObj.GetTitle().isEmpty())
+ {
+ std::unique_ptr<SgaObject> pOldObj(implReadSgaObject(pFoundEntry));
+
+ if (pOldObj)
+ {
+ const_cast<SgaObject&>(rObj).SetTitle(pOldObj->GetTitle());
+ }
+ }
+ else if (rObj.GetTitle() == "__<empty>__")
+ const_cast<SgaObject&>(rObj).SetTitle("");
+
+ implWriteSgaObject(rObj, nInsertPos, &aNewEntry);
+ pFoundEntry->nOffset = aNewEntry.nOffset;
+ }
+ else
+ implWriteSgaObject(rObj, nInsertPos, nullptr);
+}
+
+void GalleryBinaryEngine::removeObject(const std::unique_ptr<GalleryObject>& pEntry)
+{
+ if (mrGalleryObjectCollection.getObjectList().empty())
+ KillFile(GetSdgURL());
+
+ if (SgaObjKind::SvDraw == pEntry->eObjKind)
+ GetSvDrawStorage()->Remove(
+ pEntry->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE));
+}
+
+std::unique_ptr<SgaObject> GalleryBinaryEngine::implReadSgaObject(GalleryObject const* pEntry)
+{
+ std::unique_ptr<SgaObject> pSgaObj;
+
+ if (pEntry)
+ {
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream(
+ GetSdgURL().GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ));
+
+ if (pIStm)
+ {
+ sal_uInt32 nInventor;
+
+ // Check to ensure that the file is a valid SGA file
+ pIStm->Seek(pEntry->nOffset);
+ pIStm->ReadUInt32(nInventor);
+
+ if (nInventor == COMPAT_FORMAT('S', 'G', 'A', '3'))
+ {
+ pIStm->Seek(pEntry->nOffset);
+
+ switch (pEntry->eObjKind)
+ {
+ case SgaObjKind::Bitmap:
+ pSgaObj.reset(new SgaObjectBmp());
+ break;
+ case SgaObjKind::Animation:
+ pSgaObj.reset(new SgaObjectAnim());
+ break;
+ case SgaObjKind::Inet:
+ pSgaObj.reset(new SgaObjectINet());
+ break;
+ case SgaObjKind::SvDraw:
+ pSgaObj.reset(new SgaObjectSvDraw());
+ break;
+ case SgaObjKind::Sound:
+ pSgaObj.reset(new SgaObjectSound());
+ break;
+
+ default:
+ break;
+ }
+
+ if (pSgaObj)
+ {
+ ReadSgaObject(*pIStm, *pSgaObj);
+ pSgaObj->ImplUpdateURL(pEntry->getURL());
+ }
+ }
+ }
+ }
+
+ return pSgaObj;
+}
+
+bool GalleryBinaryEngine::implWriteSgaObject(const SgaObject& rObj, sal_uInt32 nPos,
+ GalleryObject* pExistentEntry)
+{
+ std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream(
+ GetSdgURL().GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::WRITE));
+ bool bRet = false;
+
+ if (pOStm)
+ {
+ const sal_uInt32 nOffset = pOStm->Seek(STREAM_SEEK_TO_END);
+
+ rObj.WriteData(*pOStm, m_aDestDir);
+
+ if (!pOStm->GetError())
+ {
+ GalleryObject* pEntry;
+
+ if (!pExistentEntry)
+ {
+ pEntry = new GalleryObject;
+ if (nPos < mrGalleryObjectCollection.size())
+ {
+ mrGalleryObjectCollection.getObjectList().emplace(
+ mrGalleryObjectCollection.getObjectList().begin() + nPos, pEntry);
+ }
+ else
+ mrGalleryObjectCollection.getObjectList().emplace_back(pEntry);
+ }
+ else
+ pEntry = pExistentEntry;
+
+ pEntry->m_pGalleryObjectStorage = std::make_unique<GalleryObjectBinaryStorage>();
+ pEntry->m_pGalleryObjectStorage->setURL(rObj.GetURL());
+
+ pEntry->nOffset = nOffset;
+ pEntry->eObjKind = rObj.GetObjKind();
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryBinaryEngine::readModel(const GalleryObject* pObject, SdrModel& rModel)
+{
+ tools::SvRef<SotStorage> xSotStorage(GetSvDrawStorage());
+ bool bRet = false;
+ const INetURLObject aURL(ImplGetURL(pObject));
+
+ if (xSotStorage.is())
+ {
+ const OUString aStreamName(GetSvDrawStreamNameFromURL(aURL));
+ tools::SvRef<SotStorageStream> xInputStream(
+ xSotStorage->OpenSotStream(aStreamName, StreamMode::READ));
+
+ if (xInputStream.is() && !xInputStream->GetError())
+ {
+ xInputStream->SetBufferSize(STREAMBUF_SIZE);
+ bRet = GallerySvDrawImport(*xInputStream, rModel);
+ xInputStream->SetBufferSize(0);
+ }
+ }
+ return bRet;
+}
+
+SgaObjectSvDraw GalleryBinaryEngine::insertModel(const FmFormModel& rModel,
+ const INetURLObject& rUserURL)
+{
+ INetURLObject aURL(implCreateUniqueURL(SgaObjKind::SvDraw, rUserURL));
+ tools::SvRef<SotStorage> xSotStorage(GetSvDrawStorage());
+ bool bRet = false;
+
+ if (xSotStorage.is())
+ {
+ const OUString aStreamName(GetSvDrawStreamNameFromURL(aURL));
+ tools::SvRef<SotStorageStream> xOutputStream(
+ xSotStorage->OpenSotStream(aStreamName, StreamMode::WRITE | StreamMode::TRUNC));
+
+ if (xOutputStream.is() && !xOutputStream->GetError())
+ {
+ SvMemoryStream aMemoryStream(65535, 65535);
+ FmFormModel* pFormModel = const_cast<FmFormModel*>(&rModel);
+
+ pFormModel->BurnInStyleSheetAttributes();
+
+ {
+ uno::Reference<io::XOutputStream> xDocOut(
+ new utl::OOutputStreamWrapper(aMemoryStream));
+
+ if (xDocOut.is())
+ (void)SvxDrawingLayerExport(pFormModel, xDocOut);
+ }
+
+ aMemoryStream.Seek(0);
+
+ xOutputStream->SetBufferSize(16348);
+ GalleryCodec aCodec(*xOutputStream);
+ aCodec.Write(aMemoryStream);
+
+ xOutputStream->SetBufferSize(0);
+ xOutputStream->Commit();
+ bRet = !xOutputStream->GetError();
+ }
+ }
+ if (bRet)
+ {
+ SgaObjectSvDraw aObjSvDraw(rModel, aURL);
+ return aObjSvDraw;
+ }
+ return SgaObjectSvDraw();
+}
+
+bool GalleryBinaryEngine::readModelStream(const GalleryObject* pObject,
+ tools::SvRef<SotTempStream> const& rxModelStream)
+{
+ const INetURLObject aURL(ImplGetURL(pObject));
+ tools::SvRef<SotStorage> xSotStorage(GetSvDrawStorage());
+ bool bRet = false;
+
+ if (xSotStorage.is())
+ {
+ const OUString aStreamName(GetSvDrawStreamNameFromURL(aURL));
+ tools::SvRef<SotStorageStream> xInputStream(
+ xSotStorage->OpenSotStream(aStreamName, StreamMode::READ));
+
+ if (xInputStream.is() && !xInputStream->GetError())
+ {
+ sal_uInt32 nVersion = 0;
+
+ xInputStream->SetBufferSize(16348);
+
+ if (GalleryCodec::IsCoded(*xInputStream, nVersion))
+ {
+ SvxGalleryDrawModel aModel;
+
+ if (aModel.GetModel())
+ {
+ if (GallerySvDrawImport(*xInputStream, *aModel.GetModel()))
+ {
+ aModel.GetModel()->BurnInStyleSheetAttributes();
+
+ {
+ uno::Reference<io::XOutputStream> xDocOut(
+ new utl::OOutputStreamWrapper(*rxModelStream));
+
+ SvxDrawingLayerExport(aModel.GetModel(), xDocOut);
+ }
+ }
+
+ bRet = (rxModelStream->GetError() == ERRCODE_NONE);
+ }
+ }
+
+ xInputStream->SetBufferSize(0);
+ }
+ }
+ return bRet;
+}
+
+SgaObjectSvDraw
+GalleryBinaryEngine::insertModelStream(const tools::SvRef<SotTempStream>& rxModelStream,
+ const INetURLObject& rUserURL)
+{
+ INetURLObject aURL(implCreateUniqueURL(SgaObjKind::SvDraw, rUserURL));
+ tools::SvRef<SotStorage> xSotStorage(GetSvDrawStorage());
+
+ if (xSotStorage.is())
+ {
+ const OUString aStreamName(GetSvDrawStreamNameFromURL(aURL));
+ tools::SvRef<SotStorageStream> xOutputStream(
+ xSotStorage->OpenSotStream(aStreamName, StreamMode::WRITE | StreamMode::TRUNC));
+
+ if (xOutputStream.is() && !xOutputStream->GetError())
+ {
+ GalleryCodec aCodec(*xOutputStream);
+
+ xOutputStream->SetBufferSize(16348);
+ aCodec.Write(*rxModelStream);
+
+ if (!xOutputStream->GetError())
+ {
+ xOutputStream->Seek(0);
+ SgaObjectSvDraw aObjSvDraw(*xOutputStream, aURL);
+ return aObjSvDraw;
+ }
+ }
+ }
+ return SgaObjectSvDraw();
+}
+
+INetURLObject GalleryBinaryEngine::implCreateUniqueURL(SgaObjKind eObjKind,
+ const INetURLObject& rUserURL,
+ ConvertDataFormat nFormat)
+{
+ INetURLObject aDir(rUserURL);
+ INetURLObject aInfoFileURL(rUserURL);
+ INetURLObject aNewURL;
+ sal_uInt32 nNextNumber = 1999;
+ char const* pExt = nullptr;
+ bool bExists;
+
+ aDir.Append(u"dragdrop");
+ CreateDir(aDir);
+
+ aInfoFileURL.Append(u"sdddndx1");
+
+ // read next possible number
+ if (FileExists(aInfoFileURL))
+ {
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream(
+ aInfoFileURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ));
+
+ if (pIStm)
+ {
+ pIStm->ReadUInt32(nNextNumber);
+ }
+ }
+
+ pExt = comphelper::GraphicMimeTypeHelper::GetExtensionForConvertDataFormat(nFormat);
+
+ do
+ {
+ // get URL
+ if (SgaObjKind::SvDraw == eObjKind)
+ {
+ OUString aFileName = "gallery/svdraw/dd" + OUString::number(++nNextNumber % 99999999);
+ aNewURL = INetURLObject(aFileName, INetProtocol::PrivSoffice);
+
+ bExists = false;
+
+ for (auto const& pObject : mrGalleryObjectCollection.getObjectList())
+ {
+ if (pObject->getURL() == aNewURL)
+ {
+ bExists = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ OUString aFileName = "dd" + OUString::number(++nNextNumber % 999999);
+
+ if (pExt)
+ aFileName += OUString(pExt, strlen(pExt), RTL_TEXTENCODING_ASCII_US);
+
+ aNewURL = aDir;
+ aNewURL.Append(aFileName);
+
+ bExists = FileExists(aNewURL);
+ }
+ } while (bExists);
+
+ // write updated number
+ std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream(
+ aInfoFileURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::WRITE));
+
+ if (pOStm)
+ {
+ pOStm->WriteUInt32(nNextNumber);
+ }
+
+ return aNewURL;
+}
+
+SgaObjectBmp GalleryBinaryEngine::insertGraphic(const Graphic& rGraphic, const GfxLink& aGfxLink,
+ const ConvertDataFormat& nExportFormat,
+ const INetURLObject& rUserURL)
+{
+ const INetURLObject aURL(implCreateUniqueURL(SgaObjKind::Bitmap, rUserURL, nExportFormat));
+ std::unique_ptr<SvStream> pOStm(
+ ::utl::UcbStreamHelper::CreateStream(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::WRITE | StreamMode::TRUNC));
+ bool bRet = false;
+
+ if (pOStm)
+ {
+ pOStm->SetVersion(SOFFICE_FILEFORMAT_50);
+
+ if (ConvertDataFormat::SVM == nExportFormat)
+ {
+ GDIMetaFile aMtf(rGraphic.GetGDIMetaFile());
+
+ SvmWriter aWriter(*pOStm);
+ aWriter.Write(aMtf);
+ bRet = (pOStm->GetError() == ERRCODE_NONE);
+ }
+ else
+ {
+ if (aGfxLink.GetDataSize() && aGfxLink.GetData())
+ {
+ pOStm->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
+ bRet = (pOStm->GetError() == ERRCODE_NONE);
+ }
+ else
+ bRet = (GraphicConverter::Export(*pOStm, rGraphic, nExportFormat) == ERRCODE_NONE);
+ }
+
+ pOStm.reset();
+ }
+ if (bRet)
+ {
+ const SgaObjectBmp aObjBmp(aURL);
+ return aObjBmp;
+ }
+ return SgaObjectBmp();
+}
+
+SgaObjectSvDraw GalleryBinaryEngine::updateSvDrawObject(const GalleryObject* pEntry)
+{
+ if (GetSvDrawStorage().is())
+ {
+ const OUString aStmName(GetSvDrawStreamNameFromURL(pEntry->getURL()));
+ tools::SvRef<SotStorageStream> pIStm
+ = GetSvDrawStorage()->OpenSotStream(aStmName, StreamMode::READ);
+
+ if (pIStm.is() && !pIStm->GetError())
+ {
+ pIStm->SetBufferSize(16384);
+
+ SgaObjectSvDraw aNewObj(*pIStm, pEntry->getURL());
+
+ pIStm->SetBufferSize(0);
+
+ return aNewObj;
+ }
+ }
+ return SgaObjectSvDraw();
+}
+
+void GalleryBinaryEngine::updateTheme()
+{
+ ::utl::TempFile aTmp;
+ INetURLObject aInURL(GetSdgURL());
+ INetURLObject aTmpURL(aTmp.GetURL());
+
+ DBG_ASSERT(aInURL.GetProtocol() != INetProtocol::NotValid, "invalid URL");
+ DBG_ASSERT(aTmpURL.GetProtocol() != INetProtocol::NotValid, "invalid URL");
+
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream(
+ aInURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ));
+ std::unique_ptr<SvStream> pTmpStm(::utl::UcbStreamHelper::CreateStream(
+ aTmpURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::WRITE | StreamMode::TRUNC));
+
+ if (pIStm && pTmpStm)
+ {
+ for (const auto& i : mrGalleryObjectCollection.getObjectList())
+ {
+ GalleryObject* pEntry = i.get();
+ std::unique_ptr<SgaObject> pObj;
+
+ switch (pEntry->eObjKind)
+ {
+ case SgaObjKind::Bitmap:
+ pObj.reset(new SgaObjectBmp());
+ break;
+ case SgaObjKind::Animation:
+ pObj.reset(new SgaObjectAnim());
+ break;
+ case SgaObjKind::Inet:
+ pObj.reset(new SgaObjectINet());
+ break;
+ case SgaObjKind::SvDraw:
+ pObj.reset(new SgaObjectSvDraw());
+ break;
+ case SgaObjKind::Sound:
+ pObj.reset(new SgaObjectSound());
+ break;
+
+ default:
+ break;
+ }
+
+ if (pObj)
+ {
+ pIStm->Seek(pEntry->nOffset);
+ ReadSgaObject(*pIStm, *pObj);
+ pEntry->nOffset = pTmpStm->Tell();
+ WriteSgaObject(*pTmpStm, *pObj);
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("File(s) could not be opened");
+ }
+
+ pIStm.reset();
+ pTmpStm.reset();
+
+ CopyFile(aTmpURL, aInURL);
+ KillFile(aTmpURL);
+
+ ErrCode nStorErr = ERRCODE_NONE;
+
+ try
+ {
+ tools::SvRef<SotStorage> aTempStorageRef(
+ new SotStorage(false, aTmpURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::STD_READWRITE));
+ GetSvDrawStorage()->CopyTo(aTempStorageRef.get());
+ nStorErr = GetSvDrawStorage()->GetError();
+ }
+ catch (const css::ucb::ContentCreationException&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "failed to open: "
+ << aTmpURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)
+ << "due to");
+ nStorErr = ERRCODE_IO_GENERAL;
+ }
+
+ if (nStorErr == ERRCODE_NONE)
+ {
+ clearSotStorage();
+ CopyFile(aTmpURL, GetSdvURL());
+ ImplCreateSvDrawStorage();
+ }
+
+ KillFile(aTmpURL);
+}
+
+void GalleryBinaryEngine::insertFileOrDirURL(const INetURLObject& rFileOrDirURL,
+ std::vector<INetURLObject>& rURLVector)
+{
+ INetURLObject aURL;
+ try
+ {
+ ::ucbhelper::Content aCnt(rFileOrDirURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ uno::Reference<ucb::XCommandEnvironment>(),
+ comphelper::getProcessComponentContext());
+ bool bFolder = false;
+
+ aCnt.getPropertyValue("IsFolder") >>= bFolder;
+
+ if (bFolder)
+ {
+ uno::Sequence<OUString> aProps{ "Url" };
+ uno::Reference<sdbc::XResultSet> xResultSet(
+ aCnt.createCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY));
+ uno::Reference<ucb::XContentAccess> xContentAccess(xResultSet, uno::UNO_QUERY);
+ if (xContentAccess.is())
+ {
+ while (xResultSet->next())
+ {
+ aURL.SetSmartURL(xContentAccess->queryContentIdentifierString());
+ rURLVector.push_back(aURL);
+ }
+ }
+ }
+ else
+ rURLVector.push_back(rFileOrDirURL);
+ }
+ catch (const ucb::ContentCreationException&)
+ {
+ }
+ catch (const uno::RuntimeException&)
+ {
+ }
+ catch (const uno::Exception&)
+ {
+ }
+}
+
+SvStream& GalleryBinaryEngine::writeGalleryTheme(SvStream& rOStm, const GalleryTheme& rTheme,
+ const GalleryThemeEntry* pThm)
+{
+ const INetURLObject rRelURL1 = rTheme.GetParent()->GetRelativeURL();
+ const INetURLObject rRelURL2 = rTheme.GetParent()->GetUserURL();
+ const sal_uInt32 rId = rTheme.GetId();
+ sal_uInt32 nCount = mrGalleryObjectCollection.size();
+ bool bRel;
+
+ rOStm.WriteUInt16(0x0004);
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, pThm->GetThemeName(),
+ RTL_TEXTENCODING_UTF8);
+ rOStm.WriteUInt32(nCount).WriteUInt16(osl_getThreadTextEncoding());
+
+ for (sal_uInt32 i = 0; i < nCount; i++)
+ {
+ const GalleryObject* pObj = mrGalleryObjectCollection.getForPosition(i);
+ OUString aPath;
+
+ if (SgaObjKind::SvDraw == pObj->eObjKind)
+ {
+ aPath = GetSvDrawStreamNameFromURL(pObj->getURL());
+ bRel = false;
+ }
+ else
+ {
+ aPath = pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ aPath = aPath.copy(
+ 0, std::min(rRelURL1.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength(),
+ aPath.getLength()));
+ bRel = aPath == rRelURL1.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+
+ if (bRel
+ && (pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength()
+ > (rRelURL1.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength() + 1)))
+ {
+ aPath = pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ aPath = aPath.copy(
+ std::min(rRelURL1.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength(),
+ aPath.getLength()));
+ }
+ else
+ {
+ aPath = pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ aPath = aPath.copy(
+ 0,
+ std::min(rRelURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength(),
+ aPath.getLength()));
+ bRel = aPath == rRelURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+
+ if (bRel
+ && (pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength()
+ > (rRelURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength()
+ + 1)))
+ {
+ aPath = pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ aPath = aPath.copy(std::min(
+ rRelURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength(),
+ aPath.getLength()));
+ }
+ else
+ aPath = pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ }
+ }
+
+ if (!m_aDestDir.isEmpty())
+ {
+ bool aFound = aPath.indexOf(m_aDestDir) != -1;
+ aPath = aPath.replaceFirst(m_aDestDir, "");
+ if (aFound)
+ bRel = m_bDestDirRelative;
+ else
+ SAL_WARN("svx", "failed to replace destdir of '" << m_aDestDir << "' in '" << aPath
+ << "'");
+ }
+
+ rOStm.WriteBool(bRel);
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, aPath, RTL_TEXTENCODING_UTF8);
+ rOStm.WriteUInt32(pObj->nOffset).WriteUInt16(static_cast<sal_uInt16>(pObj->eObjKind));
+ }
+
+ // more recently, a 512-byte reserve buffer is written,
+ // to recognize them two sal_uInt32-Ids will be written.
+ rOStm.WriteUInt32(COMPAT_FORMAT('G', 'A', 'L', 'R'))
+ .WriteUInt32(COMPAT_FORMAT('E', 'S', 'R', 'V'));
+
+ const sal_uInt64 nReservePos = rOStm.Tell();
+ std::unique_ptr<VersionCompatWrite> pCompat(new VersionCompatWrite(rOStm, 2));
+
+ rOStm.WriteUInt32(rId).WriteBool(pThm->IsNameFromResource()); // From version 2 and up
+
+ pCompat.reset();
+
+ // Fill the rest of the buffer.
+ const tools::Long nRest
+ = std::max(tools::Long(512 - (rOStm.Tell() - nReservePos)), tools::Long(0));
+
+ if (nRest)
+ {
+ std::unique_ptr<char[]> pReserve(new char[nRest]);
+ memset(pReserve.get(), 0, nRest);
+ rOStm.WriteBytes(pReserve.get(), nRest);
+ }
+
+ return rOStm;
+}
+
+DateTime GalleryBinaryEngine::getModificationDate() const
+{
+ ::ucbhelper::Content aCnt(GetThmURL().GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ uno::Reference<ucb::XCommandEnvironment>(),
+ comphelper::getProcessComponentContext());
+ util::DateTime aDateTimeModified;
+ DateTime aDateTime(DateTime::EMPTY);
+
+ aCnt.getPropertyValue("DateModified") >>= aDateTimeModified;
+ ::utl::typeConvert(aDateTimeModified, aDateTime);
+
+ return aDateTime;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallerybinaryengineentry.cxx b/svx/source/gallery2/gallerybinaryengineentry.cxx
new file mode 100644
index 000000000..f892788ae
--- /dev/null
+++ b/svx/source/gallery2/gallerybinaryengineentry.cxx
@@ -0,0 +1,180 @@
+/* -*- 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 <svx/gallerybinaryengineentry.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/gallery1.hxx>
+
+#include <unotools/ucbstreamhelper.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/vcompat.hxx>
+
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+
+static bool FileExists(const INetURLObject& rURL, std::u16string_view rExt)
+{
+ INetURLObject aURL(rURL);
+ aURL.setExtension(rExt);
+ return FileExists(aURL);
+}
+
+GalleryBinaryEngineEntry::GalleryBinaryEngineEntry()
+{
+ mpGalleryStorageLocations = std::make_unique<GalleryBinaryStorageLocations>();
+}
+
+void GalleryBinaryEngineEntry::setStorageLocations(INetURLObject& rURL)
+{
+ mpGalleryStorageLocations->SetStorageLocations(rURL);
+}
+
+std::unique_ptr<GalleryBinaryEngine> GalleryBinaryEngineEntry::createGalleryStorageEngine(
+ GalleryObjectCollection& mrGalleryObjectCollection, bool& bReadOnly)
+{
+ return std::make_unique<GalleryBinaryEngine>(*mpGalleryStorageLocations,
+ mrGalleryObjectCollection, bReadOnly);
+}
+
+void GalleryBinaryEngineEntry::CreateUniqueURL(const INetURLObject& rBaseURL, INetURLObject& aURL)
+{
+ INetURLObject aBaseNoCase(GalleryBinaryStorageLocations::ImplGetURLIgnoreCase(rBaseURL));
+ aURL = aBaseNoCase;
+ static sal_Int32 nIdx = 0;
+ while (FileExists(aURL, u"thm"))
+ { // create new URLs
+ nIdx++;
+ aURL = aBaseNoCase;
+ aURL.setName(OUStringConcatenation(aURL.getName() + OUString::number(nIdx)));
+ }
+}
+
+GalleryThemeEntry* GalleryBinaryEngineEntry::CreateThemeEntry(const INetURLObject& rURL,
+ bool bReadOnly)
+{
+ DBG_ASSERT(rURL.GetProtocol() != INetProtocol::NotValid, "invalid URL");
+
+ GalleryThemeEntry* pRet = nullptr;
+
+ if (FileExists(rURL))
+ {
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream(
+ rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ));
+
+ if (pIStm)
+ {
+ sal_uInt16 nVersion;
+
+ pIStm->ReadUInt16(nVersion);
+
+ if (nVersion <= 0x00ff)
+ {
+ bool bThemeNameFromResource = false;
+ sal_uInt32 nThemeId = 0;
+
+ OString aTmpStr = read_uInt16_lenPrefixed_uInt8s_ToOString(*pIStm);
+ OUString aThemeName = OStringToOUString(aTmpStr, RTL_TEXTENCODING_UTF8);
+
+ // execute a character conversion
+ if (nVersion >= 0x0004)
+ {
+ sal_uInt32 nCount;
+ sal_uInt16 nTemp16;
+
+ pIStm->ReadUInt32(nCount).ReadUInt16(nTemp16);
+ pIStm->Seek(STREAM_SEEK_TO_END);
+
+ // check whether there is a newer version;
+ // therefore jump back by 520Bytes (8 bytes ID + 512Bytes reserve buffer)
+ // if this is at all possible.
+ if (pIStm->Tell() >= 520)
+ {
+ sal_uInt32 nId1, nId2;
+
+ pIStm->SeekRel(-520);
+ pIStm->ReadUInt32(nId1).ReadUInt32(nId2);
+
+ if (nId1 == COMPAT_FORMAT('G', 'A', 'L', 'R')
+ && nId2 == COMPAT_FORMAT('E', 'S', 'R', 'V'))
+ {
+ VersionCompatRead aCompat(*pIStm);
+
+ pIStm->ReadUInt32(nThemeId);
+
+ if (aCompat.GetVersion() >= 2)
+ {
+ pIStm->ReadCharAsBool(bThemeNameFromResource);
+ }
+ }
+ }
+ }
+
+ pRet = new GalleryThemeEntry(false, rURL, aThemeName, bReadOnly, false, nThemeId,
+ bThemeNameFromResource);
+ }
+ }
+ }
+
+ return pRet;
+}
+
+void GalleryBinaryEngineEntry::removeTheme()
+{
+ INetURLObject aThmURL(GetThmURL());
+ INetURLObject aSdgURL(GetSdgURL());
+ INetURLObject aSdvURL(GetSdvURL());
+ INetURLObject aStrURL(GetStrURL());
+
+ KillFile(aThmURL);
+ KillFile(aSdgURL);
+ KillFile(aSdvURL);
+ KillFile(aStrURL);
+}
+
+std::unique_ptr<GalleryTheme>&
+GalleryBinaryEngineEntry::getCachedTheme(std::unique_ptr<GalleryTheme>& pNewTheme)
+{
+ INetURLObject aURL = GetThmURL();
+
+ DBG_ASSERT(aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL");
+
+ if (FileExists(aURL))
+ {
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream(
+ aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ));
+
+ if (pIStm)
+ {
+ try
+ {
+ ReadGalleryTheme(*pIStm, *pNewTheme);
+
+ if (pIStm->GetError())
+ pNewTheme.reset();
+ }
+ catch (const css::ucb::ContentCreationException&)
+ {
+ }
+ }
+ }
+ return pNewTheme;
+}
+
+SvStream& ReadGalleryTheme(SvStream& rIn, GalleryTheme& rTheme) { return rTheme.ReadData(rIn); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallerybinarystoragelocations.cxx b/svx/source/gallery2/gallerybinarystoragelocations.cxx
new file mode 100644
index 000000000..dc896f6c3
--- /dev/null
+++ b/svx/source/gallery2/gallerybinarystoragelocations.cxx
@@ -0,0 +1,75 @@
+/* -*- 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 <svx/gallerybinarystoragelocations.hxx>
+#include <svx/galmisc.hxx>
+
+INetURLObject GalleryBinaryStorageLocations::ImplGetURLIgnoreCase(const INetURLObject& rURL)
+{
+ INetURLObject aURL(rURL);
+
+ // check original file name
+ if (!FileExists(aURL))
+ {
+ // check upper case file name
+ aURL.setName(aURL.getName().toAsciiUpperCase());
+
+ if (!FileExists(aURL))
+ {
+ // check lower case file name
+ aURL.setName(aURL.getName().toAsciiLowerCase());
+ }
+ }
+
+ return aURL;
+}
+
+void GalleryBinaryStorageLocations::SetThmExtension(INetURLObject& aURL)
+{
+ aURL.setExtension(u"thm");
+ maThmURL = ImplGetURLIgnoreCase(aURL);
+}
+
+void GalleryBinaryStorageLocations::SetSdgExtension(INetURLObject& aURL)
+{
+ aURL.setExtension(u"sdg");
+ maSdgURL = ImplGetURLIgnoreCase(aURL);
+}
+
+void GalleryBinaryStorageLocations::SetSdvExtension(INetURLObject& aURL)
+{
+ aURL.setExtension(u"sdv");
+ maSdvURL = ImplGetURLIgnoreCase(aURL);
+}
+
+void GalleryBinaryStorageLocations::SetStrExtension(INetURLObject& aURL)
+{
+ aURL.setExtension(u"str");
+ maStrURL = ImplGetURLIgnoreCase(aURL);
+}
+
+void GalleryBinaryStorageLocations::SetStorageLocations(INetURLObject& rURL)
+{
+ SetThmExtension(rURL);
+ SetSdgExtension(rURL);
+ SetSdvExtension(rURL);
+ SetStrExtension(rURL);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallerydrawmodel.hxx b/svx/source/gallery2/gallerydrawmodel.hxx
new file mode 100644
index 000000000..0b2ef2582
--- /dev/null
+++ b/svx/source/gallery2/gallerydrawmodel.hxx
@@ -0,0 +1,39 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sfx2/objsh.hxx>
+
+class FmFormModel;
+
+class SvxGalleryDrawModel
+{
+public:
+ SvxGalleryDrawModel();
+ ~SvxGalleryDrawModel();
+
+ FmFormModel* GetModel() const { return mpFormModel; }
+
+private:
+ SfxObjectShellLock mxDoc;
+ FmFormModel* mpFormModel;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryfilestorage.cxx b/svx/source/gallery2/galleryfilestorage.cxx
new file mode 100644
index 000000000..dd8e74cd3
--- /dev/null
+++ b/svx/source/gallery2/galleryfilestorage.cxx
@@ -0,0 +1,24 @@
+/* -*- 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 <svx/galleryfilestorage.hxx>
+
+GalleryFileStorage::~GalleryFileStorage(){};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryfilestorageentry.cxx b/svx/source/gallery2/galleryfilestorageentry.cxx
new file mode 100644
index 000000000..d04f49bf8
--- /dev/null
+++ b/svx/source/gallery2/galleryfilestorageentry.cxx
@@ -0,0 +1,24 @@
+/* -*- 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 <svx/galleryfilestorageentry.hxx>
+
+GalleryFileStorageEntry::~GalleryFileStorageEntry(){};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryobjectbinarystorage.cxx b/svx/source/gallery2/galleryobjectbinarystorage.cxx
new file mode 100644
index 000000000..14bdc8b08
--- /dev/null
+++ b/svx/source/gallery2/galleryobjectbinarystorage.cxx
@@ -0,0 +1,25 @@
+/* -*- 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 <galleryobjectbinarystorage.hxx>
+#include <tools/urlobj.hxx>
+
+void GalleryObjectBinaryStorage::setURL(INetURLObject aURL) { m_aURL = aURL; }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryobjectcollection.cxx b/svx/source/gallery2/galleryobjectcollection.cxx
new file mode 100644
index 000000000..515f52759
--- /dev/null
+++ b/svx/source/gallery2/galleryobjectcollection.cxx
@@ -0,0 +1,60 @@
+/* -*- 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 <svx/galleryobjectcollection.hxx>
+
+GalleryObjectCollection::GalleryObjectCollection() {}
+
+void GalleryObjectCollection::clear() { m_aObjectList.clear(); }
+
+const GalleryObject* GalleryObjectCollection::searchObjectWithURL(const INetURLObject& rURL)
+{
+ for (auto const& pObject : m_aObjectList)
+ {
+ if (pObject->getURL() == rURL)
+ return pObject.get();
+ }
+ return nullptr;
+}
+
+sal_uInt32 GalleryObjectCollection::searchPosWithObject(const GalleryObject* pObj)
+{
+ for (sal_uInt32 i = 0, n = size(); i < n; ++i)
+ if (pObj == get(i).get())
+ return i;
+ return SAL_MAX_UINT32;
+}
+
+const GalleryObject* GalleryObjectCollection::getForPosition(sal_uInt32 nPos) const
+{
+ if (nPos < size())
+ return get(nPos).get();
+ return nullptr;
+}
+
+const INetURLObject g_aInvalidURL;
+
+const INetURLObject& GalleryObjectCollection::getURLForPosition(sal_uInt32 nPos) const
+{
+ if (nPos < size())
+ return get(nPos)->getURL();
+ return g_aInvalidURL;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryobjectstorage.cxx b/svx/source/gallery2/galleryobjectstorage.cxx
new file mode 100644
index 000000000..2d324b3d0
--- /dev/null
+++ b/svx/source/gallery2/galleryobjectstorage.cxx
@@ -0,0 +1,24 @@
+/* -*- 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 <svx/galleryobjectstorage.hxx>
+
+GalleryObjectStorage::~GalleryObjectStorage() = default;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryobjectxmlstorage.cxx b/svx/source/gallery2/galleryobjectxmlstorage.cxx
new file mode 100644
index 000000000..f07b7b869
--- /dev/null
+++ b/svx/source/gallery2/galleryobjectxmlstorage.cxx
@@ -0,0 +1,25 @@
+/* -*- 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 <galleryobjectxmlstorage.hxx>
+#include <tools/urlobj.hxx>
+
+void GalleryObjectXMLStorage::setURL(INetURLObject aURL) { m_aURL = aURL; }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallerystoragelocations.cxx b/svx/source/gallery2/gallerystoragelocations.cxx
new file mode 100644
index 000000000..d71ae452f
--- /dev/null
+++ b/svx/source/gallery2/gallerystoragelocations.cxx
@@ -0,0 +1,24 @@
+/* -*- 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 <svx/gallerystoragelocations.hxx>
+
+GalleryStorageLocations::~GalleryStorageLocations(){};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galmisc.cxx b/svx/source/gallery2/galmisc.cxx
new file mode 100644
index 000000000..3422f5e29
--- /dev/null
+++ b/svx/source/gallery2/galmisc.cxx
@@ -0,0 +1,563 @@
+/* -*- 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 <sal/config.h>
+
+#include <sot/storage.hxx>
+#include <unotools/streamwrap.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <ucbhelper/content.hxx>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <tools/urlobj.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <svl/itempool.hxx>
+#include <sfx2/docfile.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/unomodel.hxx>
+#include "codec.hxx"
+#include <svx/strings.hrc>
+#include <svx/galtheme.hxx>
+#include <svx/galmisc.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/awt/XProgressMonitor.hpp>
+#include <com/sun/star/ucb/TransferInfo.hpp>
+#include <com/sun/star/ucb/NameClash.hpp>
+#include <memory>
+
+using namespace ::com::sun::star;
+
+GalleryGraphicImportRet GalleryGraphicImport( const INetURLObject& rURL, Graphic& rGraphic,
+ OUString& rFilterName )
+{
+ GalleryGraphicImportRet nRet = GalleryGraphicImportRet::IMPORT_NONE;
+ SfxMedium aMedium( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ );
+
+ aMedium.Download();
+
+ SvStream* pIStm = aMedium.GetInStream();
+
+ if( pIStm )
+ {
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ sal_uInt16 nFormat;
+
+ if( !rGraphicFilter.ImportGraphic( rGraphic, rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), *pIStm, GRFILTER_FORMAT_DONTKNOW, &nFormat ) )
+ {
+ rFilterName = rGraphicFilter.GetImportFormatName( nFormat );
+ nRet = GalleryGraphicImportRet::IMPORT_FILE;
+ }
+ }
+
+ return nRet;
+}
+
+bool GallerySvDrawImport( SvStream& rIStm, SdrModel& rModel )
+{
+ sal_uInt32 nVersion;
+ bool bRet = false;
+
+ if( GalleryCodec::IsCoded( rIStm, nVersion ) )
+ {
+ SvMemoryStream aMemStm( 65535, 65535 );
+ GalleryCodec aCodec( rIStm );
+
+ aCodec.Read( aMemStm );
+ aMemStm.Seek( 0 );
+
+ if( 1 == nVersion )
+ {
+ OSL_FAIL( "staroffice binary file formats are no longer supported inside the gallery!" );
+ bRet = false;
+ }
+ else if( 2 == nVersion )
+ {
+ // recall to read as XML
+ bRet = GallerySvDrawImport( aMemStm, rModel );
+ }
+ }
+ else
+ {
+ // read as XML
+ uno::Reference< io::XInputStream > xInputStream( new utl::OInputStreamWrapper( rIStm ) );
+
+ rModel.GetItemPool().SetDefaultMetric( MapUnit::Map100thMM );
+ uno::Reference< lang::XComponent > xComponent;
+
+ bRet = SvxDrawingLayerImport( &rModel, xInputStream, xComponent, "com.sun.star.comp.Draw.XMLOasisImporter" );
+ if( !bRet || (rModel.GetPageCount() == 0) )
+ {
+ rIStm.Seek(0);
+ bRet = SvxDrawingLayerImport( &rModel, xInputStream, xComponent, "com.sun.star.comp.Draw.XMLImporter" );
+ }
+
+ }
+
+ return bRet;
+}
+
+bool CreateIMapGraphic( const FmFormModel& rModel, Graphic& rGraphic, ImageMap& rImageMap )
+{
+ if (! rModel.GetPageCount() )
+ return false;
+
+ const SdrPage* pPage = rModel.GetPage( 0 );
+ const SdrObject* pObj = pPage->GetObj( 0 );
+
+ if ( pPage->GetObjCount() != 1 )
+ return false;
+ auto pGrafObj = dynamic_cast<const SdrGrafObj*>( pObj);
+ if (!pGrafObj)
+ return false;
+
+ bool bRet = false;
+ const sal_uInt16 nCount = pObj->GetUserDataCount();
+
+ // Exist in the user data an IMap information?
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ const SdrObjUserData* pUserData = pObj->GetUserData( i );
+
+ if ( ( pUserData->GetInventor() == SdrInventor::SgaImap ) && ( pUserData->GetId() == ID_IMAPINFO ) )
+ {
+ rGraphic = pGrafObj->GetGraphic();
+ rImageMap = static_cast<const SgaIMapInfo*>( pUserData )->GetImageMap();
+ bRet = true;
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+OUString GetReducedString( const INetURLObject& rURL, sal_Int32 nMaxLen )
+{
+ OUString aReduced( rURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) );
+
+ aReduced = aReduced.copy(aReduced.lastIndexOf('/')+1);
+
+ if( INetProtocol::PrivSoffice != rURL.GetProtocol() )
+ {
+ sal_Unicode aDelimiter;
+ const OUString aPath( rURL.getFSysPath( FSysStyle::Detect, &aDelimiter ) );
+ const OUString aName( aReduced );
+
+ if( aPath.getLength() > nMaxLen )
+ {
+ sal_Int32 nPathPrefixLen = nMaxLen - aName.getLength() - 4;
+
+ if (nPathPrefixLen >= 0)
+ {
+ aReduced = OUString::Concat(aPath.subView(0, nPathPrefixLen)) + "..."
+ + OUStringChar(aDelimiter) + aName;
+ }
+ else
+ {
+ aReduced += "..." + OUStringChar(aDelimiter) + "..."
+ + aName.subView( aName.getLength() - (nMaxLen - 7) );
+ }
+ }
+ else
+ aReduced = aPath;
+ }
+
+ return aReduced;
+}
+
+OUString GetSvDrawStreamNameFromURL( const INetURLObject& rSvDrawObjURL )
+{
+ OUString aRet;
+
+ if( rSvDrawObjURL.GetProtocol() == INetProtocol::PrivSoffice &&
+ comphelper::string::getTokenCount(rSvDrawObjURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), '/') == 3 )
+ {
+ aRet = rSvDrawObjURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getToken( 2, '/' );
+ }
+
+ return aRet;
+}
+
+bool FileExists( const INetURLObject& rURL )
+{
+ bool bRet = false;
+
+ if( rURL.GetProtocol() != INetProtocol::NotValid )
+ {
+ try
+ {
+ ::ucbhelper::Content aCnt( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), uno::Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ OUString aTitle;
+
+ aCnt.getPropertyValue("Title") >>= aTitle;
+ bRet = ( !aTitle.isEmpty() );
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ return bRet;
+}
+
+bool CreateDir( const INetURLObject& rURL )
+{
+ bool bRet = FileExists( rURL );
+
+ if( !bRet )
+ {
+ try
+ {
+ uno::Reference< ucb::XCommandEnvironment > aCmdEnv;
+ INetURLObject aParentURL( rURL );
+ aParentURL.removeSegment();
+ ::ucbhelper::Content aParent( aParentURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aCmdEnv, comphelper::getProcessComponentContext() );
+ uno::Sequence< OUString > aProps{ "Title" };
+ uno::Sequence< uno::Any > aValues{ uno::Any(rURL.GetLastName()) };
+
+ ::ucbhelper::Content aContent( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aCmdEnv, comphelper::getProcessComponentContext() );
+ bRet = aParent.insertNewContent( "application/vnd.sun.staroffice.fsys-folder", aProps, aValues, aContent );
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ return bRet;
+}
+
+bool CopyFile( const INetURLObject& rSrcURL, const INetURLObject& rDstURL )
+{
+ bool bRet = false;
+
+ try
+ {
+ ::ucbhelper::Content aDestPath( rDstURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), uno::Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+
+ aDestPath.executeCommand( "transfer",
+ uno::Any( ucb::TransferInfo( false, rSrcURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ rDstURL.GetLastName(), ucb::NameClash::OVERWRITE ) ) );
+ bRet = true;
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ return bRet;
+}
+
+bool KillFile( const INetURLObject& rURL )
+{
+ bool bRet = FileExists( rURL );
+
+ if( bRet )
+ {
+ try
+ {
+ ::ucbhelper::Content aCnt( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), uno::Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ aCnt.executeCommand( "delete", uno::Any( true ) );
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ bRet = false;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ bRet = false;
+ }
+ catch( const uno::Exception& )
+ {
+ bRet = false;
+ }
+ }
+
+ return bRet;
+}
+
+
+GalleryProgress::GalleryProgress( const GraphicFilter* pFilter )
+{
+
+ uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
+
+ uno::Reference< awt::XProgressMonitor > xMonitor( xMgr->createInstance( "com.sun.star.awt.XProgressMonitor" ),
+ uno::UNO_QUERY );
+
+ if ( !xMonitor.is() )
+ return;
+
+ mxProgressBar = xMonitor;
+
+ OUString aProgressText;
+
+ if( pFilter )
+ {
+ aProgressText = SvxResId(RID_SVXSTR_GALLERY_FILTER);
+// pFilter->SetUpdatePercentHdl( LINK( this, GalleryProgress, Update ) ); // sj: progress wasn't working up from SO7 at all
+// // so I am removing this. The gallery progress should
+// // be changed to use the XStatusIndicator instead of XProgressMonitor
+ }
+ else
+ aProgressText = "Gallery";
+
+ xMonitor->addText( "Gallery", aProgressText, false ) ;
+ mxProgressBar->setRange( 0, GALLERY_PROGRESS_RANGE );
+}
+
+GalleryProgress::~GalleryProgress()
+{
+}
+
+void GalleryProgress::Update( sal_Int32 nVal, sal_Int32 nMaxVal )
+{
+ if( mxProgressBar.is() && nMaxVal )
+ mxProgressBar->setValue( std::min<sal_Int32>( static_cast<double>(nVal) / nMaxVal * GALLERY_PROGRESS_RANGE,
+ GALLERY_PROGRESS_RANGE ) );
+}
+
+
+GalleryTransferable::GalleryTransferable( GalleryTheme* pTheme, sal_uInt32 nObjectPos, bool bLazy ) :
+ mpTheme( pTheme ),
+ meObjectKind( pTheme ? mpTheme->GetObjectKind(nObjectPos) : SgaObjKind::NONE),
+ mnObjectPos( nObjectPos )
+{
+
+ InitData( bLazy );
+}
+
+void GalleryTransferable::SelectObject(sal_uInt32 nObjectPos)
+{
+ if (nObjectPos == mnObjectPos)
+ return;
+ ClearFormats();
+ mnObjectPos = nObjectPos;
+ meObjectKind = mpTheme ? mpTheme->GetObjectKind(mnObjectPos) : SgaObjKind::NONE;
+ ObjectReleased();
+ InitData(true);
+}
+
+GalleryTransferable::~GalleryTransferable()
+{
+}
+
+void GalleryTransferable::InitData( bool bLazy )
+{
+ switch( meObjectKind )
+ {
+ case SgaObjKind::SvDraw:
+ {
+ if( !bLazy )
+ {
+ if( !mpGraphicObject )
+ {
+ Graphic aGraphic;
+
+ if (mpTheme && mpTheme->GetGraphic(mnObjectPos, aGraphic))
+ mpGraphicObject.reset(new GraphicObject( aGraphic ));
+ }
+
+ if( !mxModelStream.is() )
+ {
+ mxModelStream = new SotTempStream( "" );
+ mxModelStream->SetBufferSize( 16348 );
+
+ if (!mpTheme || !mpTheme->GetModelStream(mnObjectPos, mxModelStream))
+ mxModelStream.clear();
+ else
+ mxModelStream->Seek( 0 );
+ }
+ }
+ }
+ break;
+
+ case SgaObjKind::Animation:
+ case SgaObjKind::Bitmap:
+ case SgaObjKind::Inet:
+ case SgaObjKind::Sound:
+ {
+ if( !mpURL )
+ {
+ mpURL.reset(new INetURLObject);
+
+ if (!mpTheme || !mpTheme->GetURL(mnObjectPos, *mpURL))
+ {
+ mpURL.reset();
+ }
+ }
+
+ if( ( SgaObjKind::Sound != meObjectKind ) && !mpGraphicObject )
+ {
+ Graphic aGraphic;
+
+ if (mpTheme && mpTheme->GetGraphic(mnObjectPos, aGraphic))
+ mpGraphicObject.reset(new GraphicObject( aGraphic ));
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL( "GalleryTransferable::GalleryTransferable: invalid object type" );
+ break;
+ }
+}
+
+void GalleryTransferable::AddSupportedFormats()
+{
+ if( SgaObjKind::SvDraw == meObjectKind )
+ {
+ AddFormat( SotClipboardFormatId::DRAWING );
+ AddFormat( SotClipboardFormatId::SVXB );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ }
+ else
+ {
+ if( mpURL )
+ AddFormat( SotClipboardFormatId::SIMPLE_FILE );
+
+ if( mpGraphicObject )
+ {
+ AddFormat( SotClipboardFormatId::SVXB );
+
+ if( mpGraphicObject->GetType() == GraphicType::GdiMetafile )
+ {
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ }
+ else
+ {
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ }
+ }
+ }
+}
+
+bool GalleryTransferable::GetData( const datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+{
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+ bool bRet = false;
+
+ InitData( false );
+
+ if( ( SotClipboardFormatId::DRAWING == nFormat ) && ( SgaObjKind::SvDraw == meObjectKind ) )
+ {
+ bRet = ( mxModelStream.is() && SetObject( mxModelStream.get(), 0, rFlavor ) );
+ }
+ else if( ( SotClipboardFormatId::SIMPLE_FILE == nFormat ) && mpURL )
+ {
+ bRet = SetString( mpURL->GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ }
+ else if( ( SotClipboardFormatId::SVXB == nFormat ) && mpGraphicObject )
+ {
+ bRet = SetGraphic( mpGraphicObject->GetGraphic() );
+ }
+ else if( ( SotClipboardFormatId::GDIMETAFILE == nFormat ) && mpGraphicObject )
+ {
+ bRet = SetGDIMetaFile( mpGraphicObject->GetGraphic().GetGDIMetaFile() );
+ }
+ else if( ( SotClipboardFormatId::BITMAP == nFormat ) && mpGraphicObject )
+ {
+ bRet = SetBitmapEx( mpGraphicObject->GetGraphic().GetBitmapEx(), rFlavor );
+ }
+
+ return bRet;
+}
+
+bool GalleryTransferable::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject,
+ sal_uInt32, const datatransfer::DataFlavor& )
+{
+ bool bRet = false;
+
+ if( pUserObject )
+ {
+ rxOStm->WriteStream( *static_cast< SotStorageStream* >( pUserObject ) );
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+
+ return bRet;
+}
+
+void GalleryTransferable::DragFinished( sal_Int8 nDropAction )
+{
+ if (mpTheme)
+ {
+ mpTheme->SetDragging( false );
+ mpTheme->SetDragPos( 0 );
+ }
+ if ( nDropAction )
+ {
+ vcl::Window *pFocusWindow = Application::GetFocusWindow();
+ if ( pFocusWindow )
+ pFocusWindow->GrabFocusToDocument();
+ }
+}
+
+void GalleryTransferable::ObjectReleased()
+{
+ mxModelStream.clear();
+ mpGraphicObject.reset();
+ mpURL.reset();
+}
+
+bool GalleryTransferable::StartDrag()
+{
+ INetURLObject aURL;
+ if (mpTheme && mpTheme->GetURL(mnObjectPos, aURL) && aURL.GetProtocol() != INetProtocol::NotValid)
+ {
+ mpTheme->SetDragging( true );
+ mpTheme->SetDragPos( mnObjectPos );
+ return false;
+ }
+ return true;
+}
+
+INetURLObject ImplGetURL(const GalleryObject* pObject)
+{
+ INetURLObject aURL;
+
+ if (pObject)
+ aURL = pObject->getURL();
+
+ return aURL;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galobj.cxx b/svx/source/gallery2/galobj.cxx
new file mode 100644
index 000000000..44362b9a7
--- /dev/null
+++ b/svx/source/gallery2/galobj.cxx
@@ -0,0 +1,493 @@
+/* -*- 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 <sal/config.h>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <sfx2/objsh.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/servicehelper.hxx>
+#include <tools/vcompat.hxx>
+#include <tools/helpers.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmview.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/galmisc.hxx>
+#include <galobj.hxx>
+#include <vcl/dibtools.hxx>
+#include <vcl/filter/SvmReader.hxx>
+#include <vcl/filter/SvmWriter.hxx>
+#include "gallerydrawmodel.hxx"
+#include <bitmaps.hlst>
+
+using namespace ::com::sun::star;
+
+SgaObject::SgaObject()
+: bIsValid ( false ),
+ bIsThumbBmp ( true )
+{
+}
+
+SgaObject::SgaObject(const SgaObject& aObject)
+ : aThumbBmp(aObject.aThumbBmp)
+ , aThumbMtf(aObject.aThumbMtf)
+ , aURL(aObject.aURL)
+ , aTitle(aObject.aTitle)
+ , bIsValid(aObject.bIsValid)
+ , bIsThumbBmp(aObject.bIsThumbBmp)
+{
+}
+
+BitmapEx SgaObject::createPreviewBitmapEx(const Size& rSizePixel) const
+{
+ BitmapEx aRetval;
+
+ if(rSizePixel.Width() && rSizePixel.Height())
+ {
+ if(SgaObjKind::Sound == GetObjKind())
+ {
+ aRetval = BitmapEx(RID_SVXBMP_GALLERY_MEDIA);
+ }
+ else if(IsThumbBitmap())
+ {
+ aRetval = GetThumbBmp();
+ }
+ else
+ {
+ const Graphic aGraphic(GetThumbMtf());
+
+ aRetval = aGraphic.GetBitmapEx();
+ }
+
+ if(!aRetval.IsEmpty())
+ {
+ const Size aCurrentSizePixel(aRetval.GetSizePixel());
+ const double fScaleX(static_cast<double>(rSizePixel.Width()) / static_cast<double>(aCurrentSizePixel.Width()));
+ const double fScaleY(static_cast<double>(rSizePixel.Height()) / static_cast<double>(aCurrentSizePixel.Height()));
+ const double fScale(std::min(fScaleX, fScaleY));
+
+ // only scale when need to decrease, no need to make bigger as original. Also
+ // prevent scaling close to 1.0 which is not needed for pixel graphics
+ if(fScale < 1.0 && fabs(1.0 - fScale) > 0.005)
+ {
+ aRetval.Scale(fScale, fScale, BmpScaleFlag::BestQuality);
+ }
+ }
+ }
+
+ return aRetval;
+}
+
+bool SgaObject::CreateThumb( const Graphic& rGraphic )
+{
+ bool bRet = false;
+
+ if( rGraphic.GetType() == GraphicType::Bitmap )
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+ Size aBmpSize( aBmpEx.GetSizePixel() );
+
+ if( aBmpSize.Width() && aBmpSize.Height() )
+ {
+ if( aBmpEx.GetPrefMapMode().GetMapUnit() != MapUnit::MapPixel &&
+ aBmpEx.GetPrefSize().Width() > 0 &&
+ aBmpEx.GetPrefSize().Height() > 0 )
+ {
+ Size aLogSize( OutputDevice::LogicToLogic(aBmpEx.GetPrefSize(), aBmpEx.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) );
+
+ if( !aLogSize.IsEmpty() )
+ {
+ double fFactorLog = static_cast< double >( aLogSize.Width() ) / aLogSize.Height();
+ double fFactorPix = static_cast< double >( aBmpSize.Width() ) / aBmpSize.Height();
+
+ if( fFactorPix > fFactorLog )
+ aBmpSize.setWidth( FRound( aBmpSize.Height() * fFactorLog ) );
+ else
+ aBmpSize.setHeight( FRound( aBmpSize.Width() / fFactorLog ) );
+
+ aBmpEx.Scale(aBmpSize, BmpScaleFlag::BestQuality);
+ }
+ }
+
+ // take over BitmapEx
+ aThumbBmp = aBmpEx;
+
+ if( ( aBmpSize.Width() <= S_THUMB ) && ( aBmpSize.Height() <= S_THUMB ) )
+ {
+ aThumbBmp.Convert( BmpConversion::N8BitColors );
+ bRet = true;
+ }
+ else
+ {
+ const float fFactor = static_cast<float>(aBmpSize.Width()) / aBmpSize.Height();
+ const Size aNewSize( std::max( tools::Long(fFactor < 1. ? S_THUMB * fFactor : S_THUMB), tools::Long(8) ),
+ std::max( tools::Long(fFactor < 1. ? S_THUMB : S_THUMB / fFactor), tools::Long(8) ) );
+ if(aThumbBmp.Scale(
+ static_cast<double>(aNewSize.Width()) / aBmpSize.Width(),
+ static_cast<double>(aNewSize.Height()) / aBmpSize.Height(),
+ BmpScaleFlag::BestQuality ) )
+ {
+ aThumbBmp.Convert( BmpConversion::N8BitColors );
+ bRet = true;
+ }
+ }
+ }
+ }
+ else if( rGraphic.GetType() == GraphicType::GdiMetafile )
+ {
+ const Size aPrefSize( rGraphic.GetPrefSize() );
+ const double fFactor = static_cast<double>(aPrefSize.Width()) / static_cast<double>(aPrefSize.Height());
+ Size aSize( S_THUMB, S_THUMB );
+ if ( fFactor < 1.0 )
+ aSize.setWidth( static_cast<sal_Int32>( S_THUMB * fFactor ) );
+ else
+ aSize.setHeight( static_cast<sal_Int32>( S_THUMB / fFactor ) );
+
+ const GraphicConversionParameters aParameters(aSize, false, true, true /*TODO: extra ", true" post-#i121194#*/);
+ aThumbBmp = rGraphic.GetBitmapEx(aParameters);
+
+ if( !aThumbBmp.IsEmpty() )
+ {
+ aThumbBmp.Convert( BmpConversion::N8BitColors );
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+void SgaObject::WriteData( SvStream& rOut, const OUString& rDestDir ) const
+{
+ static const sal_uInt32 nInventor = COMPAT_FORMAT( 'S', 'G', 'A', '3' );
+
+ rOut.WriteUInt32( nInventor ).WriteUInt16( 0x0004 ).WriteUInt16( GetVersion() ).WriteUInt16( static_cast<sal_uInt16>(GetObjKind()) );
+ rOut.WriteBool( bIsThumbBmp );
+
+ if( bIsThumbBmp )
+ {
+ const SvStreamCompressFlags nOldCompressMode = rOut.GetCompressMode();
+ const sal_Int32 nOldVersion = rOut.GetVersion();
+
+ rOut.SetCompressMode( SvStreamCompressFlags::ZBITMAP );
+ rOut.SetVersion( SOFFICE_FILEFORMAT_50 );
+
+ WriteDIBBitmapEx(aThumbBmp, rOut);
+
+ rOut.SetVersion( nOldVersion );
+ rOut.SetCompressMode( nOldCompressMode );
+ }
+ else
+ {
+ if(!rOut.GetError())
+ {
+ SvmWriter aWriter(rOut);
+ aWriter.Write(aThumbMtf);
+ }
+ }
+
+ OUString aURLWithoutDestDir = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ aURLWithoutDestDir = aURLWithoutDestDir.replaceFirst(rDestDir, "");
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aURLWithoutDestDir, RTL_TEXTENCODING_UTF8);
+}
+
+void SgaObject::ReadData(SvStream& rIn, sal_uInt16& rReadVersion )
+{
+ sal_uInt32 nTmp32;
+ sal_uInt16 nTmp16;
+
+ rIn.ReadUInt32( nTmp32 ).ReadUInt16( nTmp16 ).ReadUInt16( rReadVersion ).ReadUInt16( nTmp16 ).ReadCharAsBool( bIsThumbBmp );
+
+ if( bIsThumbBmp )
+ {
+ ReadDIBBitmapEx(aThumbBmp, rIn);
+ }
+ else
+ {
+ SvmReader aReader( rIn );
+ aReader.Read( aThumbMtf );
+ }
+
+ OUString aTmpStr = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
+ aURL = INetURLObject(aTmpStr);
+}
+
+OUString const & SgaObject::GetTitle() const
+{
+ return aTitle;
+}
+
+void SgaObject::SetTitle( const OUString& rTitle )
+{
+ aTitle = rTitle;
+}
+
+SvStream& WriteSgaObject( SvStream& rOut, const SgaObject& rObj )
+{
+ rObj.WriteData( rOut, "" );
+ return rOut;
+}
+
+SvStream& ReadSgaObject( SvStream& rIn, SgaObject& rObj )
+{
+ sal_uInt16 nReadVersion;
+
+ rObj.ReadData( rIn, nReadVersion );
+ rObj.bIsValid = ( rIn.GetError() == ERRCODE_NONE );
+
+ return rIn;
+}
+
+SgaObjectBmp::SgaObjectBmp()
+{
+}
+
+SgaObjectBmp::SgaObjectBmp( const INetURLObject& rURL )
+{
+ Graphic aGraphic;
+ OUString aFilter;
+
+ if ( GalleryGraphicImportRet::IMPORT_NONE != GalleryGraphicImport( rURL, aGraphic, aFilter ) )
+ Init( aGraphic, rURL );
+}
+
+SgaObjectBmp::SgaObjectBmp( const Graphic& rGraphic, const INetURLObject& rURL )
+{
+ if( FileExists( rURL ) )
+ Init( rGraphic, rURL );
+}
+
+void SgaObjectBmp::Init( const Graphic& rGraphic, const INetURLObject& rURL )
+{
+ aURL = rURL;
+ bIsValid = CreateThumb( rGraphic );
+}
+
+void SgaObjectBmp::WriteData( SvStream& rOut, const OUString& rDestDir ) const
+{
+ // Set version
+ SgaObject::WriteData( rOut, rDestDir );
+ char const aDummy[ 10 ] = { 0 };
+ rOut.WriteBytes(aDummy, 10);
+ write_uInt16_lenPrefixed_uInt8s_FromOString(rOut, ""); //dummy
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
+}
+
+void SgaObjectBmp::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
+{
+
+ SgaObject::ReadData( rIn, rReadVersion );
+ rIn.SeekRel( 10 ); // 16, 16, 32, 16
+ read_uInt16_lenPrefixed_uInt8s_ToOString(rIn); //dummy
+
+ if( rReadVersion >= 5 )
+ aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
+}
+
+
+SgaObjectSound::SgaObjectSound() :
+ eSoundType( SOUND_STANDARD )
+{
+}
+
+SgaObjectSound::SgaObjectSound( const INetURLObject& rURL ) :
+ eSoundType( SOUND_STANDARD )
+{
+
+ if( FileExists( rURL ) )
+ {
+ aURL = rURL;
+ aThumbBmp = Bitmap(Size(1, 1), vcl::PixelFormat::N1_BPP);
+ bIsValid = true;
+ }
+ else
+ bIsValid = false;
+}
+
+SgaObjectSound::~SgaObjectSound()
+{
+}
+
+BitmapEx SgaObjectSound::GetThumbBmp() const
+{
+ OUString sId;
+
+ switch( eSoundType )
+ {
+ case SOUND_COMPUTER: sId = RID_SVXBMP_GALLERY_SOUND_1; break;
+ case SOUND_MISC: sId = RID_SVXBMP_GALLERY_SOUND_2; break;
+ case SOUND_MUSIC: sId = RID_SVXBMP_GALLERY_SOUND_3; break;
+ case SOUND_NATURE: sId = RID_SVXBMP_GALLERY_SOUND_4; break;
+ case SOUND_SPEECH: sId = RID_SVXBMP_GALLERY_SOUND_5; break;
+ case SOUND_TECHNIC: sId = RID_SVXBMP_GALLERY_SOUND_6; break;
+ case SOUND_ANIMAL: sId = RID_SVXBMP_GALLERY_SOUND_7; break;
+
+ // standard
+ default:
+ sId = RID_SVXBMP_GALLERY_MEDIA;
+ break;
+ }
+
+ const BitmapEx aBmpEx(sId);
+
+ return aBmpEx;
+}
+
+void SgaObjectSound::WriteData( SvStream& rOut, const OUString& rDestDir ) const
+{
+ SgaObject::WriteData( rOut, rDestDir );
+ rOut.WriteUInt16( eSoundType );
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
+}
+
+void SgaObjectSound::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
+{
+ SgaObject::ReadData( rIn, rReadVersion );
+
+ if( rReadVersion >= 5 )
+ {
+ sal_uInt16 nTmp16;
+
+ rIn.ReadUInt16( nTmp16 ); eSoundType = static_cast<GalSoundType>(nTmp16);
+
+ if( rReadVersion >= 6 )
+ aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
+ }
+}
+
+SgaObjectAnim::SgaObjectAnim()
+{
+}
+
+SgaObjectAnim::SgaObjectAnim( const Graphic& rGraphic,
+ const INetURLObject& rURL )
+{
+ aURL = rURL;
+ bIsValid = CreateThumb( rGraphic );
+}
+
+SgaObjectINet::SgaObjectINet()
+{
+}
+
+SgaObjectINet::SgaObjectINet( const Graphic& rGraphic, const INetURLObject& rURL ) :
+ SgaObjectAnim ( rGraphic, rURL )
+{
+}
+
+SgaObjectSvDraw::SgaObjectSvDraw()
+{
+}
+
+SgaObjectSvDraw::SgaObjectSvDraw( const FmFormModel& rModel, const INetURLObject& rURL )
+{
+ aURL = rURL;
+ bIsValid = CreateThumb( rModel );
+}
+
+
+SvxGalleryDrawModel::SvxGalleryDrawModel()
+: mpFormModel( nullptr )
+{
+ mxDoc = SfxObjectShell::CreateObjectByFactoryName( "sdraw" );
+
+ if( !mxDoc.Is() )
+ return;
+
+ mxDoc->DoInitNew();
+
+ mpFormModel
+ = dynamic_cast<FmFormModel*>(comphelper::getFromUnoTunnel<SdrModel>(mxDoc->GetModel()));
+ if (mpFormModel)
+ {
+ mpFormModel->InsertPage(mpFormModel->AllocPage(false).get());
+ }
+}
+
+SvxGalleryDrawModel::~SvxGalleryDrawModel()
+{
+ if( mxDoc.Is() )
+ mxDoc->DoClose();
+
+}
+
+SgaObjectSvDraw::SgaObjectSvDraw( SvStream& rIStm, const INetURLObject& rURL )
+{
+ SvxGalleryDrawModel aModel;
+
+ if( aModel.GetModel() )
+ {
+ if( GallerySvDrawImport( rIStm, *aModel.GetModel() ) )
+ {
+ aURL = rURL;
+ bIsValid = CreateThumb( *aModel.GetModel() );
+ }
+ }
+}
+
+bool SgaObjectSvDraw::CreateThumb( const FmFormModel& rModel )
+{
+ Graphic aGraphic;
+ ImageMap aImageMap;
+ bool bRet = false;
+
+ if ( CreateIMapGraphic( rModel, aGraphic, aImageMap ) )
+ {
+ bRet = SgaObject::CreateThumb( aGraphic );
+ }
+ else
+ {
+ const FmFormPage* pPage = static_cast< const FmFormPage* >(rModel.GetPage(0));
+
+ if(pPage)
+ {
+ const tools::Rectangle aObjRect(pPage->GetAllObjBoundRect());
+
+ if(aObjRect.GetWidth() && aObjRect.GetHeight())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ FmFormView aView(const_cast< FmFormModel& >(rModel), pVDev);
+
+ aView.ShowSdrPage(const_cast< FmFormPage* >(pPage));
+ aView.MarkAllObj();
+ aThumbBmp = aView.GetMarkedObjBitmapEx(true);
+ aGraphic = Graphic(aThumbBmp);
+ bRet = SgaObject::CreateThumb(aGraphic);
+ }
+ }
+ }
+
+ return bRet;
+}
+
+void SgaObjectSvDraw::WriteData( SvStream& rOut, const OUString& rDestDir ) const
+{
+ SgaObject::WriteData( rOut, rDestDir );
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
+}
+
+void SgaObjectSvDraw::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
+{
+ SgaObject::ReadData( rIn, rReadVersion );
+
+ if( rReadVersion >= 5 )
+ aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galtheme.cxx b/svx/source/gallery2/galtheme.cxx
new file mode 100644
index 000000000..4a9d10e60
--- /dev/null
+++ b/svx/source/gallery2/galtheme.cxx
@@ -0,0 +1,780 @@
+/* -*- 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 <config_features.h>
+
+#include <sal/config.h>
+
+#include <algorithm>
+
+#include <osl/file.hxx>
+#include <osl/thread.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/vcompat.hxx>
+#include <tools/datetime.hxx>
+#include <sot/storage.hxx>
+#include <sot/formats.hxx>
+#include <sot/filelist.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmview.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/galleryobjectcollection.hxx>
+#include <galleryobjectbinarystorage.hxx>
+#include <galobj.hxx>
+#include <svx/gallery1.hxx>
+#include "gallerydrawmodel.hxx"
+#include <memory>
+
+using namespace ::com::sun::star;
+
+GalleryTheme::GalleryTheme( Gallery* pGallery, GalleryThemeEntry* pThemeEntry )
+ : pParent(pGallery)
+ , pThm(pThemeEntry)
+ , mnThemeLockCount(0)
+ , mnBroadcasterLockCount(0)
+ , nDragPos(0)
+ , bDragging(false)
+ , bAbortActualize(false)
+{
+ mpGalleryStorageEngine = pThm->createGalleryStorageEngine(maGalleryObjectCollection);
+}
+
+GalleryTheme::~GalleryTheme()
+{
+ if(pThm->IsModified())
+ if(!mpGalleryStorageEngine->implWrite(*this, pThm))
+ ImplSetModified(false);
+
+ for (auto & pEntry : maGalleryObjectCollection.getObjectList())
+ {
+ Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), pEntry.get() ) );
+ pEntry.reset();
+ }
+ maGalleryObjectCollection.clear();
+ mpGalleryStorageEngine->clearSotStorage();
+}
+
+void GalleryTheme::SetDestDir(const OUString& rDestDir, bool bRelative)
+{
+ mpGalleryStorageEngine->setDestDir(rDestDir, bRelative);
+}
+
+void GalleryTheme::ImplBroadcast(sal_uInt32 nUpdatePos)
+{
+ if( !IsBroadcasterLocked() )
+ {
+ if( GetObjectCount() && ( nUpdatePos >= GetObjectCount() ) )
+ nUpdatePos = GetObjectCount() - 1;
+
+ Broadcast( GalleryHint( GalleryHintType::THEME_UPDATEVIEW, GetName(), reinterpret_cast<void*>(nUpdatePos) ) );
+ }
+}
+
+bool GalleryTheme::UnlockTheme()
+{
+ DBG_ASSERT( mnThemeLockCount, "Theme is not locked" );
+
+ bool bRet = false;
+
+ if( mnThemeLockCount )
+ {
+ --mnThemeLockCount;
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+void GalleryTheme::UnlockBroadcaster()
+{
+ DBG_ASSERT( mnBroadcasterLockCount, "Broadcaster is not locked" );
+
+ if( mnBroadcasterLockCount && !--mnBroadcasterLockCount )
+ ImplBroadcast( 0 );
+}
+
+bool GalleryTheme::InsertObject(const SgaObject& rObj, sal_uInt32 nInsertPos)
+{
+ if (!rObj.IsValid())
+ return false;
+
+ GalleryObject* pFoundEntry = nullptr;
+ sal_uInt32 iFoundPos = 0;
+ for (sal_uInt32 n = maGalleryObjectCollection.size(); iFoundPos < n; ++iFoundPos)
+ {
+ if (maGalleryObjectCollection.get(iFoundPos)->getURL() == rObj.GetURL())
+ {
+ pFoundEntry = maGalleryObjectCollection.get(iFoundPos).get();
+ break;
+ }
+ }
+
+ mpGalleryStorageEngine->insertObject(rObj, pFoundEntry, nInsertPos);
+
+ ImplSetModified(true);
+ ImplBroadcast(pFoundEntry? iFoundPos: nInsertPos);
+
+ return true;
+}
+
+std::unique_ptr<SgaObject> GalleryTheme::AcquireObject(sal_uInt32 nPos)
+{
+ return mpGalleryStorageEngine->implReadSgaObject(maGalleryObjectCollection.getForPosition(nPos));
+}
+
+void GalleryTheme::GetPreviewBitmapExAndStrings(sal_uInt32 nPos, BitmapEx& rBitmapEx, Size& rSize, OUString& rTitle, OUString& rPath)
+{
+ const GalleryObject* pGalleryObject = maGalleryObjectCollection.get(nPos).get();
+
+ rBitmapEx = pGalleryObject->maPreviewBitmapEx;
+ rSize = pGalleryObject->maPreparedSize;
+ rTitle = pGalleryObject->maTitle;
+ rPath = pGalleryObject->maPath;
+}
+
+void GalleryTheme::SetPreviewBitmapExAndStrings(sal_uInt32 nPos, const BitmapEx& rBitmapEx, const Size& rSize, const OUString& rTitle, const OUString& rPath)
+{
+ GalleryObject* pGalleryObject = maGalleryObjectCollection.get(nPos).get();
+
+ pGalleryObject->maPreviewBitmapEx = rBitmapEx;
+ pGalleryObject->maPreparedSize = rSize;
+ pGalleryObject->maTitle = rTitle;
+ pGalleryObject->maPath = rPath;
+}
+
+void GalleryTheme::RemoveObject(sal_uInt32 nPos)
+{
+ auto it = maGalleryObjectCollection.getObjectList().begin() + nPos;
+ std::unique_ptr<GalleryObject> pEntry = std::move(*it);
+ maGalleryObjectCollection.getObjectList().erase( it );
+
+ mpGalleryStorageEngine->removeObject(pEntry);
+
+ Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), pEntry.get() ) );
+ pEntry.reset();
+
+ ImplSetModified( true );
+ ImplBroadcast( nPos );
+}
+
+bool GalleryTheme::ChangeObjectPos(sal_uInt32 nOldPos, sal_uInt32 nNewPos)
+{
+ if (nOldPos == nNewPos || nOldPos >= maGalleryObjectCollection.size())
+ return false;
+
+ std::unique_ptr<GalleryObject> pEntry = std::move(maGalleryObjectCollection.get(nOldPos));
+
+ maGalleryObjectCollection.getObjectList().insert(maGalleryObjectCollection.getObjectList().begin() + nNewPos, std::move(pEntry));
+
+ if (nNewPos < nOldPos)
+ nOldPos++;
+
+ auto it = maGalleryObjectCollection.getObjectList().begin() + nOldPos;
+ maGalleryObjectCollection.getObjectList().erase(it);
+
+ ImplSetModified(true);
+ ImplBroadcast((nNewPos < nOldPos)? nNewPos: (nNewPos - 1));
+
+ return true;
+}
+
+void GalleryTheme::Actualize( const Link<const INetURLObject&, void>& rActualizeLink, GalleryProgress* pProgress )
+{
+ if( IsReadOnly() )
+ return;
+
+ Graphic aGraphic;
+ OUString aFormat;
+ const sal_uInt32 nCount = maGalleryObjectCollection.size();
+
+ LockBroadcaster();
+ bAbortActualize = false;
+
+ // reset delete flag
+ for (sal_uInt32 i = 0; i < nCount; i++)
+ maGalleryObjectCollection.get(i)->mbDelete = false;
+
+ for (sal_uInt32 i = 0; ( i < nCount ) && !bAbortActualize; i++)
+ {
+ if( pProgress )
+ pProgress->Update( i, nCount - 1 );
+
+ GalleryObject* pEntry = maGalleryObjectCollection.get(i).get();
+
+ const INetURLObject aURL( pEntry->getURL());
+
+ rActualizeLink.Call( aURL );
+
+ // SvDraw objects will be updated later
+ if( pEntry->eObjKind != SgaObjKind::SvDraw )
+ {
+ // Still a function should be implemented,
+ // which assigns files to the relevant entry.
+ // insert graphics as graphic objects into the gallery
+ if( pEntry->eObjKind == SgaObjKind::Sound )
+ {
+ SgaObjectSound aObjSound( aURL );
+ if( !InsertObject( aObjSound ) )
+ pEntry->mbDelete = true;
+ }
+ else
+ {
+ aGraphic.Clear();
+
+ if ( GalleryGraphicImport( aURL, aGraphic, aFormat ) != GalleryGraphicImportRet::IMPORT_NONE )
+ {
+ std::unique_ptr<SgaObject> pNewObj;
+
+ if ( SgaObjKind::Inet == pEntry->eObjKind )
+ pNewObj.reset(new SgaObjectINet( aGraphic, aURL ));
+ else if ( aGraphic.IsAnimated() )
+ pNewObj.reset(new SgaObjectAnim( aGraphic, aURL ));
+ else
+ pNewObj.reset(new SgaObjectBmp( aGraphic, aURL ));
+
+ if( !InsertObject( *pNewObj ) )
+ pEntry->mbDelete = true;
+ }
+ else
+ pEntry->mbDelete = true; // set delete flag
+ }
+ }
+ else
+ {
+ //update SvDraw object
+ if ( mpGalleryStorageEngine->GetSvDrawStorage().is() )
+ {
+ SgaObjectSvDraw aNewObj = mpGalleryStorageEngine->updateSvDrawObject(pEntry);
+ if (aNewObj.IsValid() && !InsertObject(aNewObj))
+ pEntry->mbDelete = true;
+ }
+ }
+ }
+
+ // remove all entries with set flag
+ for ( auto it = maGalleryObjectCollection.getObjectList().begin(); it != maGalleryObjectCollection.getObjectList().end(); /* increment is in the body of loop */)
+ {
+ if( (*it)->mbDelete )
+ {
+ Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), it->get() ) );
+ it = maGalleryObjectCollection.getObjectList().erase( it );
+ }
+ else
+ ++it;
+ }
+
+ // update theme
+ mpGalleryStorageEngine->updateTheme();
+ ImplSetModified( true );
+ if (pThm->IsModified())
+ if (!mpGalleryStorageEngine->implWrite(*this, pThm))
+ ImplSetModified(false);
+ UnlockBroadcaster();
+}
+
+bool GalleryTheme::GetThumb(sal_uInt32 nPos, BitmapEx& rBmp)
+{
+ std::unique_ptr<SgaObject> pObj = AcquireObject( nPos );
+ bool bRet = false;
+
+ if( pObj )
+ {
+ rBmp = pObj->GetThumbBmp();
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::GetGraphic(sal_uInt32 nPos, Graphic& rGraphic)
+{
+ const GalleryObject* pObject = maGalleryObjectCollection.getForPosition( nPos );
+ bool bRet = false;
+
+ if( pObject )
+ {
+ const INetURLObject aURL( ImplGetURL( pObject ) );
+
+ switch( pObject->eObjKind )
+ {
+ case SgaObjKind::Bitmap:
+ case SgaObjKind::Animation:
+ case SgaObjKind::Inet:
+ {
+ OUString aFilterDummy;
+ bRet = ( GalleryGraphicImport( aURL, rGraphic, aFilterDummy ) != GalleryGraphicImportRet::IMPORT_NONE );
+ }
+ break;
+
+ case SgaObjKind::SvDraw:
+ {
+ SvxGalleryDrawModel aModel;
+
+ if( aModel.GetModel() )
+ {
+ if( GetModel( nPos, *aModel.GetModel() ) )
+ {
+ ImageMap aIMap;
+
+ if( CreateIMapGraphic( *aModel.GetModel(), rGraphic, aIMap ) )
+ bRet = true;
+ else
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ pVDev->SetMapMode( MapMode( MapUnit::Map100thMM ) );
+ FmFormView aView(*aModel.GetModel(), pVDev);
+
+ aView.hideMarkHandles();
+ aView.ShowSdrPage(aView.GetModel()->GetPage(0));
+ aView.MarkAll();
+ rGraphic = aView.GetAllMarkedGraphic();
+ bRet = true;
+ }
+ }
+ }
+ }
+ break;
+
+ case SgaObjKind::Sound:
+ {
+ std::unique_ptr<SgaObject> pObj = AcquireObject( nPos );
+
+ if( pObj )
+ {
+ rGraphic = pObj->GetThumbBmp();
+ //Bitmap aBmp( pObj->GetThumbBmp() );
+ //aBmp.Replace( COL_LIGHTMAGENTA, COL_WHITE );
+ //rGraphic = aBmp;
+ bRet = true;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertGraphic(const Graphic& rGraphic, sal_uInt32 nInsertPos)
+{
+ bool bRet = false;
+
+ if( rGraphic.GetType() != GraphicType::NONE )
+ {
+ ConvertDataFormat nExportFormat = ConvertDataFormat::Unknown;
+ const GfxLink aGfxLink( rGraphic.GetGfxLink() );
+
+ if( aGfxLink.GetDataSize() )
+ {
+ switch( aGfxLink.GetType() )
+ {
+ case GfxLinkType::EpsBuffer: nExportFormat = ConvertDataFormat::SVM; break;
+ case GfxLinkType::NativeGif: nExportFormat = ConvertDataFormat::GIF; break;
+
+ // #i15508# added BMP type
+ // could not find/trigger a call to this, but should do no harm
+ case GfxLinkType::NativeBmp: nExportFormat = ConvertDataFormat::BMP; break;
+
+ case GfxLinkType::NativeJpg: nExportFormat = ConvertDataFormat::JPG; break;
+ case GfxLinkType::NativePng: nExportFormat = ConvertDataFormat::PNG; break;
+ case GfxLinkType::NativeTif: nExportFormat = ConvertDataFormat::TIF; break;
+ case GfxLinkType::NativeWmf: nExportFormat = ConvertDataFormat::WMF; break;
+ case GfxLinkType::NativeMet: nExportFormat = ConvertDataFormat::MET; break;
+ case GfxLinkType::NativePct: nExportFormat = ConvertDataFormat::PCT; break;
+ case GfxLinkType::NativeSvg: nExportFormat = ConvertDataFormat::SVG; break;
+ case GfxLinkType::NativeWebp: nExportFormat = ConvertDataFormat::WEBP; break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ if( rGraphic.GetType() == GraphicType::Bitmap )
+ {
+ if( rGraphic.IsAnimated() )
+ nExportFormat = ConvertDataFormat::GIF;
+ else
+ nExportFormat = ConvertDataFormat::PNG;
+ }
+ else
+ nExportFormat = ConvertDataFormat::SVM;
+ }
+
+ const SgaObjectBmp aObjBmp = mpGalleryStorageEngine->insertGraphic(rGraphic, aGfxLink, nExportFormat, GetParent()->GetUserURL());
+
+ if (aObjBmp.IsValid())
+ bRet = InsertObject(aObjBmp, nInsertPos);
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::GetModel(sal_uInt32 nPos, SdrModel& rModel)
+{
+ const GalleryObject* pObject = maGalleryObjectCollection.getForPosition( nPos );
+ bool bRet = false;
+
+ if( pObject && ( SgaObjKind::SvDraw == pObject->eObjKind ) )
+ {
+ bRet = mpGalleryStorageEngine->readModel(pObject, rModel);
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertModel(const FmFormModel& rModel, sal_uInt32 nInsertPos)
+{
+ bool bRet = false;
+ SgaObjectSvDraw aObjSvDraw = mpGalleryStorageEngine->insertModel(rModel, GetParent()->GetUserURL());
+ if(aObjSvDraw.IsValid())
+ bRet = InsertObject( aObjSvDraw, nInsertPos );
+ return bRet;
+}
+
+bool GalleryTheme::GetModelStream(sal_uInt32 nPos, tools::SvRef<SotTempStream> const & rxModelStream)
+{
+ const GalleryObject* pObject = maGalleryObjectCollection.getForPosition( nPos );
+ bool bRet = false;
+
+ if( pObject && ( SgaObjKind::SvDraw == pObject->eObjKind ) )
+ {
+ bRet = mpGalleryStorageEngine->readModelStream(pObject, rxModelStream);
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertModelStream(const tools::SvRef<SotTempStream>& rxModelStream, sal_uInt32 nInsertPos)
+{
+ bool bRet = false;
+
+ const SgaObjectSvDraw aObjSvDraw = mpGalleryStorageEngine->insertModelStream(rxModelStream, GetParent()->GetUserURL());
+ if(aObjSvDraw.IsValid())
+ bRet = InsertObject( aObjSvDraw, nInsertPos );
+
+ return bRet;
+}
+
+bool GalleryTheme::GetURL(sal_uInt32 nPos, INetURLObject& rURL)
+{
+ const GalleryObject* pObject = maGalleryObjectCollection.getForPosition( nPos );
+ bool bRet = false;
+
+ if( pObject )
+ {
+ rURL = ImplGetURL( pObject );
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertURL(const INetURLObject& rURL, sal_uInt32 nInsertPos)
+{
+ Graphic aGraphic;
+ OUString aFormat;
+ std::unique_ptr<SgaObject> pNewObj;
+ const GalleryGraphicImportRet nImportRet = GalleryGraphicImport( rURL, aGraphic, aFormat );
+ bool bRet = false;
+
+ if( nImportRet != GalleryGraphicImportRet::IMPORT_NONE )
+ {
+ if ( aGraphic.IsAnimated() )
+ pNewObj.reset(new SgaObjectAnim( aGraphic, rURL ));
+ else
+ pNewObj.reset(new SgaObjectBmp( aGraphic, rURL ));
+ }
+#if HAVE_FEATURE_AVMEDIA
+ else if( ::avmedia::MediaWindow::isMediaURL( rURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ), ""/*TODO?*/ ) )
+ pNewObj.reset(new SgaObjectSound( rURL ));
+#endif
+ if( pNewObj && InsertObject( *pNewObj, nInsertPos ) )
+ bRet = true;
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertFileOrDirURL(const INetURLObject& rFileOrDirURL, sal_uInt32 nInsertPos)
+{
+ bool bRet = false;
+ std::vector< INetURLObject > aURLVector;
+ GalleryBinaryEngine::insertFileOrDirURL(rFileOrDirURL, aURLVector);
+
+ for( const auto& rURL : aURLVector )
+ bRet = bRet || InsertURL( rURL, nInsertPos );
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertTransferable(const uno::Reference< datatransfer::XTransferable >& rxTransferable, sal_uInt32 nInsertPos)
+{
+ bool bRet = false;
+
+ if( rxTransferable.is() )
+ {
+ TransferableDataHelper aDataHelper( rxTransferable );
+ std::unique_ptr<Graphic> pGraphic;
+
+ if( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) )
+ {
+ tools::SvRef<SotTempStream> xModelStm;
+
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::DRAWING, xModelStm ) )
+ bRet = InsertModelStream( xModelStm, nInsertPos );
+ }
+ else if( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) ||
+ aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) )
+ {
+ FileList aFileList;
+
+ if( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) )
+ aDataHelper.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList );
+ else
+ {
+ OUString aFile;
+ if (aDataHelper.GetString(SotClipboardFormatId::SIMPLE_FILE, aFile) && !aFile.isEmpty())
+ aFileList.AppendFile( aFile );
+ }
+
+ for( sal_uInt32 i = 0, nCount = aFileList.Count(); i < nCount; ++i )
+ {
+ const OUString aFile( aFileList.GetFile( i ) );
+ INetURLObject aURL( aFile );
+
+ if( aURL.GetProtocol() == INetProtocol::NotValid )
+ {
+ OUString aLocalURL;
+
+ if( osl::FileBase::getFileURLFromSystemPath( aFile, aLocalURL ) == osl::FileBase::E_None )
+ aURL = INetURLObject( aLocalURL );
+ }
+
+ if( aURL.GetProtocol() != INetProtocol::NotValid )
+ bRet = InsertFileOrDirURL( aURL, nInsertPos );
+ }
+ }
+ else
+ {
+ Graphic aGraphic;
+ SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
+
+ if( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
+ nFormat = SotClipboardFormatId::SVXB;
+ else if( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
+ nFormat = SotClipboardFormatId::GDIMETAFILE;
+ else if( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) )
+ nFormat = SotClipboardFormatId::BITMAP;
+
+ if( nFormat != SotClipboardFormatId::NONE && aDataHelper.GetGraphic( nFormat, aGraphic ) )
+ pGraphic.reset(new Graphic( aGraphic ));
+ }
+
+ if( pGraphic )
+ {
+ bRet = false;
+
+ if( aDataHelper.HasFormat( SotClipboardFormatId::SVIM ) )
+ {
+
+ ImageMap aImageMap;
+
+ // according to KA we don't need a BaseURL here
+ if( aDataHelper.GetImageMap( SotClipboardFormatId::SVIM, aImageMap ) )
+ {
+ SvxGalleryDrawModel aModel;
+
+ if( aModel.GetModel() )
+ {
+ SdrPage* pPage = aModel.GetModel()->GetPage(0);
+ SdrGrafObj* pGrafObj = new SdrGrafObj(*aModel.GetModel(), *pGraphic );
+
+ pGrafObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SgaIMapInfo( aImageMap )) );
+ pPage->InsertObject( pGrafObj );
+ bRet = InsertModel( *aModel.GetModel(), nInsertPos );
+ }
+ }
+ }
+
+ if( !bRet )
+ bRet = InsertGraphic( *pGraphic, nInsertPos );
+ }
+ }
+
+ return bRet;
+}
+
+void GalleryTheme::CopyToClipboard(const weld::Widget& rWidget, sal_uInt32 nPos)
+{
+ rtl::Reference<GalleryTransferable> pTransferable = new GalleryTransferable( this, nPos, false );
+ pTransferable->CopyToClipboard(rWidget.get_clipboard());
+}
+
+DateTime GalleryTheme::getModificationDate() const
+{
+ return mpGalleryStorageEngine->getModificationDate();
+}
+
+SvStream& GalleryTheme::ReadData( SvStream& rIStm )
+{
+ sal_uInt32 nCount;
+ sal_uInt16 nVersion;
+
+ rIStm.ReadUInt16( nVersion );
+ read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm);
+ rIStm.ReadUInt32( nCount );
+
+ if( nVersion >= 0x0004 )
+ {
+ sal_uInt16 nTmp16;
+ rIStm.ReadUInt16( nTmp16 );
+ }
+
+ if( nCount <= ( 1 << 14 ) )
+ {
+ INetURLObject aRelURL1( GetParent()->GetRelativeURL() );
+ INetURLObject aRelURL2( GetParent()->GetUserURL() );
+ sal_uInt32 nId1, nId2;
+ bool bRel;
+
+ for(auto & i : maGalleryObjectCollection.getObjectList())
+ {
+ GalleryObject* pObj = i.get();
+ Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), pObj ) );
+ i.reset();
+ }
+ maGalleryObjectCollection.clear();
+
+ for( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ std::unique_ptr<GalleryObject> pObj(new GalleryObject);
+
+ OUString aFileName;
+ sal_uInt16 nTemp;
+
+ rIStm.ReadCharAsBool( bRel );
+ OString aTempFileName = read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm);
+ rIStm.ReadUInt32( pObj->nOffset );
+ rIStm.ReadUInt16( nTemp ); pObj->eObjKind = static_cast<SgaObjKind>(nTemp);
+
+ aFileName = OStringToOUString(aTempFileName, osl_getThreadTextEncoding());
+
+ pObj->m_pGalleryObjectStorage.reset();
+ pObj->m_pGalleryObjectStorage = std::make_unique<GalleryObjectBinaryStorage>();
+
+ if( bRel )
+ {
+ aFileName = aFileName.replaceAll( "\\", "/" );
+ OUString aPath = aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ if( aFileName[ 0 ] != '/' )
+ aPath += "/";
+
+ aPath += aFileName;
+
+ pObj->m_pGalleryObjectStorage->setURL(INetURLObject(aPath));
+
+ if (!FileExists(pObj->getURL()))
+ {
+ aPath = aRelURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ if( aFileName[0] != '/' )
+ aPath += "/";
+
+ aPath += aFileName;
+
+ // assign this URL, even in the case it is not valid (#94482)
+ pObj->m_pGalleryObjectStorage->setURL(INetURLObject(aPath));
+ }
+ }
+ else
+ {
+ if( SgaObjKind::SvDraw == pObj->eObjKind )
+ {
+ OUString aDummyURL = "gallery/svdraw/" + aFileName;
+ pObj->m_pGalleryObjectStorage->setURL(INetURLObject(aDummyURL, INetProtocol::PrivSoffice));
+ }
+ else
+ {
+ OUString aLocalURL;
+
+ pObj->m_pGalleryObjectStorage->setURL(INetURLObject(aFileName));
+
+ if( ( pObj->getURL().GetProtocol() == INetProtocol::NotValid ) &&
+ osl::FileBase::getFileURLFromSystemPath( aFileName, aLocalURL ) == osl::FileBase::E_None )
+ {
+ pObj->m_pGalleryObjectStorage->setURL(INetURLObject(aLocalURL));
+ }
+ }
+ }
+ maGalleryObjectCollection.getObjectList().push_back( std::move(pObj) );
+ }
+
+ rIStm.ReadUInt32( nId1 ).ReadUInt32( nId2 );
+
+ // In newer versions a 512 byte reserve buffer is located at the end,
+ // the data is located at the beginning of this buffer and are clamped
+ // by a VersionCompatRead.
+ if( !rIStm.eof() &&
+ nId1 == COMPAT_FORMAT( 'G', 'A', 'L', 'R' ) &&
+ nId2 == COMPAT_FORMAT( 'E', 'S', 'R', 'V' ) )
+ {
+ VersionCompatRead aCompat(rIStm);
+ sal_uInt32 nTemp32;
+ bool bThemeNameFromResource = false;
+
+ rIStm.ReadUInt32( nTemp32 );
+
+ if( aCompat.GetVersion() >= 2 )
+ {
+ rIStm.ReadCharAsBool( bThemeNameFromResource );
+ }
+
+ SetId( nTemp32, bThemeNameFromResource );
+ }
+ }
+ else
+ rIStm.SetError( SVSTREAM_READ_ERROR );
+
+ ImplSetModified( false );
+
+ return rIStm;
+}
+
+void GalleryTheme::ImplSetModified( bool bModified )
+{
+ pThm->SetModified(bModified);
+}
+
+sal_uInt32 GalleryTheme::GetId() const { return pThm->GetId(); }
+void GalleryTheme::SetId( sal_uInt32 nNewId, bool bResetThemeName ) { pThm->SetId( nNewId, bResetThemeName ); }
+bool GalleryTheme::IsReadOnly() const { return pThm->IsReadOnly(); }
+bool GalleryTheme::IsDefault() const { return pThm->IsDefault(); }
+
+const OUString& GalleryTheme::GetName() const { return pThm->GetThemeName(); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */