summaryrefslogtreecommitdiffstats
path: root/framework/source/fwi
diff options
context:
space:
mode:
Diffstat (limited to 'framework/source/fwi')
-rw-r--r--framework/source/fwi/classes/converter.cxx116
-rw-r--r--framework/source/fwi/classes/protocolhandlercache.cxx257
-rw-r--r--framework/source/fwi/helper/mischelper.cxx154
-rw-r--r--framework/source/fwi/helper/shareablemutex.cxx49
-rw-r--r--framework/source/fwi/jobs/configaccess.cxx184
-rw-r--r--framework/source/fwi/threadhelp/transactionmanager.cxx219
-rw-r--r--framework/source/fwi/uielement/constitemcontainer.cxx288
-rw-r--r--framework/source/fwi/uielement/itemcontainer.cxx212
-rw-r--r--framework/source/fwi/uielement/rootitemcontainer.cxx313
9 files changed, 1792 insertions, 0 deletions
diff --git a/framework/source/fwi/classes/converter.cxx b/framework/source/fwi/classes/converter.cxx
new file mode 100644
index 000000000..a29c5b127
--- /dev/null
+++ b/framework/source/fwi/classes/converter.cxx
@@ -0,0 +1,116 @@
+/* -*- 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 <classes/converter.hxx>
+#include <rtl/ustrbuf.hxx>
+
+namespace framework{
+
+/**
+ * converts a sequence of PropertyValue to a sequence of NamedValue.
+ */
+css::uno::Sequence< css::beans::NamedValue > Converter::convert_seqPropVal2seqNamedVal( const css::uno::Sequence< css::beans::PropertyValue >& lSource )
+{
+ sal_Int32 nCount = lSource.getLength();
+ css::uno::Sequence< css::beans::NamedValue > lDestination(nCount);
+ auto lDestinationRange = asNonConstRange(lDestination);
+ for (sal_Int32 nItem=0; nItem<nCount; ++nItem)
+ {
+ lDestinationRange[nItem].Name = lSource[nItem].Name;
+ lDestinationRange[nItem].Value = lSource[nItem].Value;
+ }
+ return lDestination;
+}
+
+/**
+ * converts a sequence of unicode strings into a vector of such items
+ */
+std::vector<OUString> Converter::convert_seqOUString2OUStringList( const css::uno::Sequence< OUString >& lSource )
+{
+ std::vector<OUString> lDestination;
+ sal_Int32 nCount = lSource.getLength();
+
+ lDestination.reserve(nCount);
+ for (sal_Int32 nItem = 0; nItem < nCount; ++nItem)
+ {
+ lDestination.push_back(lSource[nItem]);
+ }
+
+ return lDestination;
+}
+
+OUString Converter::convert_DateTime2ISO8601( const DateTime& aSource )
+{
+ OUStringBuffer sBuffer(25);
+
+ sal_Int32 nYear = aSource.GetYear();
+ sal_Int32 nMonth = aSource.GetMonth();
+ sal_Int32 nDay = aSource.GetDay();
+
+ sal_Int32 nHour = aSource.GetHour();
+ sal_Int32 nMin = aSource.GetMin();
+ sal_Int32 nSec = aSource.GetSec();
+
+ // write year formatted as "YYYY"
+ if (nYear<10)
+ sBuffer.append("000");
+ else if (nYear<100)
+ sBuffer.append("00");
+ else if (nYear<1000)
+ sBuffer.append("0");
+ sBuffer.append( nYear );
+
+ sBuffer.append("-");
+ // write month formatted as "MM"
+ if (nMonth<10)
+ sBuffer.append("0");
+ sBuffer.append( nMonth );
+
+ sBuffer.append("-");
+ // write day formatted as "DD"
+ if (nDay<10)
+ sBuffer.append("0");
+ sBuffer.append( nDay );
+
+ sBuffer.append("T");
+ // write hours formatted as "hh"
+ if (nHour<10)
+ sBuffer.append("0");
+ sBuffer.append( nHour );
+
+ sBuffer.append(":");
+ // write min formatted as "mm"
+ if (nMin<10)
+ sBuffer.append("0");
+ sBuffer.append( nMin );
+
+ sBuffer.append(":");
+ // write sec formatted as "ss"
+ if (nSec<10)
+ sBuffer.append("0");
+ sBuffer.append( nSec );
+
+ sBuffer.append("Z");
+
+ return sBuffer.makeStringAndClear();
+}
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/source/fwi/classes/protocolhandlercache.cxx b/framework/source/fwi/classes/protocolhandlercache.cxx
new file mode 100644
index 000000000..7619d4323
--- /dev/null
+++ b/framework/source/fwi/classes/protocolhandlercache.cxx
@@ -0,0 +1,257 @@
+/* -*- 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 .
+ */
+
+/*TODO
+ - change "singleton" behaviour by using new helper ::comhelper::SingletonRef
+ - rename method exist() to existHandlerForURL() or similar one
+ - may it's a good idea to replace struct ProtocolHandler by css::beans::NamedValue type?!
+*/
+
+#include <classes/protocolhandlercache.hxx>
+#include <classes/converter.hxx>
+
+#include <tools/wldcrd.hxx>
+#include <unotools/configpaths.hxx>
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+
+constexpr OUStringLiteral SETNAME_HANDLER = u"HandlerSet"; // name of configuration set inside package
+
+namespace framework{
+
+/**
+ @short overloaded index operator of hash map to support pattern key search
+ @descr All keys inside this hash map are URL pattern which points to a uno
+ implementation name of a protocol handler service which is registered
+ for this pattern. This operator makes it easy to find such registered
+ handler by using a full qualified URL and compare it with all pattern
+ keys.
+
+ @param sURL
+ the full qualified URL which should match to a registered pattern
+
+ @return An iterator which points to the found item inside the hash or PatternHash::end()
+ if no pattern match this given <var>sURL</var>.
+ */
+namespace {
+
+PatternHash::const_iterator findPatternKey(PatternHash const * hash, const OUString& sURL)
+{
+ return std::find_if(hash->begin(), hash->end(),
+ [&sURL](const PatternHash::value_type& rEntry) {
+ WildCard aPattern(rEntry.first);
+ return aPattern.Matches(sURL);
+ });
+}
+
+}
+
+/**
+ @short initialize static member of class HandlerCache
+ @descr We use a singleton pattern to implement this handler cache.
+ That means it use two static member list to hold all necessary information
+ and a ref count mechanism to create/destroy it on demand.
+ */
+std::optional<HandlerHash> HandlerCache::s_pHandler;
+std::optional<PatternHash> HandlerCache::s_pPattern;
+sal_Int32 HandlerCache::m_nRefCount = 0;
+HandlerCFGAccess* HandlerCache::s_pConfig = nullptr;
+
+/**
+ @short ctor of the cache of all registered protocol handler
+ @descr It tries to open the right configuration package automatically
+ and fill the internal structures. After that the cache can be
+ used for read access on this data and perform some search
+ operations on it.
+ */
+HandlerCache::HandlerCache()
+{
+ SolarMutexGuard aGuard;
+
+ if (m_nRefCount==0)
+ {
+ s_pHandler.emplace();
+ s_pPattern.emplace();
+ s_pConfig = new HandlerCFGAccess(PACKAGENAME_PROTOCOLHANDLER);
+ s_pConfig->read(*s_pHandler, *s_pPattern);
+ s_pConfig->setCache(this);
+ }
+
+ ++m_nRefCount;
+}
+
+/**
+ @short dtor of the cache
+ @descr It frees all used memory. In further implementations (may if we support write access too)
+ it's a good place to flush changes back to the configuration - but not needed yet.
+ */
+HandlerCache::~HandlerCache()
+{
+ SolarMutexGuard aGuard;
+
+ if( m_nRefCount==1)
+ {
+ s_pConfig->setCache(nullptr);
+
+ delete s_pConfig;
+ s_pConfig = nullptr;
+ s_pHandler.reset();
+ s_pPattern.reset();
+ }
+
+ --m_nRefCount;
+}
+
+/**
+ @short dtor of the cache
+ @descr It frees all used memory. In further implementations (may if we support write access too)
+ it's a good place to flush changes back to the configuration - but not needed yet.
+ */
+bool HandlerCache::search( const OUString& sURL, ProtocolHandler* pReturn ) const
+{
+ bool bFound = false;
+
+ SolarMutexGuard aGuard;
+
+ PatternHash::const_iterator pItem = findPatternKey(s_pPattern ? &*s_pPattern : nullptr, sURL);
+ if (pItem != s_pPattern->end())
+ {
+ *pReturn = (*s_pHandler)[pItem->second];
+ bFound = true;
+ }
+
+ return bFound;
+}
+
+/**
+ @short search for a registered handler by using a URL struct
+ @descr We combine necessary parts of this struct to a valid URL string
+ and call our other search method ...
+ It's a helper for outside code.
+ */
+bool HandlerCache::search( const css::util::URL& aURL, ProtocolHandler* pReturn ) const
+{
+ return search( aURL.Complete, pReturn );
+}
+
+void HandlerCache::takeOver(HandlerHash aHandler, PatternHash aPattern)
+{
+ SolarMutexGuard aGuard;
+
+ s_pHandler = std::move(aHandler);
+ s_pPattern = std::move(aPattern);
+}
+
+/**
+ @short dtor of the config access class
+ @descr It opens the configuration package automatically by using base class mechanism.
+ After that "read()" method of this class should be called to use it.
+
+ @param sPackage
+ specifies the package name of the configuration data which should be used
+ */
+HandlerCFGAccess::HandlerCFGAccess( const OUString& sPackage )
+ : ConfigItem(sPackage)
+ , m_pCache(nullptr)
+{
+ css::uno::Sequence< OUString > lListenPaths { SETNAME_HANDLER };
+ EnableNotification(lListenPaths);
+}
+
+/**
+ @short use base class mechanism to fill given structures
+ @descr User use us as a wrapper between configuration api and his internal structures.
+ He give us some pointer to his member and we fill it.
+
+ @param rHandlerHash
+ list of protocol handler infos
+
+ @param rPatternHash
+ reverse map of handler pattern to her uno names
+ */
+void HandlerCFGAccess::read( HandlerHash& rHandlerHash, PatternHash& rPatternHash )
+{
+ // list of all uno implementation names without encoding
+ css::uno::Sequence< OUString > lNames = GetNodeNames( SETNAME_HANDLER, ::utl::ConfigNameFormat::LocalPath );
+ sal_Int32 nSourceCount = lNames.getLength();
+ sal_Int32 nTargetCount = nSourceCount;
+ // list of all full qualified path names of configuration entries
+ css::uno::Sequence< OUString > lFullNames ( nTargetCount );
+ auto lFullNamesRange = asNonConstRange(lFullNames);
+ // expand names to full path names
+ sal_Int32 nSource=0;
+ sal_Int32 nTarget=0;
+ for( nSource=0; nSource<nSourceCount; ++nSource )
+ {
+ lFullNamesRange[nTarget] =
+ SETNAME_HANDLER +
+ CFG_PATH_SEPARATOR +
+ lNames[nSource] +
+ CFG_PATH_SEPARATOR
+ PROPERTY_PROTOCOLS;
+
+ ++nTarget;
+ }
+
+ // get values at all
+ css::uno::Sequence< css::uno::Any > lValues = GetProperties( lFullNames );
+ SAL_WARN_IF( lFullNames.getLength()!=lValues.getLength(), "fwk", "HandlerCFGAccess::read(): Miss some configuration values of handler set!" );
+
+ // fill structures
+ nSource = 0;
+ for( nTarget=0; nTarget<nTargetCount; ++nTarget )
+ {
+ // create it new for every loop to guarantee a real empty object!
+ ProtocolHandler aHandler;
+ aHandler.m_sUNOName = ::utl::extractFirstFromConfigurationPath(lNames[nSource]);
+
+ // unpack all values of this handler
+ css::uno::Sequence< OUString > lTemp;
+ lValues[nTarget] >>= lTemp;
+ aHandler.m_lProtocols = Converter::convert_seqOUString2OUStringList(lTemp);
+
+ // register his pattern into the performance search hash
+ for (auto const& item : aHandler.m_lProtocols)
+ {
+ rPatternHash[item] = lNames[nSource];
+ }
+
+ // insert the handler info into the normal handler cache
+ rHandlerHash[lNames[nSource]] = aHandler;
+ ++nSource;
+ }
+}
+
+void HandlerCFGAccess::Notify(const css::uno::Sequence< OUString >& /*lPropertyNames*/)
+{
+ HandlerHash aHandler;
+ PatternHash aPattern;
+
+ read(aHandler, aPattern);
+ if (m_pCache)
+ m_pCache->takeOver(std::move(aHandler), std::move(aPattern));
+}
+
+void HandlerCFGAccess::ImplCommit()
+{
+}
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/source/fwi/helper/mischelper.cxx b/framework/source/fwi/helper/mischelper.cxx
new file mode 100644
index 000000000..e9c664d47
--- /dev/null
+++ b/framework/source/fwi/helper/mischelper.cxx
@@ -0,0 +1,154 @@
+/* -*- 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 <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/document/XDocumentLanguages.hpp>
+#include <com/sun/star/linguistic2/LanguageGuessing.hpp>
+
+#include <sal/log.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <svtools/langtab.hxx>
+#include <helper/mischelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+namespace framework
+{
+
+uno::Reference< linguistic2::XLanguageGuessing > const & LanguageGuessingHelper::GetGuesser() const
+{
+ if (!m_xLanguageGuesser.is())
+ {
+ try
+ {
+ m_xLanguageGuesser = linguistic2::LanguageGuessing::create( m_xContext );
+ }
+ catch (const uno::Exception &)
+ {
+ SAL_WARN( "fwk", "failed to get language guessing component" );
+ }
+ }
+ return m_xLanguageGuesser;
+}
+
+void FillLangItems( std::set< OUString > &rLangItems,
+ const uno::Reference< frame::XFrame > & rxFrame,
+ const LanguageGuessingHelper & rLangGuessHelper,
+ SvtScriptType nScriptType,
+ const OUString & rCurLang,
+ const OUString & rKeyboardLang,
+ const OUString & rGuessedTextLang )
+{
+ rLangItems.clear();
+
+ //1--add current language
+ if( !rCurLang.isEmpty() &&
+ LANGUAGE_DONTKNOW != SvtLanguageTable::GetLanguageType( rCurLang ))
+ rLangItems.insert( rCurLang );
+
+ //2--System
+ const AllSettings& rAllSettings = Application::GetSettings();
+ LanguageType rSystemLanguage = rAllSettings.GetLanguageTag().getLanguageType();
+ if( rSystemLanguage != LANGUAGE_DONTKNOW )
+ {
+ if ( IsScriptTypeMatchingToLanguage( nScriptType, rSystemLanguage ))
+ rLangItems.insert( SvtLanguageTable::GetLanguageString( rSystemLanguage ) );
+ }
+
+ //3--UI
+ LanguageType rUILanguage = rAllSettings.GetUILanguageTag().getLanguageType();
+ if( rUILanguage != LANGUAGE_DONTKNOW )
+ {
+ if ( IsScriptTypeMatchingToLanguage( nScriptType, rUILanguage ))
+ rLangItems.insert( SvtLanguageTable::GetLanguageString( rUILanguage ) );
+ }
+
+ //4--guessed language
+ const uno::Reference< linguistic2::XLanguageGuessing >& xLangGuesser( rLangGuessHelper.GetGuesser() );
+ if ( xLangGuesser.is() && !rGuessedTextLang.isEmpty())
+ {
+ css::lang::Locale aLocale(xLangGuesser->guessPrimaryLanguage( rGuessedTextLang, 0, rGuessedTextLang.getLength()) );
+ LanguageType nLang = LanguageTag( aLocale ).makeFallback().getLanguageType();
+ if (nLang != LANGUAGE_DONTKNOW && nLang != LANGUAGE_NONE && nLang != LANGUAGE_SYSTEM
+ && IsScriptTypeMatchingToLanguage( nScriptType, nLang ))
+ rLangItems.insert( SvtLanguageTable::GetLanguageString( nLang ));
+ }
+
+ //5--keyboard language
+ if( !rKeyboardLang.isEmpty() )
+ {
+ if ( IsScriptTypeMatchingToLanguage( nScriptType, SvtLanguageTable::GetLanguageType( rKeyboardLang )))
+ rLangItems.insert( rKeyboardLang );
+ }
+
+ //6--all languages used in current document
+ Reference< css::frame::XModel > xModel;
+ if ( rxFrame.is() )
+ {
+ Reference< css::frame::XController > xController = rxFrame->getController();
+ if ( xController.is() )
+ xModel = xController->getModel();
+ }
+ Reference< document::XDocumentLanguages > xDocumentLanguages( xModel, UNO_QUERY );
+ /*the description of nScriptType
+ LATIN : 0x001
+ ASIAN : 0x002
+ COMPLEX: 0x004
+ */
+ const sal_Int16 nMaxCount = 7;
+ if ( !xDocumentLanguages.is() )
+ return;
+
+ const Sequence< Locale > rLocales( xDocumentLanguages->getDocumentLanguages( static_cast<sal_Int16>(nScriptType), nMaxCount ));
+ for ( const Locale& rLocale : rLocales )
+ {
+ if ( rLangItems.size() == static_cast< size_t >(nMaxCount) )
+ break;
+ if( IsScriptTypeMatchingToLanguage( nScriptType, SvtLanguageTable::GetLanguageType( rLocale.Language )))
+ rLangItems.insert( rLocale.Language );
+ }
+}
+
+auto (*g_pGetMultiplexerListener)(
+ css::uno::Reference<css::uno::XComponentContext> const & xComponentContext,
+ uno::Reference<uno::XInterface> const&,
+ std::function<bool (uno::Reference<ui::XContextChangeEventListener> const&)> const&)
+ -> uno::Reference<ui::XContextChangeEventListener> = nullptr;
+
+uno::Reference<ui::XContextChangeEventListener>
+GetFirstListenerWith_Impl(
+ css::uno::Reference<css::uno::XComponentContext> const & xComponentContext,
+ uno::Reference<uno::XInterface> const& xEventFocus,
+ std::function<bool (uno::Reference<ui::XContextChangeEventListener> const&)> const& rPredicate)
+{
+ assert(g_pGetMultiplexerListener != nullptr); // should not be called too early, nor too late
+ return g_pGetMultiplexerListener(xComponentContext, xEventFocus, rPredicate);
+}
+
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/source/fwi/helper/shareablemutex.cxx b/framework/source/fwi/helper/shareablemutex.cxx
new file mode 100644
index 000000000..cd3b6bd18
--- /dev/null
+++ b/framework/source/fwi/helper/shareablemutex.cxx
@@ -0,0 +1,49 @@
+/* -*- 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 <helper/shareablemutex.hxx>
+
+namespace framework
+{
+ShareableMutex::ShareableMutex()
+{
+ m_pMutexRef = new MutexRef;
+ m_pMutexRef->acquire();
+}
+
+ShareableMutex::ShareableMutex(const ShareableMutex& rShareableMutex)
+{
+ m_pMutexRef = rShareableMutex.m_pMutexRef;
+ m_pMutexRef->acquire();
+}
+
+ShareableMutex& ShareableMutex::operator=(const ShareableMutex& rShareableMutex)
+{
+ rShareableMutex.m_pMutexRef->acquire();
+ m_pMutexRef->release();
+ m_pMutexRef = rShareableMutex.m_pMutexRef;
+ return *this;
+}
+
+void ShareableMutex::acquire() { m_pMutexRef->m_oslMutex.acquire(); }
+
+void ShareableMutex::release() { m_pMutexRef->m_oslMutex.release(); }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/source/fwi/jobs/configaccess.cxx b/framework/source/fwi/jobs/configaccess.cxx
new file mode 100644
index 000000000..fde891293
--- /dev/null
+++ b/framework/source/fwi/jobs/configaccess.cxx
@@ -0,0 +1,184 @@
+/* -*- 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 <jobs/configaccess.hxx>
+#include <services.h>
+
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/util/XChangesBatch.hpp>
+#include <utility>
+
+#include <tools/diagnose_ex.h>
+
+namespace framework{
+
+/**
+ @short open the configuration of this job
+ @descr We open the configuration of this job only. Not the whole package or the whole
+ job set. We are interested on our own properties only.
+ We set the opened configuration access as our member. So any following method,
+ which needs cfg access, can use it. That prevent us against multiple open/close requests.
+ But you can use this method to upgrade an already opened configuration too.
+
+ @param eMode
+ force opening of the configuration access in readonly or in read/write mode
+ */
+ConfigAccess::ConfigAccess( /*IN*/ css::uno::Reference< css::uno::XComponentContext > xContext,
+ /*IN*/ OUString sRoot )
+ : m_xContext (std::move( xContext))
+ , m_sRoot (std::move( sRoot ))
+ , m_eMode ( E_CLOSED )
+{
+}
+
+/**
+ @short last chance to close an open configuration access point
+ @descr In case our user forgot to close this configuration point
+ in the right way, normally he will run into some trouble -
+ e.g. losing data.
+ */
+ConfigAccess::~ConfigAccess()
+{
+ close();
+}
+
+/**
+ @short return the internal mode of this instance
+ @descr May be the outside user need any information about successfully opened
+ or closed config access point objects. He can control the internal mode to do so.
+
+ @return The internal open state of this object.
+ */
+ConfigAccess::EOpenMode ConfigAccess::getMode() const
+{
+ std::unique_lock g(m_mutex);
+ return m_eMode;
+}
+
+/**
+ @short open the configuration access in the specified mode
+ @descr We set the opened configuration access as our member. So any following method,
+ which needs cfg access, can use it. That prevent us against multiple open/close requests.
+ But you can use this method to upgrade an already opened configuration too.
+ It's possible to open a config access in READONLY mode first and "open" it at a second
+ time within the mode READWRITE. Then we will upgrade it. Downgrade will be possible too.
+
+ But note: closing will be done explicitly by calling method close() ... not by
+ downgrading with mode CLOSED!
+
+ @param eMode
+ force (re)opening of the configuration access in readonly or in read/write mode
+ */
+void ConfigAccess::open( /*IN*/ EOpenMode eMode )
+{
+ std::unique_lock g(m_mutex);
+
+ // check if configuration is already open in the right mode.
+ // By the way: Don't allow closing by using this method!
+ if ( eMode == E_CLOSED || m_eMode == eMode )
+ return;
+
+ // We have to close the old access point without any question here.
+ // It will be open again using the new mode.
+ // can be called without checks! It does the checks by itself ...
+ // e.g. for already closed or not opened configuration.
+ // Flushing of all made changes will be done here too.
+ closeImpl();
+
+ // create the configuration provider, which provides sub access points
+ css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider = css::configuration::theDefaultProvider::get(m_xContext);
+ css::beans::PropertyValue aParam;
+ aParam.Name = "nodepath";
+ aParam.Value <<= m_sRoot;
+
+ css::uno::Sequence< css::uno::Any > lParams{ css::uno::Any(aParam) };
+
+ // open it
+ try
+ {
+ if (eMode==E_READONLY)
+ m_xConfig = xConfigProvider->createInstanceWithArguments(SERVICENAME_CFGREADACCESS , lParams);
+ else
+ if (eMode==E_READWRITE)
+ m_xConfig = xConfigProvider->createInstanceWithArguments(SERVICENAME_CFGUPDATEACCESS, lParams);
+ }
+ catch(const css::uno::Exception&)
+ {
+ TOOLS_INFO_EXCEPTION("fwk", "open config");
+ }
+
+ m_eMode = E_CLOSED;
+ if (m_xConfig.is())
+ m_eMode = eMode;
+}
+
+/**
+ @short close the internal opened configuration access and flush all changes
+ @descr It checks, if the given access is valid and react in the right way.
+ It flushes all changes ... so nobody else must know this state.
+ */
+void ConfigAccess::close()
+{
+ std::unique_lock g(m_mutex);
+ closeImpl();
+}
+
+void ConfigAccess::closeImpl()
+{
+ // check already closed configuration
+ if (m_xConfig.is())
+ {
+ css::uno::Reference< css::util::XChangesBatch > xFlush(m_xConfig, css::uno::UNO_QUERY);
+ if (xFlush.is())
+ xFlush->commitChanges();
+ m_xConfig.clear();
+ m_eMode = E_CLOSED;
+ }
+}
+
+/**
+ @short provides an access to the internal wrapped configuration access
+ @descr It's not allowed to safe this c++ (!) reference outside. You have
+ to use it directly. Further you must use our public lock member m_aLock
+ to synchronize your code with our internal structures and our interface
+ methods. Acquire it before you call cfg() and release it afterwards immediately.
+
+ E.g.: ConfigAccess aAccess(...);
+ Guard aReadLock(aAccess.m_aLock);
+ Reference< XPropertySet > xSet(aAccess.cfg(), UNO_QUERY);
+ Any aProp = xSet->getPropertyValue("...");
+ aReadLock.unlock();
+
+ @attention During this time it's not allowed to call the methods open() or close()!
+ Otherwise you will change your own referenced config access. Anything will
+ be possible then.
+
+ @return A c++(!) reference to the uno instance of the configuration access point.
+ */
+const css::uno::Reference< css::uno::XInterface >& ConfigAccess::cfg()
+{
+ // must be synchronized from outside!
+ // => no lock here ...
+ return m_xConfig;
+}
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/source/fwi/threadhelp/transactionmanager.cxx b/framework/source/fwi/threadhelp/transactionmanager.cxx
new file mode 100644
index 000000000..86d5b354a
--- /dev/null
+++ b/framework/source/fwi/threadhelp/transactionmanager.cxx
@@ -0,0 +1,219 @@
+/* -*- 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 <sal/log.hxx>
+
+#include <framework/transactionmanager.hxx>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+
+namespace framework{
+
+/*-************************************************************************************************************
+ @short standard ctor
+ @descr Initialize instance with right start values for correct working.
+*//*-*************************************************************************************************************/
+TransactionManager::TransactionManager()
+ : m_eWorkingMode ( E_INIT )
+ , m_nTransactionCount ( 0 )
+{
+ m_aBarrier.open();
+}
+
+/*-************************************************************************************************************
+ @short standard dtor
+*//*-*************************************************************************************************************/
+TransactionManager::~TransactionManager()
+{
+}
+
+/*-****************************************************************************************************
+ @short set new working mode
+ @descr These implementation knows for states of working: E_INIT, E_WORK, E_BEFORECLOSE, E_CLOSE
+ You can step during this ones only from the left to the right side and start at left side again!
+ (This is necessary e.g. for refcounted objects!)
+ This call will block till all current existing transactions was finished.
+ Following results can occur:
+ E_INIT : All requests on this implementation are refused.
+ It's your decision to react in a right way.
+
+ E_WORK : The object can work now. The full functionality is available.
+
+ E_BEFORECLOSE : The object start the closing mechanism ... but sometimes
+ e.g. the dispose() method need to call some private methods.
+ These some special methods should use E_SOFTEXCEPTIONS
+ to detect this special case!
+
+ E_CLOSE : Object is already dead! All further requests will be refused.
+ It's your decision to react in a right way.
+ @param "eMode", is the new mode - but we don't accept setting mode in wrong order!
+ @onerror We do nothing.
+*//*-*****************************************************************************************************/
+void TransactionManager::setWorkingMode( EWorkingMode eMode )
+{
+ // Safe member access.
+ bool bWaitFor = false;
+ {
+ std::unique_lock aAccessGuard(m_aAccessLock);
+ // Change working mode first!
+ if (
+ (m_eWorkingMode == E_INIT && eMode == E_WORK) ||
+ ((m_eWorkingMode == E_WORK || m_eWorkingMode == E_INIT) && eMode == E_BEFORECLOSE) ||
+ (m_eWorkingMode == E_BEFORECLOSE && eMode == E_CLOSE) ||
+ (m_eWorkingMode == E_CLOSE && eMode == E_INIT)
+ )
+ {
+ m_eWorkingMode = eMode;
+ if (m_eWorkingMode == E_BEFORECLOSE || m_eWorkingMode == E_CLOSE)
+ {
+ bWaitFor = true;
+ }
+ }
+ }
+ // Wait for current existing transactions then!
+ // (Only necessary for changing to E_BEFORECLOSE or E_CLOSE!...
+ // otherwise; if you wait at setting E_WORK another thread could finish an acquire-call during our unlock() and wait() call
+ // ... and we will wait forever here!!!)
+ // Don't forget to release access mutex before.
+ if( bWaitFor )
+ {
+ m_aBarrier.wait();
+ }
+}
+
+/*-****************************************************************************************************
+ @short get current working mode
+ @descr If you stand in your close() or init() method ... but don't know
+ if you called more than ones(!) ... you can use this function to get
+ right information.
+ e.g: You have a method init() which is used to change working mode from
+ E_INIT to E_WORK and should be used to initialize some member too ...
+ What should you do:
+
+ void init( sal_Int32 nValue )
+ {
+ // Reject this call if our transaction manager say: "Object already initialized!"
+ // Otherwise initialize your member.
+ if( m_aTransactionManager.getWorkingMode() == E_INIT )
+ {
+ // Object is uninitialized ...
+ // Make member access threadsafe!
+ Guard aGuard( m_aMutex );
+
+ // Check working mode again .. because another instance could be faster.
+ // (It's possible to set this guard at first of this method too!)
+ if( m_aTransactionManager.getWorkingMode() == E_INIT )
+ {
+ m_aMember = nValue;
+
+ // Object is initialized now ... set working mode to E_WORK!
+ m_aTransactionManager.setWorkingMode( E_WORK );
+ }
+ }
+ }
+
+ @seealso method setWorkingMode()
+ @return Current set mode.
+
+ @onerror No error should occur.
+*//*-*****************************************************************************************************/
+EWorkingMode TransactionManager::getWorkingMode() const
+{
+ // Synchronize access to internal member!
+ std::unique_lock aAccessLock( m_aAccessLock );
+ return m_eWorkingMode;
+}
+
+/*-****************************************************************************************************
+ @short start new transaction
+ @descr A guard should use this method to start a new transaction. He should look for rejected
+ calls to by using parameter eMode and eReason.
+ If call was not rejected your transaction will be non breakable during releasing your transaction
+ guard! BUT ... your code isn't threadsafe then! It's a transaction manager only...
+
+ @seealso method unregisterTransaction()
+
+ @param "eMode" ,used to enable/disable throwing exceptions automatically for rejected calls
+*//*-*****************************************************************************************************/
+void TransactionManager::registerTransaction( EExceptionMode eMode )
+{
+ std::unique_lock aAccessGuard( m_aAccessLock );
+ switch( m_eWorkingMode )
+ {
+ case E_INIT:
+ if( eMode == E_HARDEXCEPTIONS )
+ {
+ // Help programmer to find out, why this exception is thrown!
+ SAL_WARN( "fwk", "TransactionManager...: Owner instance not correctly initialized yet. Call was rejected! Normally it's an algorithm error ... wrong use of class!" );
+ //ATTENTION: temp. disabled - till all bad code positions are detected and changed! */
+ // throw css::uno::RuntimeException( "TransactionManager.: Owner instance not right initialized yet. Call was rejected! Normally it's an algorithm error... wrong using of class!\n", css::uno::Reference< css::uno::XInterface >() );
+ }
+ break;
+ case E_WORK:
+ break;
+ case E_BEFORECLOSE:
+ if( eMode == E_HARDEXCEPTIONS )
+ {
+ // Help programmer to find out, why this exception is thrown!
+ SAL_WARN( "fwk", "TransactionManager...: Owner instance stand in close method. Call was rejected!" );
+ throw css::lang::DisposedException( "TransactionManager: Owner instance stand in close method. Call was rejected!" );
+ }
+ break;
+ case E_CLOSE:
+ // Help programmer to find out, why this exception is thrown!
+ SAL_WARN( "fwk", "TransactionManager...: Owner instance already closed. Call was rejected!" );
+ throw css::lang::DisposedException( "TransactionManager: Owner instance already closed. Call was rejected!" );
+ }
+
+ // Register this new transaction.
+ // If it is the first one .. close gate to disable changing of working mode.
+ ++m_nTransactionCount;
+ if( m_nTransactionCount == 1 )
+ {
+ m_aBarrier.close();
+ }
+}
+
+/*-****************************************************************************************************
+ @short finish transaction
+ @descr A guard should call this method to release current transaction.
+
+ @seealso method registerTransaction()
+*//*-*****************************************************************************************************/
+void TransactionManager::unregisterTransaction()
+{
+ // This call could not rejected!
+ // Safe access to internal member.
+ std::unique_lock aAccessGuard( m_aAccessLock );
+
+ // Deregister this transaction.
+ // If it was the last one ... open gate to enable changing of working mode!
+ // (see setWorkingMode())
+
+ --m_nTransactionCount;
+ if( m_nTransactionCount == 0 )
+ {
+ m_aBarrier.open();
+ }
+}
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/source/fwi/uielement/constitemcontainer.cxx b/framework/source/fwi/uielement/constitemcontainer.cxx
new file mode 100644
index 000000000..7e43a5009
--- /dev/null
+++ b/framework/source/fwi/uielement/constitemcontainer.cxx
@@ -0,0 +1,288 @@
+/* -*- 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 <uielement/constitemcontainer.hxx>
+#include <uielement/itemcontainer.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include <comphelper/propertysetinfo.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <rtl/ref.hxx>
+
+using namespace cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+
+const int PROPHANDLE_UINAME = 1;
+constexpr OUStringLiteral PROPNAME_UINAME = u"UIName";
+
+namespace framework
+{
+
+ConstItemContainer::ConstItemContainer()
+{
+}
+
+ConstItemContainer::ConstItemContainer( const ItemContainer& rItemContainer )
+{
+ ShareGuard aLock( rItemContainer.m_aShareMutex );
+ copyItemContainer( rItemContainer.m_aItemVector );
+}
+
+ConstItemContainer::ConstItemContainer( const Reference< XIndexAccess >& rSourceContainer, bool bFastCopy )
+{
+ // We also have to copy the UIName property
+ try
+ {
+ Reference< XPropertySet > xPropSet( rSourceContainer, UNO_QUERY );
+ if ( xPropSet.is() )
+ {
+ xPropSet->getPropertyValue("UIName") >>= m_aUIName;
+ }
+ }
+ catch ( const Exception& )
+ {
+ }
+
+ if ( !rSourceContainer.is() )
+ return;
+
+ try
+ {
+ sal_Int32 nCount = rSourceContainer->getCount();
+ m_aItemVector.reserve(nCount);
+ if ( bFastCopy )
+ {
+ for ( sal_Int32 i = 0; i < nCount; i++ )
+ {
+ Sequence< PropertyValue > aPropSeq;
+ if ( rSourceContainer->getByIndex( i ) >>= aPropSeq )
+ m_aItemVector.push_back( aPropSeq );
+ }
+ }
+ else
+ {
+ for ( sal_Int32 i = 0; i < nCount; i++ )
+ {
+ Sequence< PropertyValue > aPropSeq;
+ if ( rSourceContainer->getByIndex( i ) >>= aPropSeq )
+ {
+ sal_Int32 nContainerIndex = -1;
+ Reference< XIndexAccess > xIndexAccess;
+ for ( sal_Int32 j = 0; j < aPropSeq.getLength(); j++ )
+ {
+ if ( aPropSeq[j].Name == "ItemDescriptorContainer" )
+ {
+ aPropSeq[j].Value >>= xIndexAccess;
+ nContainerIndex = j;
+ break;
+ }
+ }
+
+ if ( xIndexAccess.is() && nContainerIndex >= 0 )
+ aPropSeq.getArray()[nContainerIndex].Value <<= deepCopyContainer( xIndexAccess );
+
+ m_aItemVector.push_back( aPropSeq );
+ }
+ }
+ }
+ }
+ catch ( const IndexOutOfBoundsException& )
+ {
+ }
+}
+
+ConstItemContainer::~ConstItemContainer()
+{
+}
+
+// private
+void ConstItemContainer::copyItemContainer( const std::vector< Sequence< PropertyValue > >& rSourceVector )
+{
+ const sal_uInt32 nCount = rSourceVector.size();
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ sal_Int32 nContainerIndex = -1;
+ Sequence< PropertyValue > aPropSeq( rSourceVector[i] );
+ Reference< XIndexAccess > xIndexAccess;
+ for ( sal_Int32 j = 0; j < aPropSeq.getLength(); j++ )
+ {
+ if ( aPropSeq[j].Name == "ItemDescriptorContainer" )
+ {
+ aPropSeq[j].Value >>= xIndexAccess;
+ nContainerIndex = j;
+ break;
+ }
+ }
+
+ if ( xIndexAccess.is() && nContainerIndex >= 0 )
+ aPropSeq.getArray()[nContainerIndex].Value <<= deepCopyContainer( xIndexAccess );
+
+ m_aItemVector.push_back( aPropSeq );
+ }
+}
+
+Reference< XIndexAccess > ConstItemContainer::deepCopyContainer( const Reference< XIndexAccess >& rSubContainer )
+{
+ Reference< XIndexAccess > xReturn;
+ if ( rSubContainer.is() )
+ {
+ ItemContainer* pSource = comphelper::getFromUnoTunnel<ItemContainer>( rSubContainer );
+ rtl::Reference<ConstItemContainer> pSubContainer;
+ if ( pSource )
+ pSubContainer = new ConstItemContainer( *pSource );
+ else
+ pSubContainer = new ConstItemContainer( rSubContainer );
+ xReturn = pSubContainer;
+ }
+
+ return xReturn;
+}
+
+// XUnoTunnel
+sal_Int64 ConstItemContainer::getSomething( const css::uno::Sequence< sal_Int8 >& rIdentifier )
+{
+ return comphelper::getSomethingImpl(rIdentifier, this);
+}
+
+const Sequence< sal_Int8 >& ConstItemContainer::getUnoTunnelId() noexcept
+{
+ static const comphelper::UnoIdInit theConstItemContainerUnoTunnelId;
+ return theConstItemContainerUnoTunnelId.getSeq();
+}
+
+// XElementAccess
+sal_Bool SAL_CALL ConstItemContainer::hasElements()
+{
+ return ( !m_aItemVector.empty() );
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL ConstItemContainer::getCount()
+{
+ return m_aItemVector.size();
+}
+
+Any SAL_CALL ConstItemContainer::getByIndex( sal_Int32 Index )
+{
+ if ( sal_Int32( m_aItemVector.size()) <= Index )
+ throw IndexOutOfBoundsException( OUString(), static_cast<OWeakObject *>(this) );
+ return Any( m_aItemVector[Index] );
+}
+
+namespace
+{
+ std::vector<comphelper::PropertyMapEntry> makePropertyMap(const css::uno::Sequence<css::beans::Property>& rProps)
+ {
+ std::vector<comphelper::PropertyMapEntry> aEntries;
+ for (auto const& it : rProps)
+ aEntries.emplace_back(it.Name, it.Handle, it.Type, it.Attributes, 0);
+ return aEntries;
+ }
+}
+
+// XPropertySet
+Reference< XPropertySetInfo > SAL_CALL ConstItemContainer::getPropertySetInfo()
+{
+ // Create structure of propertysetinfo for baseclass "OPropertySetHelper".
+ // (Use method "getInfoHelper()".)
+ static std::vector<comphelper::PropertyMapEntry> aPropertyInfos(makePropertyMap(getInfoHelper().getProperties()));
+ static Reference< XPropertySetInfo > xInfo(new comphelper::PropertySetInfo(aPropertyInfos));
+
+ return xInfo;
+}
+
+void SAL_CALL ConstItemContainer::setPropertyValue( const OUString&, const Any& )
+{
+}
+
+Any SAL_CALL ConstItemContainer::getPropertyValue( const OUString& PropertyName )
+{
+ if ( PropertyName == PROPNAME_UINAME )
+ return Any( m_aUIName );
+
+ throw UnknownPropertyException(PropertyName);
+}
+
+void SAL_CALL ConstItemContainer::addPropertyChangeListener( const OUString&, const css::uno::Reference< css::beans::XPropertyChangeListener >& )
+{
+}
+
+void SAL_CALL ConstItemContainer::removePropertyChangeListener( const OUString&, const css::uno::Reference< css::beans::XPropertyChangeListener >& )
+{
+ // Only read-only properties - do nothing
+}
+
+void SAL_CALL ConstItemContainer::addVetoableChangeListener( const OUString&, const css::uno::Reference< css::beans::XVetoableChangeListener >& )
+{
+ // Only read-only properties - do nothing
+}
+
+void SAL_CALL ConstItemContainer::removeVetoableChangeListener( const OUString&, const css::uno::Reference< css::beans::XVetoableChangeListener >& )
+{
+ // Only read-only properties - do nothing
+}
+
+// XFastPropertySet
+void SAL_CALL ConstItemContainer::setFastPropertyValue( sal_Int32, const css::uno::Any& )
+{
+}
+
+Any SAL_CALL ConstItemContainer::getFastPropertyValue( sal_Int32 nHandle )
+{
+ if ( nHandle == PROPHANDLE_UINAME )
+ return Any( m_aUIName );
+
+ throw UnknownPropertyException(OUString::number(nHandle));
+}
+
+::cppu::IPropertyArrayHelper& ConstItemContainer::getInfoHelper()
+{
+ // Define static member to give structure of properties to baseclass "OPropertySetHelper".
+ // "impl_getStaticPropertyDescriptor" is a non exported and static function, who will define a static propertytable.
+ // "true" say: Table is sorted by name.
+ static ::cppu::OPropertyArrayHelper ourInfoHelper( impl_getStaticPropertyDescriptor(), true );
+
+ return ourInfoHelper;
+}
+
+css::uno::Sequence< css::beans::Property > ConstItemContainer::impl_getStaticPropertyDescriptor()
+{
+ // Create a property array to initialize sequence!
+ // Table of all predefined properties of this class. It's used from OPropertySetHelper-class!
+ // Don't forget to change the defines (see begin of this file), if you add, change or delete a property in this list!!!
+ // It's necessary for methods of OPropertySetHelper.
+ // ATTENTION:
+ // YOU MUST SORT FOLLOW TABLE BY NAME ALPHABETICAL !!!
+
+ return
+ {
+ css::beans::Property( PROPNAME_UINAME, PROPHANDLE_UINAME ,
+ cppu::UnoType<OUString>::get(),
+ css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY )
+ };
+}
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/source/fwi/uielement/itemcontainer.cxx b/framework/source/fwi/uielement/itemcontainer.cxx
new file mode 100644
index 000000000..389bbaeaa
--- /dev/null
+++ b/framework/source/fwi/uielement/itemcontainer.cxx
@@ -0,0 +1,212 @@
+/* -*- 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/lang/IndexOutOfBoundsException.hpp>
+#include <uielement/itemcontainer.hxx>
+#include <uielement/constitemcontainer.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <rtl/ref.hxx>
+
+using namespace cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+
+constexpr OUStringLiteral WRONG_TYPE_EXCEPTION
+ = u"Type must be css::uno::Sequence< css::beans::PropertyValue >";
+
+namespace framework
+{
+
+// XInterface, XTypeProvider
+
+ItemContainer::ItemContainer( const ShareableMutex& rMutex ) :
+ m_aShareMutex( rMutex )
+{
+}
+
+ItemContainer::ItemContainer( const ConstItemContainer& rConstItemContainer, const ShareableMutex& rMutex ) : m_aShareMutex( rMutex )
+{
+ copyItemContainer( rConstItemContainer.m_aItemVector, rMutex );
+}
+
+ItemContainer::ItemContainer( const Reference< XIndexAccess >& rSourceContainer, const ShareableMutex& rMutex ) :
+ m_aShareMutex( rMutex )
+{
+ if ( !rSourceContainer.is() )
+ return;
+
+ sal_Int32 nCount = rSourceContainer->getCount();
+ try
+ {
+ for ( sal_Int32 i = 0; i < nCount; i++ )
+ {
+ Sequence< PropertyValue > aPropSeq;
+ if ( rSourceContainer->getByIndex( i ) >>= aPropSeq )
+ {
+ sal_Int32 nContainerIndex = -1;
+ Reference< XIndexAccess > xIndexAccess;
+ for ( sal_Int32 j = 0; j < aPropSeq.getLength(); j++ )
+ {
+ if ( aPropSeq[j].Name == "ItemDescriptorContainer" )
+ {
+ aPropSeq[j].Value >>= xIndexAccess;
+ nContainerIndex = j;
+ break;
+ }
+ }
+
+ if ( xIndexAccess.is() && nContainerIndex >= 0 )
+ aPropSeq.getArray()[nContainerIndex].Value <<= deepCopyContainer( xIndexAccess, rMutex );
+
+ m_aItemVector.push_back( aPropSeq );
+ }
+ }
+ }
+ catch ( const IndexOutOfBoundsException& )
+ {
+ }
+}
+
+ItemContainer::~ItemContainer()
+{
+}
+
+// private
+void ItemContainer::copyItemContainer( const std::vector< Sequence< PropertyValue > >& rSourceVector, const ShareableMutex& rMutex )
+{
+ const sal_uInt32 nCount = rSourceVector.size();
+ for ( sal_uInt32 i = 0; i < nCount; ++i )
+ {
+ sal_Int32 nContainerIndex = -1;
+ Sequence< PropertyValue > aPropSeq( rSourceVector[i] );
+ Reference< XIndexAccess > xIndexAccess;
+ for ( sal_Int32 j = 0; j < aPropSeq.getLength(); j++ )
+ {
+ if ( aPropSeq[j].Name == "ItemDescriptorContainer" )
+ {
+ aPropSeq[j].Value >>= xIndexAccess;
+ nContainerIndex = j;
+ break;
+ }
+ }
+
+ if ( xIndexAccess.is() && nContainerIndex >= 0 )
+ aPropSeq.getArray()[nContainerIndex].Value <<= deepCopyContainer( xIndexAccess, rMutex );
+
+ m_aItemVector.push_back( aPropSeq );
+ }
+}
+
+Reference< XIndexAccess > ItemContainer::deepCopyContainer( const Reference< XIndexAccess >& rSubContainer, const ShareableMutex& rMutex )
+{
+ Reference< XIndexAccess > xReturn;
+ if ( rSubContainer.is() )
+ {
+ ConstItemContainer* pSource = comphelper::getFromUnoTunnel<ConstItemContainer>( rSubContainer );
+ rtl::Reference<ItemContainer> pSubContainer;
+ if ( pSource )
+ pSubContainer = new ItemContainer( *pSource, rMutex );
+ else
+ pSubContainer = new ItemContainer( rSubContainer, rMutex );
+ xReturn = pSubContainer;
+ }
+
+ return xReturn;
+}
+
+const Sequence< sal_Int8 >& ItemContainer::getUnoTunnelId() noexcept
+{
+ static const comphelper::UnoIdInit theItemContainerUnoTunnelId;
+ return theItemContainerUnoTunnelId.getSeq();
+}
+
+// XElementAccess
+sal_Bool SAL_CALL ItemContainer::hasElements()
+{
+ ShareGuard aLock( m_aShareMutex );
+ return ( !m_aItemVector.empty() );
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL ItemContainer::getCount()
+{
+ ShareGuard aLock( m_aShareMutex );
+ return m_aItemVector.size();
+}
+
+Any SAL_CALL ItemContainer::getByIndex( sal_Int32 Index )
+{
+ ShareGuard aLock( m_aShareMutex );
+ if ( sal_Int32( m_aItemVector.size()) <= Index )
+ throw IndexOutOfBoundsException( OUString(), static_cast<OWeakObject *>(this) );
+
+ return Any( m_aItemVector[Index] );
+}
+
+// XIndexContainer
+void SAL_CALL ItemContainer::insertByIndex( sal_Int32 Index, const Any& aItem )
+{
+ Sequence< PropertyValue > aSeq;
+ if ( !(aItem >>= aSeq) )
+ throw IllegalArgumentException( WRONG_TYPE_EXCEPTION,
+ static_cast<OWeakObject *>(this), 2 );
+
+ ShareGuard aLock( m_aShareMutex );
+ if ( sal_Int32( m_aItemVector.size()) == Index )
+ m_aItemVector.push_back( aSeq );
+ else if ( sal_Int32( m_aItemVector.size()) >Index )
+ {
+ std::vector< Sequence< PropertyValue > >::iterator aIter = m_aItemVector.begin();
+ aIter += Index;
+ m_aItemVector.insert( aIter, aSeq );
+ }
+ else
+ throw IndexOutOfBoundsException( OUString(), static_cast<OWeakObject *>(this) );
+}
+
+void SAL_CALL ItemContainer::removeByIndex( sal_Int32 nIndex )
+{
+ ShareGuard aLock( m_aShareMutex );
+ if ( static_cast<sal_Int32>(m_aItemVector.size()) <= nIndex )
+ throw IndexOutOfBoundsException( OUString(), static_cast<OWeakObject *>(this) );
+
+ m_aItemVector.erase(m_aItemVector.begin() + nIndex);
+}
+
+void SAL_CALL ItemContainer::replaceByIndex( sal_Int32 Index, const Any& aItem )
+{
+ Sequence< PropertyValue > aSeq;
+ if ( !(aItem >>= aSeq) )
+ throw IllegalArgumentException( WRONG_TYPE_EXCEPTION,
+ static_cast<OWeakObject *>(this), 2 );
+
+ ShareGuard aLock( m_aShareMutex );
+ if ( sal_Int32( m_aItemVector.size()) <= Index )
+ throw IndexOutOfBoundsException( OUString(), static_cast<OWeakObject *>(this) );
+
+ m_aItemVector[Index] = aSeq;
+}
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/source/fwi/uielement/rootitemcontainer.cxx b/framework/source/fwi/uielement/rootitemcontainer.cxx
new file mode 100644
index 000000000..50ecd0d53
--- /dev/null
+++ b/framework/source/fwi/uielement/rootitemcontainer.cxx
@@ -0,0 +1,313 @@
+/* -*- 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 <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/sequence.hxx>
+#include <uielement/rootitemcontainer.hxx>
+#include <uielement/itemcontainer.hxx>
+#include <uielement/constitemcontainer.hxx>
+#include <properties.h>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <rtl/ref.hxx>
+
+using namespace cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+
+constexpr OUStringLiteral WRONG_TYPE_EXCEPTION
+ = u"Type must be css::uno::Sequence< css::beans::PropertyValue >";
+
+const int PROPHANDLE_UINAME = 1;
+constexpr OUStringLiteral PROPNAME_UINAME = u"UIName";
+
+namespace framework
+{
+
+RootItemContainer::RootItemContainer()
+ : ::cppu::OBroadcastHelperVar< ::cppu::OMultiTypeInterfaceContainerHelper, ::cppu::OMultiTypeInterfaceContainerHelper::keyType >( m_aMutex )
+ , ::cppu::OPropertySetHelper ( *static_cast< ::cppu::OBroadcastHelper* >(this) )
+{
+}
+
+RootItemContainer::RootItemContainer( const Reference< XIndexAccess >& rSourceContainer )
+ : ::cppu::OBroadcastHelperVar< ::cppu::OMultiTypeInterfaceContainerHelper, ::cppu::OMultiTypeInterfaceContainerHelper::keyType >( m_aMutex )
+ , ::cppu::OPropertySetHelper ( *static_cast< ::cppu::OBroadcastHelper* >(this) )
+{
+ // We also have to copy the UIName property
+ try
+ {
+ Reference< XPropertySet > xPropSet( rSourceContainer, UNO_QUERY );
+ if ( xPropSet.is() )
+ {
+ xPropSet->getPropertyValue("UIName") >>= m_aUIName;
+ }
+ }
+ catch ( const Exception& )
+ {
+ }
+
+ if ( !rSourceContainer.is() )
+ return;
+
+ sal_Int32 nCount = rSourceContainer->getCount();
+ try
+ {
+ for ( sal_Int32 i = 0; i < nCount; i++ )
+ {
+ Sequence< PropertyValue > aPropSeq;
+ if ( rSourceContainer->getByIndex( i ) >>= aPropSeq )
+ {
+ sal_Int32 nContainerIndex = -1;
+ Reference< XIndexAccess > xIndexAccess;
+ for ( sal_Int32 j = 0; j < aPropSeq.getLength(); j++ )
+ {
+ if ( aPropSeq[j].Name == "ItemDescriptorContainer" )
+ {
+ aPropSeq[j].Value >>= xIndexAccess;
+ nContainerIndex = j;
+ break;
+ }
+ }
+
+ if ( xIndexAccess.is() && nContainerIndex >= 0 )
+ aPropSeq.getArray()[nContainerIndex].Value <<= deepCopyContainer( xIndexAccess );
+
+ m_aItemVector.push_back( aPropSeq );
+ }
+ }
+ }
+ catch ( const IndexOutOfBoundsException& )
+ {
+ }
+}
+
+RootItemContainer::~RootItemContainer()
+{
+}
+
+Any SAL_CALL RootItemContainer::queryInterface( const Type& _rType )
+{
+ Any aRet = RootItemContainer_BASE::queryInterface( _rType );
+ if ( !aRet.hasValue() )
+ aRet = OPropertySetHelper::queryInterface( _rType );
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL RootItemContainer::getTypes( )
+{
+ return comphelper::concatSequences(
+ RootItemContainer_BASE::getTypes(),
+ ::cppu::OPropertySetHelper::getTypes()
+ );
+}
+
+Reference< XIndexAccess > RootItemContainer::deepCopyContainer( const Reference< XIndexAccess >& rSubContainer )
+{
+ Reference< XIndexAccess > xReturn;
+ if ( rSubContainer.is() )
+ {
+ ConstItemContainer* pSource = comphelper::getFromUnoTunnel<ConstItemContainer>( rSubContainer );
+ rtl::Reference<ItemContainer> pSubContainer;
+ if ( pSource )
+ pSubContainer = new ItemContainer( *pSource, m_aShareMutex );
+ else
+ pSubContainer = new ItemContainer( rSubContainer, m_aShareMutex );
+ xReturn = pSubContainer;
+ }
+
+ return xReturn;
+}
+
+// XUnoTunnel
+sal_Int64 RootItemContainer::getSomething( const css::uno::Sequence< sal_Int8 >& rIdentifier )
+{
+ return comphelper::getSomethingImpl(rIdentifier, this);
+}
+
+const Sequence< sal_Int8 >& RootItemContainer::getUnoTunnelId() noexcept
+{
+ static const comphelper::UnoIdInit theRootItemContainerUnoTunnelId;
+ return theRootItemContainerUnoTunnelId.getSeq();
+}
+
+// XElementAccess
+sal_Bool SAL_CALL RootItemContainer::hasElements()
+{
+ ShareGuard aLock( m_aShareMutex );
+ return ( !m_aItemVector.empty() );
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL RootItemContainer::getCount()
+{
+ ShareGuard aLock( m_aShareMutex );
+ return m_aItemVector.size();
+}
+
+Any SAL_CALL RootItemContainer::getByIndex( sal_Int32 Index )
+{
+ ShareGuard aLock( m_aShareMutex );
+ if ( sal_Int32( m_aItemVector.size()) <= Index )
+ throw IndexOutOfBoundsException( OUString(), static_cast<OWeakObject *>(this) );
+
+ return Any( m_aItemVector[Index] );
+}
+
+// XIndexContainer
+void SAL_CALL RootItemContainer::insertByIndex( sal_Int32 Index, const Any& aItem )
+{
+ Sequence< PropertyValue > aSeq;
+ if ( !(aItem >>= aSeq) )
+ throw IllegalArgumentException( WRONG_TYPE_EXCEPTION, static_cast<OWeakObject *>(this), 2 );
+
+ ShareGuard aLock( m_aShareMutex );
+ if ( sal_Int32( m_aItemVector.size()) == Index )
+ m_aItemVector.push_back( aSeq );
+ else if ( sal_Int32( m_aItemVector.size()) >Index )
+ {
+ std::vector< Sequence< PropertyValue > >::iterator aIter = m_aItemVector.begin();
+ aIter += Index;
+ m_aItemVector.insert( aIter, aSeq );
+ }
+ else
+ throw IndexOutOfBoundsException( OUString(), static_cast<OWeakObject *>(this) );
+}
+
+void SAL_CALL RootItemContainer::removeByIndex( sal_Int32 nIndex )
+{
+ ShareGuard aLock( m_aShareMutex );
+ if ( static_cast<sal_Int32>(m_aItemVector.size()) <= nIndex )
+ throw IndexOutOfBoundsException( OUString(), static_cast<OWeakObject *>(this) );
+
+ m_aItemVector.erase(m_aItemVector.begin() + nIndex);
+}
+
+void SAL_CALL RootItemContainer::replaceByIndex( sal_Int32 Index, const Any& aItem )
+{
+ Sequence< PropertyValue > aSeq;
+ if ( !(aItem >>= aSeq) )
+ throw IllegalArgumentException( WRONG_TYPE_EXCEPTION, static_cast<OWeakObject *>(this), 2 );
+
+ ShareGuard aLock( m_aShareMutex );
+ if ( sal_Int32( m_aItemVector.size()) <= Index )
+ throw IndexOutOfBoundsException( OUString(), static_cast<OWeakObject *>(this) );
+
+ m_aItemVector[Index] = aSeq;
+}
+
+Reference< XInterface > SAL_CALL RootItemContainer::createInstanceWithContext( const Reference< XComponentContext >& )
+{
+ return static_cast<OWeakObject *>(new ItemContainer( m_aShareMutex ));
+}
+
+Reference< XInterface > SAL_CALL RootItemContainer::createInstanceWithArgumentsAndContext( const Sequence< Any >&, const Reference< XComponentContext >& )
+{
+ return static_cast<OWeakObject *>(new ItemContainer( m_aShareMutex ));
+}
+
+// XPropertySet helper
+sal_Bool SAL_CALL RootItemContainer::convertFastPropertyValue( Any& aConvertedValue ,
+ Any& aOldValue ,
+ sal_Int32 nHandle ,
+ const Any& aValue )
+{
+ // Initialize state with sal_False !!!
+ // (Handle can be invalid)
+ bool bReturn = false;
+
+ switch( nHandle )
+ {
+ case PROPHANDLE_UINAME:
+ bReturn = PropHelper::willPropertyBeChanged(
+ css::uno::Any(m_aUIName),
+ aValue,
+ aOldValue,
+ aConvertedValue);
+ break;
+ }
+
+ // Return state of operation.
+ return bReturn;
+}
+
+void SAL_CALL RootItemContainer::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle ,
+ const css::uno::Any& aValue )
+{
+ switch( nHandle )
+ {
+ case PROPHANDLE_UINAME:
+ aValue >>= m_aUIName;
+ break;
+ }
+}
+
+void SAL_CALL RootItemContainer::getFastPropertyValue( css::uno::Any& aValue ,
+ sal_Int32 nHandle ) const
+{
+ switch( nHandle )
+ {
+ case PROPHANDLE_UINAME:
+ aValue <<= m_aUIName;
+ break;
+ }
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL RootItemContainer::getInfoHelper()
+{
+ // Define static member to give structure of properties to baseclass "OPropertySetHelper".
+ // "impl_getStaticPropertyDescriptor" is a non exported and static function, who will define a static propertytable.
+ // "true" say: Table is sorted by name.
+ static ::cppu::OPropertyArrayHelper ourInfoHelper( impl_getStaticPropertyDescriptor(), true );
+
+ return ourInfoHelper;
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL RootItemContainer::getPropertySetInfo()
+{
+ // Create structure of propertysetinfo for baseclass "OPropertySetHelper".
+ // (Use method "getInfoHelper()".)
+ static css::uno::Reference< css::beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+
+ return xInfo;
+}
+
+css::uno::Sequence< css::beans::Property > RootItemContainer::impl_getStaticPropertyDescriptor()
+{
+ // Create a property array to initialize sequence!
+ // Table of all predefined properties of this class. It's used from OPropertySetHelper-class!
+ // Don't forget to change the defines (see begin of this file), if you add, change or delete a property in this list!!!
+ // It's necessary for methods of OPropertySetHelper.
+ // ATTENTION:
+ // YOU MUST SORT FOLLOW TABLE BY NAME ALPHABETICAL !!!
+
+ return
+ {
+ css::beans::Property( PROPNAME_UINAME, PROPHANDLE_UINAME ,
+ cppu::UnoType<OUString>::get(),
+ css::beans::PropertyAttribute::TRANSIENT )
+ };
+}
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */