diff options
Diffstat (limited to 'svx/source/gallery2')
-rw-r--r-- | svx/source/gallery2/GalleryControl.cxx | 47 | ||||
-rw-r--r-- | svx/source/gallery2/codec.cxx | 148 | ||||
-rw-r--r-- | svx/source/gallery2/codec.hxx | 40 | ||||
-rw-r--r-- | svx/source/gallery2/galbrws1.cxx | 485 | ||||
-rw-r--r-- | svx/source/gallery2/galbrws1.hxx | 91 | ||||
-rw-r--r-- | svx/source/gallery2/galbrws2.cxx | 1243 | ||||
-rw-r--r-- | svx/source/gallery2/galctrl.cxx | 409 | ||||
-rw-r--r-- | svx/source/gallery2/galexpl.cxx | 299 | ||||
-rw-r--r-- | svx/source/gallery2/galini.cxx | 95 | ||||
-rw-r--r-- | svx/source/gallery2/gallery1.cxx | 732 | ||||
-rw-r--r-- | svx/source/gallery2/gallerydrawmodel.hxx | 39 | ||||
-rw-r--r-- | svx/source/gallery2/galleryfilestorage.cxx | 812 | ||||
-rw-r--r-- | svx/source/gallery2/galleryfilestorageentry.cxx | 178 | ||||
-rw-r--r-- | svx/source/gallery2/galleryobjectcollection.cxx | 60 | ||||
-rw-r--r-- | svx/source/gallery2/gallerystoragelocations.cxx | 75 | ||||
-rw-r--r-- | svx/source/gallery2/galmisc.cxx | 563 | ||||
-rw-r--r-- | svx/source/gallery2/galobj.cxx | 493 | ||||
-rw-r--r-- | svx/source/gallery2/galtheme.cxx | 780 |
18 files changed, 6589 insertions, 0 deletions
diff --git a/svx/source/gallery2/GalleryControl.cxx b/svx/source/gallery2/GalleryControl.cxx new file mode 100644 index 0000000000..d7b2a96935 --- /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 0000000000..062c60dbec --- /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 0000000000..726b80157b --- /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 0000000000..7054bf0f1a --- /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 <utility> +#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, + std::function<void ()> aThemeSelectionHandler) + : + 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(std::move(aThemeSelectionHandler)) +{ + 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->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<OUString>& 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::u16string_view rIdent) +{ + if (rIdent == u"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 == u"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 == u"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 == u"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 == u"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<OUString> aExecVector; + ImplGetExecuteVector(aExecVector); + OUString 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<OUString> 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()); + + OUString 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 0000000000..ffe05c942b --- /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<OUString>& o_aExec); + void ImplExecute(std::u16string_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, + ::std::function<void ()> aThemeSelectionHandler); + + ~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 0000000000..8285419d18 --- /dev/null +++ b/svx/source/gallery2/galbrws2.cxx @@ -0,0 +1,1243 @@ +/* -*- 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::u16string_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::u16string_view rIdent) +{ + if (rIdent.empty()) + return; + + sal_uInt16 nSubMenuId = o3tl::toUInt32(rIdent); + if (nSubMenuId) + { + BackgroundMenuSelectHdl(nSubMenuId-1); + return; + } + + if (rIdent == u"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(); +} + +bool 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 false; + + ImplSelectItemId( nItemId ); + + css::uno::Reference< css::frame::XFrame > xFrame( GetFrame() ); + if ( !xFrame.is() ) + return false; + + weld::Widget* pParent = GetViewWindow(); + mnCurActionPos = nItemId - 1; + rtl::Reference< GalleryThemePopup > xPopup( + new GalleryThemePopup( + pParent, + mpCurTheme, + mnCurActionPos, + GALLERYBROWSERMODE_PREVIEW == GetMode(), + this ) ); + xPopup->ExecutePopup(pParent, aSelPos); + return true; +} + +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) + { + OUString 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->SetDragDataTransferable(xHelper, DND_ACTION_COPY | DND_ACTION_LINK); + mxPreview->SetDragDataTransferable(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::u16string_view rIdent) +{ + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos ); + + if( !(mpCurTheme && nItemId) ) + return; + + mnCurActionPos = nItemId - 1; + + if (rIdent == u"preview") + SetMode( ( GALLERYBROWSERMODE_PREVIEW != GetMode() ) ? GALLERYBROWSERMODE_PREVIEW : meLastMode ); + else if (rIdent == u"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 == u"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 == u"copy") + { + mpCurTheme->CopyToClipboard(*GetViewWindow(), mnCurActionPos); + } + else if (rIdent == u"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 0000000000..1c3ffbf032 --- /dev/null +++ b/svx/source/gallery2/galctrl.cxx @@ -0,0 +1,409 @@ +/* -*- 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> +#include <svl/itemset.hxx> + +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 (!bRet && rCEvt.GetCommand() == CommandEventId::ContextMenu) + { + bRet = 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 0000000000..b1e70919c9 --- /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 0000000000..c88a7f4f2f --- /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 <galleryfilestorageentry.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <o3tl/string_view.hxx> +#include <memory> + +OUString GalleryFileStorageEntry::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 0000000000..9d4885244f --- /dev/null +++ b/svx/source/gallery2/gallery1.cxx @@ -0,0 +1,732 @@ +/* -*- 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 <galleryfilestorageentry.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; + + +constexpr std::pair<sal_uInt16, OUString> 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) + { + GalleryFileStorageEntry::CreateUniqueURL(rBaseURL,aURL); + } + + mpGalleryStorageEngineEntry = std::make_unique<GalleryFileStorageEntry>(); + 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; +} + +GalleryThemeEntry::~GalleryThemeEntry() +{} + +void GalleryThemeEntry::setStorageLocations(INetURLObject & rURL) +{ + mpGalleryStorageEngineEntry->setStorageLocations(rURL); +} + +GalleryTheme* GalleryThemeEntry::createGalleryTheme(Gallery* pGallery) +{ + return new GalleryTheme(pGallery,this); +} + +std::unique_ptr<GalleryFileStorage> 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( Concat2View(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 OUString s_sTitle = u"Title"_ustr; + static constexpr OUString s_sIsReadOnly = u"IsReadOnly"_ustr; + + 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 = GalleryFileStorageEntry::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; +} + +GalleryStorageLocations& GalleryThemeEntry::getGalleryStorageLocations() const +{ + return mpGalleryStorageEngineEntry->getGalleryStorageLocations(); +} + +/* 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 0000000000..0b2ef25821 --- /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 0000000000..e9a8cd0aa8 --- /dev/null +++ b/svx/source/gallery2/galleryfilestorage.cxx @@ -0,0 +1,812 @@ +/* -*- 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 <svx/galtheme.hxx> +#include <galobj.hxx> +#include <galleryfilestorage.hxx> +#include <svx/galleryobjectcollection.hxx> +#include <svx/gallery1.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 <comphelper/diagnose_ex.hxx> +#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; + +GalleryFileStorage::GalleryFileStorage( + const GalleryStorageLocations& rGalleryBinaryStorageLocations, + GalleryObjectCollection& rGalleryObjectCollection, bool bReadOnly) + : maGalleryStorageLocations(rGalleryBinaryStorageLocations) + , mrGalleryObjectCollection(rGalleryObjectCollection) + , mbReadOnly(bReadOnly) + , m_bDestDirRelative(false) +{ + ImplCreateSvDrawStorage(); +} + +GalleryFileStorage::~GalleryFileStorage() { clearSotStorage(); } + +void GalleryFileStorage::setDestDir(const OUString& rDestDir, bool bRelative) +{ + m_aDestDir = rDestDir; + m_bDestDirRelative = bRelative; +} + +void GalleryFileStorage::clearSotStorage() { m_aSvDrawStorageRef.clear(); } + +void GalleryFileStorage::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>& GalleryFileStorage::GetSvDrawStorage() const +{ + return m_aSvDrawStorageRef; +} + +bool GalleryFileStorage::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 GalleryFileStorage::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 GalleryFileStorage::removeObject(const std::unique_ptr<GalleryObject>& pEntry) +{ + if (mrGalleryObjectCollection.getObjectList().empty()) + KillFile(GetSdgURL()); + + if (SgaObjKind::SvDraw == pEntry->eObjKind) + GetSvDrawStorage()->Remove( + pEntry->m_oStorageUrl->GetMainURL(INetURLObject::DecodeMechanism::NONE)); +} + +std::unique_ptr<SgaObject> GalleryFileStorage::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->m_oStorageUrl); + } + } + } + } + + return pSgaObj; +} + +bool GalleryFileStorage::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_oStorageUrl = rObj.GetURL(); + + pEntry->nOffset = nOffset; + pEntry->eObjKind = rObj.GetObjKind(); + bRet = true; + } + } + + return bRet; +} + +bool GalleryFileStorage::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 GalleryFileStorage::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 GalleryFileStorage::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 +GalleryFileStorage::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 GalleryFileStorage::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->m_oStorageUrl == 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 GalleryFileStorage::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 GalleryFileStorage::updateSvDrawObject(const GalleryObject* pEntry) +{ + if (GetSvDrawStorage().is()) + { + const OUString aStmName(GetSvDrawStreamNameFromURL(*pEntry->m_oStorageUrl)); + tools::SvRef<SotStorageStream> pIStm + = GetSvDrawStorage()->OpenSotStream(aStmName, StreamMode::READ); + + if (pIStm.is() && !pIStm->GetError()) + { + pIStm->SetBufferSize(16384); + + SgaObjectSvDraw aNewObj(*pIStm, *pEntry->m_oStorageUrl); + + pIStm->SetBufferSize(0); + + return aNewObj; + } + } + return SgaObjectSvDraw(); +} + +void GalleryFileStorage::updateTheme() +{ + ::utl::TempFileNamed 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 GalleryFileStorage::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& GalleryFileStorage::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); + rOStm.WriteUInt16(RTL_TEXTENCODING_UTF8); // unused on reading + + for (sal_uInt32 i = 0; i < nCount; i++) + { + const GalleryObject* pObj = mrGalleryObjectCollection.getForPosition(i); + OUString aPath; + + if (SgaObjKind::SvDraw == pObj->eObjKind) + { + aPath = GetSvDrawStreamNameFromURL(*pObj->m_oStorageUrl); + bRel = false; + } + else + { + aPath = pObj->m_oStorageUrl->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->m_oStorageUrl->GetMainURL(INetURLObject::DecodeMechanism::NONE) + .getLength() + > (rRelURL1.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength() + 1))) + { + aPath = pObj->m_oStorageUrl->GetMainURL(INetURLObject::DecodeMechanism::NONE); + aPath = aPath.copy( + std::min(rRelURL1.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength(), + aPath.getLength())); + } + else + { + aPath = pObj->m_oStorageUrl->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->m_oStorageUrl->GetMainURL(INetURLObject::DecodeMechanism::NONE) + .getLength() + > (rRelURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength() + + 1))) + { + aPath = pObj->m_oStorageUrl->GetMainURL(INetURLObject::DecodeMechanism::NONE); + aPath = aPath.copy(std::min( + rRelURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength(), + aPath.getLength())); + } + else + aPath = pObj->m_oStorageUrl->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 GalleryFileStorage::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/galleryfilestorageentry.cxx b/svx/source/gallery2/galleryfilestorageentry.cxx new file mode 100644 index 0000000000..593396aaed --- /dev/null +++ b/svx/source/gallery2/galleryfilestorageentry.cxx @@ -0,0 +1,178 @@ +/* -*- 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 <galleryfilestorageentry.hxx> +#include <gallerystoragelocations.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); +} + +GalleryFileStorageEntry::GalleryFileStorageEntry() {} + +void GalleryFileStorageEntry::setStorageLocations(INetURLObject& rURL) +{ + maGalleryStorageLocations.SetStorageLocations(rURL); +} + +std::unique_ptr<GalleryFileStorage> GalleryFileStorageEntry::createGalleryStorageEngine( + GalleryObjectCollection& mrGalleryObjectCollection, bool& bReadOnly) +{ + return std::make_unique<GalleryFileStorage>(maGalleryStorageLocations, + mrGalleryObjectCollection, bReadOnly); +} + +void GalleryFileStorageEntry::CreateUniqueURL(const INetURLObject& rBaseURL, INetURLObject& aURL) +{ + INetURLObject aBaseNoCase(GalleryStorageLocations::ImplGetURLIgnoreCase(rBaseURL)); + aURL = aBaseNoCase; + static sal_Int32 nIdx = 0; + while (FileExists(aURL, u"thm")) + { // create new URLs + nIdx++; + aURL = aBaseNoCase; + aURL.setName(Concat2View(aURL.getName() + OUString::number(nIdx))); + } +} + +GalleryThemeEntry* GalleryFileStorageEntry::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 GalleryFileStorageEntry::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>& +GalleryFileStorageEntry::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/galleryobjectcollection.cxx b/svx/source/gallery2/galleryobjectcollection.cxx new file mode 100644 index 0000000000..bfcca1fb2a --- /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->m_oStorageUrl == 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)->m_oStorageUrl; + return g_aInvalidURL; +} + +/* 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 0000000000..bd2a81c335 --- /dev/null +++ b/svx/source/gallery2/gallerystoragelocations.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 <gallerystoragelocations.hxx> +#include <svx/galmisc.hxx> + +INetURLObject GalleryStorageLocations::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 GalleryStorageLocations::SetThmExtension(INetURLObject& aURL) +{ + aURL.setExtension(u"thm"); + maThmURL = ImplGetURLIgnoreCase(aURL); +} + +void GalleryStorageLocations::SetSdgExtension(INetURLObject& aURL) +{ + aURL.setExtension(u"sdg"); + maSdgURL = ImplGetURLIgnoreCase(aURL); +} + +void GalleryStorageLocations::SetSdvExtension(INetURLObject& aURL) +{ + aURL.setExtension(u"sdv"); + maSdvURL = ImplGetURLIgnoreCase(aURL); +} + +void GalleryStorageLocations::SetStrExtension(INetURLObject& aURL) +{ + aURL.setExtension(u"str"); + maStrURL = ImplGetURLIgnoreCase(aURL); +} + +void GalleryStorageLocations::SetStorageLocations(INetURLObject& rURL) +{ + SetThmExtension(rURL); + SetSdgExtension(rURL); + SetSdvExtension(rURL); + SetStrExtension(rURL); +} + +/* 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 0000000000..ab5713f7a4 --- /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( std::move(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( std::move(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->m_oStorageUrl; + + 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 0000000000..f083ad85bb --- /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::N8_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 0000000000..1fd04b4542 --- /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 <galleryfilestorage.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)->m_oStorageUrl == 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->m_oStorageUrl ); + + 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; + GalleryFileStorage::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::optional<Graphic> oGraphic; + + 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 ) ) + oGraphic.emplace( aGraphic ); + } + + if( oGraphic ) + { + 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); + rtl::Reference<SdrGrafObj> pGrafObj = new SdrGrafObj(*aModel.GetModel(), *oGraphic ); + + pGrafObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SgaIMapInfo( aImageMap )) ); + pPage->InsertObject( pGrafObj.get() ); + bRet = InsertModel( *aModel.GetModel(), nInsertPos ); + } + } + } + + if( !bRet ) + bRet = InsertGraphic( *oGraphic, 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_oStorageUrl.emplace(); + + if( bRel ) + { + aFileName = aFileName.replaceAll( "\\", "/" ); + OUString aPath = aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + + if( aFileName[ 0 ] != '/' ) + aPath += "/"; + + aPath += aFileName; + + pObj->m_oStorageUrl = INetURLObject(aPath); + + if (!FileExists(*pObj->m_oStorageUrl)) + { + 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_oStorageUrl = INetURLObject(aPath); + } + } + else + { + if( SgaObjKind::SvDraw == pObj->eObjKind ) + { + OUString aDummyURL = "gallery/svdraw/" + aFileName; + pObj->m_oStorageUrl = INetURLObject(aDummyURL, INetProtocol::PrivSoffice); + } + else + { + OUString aLocalURL; + + pObj->m_oStorageUrl = INetURLObject(aFileName); + + if( ( pObj->m_oStorageUrl->GetProtocol() == INetProtocol::NotValid ) && + osl::FileBase::getFileURLFromSystemPath( aFileName, aLocalURL ) == osl::FileBase::E_None ) + { + pObj->m_oStorageUrl = 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(); } +const INetURLObject& GalleryTheme::getThemeURL() const { return mpGalleryStorageEngine->getThemeURL(); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |