diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /svx/source/gallery2 | |
parent | Initial commit. (diff) | |
download | libreoffice-1ad18e38974bb28c3d98d0be8f7d8c18fc56de29.tar.xz libreoffice-1ad18e38974bb28c3d98d0be8f7d8c18fc56de29.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'svx/source/gallery2')
-rw-r--r-- | svx/source/gallery2/GalleryControl.cxx | 62 | ||||
-rw-r--r-- | svx/source/gallery2/codec.cxx | 152 | ||||
-rw-r--r-- | svx/source/gallery2/codec.hxx | 42 | ||||
-rw-r--r-- | svx/source/gallery2/galbrws1.cxx | 487 | ||||
-rw-r--r-- | svx/source/gallery2/galbrws1.hxx | 89 | ||||
-rw-r--r-- | svx/source/gallery2/galbrws2.cxx | 1249 | ||||
-rw-r--r-- | svx/source/gallery2/galctrl.cxx | 407 | ||||
-rw-r--r-- | svx/source/gallery2/galexpl.cxx | 296 | ||||
-rw-r--r-- | svx/source/gallery2/galini.cxx | 94 | ||||
-rw-r--r-- | svx/source/gallery2/gallery1.cxx | 769 | ||||
-rw-r--r-- | svx/source/gallery2/gallerydrawmodel.hxx | 39 | ||||
-rw-r--r-- | svx/source/gallery2/galmisc.cxx | 553 | ||||
-rw-r--r-- | svx/source/gallery2/galobj.cxx | 481 | ||||
-rw-r--r-- | svx/source/gallery2/galtheme.cxx | 1468 |
14 files changed, 6188 insertions, 0 deletions
diff --git a/svx/source/gallery2/GalleryControl.cxx b/svx/source/gallery2/GalleryControl.cxx new file mode 100644 index 000000000..a25d178d4 --- /dev/null +++ b/svx/source/gallery2/GalleryControl.cxx @@ -0,0 +1,62 @@ +/* -*- 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(vcl::Window* pParent) + : PanelLayout(pParent, "GalleryPanel", "svx/ui/sidebargallery.ui", nullptr) + , 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() +{ + disposeOnce(); +} + +void GalleryControl::dispose() +{ + mxBrowser2.reset(); + mxBrowser1.reset(); + PanelLayout::dispose(); +} + +void GalleryControl::GetFocus() +{ + Window::GetFocus(); + if (mxBrowser1) + mxBrowser1->GrabFocus(); +} + +} // end of namespace svx::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/codec.cxx b/svx/source/gallery2/codec.cxx new file mode 100644 index 000000000..5063632d1 --- /dev/null +++ b/svx/source/gallery2/codec.cxx @@ -0,0 +1,152 @@ +/* -*- 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 ) +{ +} + +GalleryCodec::~GalleryCodec() +{ +} + +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 ) ) + { + sal_uInt32 nCompressedSize, nUnCompressedSize; + + rStm.SeekRel( 6 ); + rStm.ReadUInt32( nUnCompressedSize ).ReadUInt32( nCompressedSize ); + + // decompress + if( 1 == nVersion ) + { + std::unique_ptr<sal_uInt8[]> pCompressedBuffer(new sal_uInt8[ nCompressedSize ]); + rStm.ReadBytes(pCompressedBuffer.get(), nCompressedSize); + sal_uInt8* pInBuf = pCompressedBuffer.get(); + std::unique_ptr<sal_uInt8[]> pOutBuf(new sal_uInt8[ nUnCompressedSize ]); + sal_uInt8* pTmpBuf = pOutBuf.get(); + sal_uInt8* pLast = pOutBuf.get() + nUnCompressedSize - 1; + sal_uIntPtr nIndex = 0, nCountByte, nRunByte; + bool bEndDecoding = false; + + do + { + nCountByte = *pInBuf++; + + if ( !nCountByte ) + { + nRunByte = *pInBuf++; + + if ( nRunByte > 2 ) + { + // filling absolutely + memcpy( &pTmpBuf[ nIndex ], pInBuf, nRunByte ); + pInBuf += nRunByte; + nIndex += nRunByte; + + // note WORD alignment + if ( nRunByte & 1 ) + pInBuf++; + } + else if ( nRunByte == 1 ) // End of the image + bEndDecoding = true; + } + else + { + const sal_uInt8 cVal = *pInBuf++; + + memset( &pTmpBuf[ nIndex ], cVal, nCountByte ); + nIndex += nCountByte; + } + } + while ( !bEndDecoding && ( pTmpBuf <= pLast ) ); + + rStmToRead.WriteBytes(pOutBuf.get(), nUnCompressedSize); + } + else if( 2 == nVersion ) + { + ZCodec aCodec; + + aCodec.BeginCompression(); + aCodec.Decompress( rStm, rStmToRead ); + aCodec.EndCompression(); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/codec.hxx b/svx/source/gallery2/codec.hxx new file mode 100644 index 000000000..35ead899c --- /dev/null +++ b/svx/source/gallery2/codec.hxx @@ -0,0 +1,42 @@ +/* -*- 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 ); + ~GalleryCodec(); + + void Write( SvStream& rStmToWrite ); + void Read( SvStream& rStmToRead ); + + static bool IsCoded( SvStream& rStm, sal_uInt32& rVersion ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/galbrws1.cxx b/svx/source/gallery2/galbrws1.cxx new file mode 100644 index 000000000..f4c3da3b4 --- /dev/null +++ b/svx/source/gallery2/galbrws1.cxx @@ -0,0 +1,487 @@ +/* -*- 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 <comphelper/processfactory.hxx> +#include <tools/datetime.hxx> +#include <unotools/datetime.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <ucbhelper/content.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 <com/sun/star/util/DateTime.hpp> +#include <svx/strings.hrc> +#include <algorithm> +#include <svx/dialmgr.hxx> + +#include <svx/svxdlg.hxx> +#include <memory> +#include <bitmaps.hlst> + +using namespace ::com::sun::star; + +GalleryBrowser1::GalleryBrowser1( + weld::Builder& rBuilder, + Gallery* pGallery, + const std::function<void ()>& rThemeSlectionHandler) + : + mxNewTheme(rBuilder.weld_button("insert")), + mxThemes(rBuilder.weld_tree_view("themelist")), + mpGallery ( pGallery ), + mpExchangeData ( new ExchangeData ), + aImgNormal ( RID_SVXBMP_THEME_NORMAL ), + aImgDefault ( RID_SVXBMP_THEME_DEFAULT ), + aImgReadOnly ( RID_SVXBMP_THEME_READONLY ), + maThemeSlectionHandler(rThemeSlectionHandler) +{ + 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)); + + // 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 ) ) + { + 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 + { + ::ucbhelper::Content aCnt( pThm->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 ); + rData.aThemeChangeDate = aDateTime; + rData.aThemeChangeTime = aDateTime; + } + catch( const ucb::ContentCreationException& ) + { + } + catch( const uno::RuntimeException& ) + { + } + catch( const uno::Exception& ) + { + } +} + +void GalleryBrowser1::ImplGetExecuteVector(std::vector<OString>& o_aExec) +{ + GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this ); + + if( pTheme ) + { + 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( const OUString & 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(const OString &rIdent) +{ + if (rIdent == "update") + { + GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this ); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<VclAbstractDialog> aActualizeProgress(pFact->CreateActualizeProgressDialog(mxThemes.get(), pTheme)); + + aActualizeProgress->Execute(); + mpGallery->ReleaseTheme( pTheme, *this ); + } + else if (rIdent == "delete") + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxThemes.get(), "svx/ui/querydeletethemedialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryDeleteThemeDialog")); + if (xQuery->run() == RET_YES) + mpGallery->RemoveTheme( mxThemes->get_selected_text() ); + } + else if (rIdent == "rename") + { + GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this ); + const OUString aOldName( pTheme->GetName() ); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractTitleDialog> aDlg(pFact->CreateTitleDialog(mxThemes.get(), aOldName)); + + if( aDlg->Execute() == RET_OK ) + { + const OUString aNewName( aDlg->GetTitle() ); + + if( !aNewName.isEmpty() && ( aNewName != aOldName ) ) + { + OUString aName( aNewName ); + sal_uInt16 nCount = 0; + + while( mpGallery->HasTheme( aName ) && ( nCount++ < 16000 ) ) + { + aName = aNewName + " " + OUString::number( nCount ); + } + + mpGallery->RenameTheme( aOldName, aName ); + } + } + mpGallery->ReleaseTheme( pTheme, *this ); + } + else if (rIdent == "assign") + { + GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this ); + + if (pTheme && !pTheme->IsReadOnly()) + { + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractGalleryIdDialog> aDlg(pFact->CreateGalleryIdDialog(mxThemes.get(), pTheme)); + if( aDlg->Execute() == RET_OK ) + pTheme->SetId( aDlg->GetId(), true ); + } + + mpGallery->ReleaseTheme( pTheme, *this ); + } + else if (rIdent == "properties") + { + ImplGalleryThemeProperties( GetSelectedTheme(), false ); + } +} + +void GalleryBrowser1::GrabFocus() +{ + if (mxNewTheme->get_sensitive()) + mxNewTheme->grab_focus(); + else + mxThemes->grab_focus(); +} + +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_LINK(GalleryBrowser1, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bRet = false; + + std::vector<OString> aExecVector; + ImplGetExecuteVector(aExecVector); + OString sExecuteIdent; + bool bMod1 = rKEvt.GetKeyCode().IsMod1(); + + switch( rKEvt.GetKeyCode().GetCode() ) + { + case KEY_INSERT: + ClickNewThemeHdl(*mxNewTheme); + break; + + case KEY_I: + { + if( bMod1 ) + ClickNewThemeHdl(*mxNewTheme); + } + break; + + case KEY_U: + { + if( bMod1 ) + sExecuteIdent = "update"; + } + break; + + case KEY_DELETE: + sExecuteIdent = "delete"; + break; + + case KEY_D: + { + if( bMod1 ) + sExecuteIdent = "delete"; + } + break; + + case KEY_R: + { + if( bMod1 ) + sExecuteIdent = "rename"; + } + break; + + case KEY_RETURN: + { + if( bMod1 ) + sExecuteIdent = "properties"; + } + break; + } + + if (!sExecuteIdent.isEmpty() && (std::find( aExecVector.begin(), aExecVector.end(), sExecuteIdent) != aExecVector.end())) + { + ImplExecute(sExecuteIdent); + bRet = true; + } + + return bRet; +} + +IMPL_LINK(GalleryBrowser1, PopupMenuHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + + std::vector<OString> aExecVector; + ImplGetExecuteVector(aExecVector); + + if (aExecVector.empty()) + return true; + + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxThemes.get(), "svx/ui/gallerymenu1.ui")); + std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu")); + + xMenu->set_visible("update", std::find( aExecVector.begin(), aExecVector.end(), "update" ) != aExecVector.end()); + xMenu->set_visible("rename", std::find( aExecVector.begin(), aExecVector.end(), "rename" ) != aExecVector.end()); + xMenu->set_visible("delete", std::find( aExecVector.begin(), aExecVector.end(), "delete" ) != aExecVector.end()); + xMenu->set_visible("assign", std::find( aExecVector.begin(), aExecVector.end(), "assign" ) != aExecVector.end()); + xMenu->set_visible("properties", std::find( aExecVector.begin(), aExecVector.end(), "properties" ) != aExecVector.end()); + + OString sCommand(xMenu->popup_at_rect(mxThemes.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)))); + ImplExecute(sCommand); + + return true; +} + +IMPL_LINK_NOARG(GalleryBrowser1, SelectThemeHdl, weld::TreeView&, void) +{ + if (maThemeSlectionHandler) + maThemeSlectionHandler(); +} + +IMPL_LINK_NOARG(GalleryBrowser1, ClickNewThemeHdl, weld::Button&, void) +{ + OUString aNewTheme( SvxResId(RID_SVXSTR_GALLERY_NEWTHEME) ); + OUString aName( aNewTheme ); + sal_uInt16 nCount = 0; + + while( mpGallery->HasTheme( aName ) && ( nCount++ < 16000 ) ) + { + aName = aNewTheme + " " + OUString::number( nCount ); + } + + if( !mpGallery->HasTheme( aName ) && mpGallery->CreateTheme( aName ) ) + { + ImplGalleryThemeProperties( aName, true ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/galbrws1.hxx b/svx/source/gallery2/galbrws1.hxx new file mode 100644 index 000000000..91524f202 --- /dev/null +++ b/svx/source/gallery2/galbrws1.hxx @@ -0,0 +1,89 @@ +/* -*- 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 <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; + Gallery* mpGallery; + std::unique_ptr<ExchangeData> mpExchangeData; + std::unique_ptr<SfxItemSet> mpThemePropsDlgItemSet; + + OUString aImgNormal; + OUString aImgDefault; + OUString aImgReadOnly; + + ::std::function<void ()> maThemeSlectionHandler; + + void ImplInsertThemeEntry( const GalleryThemeEntry* pEntry ); + static void ImplFillExchangeData( const GalleryTheme* pThm, ExchangeData& rData ); + void ImplGetExecuteVector(std::vector<OString>& o_aExec); + void ImplExecute(const OString &rIdent); + void ImplGalleryThemeProperties( const OUString & 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 ); + +public: + + GalleryBrowser1( + weld::Builder& rBuilder, + Gallery* pGallery, + const ::std::function<void ()>& rThemeSlectionHandler); + + ~GalleryBrowser1(); + + void SelectTheme( sal_uInt16 nThemePos ) { mxThemes->select( nThemePos ); SelectThemeHdl( *mxThemes ); } + OUString GetSelectedTheme() const { return mxThemes->get_selected_text(); } + void GrabFocus(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/galbrws2.cxx b/svx/source/gallery2/galbrws2.cxx new file mode 100644 index 000000000..7232929e6 --- /dev/null +++ b/svx/source/gallery2/galbrws2.cxx @@ -0,0 +1,1249 @@ +/* -*- 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 <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 <map> +#include <memory> +#include <cppuhelper/implbase.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(const OString& 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(const OString& rIdent) +{ + if (rIdent.isEmpty()) + return; + + sal_uInt16 nSubMenuId = rIdent.toUInt32(); + if (nSubMenuId) + { + BackgroundMenuSelectHdl(nSubMenuId-1); + return; + } + + if (rIdent == "add") + { + const CommandInfoMap::const_iterator it = m_aCommandInfo.find( SID_GALLERY_FORMATS ); + if (it != m_aCommandInfo.end()) + mpBrowser->DispatchAdd(it->second.Dispatch, it->second.URL); + } + else + mpBrowser->Execute(rIdent); +} + +void GalleryThemePopup::BackgroundMenuSelectHdl(sal_uInt16 nPos) +{ + OUString aURL( mpBrowser->GetURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + OUString aFilterName( mpBrowser->GetFilterName() ); + + css::uno::Sequence< css::beans::PropertyValue > aArgs( 6 ); + aArgs[0].Name = "Background.Transparent"; + aArgs[0].Value <<= sal_Int32( 0 ); // 0 - 100 + aArgs[1].Name = "Background.BackColor"; + aArgs[1].Value <<= sal_Int32( - 1 ); + aArgs[2].Name = "Background.URL"; + aArgs[2].Value <<= aURL; + aArgs[3].Name = "Background.Filtername"; // FIXME should be FilterName + aArgs[3].Value <<= aFilterName; + aArgs[4].Name = "Background.Position"; + aArgs[4].Value <<= css::style::GraphicLocation_TILED; + aArgs[5].Name = "Position"; + aArgs[5].Value <<= 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"))) + , 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")) + , mxDev(mxListView->create_virtual_device()) + , maPreviewSize(28, 28) + , mnCurActionPos ( 0xffffffff ) + , meMode ( GALLERYBROWSERMODE_NONE ) + , meLastMode ( GALLERYBROWSERMODE_NONE ) +{ + mxDev->SetOutputSizePixel(maPreviewSize); + + 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( DropTargetHelper& rTarget ) +{ + sal_Int8 nRet = DND_ACTION_NONE; + + if( mpCurTheme && !mpCurTheme->IsReadOnly() ) + { + if( !mpCurTheme->IsDragging() ) + { + if( rTarget.IsDropFormatSupported( SotClipboardFormatId::DRAWING ) || + rTarget.IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) || + rTarget.IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) || + rTarget.IsDropFormatSupported( SotClipboardFormatId::SVXB ) || + rTarget.IsDropFormatSupported( SotClipboardFormatId::GDIMETAFILE ) || + rTarget.IsDropFormatSupported( SotClipboardFormatId::BITMAP ) ) + { + nRet = DND_ACTION_COPY; + } + } + else + nRet = DND_ACTION_COPY; + } + + return nRet; +} + +sal_Int8 GalleryBrowser2::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + sal_Int8 nRet = DND_ACTION_NONE; + + if( mpCurTheme ) + { + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( &rEvt.maPosPixel, aSelPos ); + const sal_uInt32 nInsertPos = (nItemId ? (nItemId - 1) : mpCurTheme->GetObjectCount()); + + if( mpCurTheme->IsDragging() ) + mpCurTheme->ChangeObjectPos( mpCurTheme->GetDragPos(), nInsertPos ); + else + nRet = mpCurTheme->InsertTransferable( rEvt.maDropEvent.Transferable, nInsertPos ) ? 1 : 0; + } + + return nRet; +} + +bool GalleryBrowser2::StartDrag() +{ + if (!mpCurTheme) + return true; + return m_xHelper->StartDrag(); +} + +IMPL_LINK(GalleryBrowser2, DragBeginHdl, bool&, rUnsetDragIcon, bool) +{ + rUnsetDragIcon = false; + return StartDrag(); +} + +void GalleryBrowser2::TogglePreview() +{ + SetMode( ( GALLERYBROWSERMODE_PREVIEW != GetMode() ) ? GALLERYBROWSERMODE_PREVIEW : meLastMode ); + GetViewWindow()->grab_focus(); +} + +void GalleryBrowser2::ShowContextMenu(const CommandEvent& rCEvt) +{ + Point aMousePos = rCEvt.GetMousePosPixel(); + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( rCEvt.IsMouseEvent() ? &aMousePos : nullptr, aSelPos ); + + if( mpCurTheme && nItemId && ( nItemId <= mpCurTheme->GetObjectCount() ) ) + { + ImplSelectItemId( nItemId ); + + css::uno::Reference< css::frame::XFrame > xFrame( GetFrame() ); + if ( xFrame.is() ) + { + weld::Widget* pParent = GetViewWindow(); + mnCurActionPos = nItemId - 1; + rtl::Reference< GalleryThemePopup > xPopup( + new GalleryThemePopup( + pParent, + mpCurTheme, + mnCurActionPos, + GALLERYBROWSERMODE_PREVIEW == GetMode(), + this ) ); + xPopup->ExecutePopup(pParent, aSelPos); + } + } +} + +bool GalleryBrowser2::ViewBoxHasFocus() const +{ + return mxIconButton->has_focus() || mxListButton->has_focus(); +} + +bool GalleryBrowser2::KeyInput(const KeyEvent& rKEvt) +{ + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos ); + bool bRet = false; + + if (!ViewBoxHasFocus() && nItemId && mpCurTheme) + { + OString sExecuteIdent; + INetURLObject aURL; + + mpCurTheme->GetURL( nItemId - 1, aURL ); + + const bool bValidURL = ( aURL.GetProtocol() != INetProtocol::NotValid ); + bool bPreview = bValidURL; + bool bDelete = false; + bool bTitle = false; + + if( !mpCurTheme->IsReadOnly() && mpCurTheme->GetObjectCount() ) + { + bDelete = ( GALLERYBROWSERMODE_PREVIEW != GetMode() ); + bTitle = true; + } + + switch( rKEvt.GetKeyCode().GetCode() ) + { + case KEY_SPACE: + case KEY_RETURN: + case KEY_P: + { + if( bPreview ) + { + TogglePreview(); + bRet = true; + } + } + break; + + case KEY_INSERT: + case KEY_I: + { + // Inserting a gallery item in the document must be dispatched + if( bValidURL ) + { + DispatchAdd(css::uno::Reference<css::frame::XDispatch>(), css::util::URL()); + return true; + } + } + break; + + case KEY_DELETE: + case KEY_D: + { + if( bDelete ) + sExecuteIdent = "delete"; + } + break; + + case KEY_T: + { + if( bTitle ) + sExecuteIdent = "title"; + } + break; + + default: + break; + } + + if (!sExecuteIdent.isEmpty()) + { + Execute(sExecuteIdent); + bRet = true; + } + } + + return bRet; +} + +void GalleryBrowser2::SelectTheme( const OUString& 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.get()); + mxListView->enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK); + mxIconView->SetDragDataTransferrable(xHelper, DND_ACTION_COPY | DND_ACTION_LINK); + mxPreview->SetDragDataTransferrable(xHelper, DND_ACTION_COPY | DND_ACTION_LINK); + + mxIconView->SetTheme(mpCurTheme); + mxPreview->SetTheme(mpCurTheme); + + if( GALLERYBROWSERMODE_PREVIEW == GetMode() ) + meMode = meLastMode; + + ImplUpdateViews( 1 ); + + bool bIconMode = (GALLERYBROWSERMODE_ICON == GetMode()); + mxIconButton->set_sensitive(true); + mxListButton->set_sensitive(true); + mxIconButton->set_active(bIconMode); + mxListButton->set_active(!bIconMode); +} + +void GalleryBrowser2::SetMode( GalleryBrowserMode eMode ) +{ + if( GetMode() != eMode ) + { + 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 ) + { + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos ); + + if( nItemId ) + { + 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 ) + { + ImplSelectItemId( nNewItemId ); + ImplUpdateInfoBar(); + + if( GALLERYBROWSERMODE_PREVIEW == GetMode() ) + { + 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(); + + OUString sCreateOnDemand; + 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), sCreateOnDemand); // 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); + } + } + + if (!aBitmapEx.IsEmpty()) + { + const Size aBitmapExSizePixel(aBitmapEx.GetSizePixel()); + const Point aPos( + ((maPreviewSize.Width() - aBitmapExSizePixel.Width()) >> 1), + ((maPreviewSize.Height() - aBitmapExSizePixel.Height()) >> 1)); + + mxDev->Erase(); + + if (aBitmapEx.IsTransparent()) + { + // draw checkered background + GalleryIconView::drawTransparenceBackground(*mxDev, aPos, aBitmapExSizePixel); + } + + mxDev->DrawBitmapEx(aPos, aBitmapEx); + } + + mxListView->set_text(rEntry, sItemTextTitle); + mxListView->set_image(rEntry, *mxDev); + 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())) + 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( SVXGALLERYITEM_PARAMS ); + + aSeq[0].Name = SVXGALLERYITEM_TYPE; + aSeq[0].Value <<= nType; + aSeq[1].Name = SVXGALLERYITEM_URL; + aSeq[1].Value <<= OUString(); + aSeq[2].Name = SVXGALLERYITEM_FILTER; + aSeq[2].Value <<= aFilterName; + aSeq[3].Name = SVXGALLERYITEM_DRAWING; + aSeq[3].Value <<= xDrawing; + aSeq[4].Name = SVXGALLERYITEM_GRAPHIC; + aSeq[4].Value <<= xGraphic; + + css::uno::Sequence< css::beans::PropertyValue > aArgs( 1 ); + aArgs[0].Name = SVXGALLERYITEM_ARGNAME; + aArgs[0].Value <<= 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(const OString &rIdent) +{ + Point aSelPos; + const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos ); + + if( mpCurTheme && nItemId ) + { + mnCurActionPos = nItemId - 1; + + if (rIdent == "preview") + SetMode( ( GALLERYBROWSERMODE_PREVIEW != GetMode() ) ? GALLERYBROWSERMODE_PREVIEW : meLastMode ); + else if (rIdent == "delete") + { + if (!mpCurTheme->IsReadOnly()) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetViewWindow(), "svx/ui/querydeleteobjectdialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryDeleteObjectDialog")); + if (xQuery->run() == RET_YES) + { + mpCurTheme->RemoveObject( mnCurActionPos ); + } + } + } + else if (rIdent == "title") + { + std::unique_ptr<SgaObject> pObj = mpCurTheme->AcquireObject( mnCurActionPos ); + + if( pObj ) + { + const OUString aOldTitle( GetItemText( *pObj, GalleryItemFlags::Title ) ); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractTitleDialog> aDlg(pFact->CreateTitleDialog(GetViewWindow(), aOldTitle)); + if( aDlg->Execute() == RET_OK ) + { + OUString aNewTitle( aDlg->GetTitle() ); + + if( ( aNewTitle.isEmpty() && !pObj->GetTitle().isEmpty() ) || ( aNewTitle != aOldTitle ) ) + { + if( aNewTitle.isEmpty() ) + aNewTitle = "__<empty>__"; + + pObj->SetTitle( aNewTitle ); + mpCurTheme->InsertObject( *pObj ); + } + } + } + } + else if (rIdent == "copy") + { + mpCurTheme->CopyToClipboard(mnCurActionPos); + } + else if (rIdent == "paste") + { + if( !mpCurTheme->IsReadOnly() ) + { + TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromClipboard(GetSystemClipboard())); + 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::ToggleButton&, rBox, void) +{ + if (&rBox == mxIconButton.get()) + SetMode(rBox.get_active() ? GALLERYBROWSERMODE_ICON : GALLERYBROWSERMODE_LIST); + else if (&rBox == mxListButton.get()) + SetMode(rBox.get_active() ? GALLERYBROWSERMODE_LIST : GALLERYBROWSERMODE_ICON); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/galctrl.cxx b/svx/source/gallery2/galctrl.cxx new file mode 100644 index 000000000..47ef17577 --- /dev/null +++ b/svx/source/gallery2/galctrl.cxx @@ -0,0 +1,407 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> + +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/sfxsids.hrc> +#include <avmedia/mediaplayer.hxx> +#include <helpids.h> +#include <galbrws2.hxx> +#include <svx/galtheme.hxx> +#include <svx/galmisc.hxx> +#include <svx/galctrl.hxx> +#include <galobj.hxx> +#include <avmedia/mediawindow.hxx> +#include <vcl/event.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/graphicfilter.hxx> +#include <bitmaps.hlst> + +GalleryPreview::GalleryPreview(GalleryBrowser2* pParent, std::unique_ptr<weld::ScrolledWindow> xScrolledWindow) + : mxScrolledWindow(std::move(xScrolledWindow)) + , mpParent(pParent) + , mpTheme(nullptr) +{ +} + +void GalleryPreview::Show() +{ + mxScrolledWindow->show(); + weld::CustomWidgetController::Show(); +} + +void GalleryPreview::Hide() +{ + weld::CustomWidgetController::Hide(); + mxScrolledWindow->hide(); +} + +GalleryPreview::~GalleryPreview() +{ +} + +void GalleryPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + CustomWidgetController::SetDrawingArea(pDrawingArea); + Size aSize = pDrawingArea->get_ref_device().LogicToPixel(Size(70, 88), MapMode(MapUnit::MapAppFont)); + pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); + SetOutputSizePixel(aSize); + + pDrawingArea->set_help_id(HID_GALLERY_WINDOW); + + mxDragDropTargetHelper.reset(new GalleryDragDrop(mpParent, pDrawingArea->get_drop_target())); +} + +namespace +{ + bool ImplGetGraphicCenterRect(const weld::CustomWidgetController& rWidget, const Graphic& rGraphic, tools::Rectangle& rResultRect) + { + const Size aWinSize(rWidget.GetOutputSizePixel()); + Size aNewSize(rWidget.GetDrawingArea()->get_ref_device().LogicToPixel(rGraphic.GetPrefSize(), rGraphic.GetPrefMapMode())); + bool bRet = false; + + if( aNewSize.Width() && aNewSize.Height() ) + { + // scale to fit window + const double fGrfWH = static_cast<double>(aNewSize.Width()) / aNewSize.Height(); + const double fWinWH = static_cast<double>(aWinSize.Width()) / aWinSize.Height(); + + if ( fGrfWH < fWinWH ) + { + aNewSize.setWidth( static_cast<long>( aWinSize.Height() * fGrfWH ) ); + aNewSize.setHeight( aWinSize.Height() ); + } + else + { + aNewSize.setWidth( aWinSize.Width() ); + aNewSize.setHeight( static_cast<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) + { + ::avmedia::MediaFloater* pFloater = avmedia::getMediaFloater(); + + if (!pFloater) + { + SfxViewFrame::Current()->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.IsTransparent()) + { + // draw checkered background for full rectangle. + GalleryIconView::drawTransparenceBackground(*pDev, rRect.TopLeft(), rRect.GetSize()); + } + + pDev->DrawBitmapEx(aPos, aBitmapEx); + } + + SetItemText(nId, aItemTextTitle); +} + +bool GalleryIconView::MouseButtonDown(const MouseEvent& rMEvt) +{ + bool bRet = ValueSet::MouseButtonDown(rMEvt); + + if (rMEvt.GetClicks() == 2) + mpParent->TogglePreview(); + + return bRet; +} + +bool GalleryIconView::Command(const CommandEvent& rCEvt) +{ + bool bRet = ValueSet::Command(rCEvt); + + if (rCEvt.GetCommand() == CommandEventId::ContextMenu) + { + mpParent->ShowContextMenu(rCEvt); + } + + return bRet; +} + +bool GalleryIconView::KeyInput(const KeyEvent& rKEvt) +{ + if (!mpTheme || !mpParent->KeyInput(rKEvt)) + return ValueSet::KeyInput(rKEvt); + return true; +} + +bool GalleryIconView::StartDrag() +{ + Select(); + return mpParent->StartDrag(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/galexpl.cxx b/svx/source/gallery2/galexpl.cxx new file mode 100644 index 000000000..b2d34749b --- /dev/null +++ b/svx/source/gallery2/galexpl.cxx @@ -0,0 +1,296 @@ +/* -*- 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 <rtl/instance.hxx> +#include <svx/gallery1.hxx> +#include <svx/galtheme.hxx> +#include <svx/gallery.hxx> +#include <galobj.hxx> + +namespace +{ + class theLockListener : public rtl::Static< SfxListener, theLockListener > {}; +} + + +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( const OUString& 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( const OUString& rThemeName, const OUString& 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, const OUString& rURL ) +{ + Gallery* pGal = ::Gallery::GetGalleryInstance(); + return pGal && InsertURL( pGal->GetThemeName( nThemeId ), rURL ); +} + +bool GalleryExplorer::GetGraphicObj( const OUString& 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( const OUString& 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( const OUString& 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( const OUString& rThemeName ) +{ + Gallery* pGal = ::Gallery::GetGalleryInstance(); + bool bRet = false; + + if( pGal ) + { + GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, theLockListener::get() ); + + 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( const OUString& 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::get() ); + bRet = true; + } + } + } + + return bRet; +} + +bool GalleryExplorer::EndLocking( sal_uInt32 nThemeId ) +{ + Gallery* pGal = ::Gallery::GetGalleryInstance(); + return pGal && EndLocking( pGal->GetThemeName( nThemeId ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/galini.cxx b/svx/source/gallery2/galini.cxx new file mode 100644 index 000000000..55c19161b --- /dev/null +++ b/svx/source/gallery2/galini.cxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * The world's quickest and lamest .desktop / .ini file parser. + * Ideally the .thm file would move to a .desktop file in + * future. + */ + +#include <sal/config.h> +#include <sal/log.hxx> + +#include <unotools/ucbstreamhelper.hxx> +#include <svx/gallery1.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <memory> + +OUString GalleryThemeEntry::ReadStrFromIni(const OUString &aKeyName ) +{ + 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( + aLine.copy( 0, n ).trim(), RTL_TEXTENCODING_ASCII_US ); + aValue = OStringToOUString( + aLine.copy( n + 1 ).trim(), RTL_TEXTENCODING_UTF8 ); + + if( ( n = aKey.indexOf( '[' ) ) >= 1 ) + { + aLocale = aKey.copy( n + 1 ).trim(); + aKey = aKey.copy( 0, n ).trim(); + if( (n = aLocale.indexOf( ']' ) ) >= 1 ) + aLocale = aLocale.copy( 0, n ).trim(); + } + } + SAL_INFO("svx", "ini file has '" << aKey << "' [ '" << aLocale << "' ] = '" << aValue << "'"); + + // grisly language matching, is this not available somewhere else? + if( aKey == aKeyName ) + { + /* FIXME-BCP47: what is this supposed to do? */ + n = 0; + OUString aLang = aLocale.replace('_','-'); + for( const auto& rFallback : aFallbacks ) + { + SAL_INFO( "svx", "compare '" << aLang << "' with '" << rFallback << "' rank " << nRank << " vs. " << n ); + if( rFallback == aLang && n < nRank ) { + nRank = n; // try to get the most accurate match + aResult = aValue; + } + ++n; + } + } + } + } + + SAL_INFO( "svx", "readStrFromIni returns '" << aResult << "'"); + return aResult; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/gallery1.cxx b/svx/source/gallery2/gallery1.cxx new file mode 100644 index 000000000..685f3d99d --- /dev/null +++ b/svx/source/gallery2/gallery1.cxx @@ -0,0 +1,769 @@ +/* -*- 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 <unotools/configmgr.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/pathoptions.hxx> +#include <svx/dialmgr.hxx> +#include <svx/gallery.hxx> +#include <svx/strings.hrc> +#include <strings.hxx> +#include <svx/galmisc.hxx> +#include <svx/galtheme.hxx> +#include <svx/gallery1.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; + + +static bool FileExists( const INetURLObject &rURL, const OUString &rExt ) +{ + INetURLObject aURL( rURL ); + aURL.setExtension( rExt ); + return FileExists( aURL ); +} + +const std::pair<sal_uInt16, const char*> 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, const char*> 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) + { + INetURLObject aBaseNoCase( ImplGetURLIgnoreCase( rBaseURL ) ); + aURL = aBaseNoCase; + static sal_Int32 nIdx = 0; + while( FileExists( aURL, "thm" ) ) + { // create new URLs + nIdx++; + aURL = aBaseNoCase; + aURL.setName( aURL.getName() + OUString::number(nIdx)); + } + } + + aURL.setExtension( "thm" ); + aThmURL = ImplGetURLIgnoreCase( aURL ); + + aURL.setExtension( "sdg" ); + aSdgURL = ImplGetURLIgnoreCase( aURL ); + + aURL.setExtension( "sdv" ); + aSdvURL = ImplGetURLIgnoreCase( aURL ); + + aURL.setExtension( "str" ); + aStrURL = ImplGetURLIgnoreCase( aURL ); + + SetModified( _bNewFile ); + + aName = ReadStrFromIni( "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 = OUString::createFromAscii(aUnlocalized[i].second); + break; + } + } + //look up the rest of the ids in string resources + if (aName.isEmpty()) + { + for (size_t i = 0; i < SAL_N_ELEMENTS(aLocalized); ++i) + { + if (aLocalized[i].first == nId) + { + aName = SvxResId(aLocalized[i].second); + break; + } + } + } + } + + if( aName.isEmpty() ) + aName = rName; +} + +void GalleryTheme::InsertAllThemes(weld::ComboBox& rListBox) +{ + for (size_t i = 0; i < SAL_N_ELEMENTS(aUnlocalized); ++i) + rListBox.append_text(OUString::createFromAscii(aUnlocalized[i].second)); + + for (size_t i = 0; i < SAL_N_ELEMENTS(aLocalized); ++i) + rListBox.append_text(SvxResId(aLocalized[i].second)); +} + +INetURLObject GalleryThemeEntry::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 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 ); +} + + +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( const OUString& 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( const OUString& rMultiPath ) +{ + bool bIsReadOnlyDir {false}; + + bMultiPath = !rMultiPath.isEmpty(); + + INetURLObject aCurURL(SvtPathOptions().GetConfigPath()); + ImplLoadSubDirs( aCurURL, bIsReadOnlyDir ); + + if( !bIsReadOnlyDir ) + aUserURL = aCurURL; + + if( bMultiPath ) + { + bool bIsRelURL {true}; + sal_Int32 nIdx {0}; + do + { + aCurURL = INetURLObject(rMultiPath.getToken(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( OUString( appBundle, strlen( appBundle ), RTL_TEXTENCODING_UTF8 ) + "/" ) ) + rbDirIsReadOnly = true; + } +#else + try + { + // check readonlyness the very hard way + INetURLObject aTestURL( rBaseURL ); + + aTestURL.Append( "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 const char s_sTitle[] = "Title"; + static const char s_sIsReadOnly[] = "IsReadOnly"; + + while( xResultSet->next() ) + { + INetURLObject aThmURL( xContentAccess->queryContentIdentifierString() ); + + if (aThmURL.GetFileExtension().equalsIgnoreAsciiCase("thm")) + { + INetURLObject aSdgURL( aThmURL); aSdgURL.SetExtension( "sdg" ); + INetURLObject aSdvURL( aThmURL ); aSdvURL.SetExtension( "sdv" ); + OUString aTitle; + + 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() ); + + 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 = GalleryTheme::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( const OUString& rThemeName ) +{ + if( !rThemeName.isEmpty() ) + { + 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( const OUString& 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 new GalleryTheme( this, pNewEntry ); + 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() ) + { + SfxListener aListener; + GalleryTheme* pThm = AcquireTheme( rOldName, aListener ); + + if( pThm ) + { + pThemeEntry->SetName( rNewName ); + pThm->ImplWrite(); + + 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 ) + { + INetURLObject aThmURL( pThm->GetThmURL() ); + INetURLObject aSdgURL( pThm->GetSdgURL() ); + INetURLObject aSdvURL( pThm->GetSdvURL() ); + INetURLObject aStrURL( pThm->GetStrURL() ); + + ReleaseTheme( pThm, aListener ); + + KillFile( aThmURL ); + KillFile( aSdgURL ); + KillFile( aSdvURL ); + KillFile( aStrURL ); + } + + 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; +} + +GalleryTheme* Gallery::ImplGetCachedTheme(const 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 ) + { + INetURLObject aURL = pThemeEntry->GetThmURL(); + + DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" ); + + std::unique_ptr<GalleryTheme> pNewTheme; + if( FileExists( aURL ) ) + { + std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ )); + + if( pIStm ) + { + try + { + pNewTheme.reset( new GalleryTheme( this, const_cast<GalleryThemeEntry*>(pThemeEntry) ) ); + ReadGalleryTheme( *pIStm, *pNewTheme ); + + if( pIStm->GetError() ) + pNewTheme.reset(); + } + catch (const css::ucb::ContentCreationException&) + { + } + } + } + + 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( const OUString& rThemeName, SfxListener& rListener ) +{ + GalleryTheme* pTheme = nullptr; + GalleryThemeEntry* pThemeEntry = ImplGetThemeEntry( rThemeName ); + + if( pThemeEntry ) + { + pTheme = ImplGetCachedTheme( pThemeEntry ); + if (pTheme) + rListener.StartListening(*pTheme, DuplicateHandling::Prevent); + } + return pTheme; +} + +void Gallery::ReleaseTheme( GalleryTheme* pTheme, SfxListener& rListener ) +{ + if( pTheme ) + { + rListener.EndListening( *pTheme ); + + if( !pTheme->HasListeners() ) + ImplDeleteCachedTheme( pTheme ); + } +} + +bool GalleryThemeEntry::IsDefault() const +{ + return nId > 0 && nId != GALLERY_THEME_MYTHEME; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/gallerydrawmodel.hxx b/svx/source/gallery2/gallerydrawmodel.hxx new file mode 100644 index 000000000..0b2ef2582 --- /dev/null +++ b/svx/source/gallery2/gallerydrawmodel.hxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sfx2/objsh.hxx> + +class FmFormModel; + +class SvxGalleryDrawModel +{ +public: + SvxGalleryDrawModel(); + ~SvxGalleryDrawModel(); + + FmFormModel* GetModel() const { return mpFormModel; } + +private: + SfxObjectShellLock mxDoc; + FmFormModel* mpFormModel; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/galmisc.cxx b/svx/source/gallery2/galmisc.cxx new file mode 100644 index 000000000..b51cdb1af --- /dev/null +++ b/svx/source/gallery2/galmisc.cxx @@ -0,0 +1,553 @@ +/* -*- 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 <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 ) +{ + bool bRet = false; + + if ( rModel.GetPageCount() ) + { + const SdrPage* pPage = rModel.GetPage( 0 ); + const SdrObject* pObj = pPage->GetObj( 0 ); + + if ( pPage->GetObjCount() == 1 && dynamic_cast<const SdrGrafObj*>( pObj) != nullptr ) + { + 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 = static_cast<const SdrGrafObj*>( pObj )->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 = aPath.copy(0, nPathPrefixLen) + "..." + + OUStringChar(aDelimiter) + aName; + } + else + { + aReduced += "..." + OUStringChar(aDelimiter) + "..." + + aName.copy( 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( 1 ); + uno::Sequence< uno::Any > aValues( 1 ); + + aProps[0] = "Title"; + aValues[0] <<= 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::makeAny( 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::makeAny( 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() ) + { + mxProgressBar = xMonitor; + + OUString aProgressText; + + if( pFilter ) + { + aProgressText = SvxResId(RID_SVXSTR_GALLERY_FILTER); +// pFilter->SetUpdatePercentHdl( LINK( this, GalleryProgress, Update ) ); // sj: progress wasn't working up from SO7 at all +// // so I am removing this. The gallery progress should +// // be changed to use the XStatusIndicator instead of XProgressMonitor + } + else + aProgressText = "Gallery"; + + xMonitor->addText( "Gallery", aProgressText, false ) ; + mxProgressBar->setRange( 0, GALLERY_PROGRESS_RANGE ); + } +} + +GalleryProgress::~GalleryProgress() +{ +} + +void GalleryProgress::Update( sal_Int32 nVal, sal_Int32 nMaxVal ) +{ + if( mxProgressBar.is() && nMaxVal ) + mxProgressBar->setValue( std::min<sal_Int32>( static_cast<double>(nVal) / nMaxVal * GALLERY_PROGRESS_RANGE, + GALLERY_PROGRESS_RANGE ) ); +} + + +GalleryTransferable::GalleryTransferable( GalleryTheme* pTheme, sal_uInt32 nObjectPos, bool bLazy ) : + mpTheme( pTheme ), + meObjectKind( pTheme ? mpTheme->GetObjectKind(nObjectPos) : SgaObjKind::NONE), + mnObjectPos( nObjectPos ) +{ + + InitData( bLazy ); +} + +void GalleryTransferable::SelectObject(sal_uInt32 nObjectPos) +{ + if (nObjectPos == mnObjectPos) + return; + ClearFormats(); + mnObjectPos = nObjectPos; + meObjectKind = mpTheme ? mpTheme->GetObjectKind(mnObjectPos) : SgaObjKind::NONE; + ObjectReleased(); + InitData(true); +} + +GalleryTransferable::~GalleryTransferable() +{ +} + +void GalleryTransferable::InitData( bool bLazy ) +{ + switch( meObjectKind ) + { + case SgaObjKind::SvDraw: + { + if( !bLazy ) + { + if( !mpGraphicObject ) + { + Graphic aGraphic; + + if (mpTheme && mpTheme->GetGraphic(mnObjectPos, aGraphic)) + mpGraphicObject.reset(new GraphicObject( aGraphic )); + } + + if( !mxModelStream.is() ) + { + mxModelStream = new SotStorageStream( "" ); + mxModelStream->SetBufferSize( 16348 ); + + if (!mpTheme || !mpTheme->GetModelStream(mnObjectPos, mxModelStream)) + mxModelStream.clear(); + else + mxModelStream->Seek( 0 ); + } + } + } + break; + + case SgaObjKind::Animation: + case SgaObjKind::Bitmap: + case SgaObjKind::Inet: + case SgaObjKind::Sound: + { + if( !mpURL ) + { + mpURL.reset(new INetURLObject); + + if (!mpTheme || !mpTheme->GetURL(mnObjectPos, *mpURL)) + { + mpURL.reset(); + } + } + + if( ( SgaObjKind::Sound != meObjectKind ) && !mpGraphicObject ) + { + Graphic aGraphic; + + if (mpTheme && mpTheme->GetGraphic(mnObjectPos, aGraphic)) + mpGraphicObject.reset(new GraphicObject( aGraphic )); + } + } + break; + + default: + OSL_FAIL( "GalleryTransferable::GalleryTransferable: invalid object type" ); + break; + } +} + +void GalleryTransferable::AddSupportedFormats() +{ + if( SgaObjKind::SvDraw == meObjectKind ) + { + AddFormat( SotClipboardFormatId::DRAWING ); + AddFormat( SotClipboardFormatId::SVXB ); + AddFormat( SotClipboardFormatId::GDIMETAFILE ); + AddFormat( SotClipboardFormatId::BITMAP ); + } + else + { + if( mpURL ) + AddFormat( SotClipboardFormatId::SIMPLE_FILE ); + + if( mpGraphicObject ) + { + AddFormat( SotClipboardFormatId::SVXB ); + + if( mpGraphicObject->GetType() == GraphicType::GdiMetafile ) + { + AddFormat( SotClipboardFormatId::GDIMETAFILE ); + AddFormat( SotClipboardFormatId::BITMAP ); + } + else + { + AddFormat( SotClipboardFormatId::BITMAP ); + AddFormat( SotClipboardFormatId::GDIMETAFILE ); + } + } + } +} + +bool GalleryTransferable::GetData( const datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ ) +{ + SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor ); + bool bRet = false; + + InitData( false ); + + if( ( SotClipboardFormatId::DRAWING == nFormat ) && ( SgaObjKind::SvDraw == meObjectKind ) ) + { + bRet = ( mxModelStream.is() && SetObject( mxModelStream.get(), 0, rFlavor ) ); + } + else if( ( SotClipboardFormatId::SIMPLE_FILE == nFormat ) && mpURL ) + { + bRet = SetString( mpURL->GetMainURL( INetURLObject::DecodeMechanism::NONE ), rFlavor ); + } + 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<SotStorageStream>& 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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/galobj.cxx b/svx/source/gallery2/galobj.cxx new file mode 100644 index 000000000..5d97eb9f2 --- /dev/null +++ b/svx/source/gallery2/galobj.cxx @@ -0,0 +1,481 @@ +/* -*- 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 <com/sun/star/lang/XUnoTunnel.hpp> +#include <sfx2/objsh.hxx> +#include <comphelper/fileformat.h> +#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 "gallerydrawmodel.hxx" +#include <bitmaps.hlst> + +using namespace ::com::sun::star; + +SgaObject::SgaObject() +: bIsValid ( false ), + bIsThumbBmp ( true ) +{ +} + +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( static_cast<long>(fFactor < 1. ? S_THUMB * fFactor : S_THUMB), 8L ), + std::max( static_cast<long>(fFactor < 1. ? S_THUMB : S_THUMB / fFactor), 8L ) ); + 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 + WriteGDIMetaFile( rOut, 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 + { + ReadGDIMetaFile( rIn, 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, OString()); //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 ), 1 ); + 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 ) +{ + + const OUString sFactoryURL("sdraw"); + + mxDoc = SfxObjectShell::CreateObjectByFactoryName( sFactoryURL ); + + if( mxDoc.Is() ) + { + mxDoc->DoInitNew(); + + uno::Reference< lang::XUnoTunnel > xTunnel( mxDoc->GetModel(), uno::UNO_QUERY ); + if( xTunnel.is() ) + { + mpFormModel = dynamic_cast< FmFormModel* >( + reinterpret_cast<SdrModel*>(xTunnel->getSomething(SdrModel::getUnoTunnelId()))); + if( mpFormModel ) + { + mpFormModel->InsertPage( mpFormModel->AllocPage( false ) ); + } + } + } +} + +SvxGalleryDrawModel::~SvxGalleryDrawModel() +{ + if( mxDoc.Is() ) + mxDoc->DoClose(); + +} + +SgaObjectSvDraw::SgaObjectSvDraw( SvStream& rIStm, const INetURLObject& rURL ) +{ + SvxGalleryDrawModel aModel; + + if( aModel.GetModel() ) + { + if( GallerySvDrawImport( rIStm, *aModel.GetModel() ) ) + { + aURL = rURL; + bIsValid = CreateThumb( *aModel.GetModel() ); + } + } +} + +bool SgaObjectSvDraw::CreateThumb( const FmFormModel& rModel ) +{ + Graphic aGraphic; + ImageMap aImageMap; + bool bRet = false; + + if ( CreateIMapGraphic( rModel, aGraphic, aImageMap ) ) + { + bRet = SgaObject::CreateThumb( aGraphic ); + } + else + { + const FmFormPage* pPage = static_cast< const FmFormPage* >(rModel.GetPage(0)); + + if(pPage) + { + const tools::Rectangle aObjRect(pPage->GetAllObjBoundRect()); + + if(aObjRect.GetWidth() && aObjRect.GetHeight()) + { + ScopedVclPtrInstance< VirtualDevice > pVDev; + FmFormView aView(const_cast< FmFormModel& >(rModel), pVDev); + + aView.ShowSdrPage(const_cast< FmFormPage* >(pPage)); + aView.MarkAllObj(); + aThumbBmp = aView.GetMarkedObjBitmapEx(true); + aGraphic = Graphic(aThumbBmp); + bRet = SgaObject::CreateThumb(aGraphic); + } + } + } + + return bRet; +} + +void SgaObjectSvDraw::WriteData( SvStream& rOut, const OUString& rDestDir ) const +{ + SgaObject::WriteData( rOut, rDestDir ); + write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8); +} + +void SgaObjectSvDraw::ReadData( SvStream& rIn, sal_uInt16& rReadVersion ) +{ + SgaObject::ReadData( rIn, rReadVersion ); + + if( rReadVersion >= 5 ) + aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/gallery2/galtheme.cxx b/svx/source/gallery2/galtheme.cxx new file mode 100644 index 000000000..a5b60f572 --- /dev/null +++ b/svx/source/gallery2/galtheme.cxx @@ -0,0 +1,1468 @@ +/* -*- 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 <sal/log.hxx> + +#include <algorithm> + +#include <comphelper/fileformat.h> +#include <comphelper/processfactory.hxx> +#include <osl/file.hxx> +#include <osl/thread.hxx> +#include <tools/diagnose_ex.h> +#include <tools/urlobj.hxx> +#include <tools/vcompat.hxx> +#include <unotools/streamwrap.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/tempfile.hxx> +#include <ucbhelper/content.hxx> +#include <com/sun/star/ucb/ContentCreationException.hpp> +#include <sot/storage.hxx> +#include <sot/formats.hxx> +#include <sot/filelist.hxx> +#include <vcl/virdev.hxx> +#include <vcl/cvtgrf.hxx> +#include <avmedia/mediawindow.hxx> +#include <svx/svdograf.hxx> +#include "codec.hxx" +#include <svx/unomodel.hxx> +#include <svx/fmmodel.hxx> +#include <svx/fmview.hxx> +#include <svx/galmisc.hxx> +#include <svx/galtheme.hxx> +#include <svx/svdpage.hxx> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <galobj.hxx> +#include <svx/gallery1.hxx> +#include "gallerydrawmodel.hxx" +#include <memory> + +using namespace ::com::sun::star; + + +GalleryTheme::GalleryTheme( Gallery* pGallery, GalleryThemeEntry* pThemeEntry ) + : m_bDestDirRelative(false) + , pParent(pGallery) + , pThm(pThemeEntry) + , mnThemeLockCount(0) + , mnBroadcasterLockCount(0) + , nDragPos(0) + , bDragging(false) + , bAbortActualize(false) +{ + ImplCreateSvDrawStorage(); +} + +GalleryTheme::~GalleryTheme() +{ + ImplWrite(); + + for (auto & pEntry : aObjectList) + { + Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), pEntry.get() ) ); + pEntry.reset(); + } + aObjectList.clear(); + +} + +void GalleryTheme::ImplCreateSvDrawStorage() +{ + try + { + aSvDrawStorageRef = new SotStorage( false, GetSdvURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ), pThm->IsReadOnly() ? StreamMode::READ : StreamMode::STD_READWRITE ); + // #i50423# ReadOnly may not been set though the file can't be written (because of security reasons) + if ( ( aSvDrawStorageRef->GetError() != ERRCODE_NONE ) && !pThm->IsReadOnly() ) + 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"); + } +} + +bool GalleryTheme::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 < aObjectList.size() ) + { + aObjectList.emplace( aObjectList.begin() + nPos, pEntry ); + } + else + aObjectList.emplace_back( pEntry ); + } + else + pEntry = pExistentEntry; + + pEntry->aURL = rObj.GetURL(); + pEntry->nOffset = nOffset; + pEntry->eObjKind = rObj.GetObjKind(); + bRet = true; + } + } + + return bRet; +} + +std::unique_ptr<SgaObject> GalleryTheme::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->aURL ); + } + } + } + } + + return pSgaObj; +} + +void GalleryTheme::ImplWrite() +{ + if( pThm->IsModified() ) + { + 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, *this ); + pOStm.reset(); + } + + ImplSetModified( false ); + } + } +} + +const GalleryObject* GalleryTheme::ImplGetGalleryObject( const INetURLObject& rURL ) +{ + for (auto const & i : aObjectList) + if ( i->aURL == rURL ) + return i.get(); + return nullptr; +} + +INetURLObject GalleryTheme::ImplGetURL( const GalleryObject* pObject ) +{ + INetURLObject aURL; + + if( pObject ) + aURL = pObject->aURL; + + return aURL; +} + +INetURLObject GalleryTheme::ImplCreateUniqueURL( SgaObjKind eObjKind, ConvertDataFormat nFormat ) +{ + INetURLObject aDir( GetParent()->GetUserURL() ); + INetURLObject aInfoFileURL( GetParent()->GetUserURL() ); + INetURLObject aNewURL; + sal_uInt32 nNextNumber = 1999; + char const* pExt = nullptr; + bool bExists; + + aDir.Append( "dragdrop" ); + CreateDir( aDir ); + + aInfoFileURL.Append( "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 ); + } + } + + // create extension + if( nFormat != ConvertDataFormat::Unknown ) + { + switch( nFormat ) + { + case ConvertDataFormat::BMP: pExt = ".bmp"; break; + case ConvertDataFormat::GIF: pExt = ".gif"; break; + case ConvertDataFormat::JPG: pExt = ".jpg"; break; + case ConvertDataFormat::MET: pExt = ".met"; break; + case ConvertDataFormat::PCT: pExt = ".pct"; break; + case ConvertDataFormat::PNG: pExt = ".png"; break; + case ConvertDataFormat::SVM: pExt = ".svm"; break; + case ConvertDataFormat::TIF: pExt = ".tif"; break; + case ConvertDataFormat::WMF: pExt = ".wmf"; break; + case ConvertDataFormat::EMF: pExt = ".emf"; break; + + default: + pExt = ".grf"; + break; + } + } + + 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 & p : aObjectList) + if ( p->aURL == 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; +} + +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 = aObjectList.size(); iFoundPos < n; ++iFoundPos) + { + if (aObjectList[ iFoundPos ]->aURL == rObj.GetURL()) + { + pFoundEntry = aObjectList[ iFoundPos ].get(); + break; + } + } + + 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); + + ImplSetModified(true); + ImplBroadcast(pFoundEntry? iFoundPos: nInsertPos); + + return true; +} + +std::unique_ptr<SgaObject> GalleryTheme::AcquireObject(sal_uInt32 nPos) +{ + return ImplReadSgaObject(ImplGetGalleryObject(nPos)); +} + +void GalleryTheme::GetPreviewBitmapExAndStrings(sal_uInt32 nPos, BitmapEx& rBitmapEx, Size& rSize, OUString& rTitle, OUString& rPath) const +{ + const GalleryObject* pGalleryObject = aObjectList[ 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 = aObjectList[ nPos ].get(); + + pGalleryObject->maPreviewBitmapEx = rBitmapEx; + pGalleryObject->maPreparedSize = rSize; + pGalleryObject->maTitle = rTitle; + pGalleryObject->maPath = rPath; +} + +void GalleryTheme::RemoveObject(sal_uInt32 nPos) +{ + auto it = aObjectList.begin() + nPos; + std::unique_ptr<GalleryObject> pEntry = std::move(*it); + aObjectList.erase( it ); + + if( aObjectList.empty() ) + KillFile( GetSdgURL() ); + + if( SgaObjKind::SvDraw == pEntry->eObjKind ) + aSvDrawStorageRef->Remove( pEntry->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + + 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 >= aObjectList.size()) + return false; + + std::unique_ptr<GalleryObject> pEntry = std::move(aObjectList[nOldPos]); + + aObjectList.insert(aObjectList.begin() + nNewPos, std::move(pEntry)); + + if (nNewPos < nOldPos) + nOldPos++; + + auto it = aObjectList.begin() + nOldPos; + aObjectList.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 = aObjectList.size(); + + LockBroadcaster(); + bAbortActualize = false; + + // reset delete flag + for (sal_uInt32 i = 0; i < nCount; i++) + aObjectList[ i ]->mbDelete = false; + + for (sal_uInt32 i = 0; ( i < nCount ) && !bAbortActualize; i++) + { + if( pProgress ) + pProgress->Update( i, nCount - 1 ); + + GalleryObject* pEntry = aObjectList[ i ].get(); + + const INetURLObject aURL( pEntry->aURL ); + + 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 + { + if ( aSvDrawStorageRef.is() ) + { + const OUString aStmName( GetSvDrawStreamNameFromURL( pEntry->aURL ) ); + tools::SvRef<SotStorageStream> pIStm = aSvDrawStorageRef->OpenSotStream( aStmName, StreamMode::READ ); + + if( pIStm.is() && !pIStm->GetError() ) + { + pIStm->SetBufferSize( 16384 ); + + SgaObjectSvDraw aNewObj( *pIStm, pEntry->aURL ); + + if( !InsertObject( aNewObj ) ) + pEntry->mbDelete = true; + + pIStm->SetBufferSize( 0 ); + } + } + } + } + + // remove all entries with set flag + for ( auto it = aObjectList.begin(); it != aObjectList.end(); /* increment is in the body of loop */) + { + if( (*it)->mbDelete ) + { + Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), it->get() ) ); + it = aObjectList.erase( it ); + } + else + ++it; + } + + // update theme + ::utl::TempFile aTmp; + INetURLObject aInURL( GetSdgURL() ); + INetURLObject aTmpURL( aTmp.GetURL() ); + + DBG_ASSERT( aInURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" ); + DBG_ASSERT( aTmpURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" ); + + std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream( aInURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ )); + std::unique_ptr<SvStream> pTmpStm(::utl::UcbStreamHelper::CreateStream( aTmpURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::TRUNC )); + + if( pIStm && pTmpStm ) + { + for (const auto & i : aObjectList) + { + 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 ) ); + aSvDrawStorageRef->CopyTo( aTempStorageRef.get() ); + nStorErr = aSvDrawStorageRef->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 ) + { + aSvDrawStorageRef.clear(); + CopyFile( aTmpURL, GetSdvURL() ); + ImplCreateSvDrawStorage(); + } + + KillFile( aTmpURL ); + ImplSetModified( true ); + ImplWrite(); + UnlockBroadcaster(); +} + +GalleryThemeEntry* GalleryTheme::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 ) + { + OUString aThemeName; + sal_uInt16 nVersion; + + pIStm->ReadUInt16( nVersion ); + + if( nVersion <= 0x00ff ) + { + bool bThemeNameFromResource = false; + sal_uInt32 nThemeId = 0; + + OString aTmpStr = read_uInt16_lenPrefixed_uInt8s_ToOString(*pIStm); + 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' ) ) + { + VersionCompat aCompat( *pIStm, StreamMode::READ ); + + pIStm->ReadUInt32( nThemeId ); + + if( aCompat.GetVersion() >= 2 ) + { + pIStm->ReadCharAsBool( bThemeNameFromResource ); + } + } + } + } + + pRet = new GalleryThemeEntry( false, rURL, aThemeName, + bReadOnly, false, nThemeId, + bThemeNameFromResource ); + } + } + } + + return pRet; +} + +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 = ImplGetGalleryObject( 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; + default: + break; + } + } + else + { + if( rGraphic.GetType() == GraphicType::Bitmap ) + { + if( rGraphic.IsAnimated() ) + nExportFormat = ConvertDataFormat::GIF; + else + nExportFormat = ConvertDataFormat::PNG; + } + else + nExportFormat = ConvertDataFormat::SVM; + } + + const INetURLObject aURL( ImplCreateUniqueURL( SgaObjKind::Bitmap, nExportFormat ) ); + std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::TRUNC )); + + if( pOStm ) + { + pOStm->SetVersion( SOFFICE_FILEFORMAT_50 ); + + if( ConvertDataFormat::SVM == nExportFormat ) + { + GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() ); + + aMtf.Write( *pOStm ); + 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 ); + InsertObject( aObjBmp, nInsertPos ); + } + } + + return bRet; +} + +bool GalleryTheme::GetModel(sal_uInt32 nPos, SdrModel& rModel) +{ + const GalleryObject* pObject = ImplGetGalleryObject( nPos ); + bool bRet = false; + + if( pObject && ( SgaObjKind::SvDraw == pObject->eObjKind ) ) + { + const INetURLObject aURL( ImplGetURL( pObject ) ); + tools::SvRef<SotStorage> xStor( GetSvDrawStorage() ); + + if( xStor.is() ) + { + const OUString aStmName( GetSvDrawStreamNameFromURL( aURL ) ); + tools::SvRef<SotStorageStream> xIStm( xStor->OpenSotStream( aStmName, StreamMode::READ ) ); + + if( xIStm.is() && !xIStm->GetError() ) + { + xIStm->SetBufferSize( STREAMBUF_SIZE ); + bRet = GallerySvDrawImport( *xIStm, rModel ); + xIStm->SetBufferSize( 0 ); + } + } + } + + return bRet; +} + +bool GalleryTheme::InsertModel(const FmFormModel& rModel, sal_uInt32 nInsertPos) +{ + INetURLObject aURL( ImplCreateUniqueURL( SgaObjKind::SvDraw ) ); + tools::SvRef<SotStorage> xStor( GetSvDrawStorage() ); + bool bRet = false; + + if( xStor.is() ) + { + const OUString aStmName( GetSvDrawStreamNameFromURL( aURL ) ); + tools::SvRef<SotStorageStream> xOStm( xStor->OpenSotStream( aStmName, StreamMode::WRITE | StreamMode::TRUNC ) ); + + if( xOStm.is() && !xOStm->GetError() ) + { + SvMemoryStream aMemStm( 65535, 65535 ); + FmFormModel* pFormModel = const_cast<FmFormModel*>(&rModel); + + pFormModel->BurnInStyleSheetAttributes(); + + { + uno::Reference< io::XOutputStream > xDocOut( new utl::OOutputStreamWrapper( aMemStm ) ); + + if (xDocOut.is()) + (void)SvxDrawingLayerExport( pFormModel, xDocOut ); + } + + aMemStm.Seek( 0 ); + + xOStm->SetBufferSize( 16348 ); + GalleryCodec aCodec( *xOStm ); + aCodec.Write( aMemStm ); + + if( !xOStm->GetError() ) + { + SgaObjectSvDraw aObjSvDraw( rModel, aURL ); + bRet = InsertObject( aObjSvDraw, nInsertPos ); + } + + xOStm->SetBufferSize( 0 ); + xOStm->Commit(); + } + } + + return bRet; +} + +bool GalleryTheme::GetModelStream(sal_uInt32 nPos, tools::SvRef<SotStorageStream> const & rxModelStream) +{ + const GalleryObject* pObject = ImplGetGalleryObject( nPos ); + bool bRet = false; + + if( pObject && ( SgaObjKind::SvDraw == pObject->eObjKind ) ) + { + const INetURLObject aURL( ImplGetURL( pObject ) ); + tools::SvRef<SotStorage> xStor( GetSvDrawStorage() ); + + if( xStor.is() ) + { + const OUString aStmName( GetSvDrawStreamNameFromURL( aURL ) ); + tools::SvRef<SotStorageStream> xIStm( xStor->OpenSotStream( aStmName, StreamMode::READ ) ); + + if( xIStm.is() && !xIStm->GetError() ) + { + sal_uInt32 nVersion = 0; + + xIStm->SetBufferSize( 16348 ); + + if( GalleryCodec::IsCoded( *xIStm, nVersion ) ) + { + SvxGalleryDrawModel aModel; + + if( aModel.GetModel() ) + { + if( GallerySvDrawImport( *xIStm, *aModel.GetModel() ) ) + { + aModel.GetModel()->BurnInStyleSheetAttributes(); + + { + uno::Reference< io::XOutputStream > xDocOut( new utl::OOutputStreamWrapper( *rxModelStream ) ); + + if( SvxDrawingLayerExport( aModel.GetModel(), xDocOut ) ) + rxModelStream->Commit(); + } + } + + bRet = ( rxModelStream->GetError() == ERRCODE_NONE ); + } + } + + xIStm->SetBufferSize( 0 ); + } + } + } + + return bRet; +} + +bool GalleryTheme::InsertModelStream(const tools::SvRef<SotStorageStream>& rxModelStream, sal_uInt32 nInsertPos) +{ + INetURLObject aURL( ImplCreateUniqueURL( SgaObjKind::SvDraw ) ); + tools::SvRef<SotStorage> xStor( GetSvDrawStorage() ); + bool bRet = false; + + if( xStor.is() ) + { + const OUString aStmName( GetSvDrawStreamNameFromURL( aURL ) ); + tools::SvRef<SotStorageStream> xOStm( xStor->OpenSotStream( aStmName, StreamMode::WRITE | StreamMode::TRUNC ) ); + + if( xOStm.is() && !xOStm->GetError() ) + { + GalleryCodec aCodec( *xOStm ); + + xOStm->SetBufferSize( 16348 ); + aCodec.Write( *rxModelStream ); + + if( !xOStm->GetError() ) + { + xOStm->Seek( 0 ); + SgaObjectSvDraw aObjSvDraw( *xOStm, aURL ); + bRet = InsertObject( aObjSvDraw, nInsertPos ); + } + + xOStm->SetBufferSize( 0 ); + xOStm->Commit(); + } + } + + return bRet; +} + +bool GalleryTheme::GetURL(sal_uInt32 nPos, INetURLObject& rURL) +{ + const GalleryObject* pObject = ImplGetGalleryObject( 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) +{ + INetURLObject aURL; + ::std::vector< INetURLObject > aURLVector; + bool bRet = false; + + 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() ); + aURLVector.push_back( aURL ); + } + } + } + else + aURLVector.push_back( rFileOrDirURL ); + } + catch( const ucb::ContentCreationException& ) + { + } + catch( const uno::RuntimeException& ) + { + } + catch( const uno::Exception& ) + { + } + + for( const auto& rURL : aURLVector ) + bRet = bRet || InsertURL( rURL, nInsertPos ); + + return bRet; +} + +bool GalleryTheme::InsertTransferable(const uno::Reference< datatransfer::XTransferable >& rxTransferable, sal_uInt32 nInsertPos) +{ + bool bRet = false; + + if( rxTransferable.is() ) + { + TransferableDataHelper aDataHelper( rxTransferable ); + std::unique_ptr<Graphic> pGraphic; + + if( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) ) + { + tools::SvRef<SotStorageStream> xModelStm; + + if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::DRAWING, xModelStm ) ) + bRet = InsertModelStream( xModelStm, nInsertPos ); + } + else if( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) || + aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) ) + { + FileList aFileList; + + if( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) ) + aDataHelper.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList ); + else + { + OUString aFile; + if (aDataHelper.GetString(SotClipboardFormatId::SIMPLE_FILE, aFile) && !aFile.isEmpty()) + aFileList.AppendFile( aFile ); + } + + for( sal_uInt32 i = 0, nCount = aFileList.Count(); i < nCount; ++i ) + { + const OUString aFile( aFileList.GetFile( i ) ); + INetURLObject aURL( aFile ); + + if( aURL.GetProtocol() == INetProtocol::NotValid ) + { + OUString aLocalURL; + + if( osl::FileBase::getFileURLFromSystemPath( aFile, aLocalURL ) == osl::FileBase::E_None ) + aURL = INetURLObject( aLocalURL ); + } + + if( aURL.GetProtocol() != INetProtocol::NotValid ) + bRet = InsertFileOrDirURL( aURL, nInsertPos ); + } + } + else + { + Graphic aGraphic; + SotClipboardFormatId nFormat = SotClipboardFormatId::NONE; + + if( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) ) + nFormat = SotClipboardFormatId::SVXB; + else if( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) ) + nFormat = SotClipboardFormatId::GDIMETAFILE; + else if( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) ) + nFormat = SotClipboardFormatId::BITMAP; + + if( nFormat != SotClipboardFormatId::NONE && aDataHelper.GetGraphic( nFormat, aGraphic ) ) + pGraphic.reset(new Graphic( aGraphic )); + } + + if( pGraphic ) + { + bRet = false; + + if( aDataHelper.HasFormat( SotClipboardFormatId::SVIM ) ) + { + + ImageMap aImageMap; + + // according to KA we don't need a BaseURL here + if( aDataHelper.GetImageMap( SotClipboardFormatId::SVIM, aImageMap ) ) + { + SvxGalleryDrawModel aModel; + + if( aModel.GetModel() ) + { + SdrPage* pPage = aModel.GetModel()->GetPage(0); + SdrGrafObj* pGrafObj = new SdrGrafObj(*aModel.GetModel(), *pGraphic ); + + pGrafObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SgaIMapInfo( aImageMap )) ); + pPage->InsertObject( pGrafObj ); + bRet = InsertModel( *aModel.GetModel(), nInsertPos ); + } + } + } + + if( !bRet ) + bRet = InsertGraphic( *pGraphic, nInsertPos ); + } + } + + return bRet; +} + +void GalleryTheme::CopyToClipboard(sal_uInt32 nPos) +{ + GalleryTransferable* pTransferable = new GalleryTransferable( this, nPos, false ); + pTransferable->CopyToClipboard(GetSystemClipboard()); +} + +SvStream& GalleryTheme::WriteData( SvStream& rOStm ) const +{ + const INetURLObject aRelURL1( GetParent()->GetRelativeURL() ); + const INetURLObject aRelURL2( GetParent()->GetUserURL() ); + sal_uInt32 nCount = GetObjectCount(); + bool bRel; + + rOStm.WriteUInt16( 0x0004 ); + write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, pThm->GetThemeName(), RTL_TEXTENCODING_UTF8); + rOStm.WriteUInt32( nCount ).WriteUInt16( osl_getThreadTextEncoding() ); + + for( sal_uInt32 i = 0; i < nCount; i++ ) + { + const GalleryObject* pObj = ImplGetGalleryObject( i ); + OUString aPath; + + if( SgaObjKind::SvDraw == pObj->eObjKind ) + { + aPath = GetSvDrawStreamNameFromURL( pObj->aURL ); + bRel = false; + } + else + { + aPath = pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + aPath = aPath.copy( 0, std::min(aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength(), aPath.getLength()) ); + bRel = aPath == aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + + if( bRel && ( pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength() > ( aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength() + 1 ) ) ) + { + aPath = pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + aPath = aPath.copy( std::min(aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength(), aPath.getLength()) ); + } + else + { + aPath = pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + aPath = aPath.copy( 0, std::min(aRelURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength(), aPath.getLength()) ); + bRel = aPath == aRelURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + + if( bRel && ( pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength() > ( aRelURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength() + 1 ) ) ) + { + aPath = pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + aPath = aPath.copy( std::min(aRelURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength(), aPath.getLength()) ); + } + else + aPath = pObj->aURL.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 long nReservePos = rOStm.Tell(); + std::unique_ptr<VersionCompat> pCompat(new VersionCompat( rOStm, StreamMode::WRITE, 2 )); + + rOStm.WriteUInt32( GetId() ).WriteBool( pThm->IsNameFromResource() ); // From version 2 and up + + pCompat.reset(); + + // Fill the rest of the buffer. + const long nRest = std::max( 512L - ( static_cast<long>(rOStm.Tell()) - nReservePos ), 0L ); + + if( nRest ) + { + std::unique_ptr<char[]> pReserve(new char[ nRest ]); + memset( pReserve.get(), 0, nRest ); + rOStm.WriteBytes(pReserve.get(), nRest); + } + + return rOStm; +} + +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 : aObjectList) + { + GalleryObject* pObj = i.get(); + Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), pObj ) ); + i.reset(); + } + aObjectList.clear(); + + for( sal_uInt32 i = 0; i < nCount; i++ ) + { + std::unique_ptr<GalleryObject> pObj(new GalleryObject); + + OUString aFileName; + OUString aPath; + 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()); + + if( bRel ) + { + aFileName = aFileName.replaceAll( "\\", "/" ); + aPath = aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + + if( aFileName[ 0 ] != '/' ) + aPath += "/"; + + aPath += aFileName; + + pObj->aURL = INetURLObject( aPath ); + + if( !FileExists( pObj->aURL ) ) + { + 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->aURL = INetURLObject( aPath ); + } + } + else + { + if( SgaObjKind::SvDraw == pObj->eObjKind ) + { + OUString aDummyURL = "gallery/svdraw/" + aFileName; + pObj->aURL = INetURLObject( aDummyURL, INetProtocol::PrivSoffice ); + } + else + { + OUString aLocalURL; + + pObj->aURL = INetURLObject( aFileName ); + + if( ( pObj->aURL.GetProtocol() == INetProtocol::NotValid ) && + osl::FileBase::getFileURLFromSystemPath( aFileName, aLocalURL ) == osl::FileBase::E_None ) + { + pObj->aURL = INetURLObject( aLocalURL ); + } + } + } + aObjectList.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 VersionCompat. + if( !rIStm.eof() && + nId1 == COMPAT_FORMAT( 'G', 'A', 'L', 'R' ) && + nId2 == COMPAT_FORMAT( 'E', 'S', 'R', 'V' ) ) + { + VersionCompat aCompat( rIStm, StreamMode::READ ); + 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; +} + +SvStream& WriteGalleryTheme( SvStream& rOut, const GalleryTheme& rTheme ) +{ + return rTheme.WriteData( rOut ); +} + +SvStream& ReadGalleryTheme( SvStream& rIn, GalleryTheme& rTheme ) +{ + return rTheme.ReadData( rIn ); +} + +void GalleryTheme::ImplSetModified( bool bModified ) +{ + pThm->SetModified(bModified); +} + +const INetURLObject& GalleryTheme::GetThmURL() const { return pThm->GetThmURL(); } +const INetURLObject& GalleryTheme::GetSdgURL() const { return pThm->GetSdgURL(); } +const INetURLObject& GalleryTheme::GetSdvURL() const { return pThm->GetSdvURL(); } +const INetURLObject& GalleryTheme::GetStrURL() const { return pThm->GetStrURL(); } +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 tools::SvRef<SotStorage>& GalleryTheme::GetSvDrawStorage() const +{ + return aSvDrawStorageRef; +} + +const OUString& GalleryTheme::GetName() const { return pThm->GetThemeName(); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |