diff options
Diffstat (limited to 'framework/source/accelerators')
-rw-r--r-- | framework/source/accelerators/acceleratorcache.cxx | 250 | ||||
-rw-r--r-- | framework/source/accelerators/acceleratorconfiguration.cxx | 1717 | ||||
-rw-r--r-- | framework/source/accelerators/acceleratorexecute.cxx | 382 | ||||
-rw-r--r-- | framework/source/accelerators/acceleratorexecute.hxx | 255 | ||||
-rw-r--r-- | framework/source/accelerators/documentacceleratorconfiguration.cxx | 240 | ||||
-rw-r--r-- | framework/source/accelerators/globalacceleratorconfiguration.cxx | 127 | ||||
-rw-r--r-- | framework/source/accelerators/keymapping.cxx | 229 | ||||
-rw-r--r-- | framework/source/accelerators/makefile.mk | 52 | ||||
-rw-r--r-- | framework/source/accelerators/moduleacceleratorconfiguration.cxx | 175 | ||||
-rw-r--r-- | framework/source/accelerators/presethandler.cxx | 937 | ||||
-rw-r--r-- | framework/source/accelerators/storageholder.cxx | 637 |
11 files changed, 5001 insertions, 0 deletions
diff --git a/framework/source/accelerators/acceleratorcache.cxx b/framework/source/accelerators/acceleratorcache.cxx new file mode 100644 index 000000000000..96a266818d31 --- /dev/null +++ b/framework/source/accelerators/acceleratorcache.cxx @@ -0,0 +1,250 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include <accelerators/acceleratorcache.hxx> + +//_______________________________________________ +// own includes + +#ifndef __FRAMEWORK_XML_ACCELERATORCONFIGURATIONREADER_HXX_ +#include <xml/acceleratorconfigurationreader.hxx> +#endif +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> + +//_______________________________________________ +// interface includes + +#ifndef __COM_SUN_STAR_CONTAINER_ELEMENTEXISTEXCEPTION_HPP_ +#include <com/sun/star/container/ElementExistException.hpp> +#endif + +#ifndef __COM_SUN_STAR_CONTAINER_NOSUCHELEMENTEXCEPTION_HPP_ +#include <com/sun/star/container/NoSuchElementException.hpp> +#endif + +//_______________________________________________ +// other includes +#include <vcl/svapp.hxx> + +namespace framework +{ + +//----------------------------------------------- +AcceleratorCache::AcceleratorCache() + : ThreadHelpBase(&Application::GetSolarMutex()) +{ +} + +//----------------------------------------------- +AcceleratorCache::AcceleratorCache(const AcceleratorCache& rCopy) + : ThreadHelpBase(&Application::GetSolarMutex()) +{ + m_lCommand2Keys = rCopy.m_lCommand2Keys; + m_lKey2Commands = rCopy.m_lKey2Commands; +} + +//----------------------------------------------- +AcceleratorCache::~AcceleratorCache() +{ + // Dont save anything automaticly here. + // The user has to do that explicitly! +} + +//----------------------------------------------- +void AcceleratorCache::takeOver(const AcceleratorCache& rCopy) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + m_lCommand2Keys = rCopy.m_lCommand2Keys; + m_lKey2Commands = rCopy.m_lKey2Commands; + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +AcceleratorCache& AcceleratorCache::operator=(const AcceleratorCache& rCopy) +{ + takeOver(rCopy); + return *this; +} + +//----------------------------------------------- +sal_Bool AcceleratorCache::hasKey(const css::awt::KeyEvent& aKey) const +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + return (m_lKey2Commands.find(aKey) != m_lKey2Commands.end()); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +sal_Bool AcceleratorCache::hasCommand(const ::rtl::OUString& sCommand) const +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + return (m_lCommand2Keys.find(sCommand) != m_lCommand2Keys.end()); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +AcceleratorCache::TKeyList AcceleratorCache::getAllKeys() const +{ + TKeyList lKeys; + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + lKeys.reserve(m_lKey2Commands.size()); + + TKey2Commands::const_iterator pIt; + TKey2Commands::const_iterator pEnd = m_lKey2Commands.end(); + for ( pIt = m_lKey2Commands.begin(); + pIt != pEnd ; + ++pIt ) + { + lKeys.push_back(pIt->first); + } + + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + return lKeys; +} + +//----------------------------------------------- +void AcceleratorCache::setKeyCommandPair(const css::awt::KeyEvent& aKey , + const ::rtl::OUString& sCommand) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + // register command for the specified key + m_lKey2Commands[aKey] = sCommand; + + // update optimized structure to bind multiple keys to one command + TKeyList& rKeyList = m_lCommand2Keys[sCommand]; + rKeyList.push_back(aKey); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +AcceleratorCache::TKeyList AcceleratorCache::getKeysByCommand(const ::rtl::OUString& sCommand) const +{ + TKeyList lKeys; + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + TCommand2Keys::const_iterator pCommand = m_lCommand2Keys.find(sCommand); + if (pCommand == m_lCommand2Keys.end()) + throw css::container::NoSuchElementException( + ::rtl::OUString(), css::uno::Reference< css::uno::XInterface >()); + lKeys = pCommand->second; + + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + return lKeys; +} + +//----------------------------------------------- +::rtl::OUString AcceleratorCache::getCommandByKey(const css::awt::KeyEvent& aKey) const +{ + ::rtl::OUString sCommand; + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + TKey2Commands::const_iterator pKey = m_lKey2Commands.find(aKey); + if (pKey == m_lKey2Commands.end()) + throw css::container::NoSuchElementException( + ::rtl::OUString(), css::uno::Reference< css::uno::XInterface >()); + sCommand = pKey->second; + + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + return sCommand; +} + +//----------------------------------------------- +void AcceleratorCache::removeKey(const css::awt::KeyEvent& aKey) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + // check if key exists + TKey2Commands::const_iterator pKey = m_lKey2Commands.find(aKey); + if (pKey == m_lKey2Commands.end()) + return; + + // get its registered command + // Because we must know its place inside the optimized + // structure, which bind keys to commands, too! + ::rtl::OUString sCommand = pKey->second; + pKey = m_lKey2Commands.end(); // nobody should use an undefined value .-) + + // remove key from primary list + m_lKey2Commands.erase(aKey); + + // remove key from optimized command list + m_lCommand2Keys.erase(sCommand); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void AcceleratorCache::removeCommand(const ::rtl::OUString& sCommand) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + const TKeyList& lKeys = getKeysByCommand(sCommand); + AcceleratorCache::TKeyList::const_iterator pKey ; + for ( pKey = lKeys.begin(); + pKey != lKeys.end() ; + ++pKey ) + { + const css::awt::KeyEvent& rKey = *pKey; + removeKey(rKey); + } + m_lCommand2Keys.erase(sCommand); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +} // namespace framework diff --git a/framework/source/accelerators/acceleratorconfiguration.cxx b/framework/source/accelerators/acceleratorconfiguration.cxx new file mode 100644 index 000000000000..43772f5c4273 --- /dev/null +++ b/framework/source/accelerators/acceleratorconfiguration.cxx @@ -0,0 +1,1717 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include <accelerators/acceleratorconfiguration.hxx> + +//_______________________________________________ +// own includes +#include <pattern/configuration.hxx> +#include <accelerators/presethandler.hxx> + +#include <xml/saxnamespacefilter.hxx> +#include <xml/acceleratorconfigurationreader.hxx> +#include <xml/acceleratorconfigurationwriter.hxx> + +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> + +#include <acceleratorconst.h> +#include <services.h> + +//_______________________________________________ +// interface includes +#include <com/sun/star/xml/sax/XParser.hpp> +#include <com/sun/star/xml/sax/InputSource.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +//_______________________________________________ +// other includes +#include <vcl/svapp.hxx> + +#ifndef _COM_SUN_STAR_CONTAINER_XNAMED_HPP_ +#include <com/sun/star/container/XNamed.hpp> +#endif + +#ifndef _COM_SUN_STAR_CONTAINER_XNAMECONTAINER_HPP_ +#include <com/sun/star/container/XNameContainer.hpp> +#endif + +#ifndef __COM_SUN_STAR_AWT_KEYEVENT_HPP_ +#include <com/sun/star/awt/KeyEvent.hpp> +#endif + +#ifndef __COM_SUN_STAR_AWT_KEYMODIFIER_HPP_ +#include <com/sun/star/awt/KeyModifier.hpp> +#endif + +#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_ +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#endif + +#ifndef _COM_SUN_STAR_UTIL_XCHANGESNOTIFIER_HPP_ +#include <com/sun/star/util/XChangesNotifier.hpp> +#endif + +#ifndef _COMPHELPER_CONFIGURATIONHELPER_HXX_ +#include <comphelper/configurationhelper.hxx> +#endif + +#ifndef UNOTOOLS_CONFIGPATHES_HXX_INCLUDED +#include <unotools/configpathes.hxx> +#endif + +#ifndef _RTL_LOGFILE_HXX_ +#include <rtl/logfile.hxx> +#endif + +#include <svtools/acceleratorexecute.hxx> + +#include <stdio.h> + +//_______________________________________________ +// const + +namespace framework +{ + +#ifdef fpc + #error "Who exports this define? I use it as namespace alias ..." +#else + namespace fpc = ::framework::pattern::configuration; +#endif + + ::rtl::OUString lcl_getKeyString(salhelper::SingletonRef<framework::KeyMapping>& _rKeyMapping, const css::awt::KeyEvent& aKeyEvent) + { + const sal_Int32 nBeginIndex = 4; // "KEY_" is the prefix of a identifier... + ::rtl::OUStringBuffer sKeyBuffer((_rKeyMapping->mapCodeToIdentifier(aKeyEvent.KeyCode)).copy(nBeginIndex)); + + if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::SHIFT) == css::awt::KeyModifier::SHIFT ) + sKeyBuffer.appendAscii("_SHIFT"); + if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD1 ) == css::awt::KeyModifier::MOD1 ) + sKeyBuffer.appendAscii("_MOD1"); + if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD2 ) == css::awt::KeyModifier::MOD2 ) + sKeyBuffer.appendAscii("_MOD2"); + if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD3 ) == css::awt::KeyModifier::MOD3 ) + sKeyBuffer.appendAscii("_MOD3"); + + return sKeyBuffer.makeStringAndClear(); + } + +//----------------------------------------------- +// XInterface, XTypeProvider +DEFINE_XINTERFACE_6(XMLBasedAcceleratorConfiguration , + OWeakObject , + DIRECT_INTERFACE(css::lang::XTypeProvider ), + DIRECT_INTERFACE(css::ui::XAcceleratorConfiguration ), + DIRECT_INTERFACE(css::form::XReset ), + DIRECT_INTERFACE(css::ui::XUIConfigurationPersistence), + DIRECT_INTERFACE(css::ui::XUIConfigurationStorage ), + DIRECT_INTERFACE(css::ui::XUIConfiguration )) + +DEFINE_XTYPEPROVIDER_6(XMLBasedAcceleratorConfiguration , + css::lang::XTypeProvider , + css::ui::XAcceleratorConfiguration , + css::form::XReset , + css::ui::XUIConfigurationPersistence, + css::ui::XUIConfigurationStorage , + css::ui::XUIConfiguration ) + +//----------------------------------------------- +XMLBasedAcceleratorConfiguration::XMLBasedAcceleratorConfiguration(const css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR) + : ThreadHelpBase (&Application::GetSolarMutex()) + , m_xSMGR (xSMGR ) + , m_aPresetHandler(xSMGR ) + , m_pWriteCache (0 ) +{ +} + +//----------------------------------------------- +XMLBasedAcceleratorConfiguration::~XMLBasedAcceleratorConfiguration() +{ + LOG_ASSERT(!m_pWriteCache, "XMLBasedAcceleratorConfiguration::~XMLBasedAcceleratorConfiguration()\nChanges not flushed. Ignore it ...") +} + +//----------------------------------------------- +css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XMLBasedAcceleratorConfiguration::getAllKeyEvents() + throw(css::uno::RuntimeException) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + AcceleratorCache& rCache = impl_getCFG(); + AcceleratorCache::TKeyList lKeys = rCache.getAllKeys(); + return lKeys.getAsConstList(); + + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +::rtl::OUString SAL_CALL XMLBasedAcceleratorConfiguration::getCommandByKeyEvent(const css::awt::KeyEvent& aKeyEvent) + throw(css::container::NoSuchElementException, + css::uno::RuntimeException ) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + AcceleratorCache& rCache = impl_getCFG(); + if (!rCache.hasKey(aKeyEvent)) + throw css::container::NoSuchElementException( + ::rtl::OUString(), + static_cast< ::cppu::OWeakObject* >(this)); + return rCache.getCommandByKey(aKeyEvent); + + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::setKeyEvent(const css::awt::KeyEvent& aKeyEvent, + const ::rtl::OUString& sCommand ) + throw(css::lang::IllegalArgumentException, + css::uno::RuntimeException ) +{ + if ( + (aKeyEvent.KeyCode == 0) && + (aKeyEvent.KeyChar == 0) && + (aKeyEvent.KeyFunc == 0) && + (aKeyEvent.Modifiers == 0) + ) + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Such key event seams not to be supported by any operating system."), + static_cast< ::cppu::OWeakObject* >(this), + 0); + + if (!sCommand.getLength()) + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Empty command strings are not allowed here."), + static_cast< ::cppu::OWeakObject* >(this), + 1); + + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + AcceleratorCache& rCache = impl_getCFG(sal_True); // TRUE => force getting of a writeable cache! + rCache.setKeyCommandPair(aKeyEvent, sCommand); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::removeKeyEvent(const css::awt::KeyEvent& aKeyEvent) +throw(css::container::NoSuchElementException, + css::uno::RuntimeException ) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + AcceleratorCache& rCache = impl_getCFG(sal_True); // true => force using of a writeable cache + if (!rCache.hasKey(aKeyEvent)) + throw css::container::NoSuchElementException( + ::rtl::OUString(), + static_cast< ::cppu::OWeakObject* >(this)); + rCache.removeKey(aKeyEvent); + + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XMLBasedAcceleratorConfiguration::getKeyEventsByCommand(const ::rtl::OUString& sCommand) + throw(css::lang::IllegalArgumentException , + css::container::NoSuchElementException, + css::uno::RuntimeException ) +{ + if (!sCommand.getLength()) + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Empty command strings are not allowed here."), + static_cast< ::cppu::OWeakObject* >(this), + 1); + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + AcceleratorCache& rCache = impl_getCFG(); + if (!rCache.hasCommand(sCommand)) + throw css::container::NoSuchElementException( + ::rtl::OUString(), + static_cast< ::cppu::OWeakObject* >(this)); + + AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(sCommand); + return lKeys.getAsConstList(); + + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +css::uno::Sequence< css::uno::Any > SAL_CALL XMLBasedAcceleratorConfiguration::getPreferredKeyEventsForCommandList(const css::uno::Sequence< ::rtl::OUString >& lCommandList) + throw(css::lang::IllegalArgumentException , + css::uno::RuntimeException ) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + sal_Int32 i = 0; + sal_Int32 c = lCommandList.getLength(); + css::uno::Sequence< css::uno::Any > lPreferredOnes (c); // dont pack list! + AcceleratorCache& rCache = impl_getCFG(); + + for (i=0; i<c; ++i) + { + const ::rtl::OUString& rCommand = lCommandList[i]; + if (!rCommand.getLength()) + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Empty command strings are not allowed here."), + static_cast< ::cppu::OWeakObject* >(this), + (sal_Int16)i); + + if (!rCache.hasCommand(rCommand)) + continue; + + AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(rCommand); + if ( lKeys.empty() ) + continue; + + css::uno::Any& rAny = lPreferredOnes[i]; + rAny <<= *(lKeys.begin()); + } + + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + return lPreferredOnes; +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::removeCommandFromAllKeyEvents(const ::rtl::OUString& sCommand) + throw(css::lang::IllegalArgumentException , + css::container::NoSuchElementException, + css::uno::RuntimeException ) +{ + if (!sCommand.getLength()) + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Empty command strings are not allowed here."), + static_cast< ::cppu::OWeakObject* >(this), + 0); + + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + AcceleratorCache& rCache = impl_getCFG(sal_True); // TRUE => force getting of a writeable cache! + if (!rCache.hasCommand(sCommand)) + throw css::container::NoSuchElementException( + ::rtl::OUString::createFromAscii("Command does not exists inside this container."), + static_cast< ::cppu::OWeakObject* >(this)); + rCache.removeCommand(sCommand); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::reload() + throw(css::uno::Exception , + css::uno::RuntimeException) +{ + css::uno::Reference< css::io::XStream > xStreamNoLang; + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::io::XStream > xStream = m_aPresetHandler.openTarget(PresetHandler::TARGET_CURRENT(), sal_True); // TRUE => open or create! + try + { + xStreamNoLang = m_aPresetHandler.openPreset(PresetHandler::PRESET_DEFAULT(), sal_True); + } + catch(const css::io::IOException&) {} // does not have to exist + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::io::XInputStream > xIn; + if (xStream.is()) + xIn = xStream->getInputStream(); + if (!xIn.is()) + throw css::io::IOException( + ::rtl::OUString::createFromAscii("Could not open accelerator configuration for reading."), + static_cast< ::cppu::OWeakObject* >(this)); + + // impl_ts_load() does not clear the cache + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + m_aReadCache = AcceleratorCache(); + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + impl_ts_load(xIn); + + // Load also the general language independent default accelerators + // (ignoring the already defined accelerators) + if (xStreamNoLang.is()) + { + xIn = xStreamNoLang->getInputStream(); + if (xIn.is()) + impl_ts_load(xIn); + } +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::store() + throw(css::uno::Exception , + css::uno::RuntimeException) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::io::XStream > xStream = m_aPresetHandler.openTarget(PresetHandler::TARGET_CURRENT(), sal_True); // TRUE => open or create! + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::io::XOutputStream > xOut; + if (xStream.is()) + xOut = xStream->getOutputStream(); + + if (!xOut.is()) + throw css::io::IOException( + ::rtl::OUString::createFromAscii("Could not open accelerator configuration for saving."), + static_cast< ::cppu::OWeakObject* >(this)); + + impl_ts_save(xOut); + + xOut.clear(); + xStream.clear(); + + m_aPresetHandler.commitUserChanges(); +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::storeToStorage(const css::uno::Reference< css::embed::XStorage >& xStorage) + throw(css::uno::Exception , + css::uno::RuntimeException) +{ + css::uno::Reference< css::io::XStream > xStream = StorageHolder::openSubStreamWithFallback( + xStorage, + PresetHandler::TARGET_CURRENT(), + css::embed::ElementModes::READWRITE, + sal_False); // False => no fallback from read/write to readonly! + css::uno::Reference< css::io::XOutputStream > xOut; + if (xStream.is()) + xOut = xStream->getOutputStream(); + + if (!xOut.is()) + throw css::io::IOException( + ::rtl::OUString::createFromAscii("Could not open accelerator configuration for saving."), + static_cast< ::cppu::OWeakObject* >(this)); + + impl_ts_save(xOut); + + // TODO inform listener about success, so it can flush the root and sub storage of this stream! +} + +//----------------------------------------------- +::sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::isModified() + throw(css::uno::RuntimeException) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + return (m_pWriteCache != 0); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +::sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::isReadOnly() + throw(css::uno::RuntimeException) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::io::XStream > xStream = m_aPresetHandler.openTarget(PresetHandler::TARGET_CURRENT(), sal_True); // TRUE => open or create! + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::io::XOutputStream > xOut; + if (xStream.is()) + xOut = xStream->getOutputStream(); + return !(xOut.is()); +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& /*xStorage*/) + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XMLBasedAcceleratorConfiguration::setStorage()", "TODO implement this HACK .-)") +} + +//----------------------------------------------- +::sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::hasStorage() + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XMLBasedAcceleratorConfiguration::hasStorage()", "TODO implement this HACK .-)") + return sal_False; +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::addConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/) + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XMLBasedAcceleratorConfiguration::addConfigurationListener()", "TODO implement me") +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::removeConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/) + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XMLBasedAcceleratorConfiguration::removeConfigurationListener()", "TODO implement me") +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::reset() +throw(css::uno::RuntimeException) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + m_aPresetHandler.copyPresetToTarget(PresetHandler::PRESET_DEFAULT(), PresetHandler::TARGET_CURRENT()); + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + reload(); +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::addResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/) + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XMLBasedAcceleratorConfiguration::addResetListener()", "TODO implement me") +} + +//----------------------------------------------- +void SAL_CALL XMLBasedAcceleratorConfiguration::removeResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/) + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XMLBasedAcceleratorConfiguration::removeResetListener()", "TODO implement me") +} + +//----------------------------------------------- +// IStorageListener +void XMLBasedAcceleratorConfiguration::changesOccured(const ::rtl::OUString& /*sPath*/) +{ + reload(); +} + +//----------------------------------------------- +void XMLBasedAcceleratorConfiguration::impl_ts_load(const css::uno::Reference< css::io::XInputStream >& xStream) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + if (m_pWriteCache) + { + // be aware of reentrance problems - use temp variable for calling delete ... :-) + AcceleratorCache* pTemp = m_pWriteCache; + m_pWriteCache = 0; + delete pTemp; + } + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY); + if (xSeek.is()) + xSeek->seek(0); + + // add accelerators to the cache (the cache is not cleared) + // SAFE -> ---------------------------------- + aWriteLock.lock(); + + // create the parser queue + // Note: Use special filter object between parser and reader + // to get filtered xml with right namespaces ... + // Use further a temp cache for reading! + AcceleratorConfigurationReader* pReader = new AcceleratorConfigurationReader(m_aReadCache); + css::uno::Reference< css::xml::sax::XDocumentHandler > xReader (static_cast< ::cppu::OWeakObject* >(pReader), css::uno::UNO_QUERY_THROW); + SaxNamespaceFilter* pFilter = new SaxNamespaceFilter(xReader); + css::uno::Reference< css::xml::sax::XDocumentHandler > xFilter (static_cast< ::cppu::OWeakObject* >(pFilter), css::uno::UNO_QUERY_THROW); + + // connect parser, filter and stream + css::uno::Reference< css::xml::sax::XParser > xParser(xSMGR->createInstance(SERVICENAME_SAXPARSER), css::uno::UNO_QUERY_THROW); + xParser->setDocumentHandler(xFilter); + + css::xml::sax::InputSource aSource; + aSource.aInputStream = xStream; + + // TODO think about error handling + xParser->parseStream(aSource); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void XMLBasedAcceleratorConfiguration::impl_ts_save(const css::uno::Reference< css::io::XOutputStream >& xStream) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + AcceleratorCache aCache; + sal_Bool bChanged = (m_pWriteCache != 0); + if (bChanged) + aCache.takeOver(*m_pWriteCache); + else + aCache.takeOver(m_aReadCache); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::io::XTruncate > xClearable(xStream, css::uno::UNO_QUERY_THROW); + xClearable->truncate(); + + // TODO can be removed if seek(0) is done by truncate() automaticly! + css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY); + if (xSeek.is()) + xSeek->seek(0); + + // combine writer/cache/stream etcpp. + css::uno::Reference< css::xml::sax::XDocumentHandler > xWriter (xSMGR->createInstance(SERVICENAME_SAXWRITER), css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::io::XActiveDataSource> xDataSource(xWriter , css::uno::UNO_QUERY_THROW); + xDataSource->setOutputStream(xStream); + + // write into the stream + AcceleratorConfigurationWriter aWriter(aCache, xWriter); + aWriter.flush(); + + // take over all changes into the original container + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + // take over all changes into the readonly cache ... + // and forget the copy-on-write copied cache + if (bChanged) + { + m_aReadCache.takeOver(*m_pWriteCache); + // live with reentrance .-) + AcceleratorCache* pTemp = m_pWriteCache; + m_pWriteCache = 0; + delete pTemp; + } + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +AcceleratorCache& XMLBasedAcceleratorConfiguration::impl_getCFG(sal_Bool bWriteAccessRequested) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + //create copy of our readonly-cache, if write access is forced ... but + //not still possible! + if ( + (bWriteAccessRequested) && + (!m_pWriteCache ) + ) + { + m_pWriteCache = new AcceleratorCache(m_aReadCache); + } + + // in case, we have a writeable cache, we use it for reading too! + // Otherwhise the API user cant find its own changes ... + if (m_pWriteCache) + return *m_pWriteCache; + else + return m_aReadCache; + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +::comphelper::Locale XMLBasedAcceleratorConfiguration::impl_ts_getLocale() const +{ + static ::rtl::OUString LOCALE_PACKAGE = ::rtl::OUString::createFromAscii("/org.openoffice.Setup"); + static ::rtl::OUString LOCALE_PATH = ::rtl::OUString::createFromAscii("L10N" ); + static ::rtl::OUString LOCALE_KEY = ::rtl::OUString::createFromAscii("ooLocale" ); + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::uno::XInterface > xCFG = fpc::ConfigurationHelper::openConfig(xSMGR, LOCALE_PACKAGE, LOCALE_PATH, fpc::ConfigurationHelper::E_READONLY); + css::uno::Reference< css::beans::XPropertySet > xProp (xCFG, css::uno::UNO_QUERY_THROW); + ::rtl::OUString sISOLocale; + xProp->getPropertyValue(LOCALE_KEY) >>= sISOLocale; + + if (!sISOLocale.getLength()) + return ::comphelper::Locale::EN_US(); + return ::comphelper::Locale(sISOLocale); +} + +/******************************************************************************* +* +* XCU based accelerator configuration +* +*******************************************************************************/ + +//----------------------------------------------- +// XInterface, XTypeProvider +DEFINE_XINTERFACE_7(XCUBasedAcceleratorConfiguration , + OWeakObject , + DIRECT_INTERFACE(css::lang::XTypeProvider ), + DIRECT_INTERFACE(css::ui::XAcceleratorConfiguration ), + DIRECT_INTERFACE(css::util::XChangesListener ), + DIRECT_INTERFACE(css::form::XReset ), + DIRECT_INTERFACE(css::ui::XUIConfigurationPersistence), + DIRECT_INTERFACE(css::ui::XUIConfigurationStorage ), + DIRECT_INTERFACE(css::ui::XUIConfiguration )) + + DEFINE_XTYPEPROVIDER_7(XCUBasedAcceleratorConfiguration , + css::lang::XTypeProvider , + css::ui::XAcceleratorConfiguration , + css::util::XChangesListener , + css::form::XReset , + css::ui::XUIConfigurationPersistence, + css::ui::XUIConfigurationStorage , + css::ui::XUIConfiguration ) + +//----------------------------------------------- +XCUBasedAcceleratorConfiguration::XCUBasedAcceleratorConfiguration(const css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR) + : ThreadHelpBase (&Application::GetSolarMutex()) + , m_xSMGR (xSMGR ) + , m_pPrimaryWriteCache(0 ) + , m_pSecondaryWriteCache(0 ) +{ + static const ::rtl::OUString CFG_ENTRY_ACCELERATORS(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.Office.Accelerators")); + m_xCfg = css::uno::Reference< css::container::XNameAccess > ( + ::comphelper::ConfigurationHelper::openConfig( m_xSMGR, CFG_ENTRY_ACCELERATORS, ::comphelper::ConfigurationHelper::E_ALL_LOCALES ), + css::uno::UNO_QUERY ); +} + +//----------------------------------------------- +XCUBasedAcceleratorConfiguration::~XCUBasedAcceleratorConfiguration() +{ +} + +//----------------------------------------------- +css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getAllKeyEvents() + throw(css::uno::RuntimeException) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + AcceleratorCache::TKeyList lKeys = impl_getCFG(sal_True).getAllKeys(); //get keys from PrimaryKeys set + + AcceleratorCache::TKeyList lSecondaryKeys = impl_getCFG(sal_False).getAllKeys(); //get keys from SecondaryKeys set + lKeys.reserve(lKeys.size()+lSecondaryKeys.size()); + AcceleratorCache::TKeyList::const_iterator pIt; + AcceleratorCache::TKeyList::const_iterator pEnd = lSecondaryKeys.end(); + for ( pIt = lSecondaryKeys.begin(); pIt != pEnd; ++pIt ) + lKeys.push_back(*pIt); + + return lKeys.getAsConstList(); + + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +::rtl::OUString SAL_CALL XCUBasedAcceleratorConfiguration::getCommandByKeyEvent(const css::awt::KeyEvent& aKeyEvent) + throw(css::container::NoSuchElementException, + css::uno::RuntimeException ) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + AcceleratorCache& rPrimaryCache = impl_getCFG(sal_True ); + AcceleratorCache& rSecondaryCache = impl_getCFG(sal_False); + + if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent)) + throw css::container::NoSuchElementException( + ::rtl::OUString(), + static_cast< ::cppu::OWeakObject* >(this)); + + if (rPrimaryCache.hasKey(aKeyEvent)) + return rPrimaryCache.getCommandByKey(aKeyEvent); + else + return rSecondaryCache.getCommandByKey(aKeyEvent); + + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::setKeyEvent(const css::awt::KeyEvent& aKeyEvent, + const ::rtl::OUString& sCommand ) + throw(css::lang::IllegalArgumentException, + css::uno::RuntimeException ) +{ + RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "XCUBasedAcceleratorConfiguration::setKeyEvent" ); + + if ( + (aKeyEvent.KeyCode == 0) && + (aKeyEvent.KeyChar == 0) && + (aKeyEvent.KeyFunc == 0) && + (aKeyEvent.Modifiers == 0) + ) + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Such key event seams not to be supported by any operating system."), + static_cast< ::cppu::OWeakObject* >(this), + 0); + + if (!sCommand.getLength()) + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Empty command strings are not allowed here."), + static_cast< ::cppu::OWeakObject* >(this), + 1); + + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + AcceleratorCache& rPrimaryCache = impl_getCFG(sal_True, sal_True ); // TRUE => force getting of a writeable cache! + AcceleratorCache& rSecondaryCache = impl_getCFG(sal_False, sal_True); // TRUE => force getting of a writeable cache! + + if ( rPrimaryCache.hasKey(aKeyEvent) ) + { + ::rtl::OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent); + if ( sCommand != sOriginalCommand ) + { + if (rSecondaryCache.hasCommand(sOriginalCommand)) + { + AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand); + rSecondaryCache.removeKey(lSecondaryKeys[0]); + rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand); + } + + if (rPrimaryCache.hasCommand(sCommand)) + { + AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand); + rPrimaryCache.removeKey(lPrimaryKeys[0]); + rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand); + } + + rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand); + } + } + + else if ( rSecondaryCache.hasKey(aKeyEvent) ) + { + ::rtl::OUString sOriginalCommand = rSecondaryCache.getCommandByKey(aKeyEvent); + if (sCommand != sOriginalCommand) + { + if (rPrimaryCache.hasCommand(sCommand)) + { + AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand); + rPrimaryCache.removeKey(lPrimaryKeys[0]); + rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand); + } + + rSecondaryCache.removeKey(aKeyEvent); + rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand); + } + } + + else + { + if (rPrimaryCache.hasCommand(sCommand)) + { + AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand); + rPrimaryCache.removeKey(lPrimaryKeys[0]); + rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand); + } + + rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand); + } + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::removeKeyEvent(const css::awt::KeyEvent& aKeyEvent) + throw(css::container::NoSuchElementException, + css::uno::RuntimeException ) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + AcceleratorCache& rPrimaryCache = impl_getCFG(sal_True, sal_True ); + AcceleratorCache& rSecondaryCache = impl_getCFG(sal_False, sal_True); + + if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent)) + throw css::container::NoSuchElementException( + ::rtl::OUString(), + static_cast< ::cppu::OWeakObject* >(this)); + + if (rPrimaryCache.hasKey(aKeyEvent)) + { + ::rtl::OUString sDelCommand = rPrimaryCache.getCommandByKey(aKeyEvent); + if (sDelCommand.getLength() > 0) + { + ::rtl::OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent); + if (rSecondaryCache.hasCommand(sOriginalCommand)) + { + AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand); + rSecondaryCache.removeKey(lSecondaryKeys[0]); + rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand); + } + + rPrimaryCache.removeKey(aKeyEvent); + } + + } + else + { + ::rtl::OUString sDelCommand = rSecondaryCache.getCommandByKey(aKeyEvent); + if (sDelCommand.getLength() > 0) + rSecondaryCache.removeKey(aKeyEvent); + } + + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getKeyEventsByCommand(const ::rtl::OUString& sCommand) + throw(css::lang::IllegalArgumentException , + css::container::NoSuchElementException, + css::uno::RuntimeException ) +{ + if (!sCommand.getLength()) + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Empty command strings are not allowed here."), + static_cast< ::cppu::OWeakObject* >(this), + 1); + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + AcceleratorCache& rPrimaryCache = impl_getCFG(sal_True ); + AcceleratorCache& rSecondaryCache = impl_getCFG(sal_False); + + if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand)) + throw css::container::NoSuchElementException( + ::rtl::OUString(), + static_cast< ::cppu::OWeakObject* >(this)); + + AcceleratorCache::TKeyList lKeys = rPrimaryCache.getKeysByCommand(sCommand); + + AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sCommand); + AcceleratorCache::TKeyList::const_iterator pIt; + for (pIt = lSecondaryKeys.begin(); pIt != lSecondaryKeys.end(); ++pIt) + lKeys.push_back(*pIt); + + return lKeys.getAsConstList(); + + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +AcceleratorCache::TKeyList::const_iterator lcl_getPreferredKey(const AcceleratorCache::TKeyList& lKeys) +{ + AcceleratorCache::TKeyList::const_iterator pIt; + for ( pIt = lKeys.begin (); + pIt != lKeys.end (); + ++pIt ) + { + const css::awt::KeyEvent& rAWTKey = *pIt; + const KeyCode aVCLKey = ::svt::AcceleratorExecute::st_AWTKey2VCLKey(rAWTKey); + const String sName = aVCLKey.GetName(); + + if (sName.Len () > 0) + return pIt; + } + + return lKeys.end (); +} + +//----------------------------------------------- +css::uno::Sequence< css::uno::Any > SAL_CALL XCUBasedAcceleratorConfiguration::getPreferredKeyEventsForCommandList(const css::uno::Sequence< ::rtl::OUString >& lCommandList) + throw(css::lang::IllegalArgumentException , + css::uno::RuntimeException ) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + sal_Int32 i = 0; + sal_Int32 c = lCommandList.getLength(); + css::uno::Sequence< css::uno::Any > lPreferredOnes (c); // dont pack list! + AcceleratorCache& rCache = impl_getCFG(sal_True); + + for (i=0; i<c; ++i) + { + const ::rtl::OUString& rCommand = lCommandList[i]; + if (!rCommand.getLength()) + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Empty command strings are not allowed here."), + static_cast< ::cppu::OWeakObject* >(this), + (sal_Int16)i); + + if (!rCache.hasCommand(rCommand)) + continue; + + AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(rCommand); + if ( lKeys.empty() ) + continue; + + AcceleratorCache::TKeyList::const_iterator pPreferredKey = lcl_getPreferredKey(lKeys); + if (pPreferredKey != lKeys.end ()) + { + css::uno::Any& rAny = lPreferredOnes[i]; + rAny <<= *(pPreferredKey); + } + } + + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + return lPreferredOnes; +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::removeCommandFromAllKeyEvents(const ::rtl::OUString& sCommand) + throw(css::lang::IllegalArgumentException , + css::container::NoSuchElementException, + css::uno::RuntimeException ) +{ + if (!sCommand.getLength()) + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Empty command strings are not allowed here."), + static_cast< ::cppu::OWeakObject* >(this), + 0); + + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + AcceleratorCache& rPrimaryCache = impl_getCFG(sal_True, sal_True ); + AcceleratorCache& rSecondaryCache = impl_getCFG(sal_False, sal_True); + + if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand)) + throw css::container::NoSuchElementException( + ::rtl::OUString::createFromAscii("Command does not exists inside this container."), + static_cast< ::cppu::OWeakObject* >(this)); + + if (rPrimaryCache.hasCommand(sCommand)) + rPrimaryCache.removeCommand(sCommand); + if (rSecondaryCache.hasCommand(sCommand)) + rSecondaryCache.removeCommand(sCommand); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::reload() + throw(css::uno::Exception , + css::uno::RuntimeException) +{ + RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "XCUBasedAcceleratorConfiguration::reload()" ); + + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + sal_Bool bPreferred; + css::uno::Reference< css::container::XNameAccess > xAccess; + + bPreferred = sal_True; + m_aPrimaryReadCache = AcceleratorCache(); + if (m_pPrimaryWriteCache) + { + // be aware of reentrance problems - use temp variable for calling delete ... :-) + AcceleratorCache* pTemp = m_pPrimaryWriteCache; + m_pPrimaryWriteCache = 0; + delete pTemp; + } + m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess; + impl_ts_load(bPreferred, xAccess); // load the preferred keys + + bPreferred = sal_False; + m_aSecondaryReadCache = AcceleratorCache(); + if (m_pSecondaryWriteCache) + { + // be aware of reentrance problems - use temp variable for calling delete ... :-) + AcceleratorCache* pTemp = m_pSecondaryWriteCache; + m_pSecondaryWriteCache = 0; + delete pTemp; + } + m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess; + impl_ts_load(bPreferred, xAccess); // load the secondary keys + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::store() + throw(css::uno::Exception , + css::uno::RuntimeException) +{ + RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "XCUBasedAcceleratorConfiguration::store()" ); + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + sal_Bool bPreferred; + css::uno::Reference< css::container::XNameAccess > xAccess; + + bPreferred = sal_True; + // on-demand creation of the primary write cache + impl_getCFG(bPreferred, sal_True); + m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess; + impl_ts_save(bPreferred, xAccess); + + bPreferred = sal_False; + // on-demand creation of the secondary write cache + impl_getCFG(bPreferred, sal_True); + m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess; + impl_ts_save(bPreferred, xAccess); + + aReadLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::storeToStorage(const css::uno::Reference< css::embed::XStorage >& xStorage) + throw(css::uno::Exception , + css::uno::RuntimeException) +{ + // use m_aCache + old AcceleratorXMLWriter to store data directly on storage given as parameter ... + if (!xStorage.is()) + return; + + long nOpenModes = css::embed::ElementModes::READWRITE; + css::uno::Reference< css::embed::XStorage > xAcceleratorTypeStorage = xStorage->openStorageElement(::rtl::OUString::createFromAscii("accelerator"), nOpenModes); + if (!xAcceleratorTypeStorage.is()) + return; + + css::uno::Reference< css::io::XStream > xStream = xAcceleratorTypeStorage->openStreamElement(::rtl::OUString::createFromAscii("current"), nOpenModes); + css::uno::Reference< css::io::XOutputStream > xOut; + if (xStream.is()) + xOut = xStream->getOutputStream(); + if (!xOut.is()) + throw css::io::IOException( + ::rtl::OUString::createFromAscii("Could not open accelerator configuration for saving."), + static_cast< ::cppu::OWeakObject* >(this)); + + // the original m_aCache has been split into primay cache and secondary cache... + // we should merge them before storing to storage + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + AcceleratorCache aCache; + if (m_pPrimaryWriteCache != 0) + aCache.takeOver(*m_pPrimaryWriteCache); + else + aCache.takeOver(m_aPrimaryReadCache); + + AcceleratorCache::TKeyList lKeys; + AcceleratorCache::TKeyList::const_iterator pIt; + if (m_pSecondaryWriteCache!=0) + { + lKeys = m_pSecondaryWriteCache->getAllKeys(); + for ( pIt=lKeys.begin(); pIt!=lKeys.end(); ++pIt ) + aCache.setKeyCommandPair(*pIt, m_pSecondaryWriteCache->getCommandByKey(*pIt)); + } + else + { + lKeys = m_aSecondaryReadCache.getAllKeys(); + for ( pIt=lKeys.begin(); pIt!=lKeys.end(); ++pIt ) + aCache.setKeyCommandPair(*pIt, m_aSecondaryReadCache.getCommandByKey(*pIt)); + } + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::io::XTruncate > xClearable(xOut, css::uno::UNO_QUERY_THROW); + xClearable->truncate(); + css::uno::Reference< css::io::XSeekable > xSeek(xOut, css::uno::UNO_QUERY); + if (xSeek.is()) + xSeek->seek(0); + + css::uno::Reference< css::xml::sax::XDocumentHandler > xWriter (m_xSMGR->createInstance(SERVICENAME_SAXWRITER), css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::io::XActiveDataSource> xDataSource(xWriter , css::uno::UNO_QUERY_THROW); + xDataSource->setOutputStream(xOut); + + // write into the stream + AcceleratorConfigurationWriter aWriter(aCache, xWriter); + aWriter.flush(); +} + +//----------------------------------------------- +::sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isModified() + throw(css::uno::RuntimeException) +{ + return sal_False; +} + +//----------------------------------------------- +::sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isReadOnly() + throw(css::uno::RuntimeException) +{ + return sal_False; +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& /*xStorage*/) + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XCUBasedAcceleratorConfiguration::setStorage()", "TODO implement this HACK .-)") +} + +//----------------------------------------------- +::sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::hasStorage() + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XCUBasedAcceleratorConfiguration::hasStorage()", "TODO implement this HACK .-)") + return sal_False; +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::addConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/) + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XCUBasedAcceleratorConfiguration::addConfigurationListener()", "TODO implement me") +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::removeConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/) + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XCUBasedAcceleratorConfiguration::removeConfigurationListener()", "TODO implement me") +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::reset() + throw(css::uno::RuntimeException) +{ + css::uno::Reference< css::container::XNamed > xNamed(m_xCfg, css::uno::UNO_QUERY); + ::rtl::OUString sConfig = xNamed->getName(); + if ( sConfig.equalsAscii("Global") ) + { + m_xCfg = css::uno::Reference< css::container::XNameAccess > ( + ::comphelper::ConfigurationHelper::openConfig( m_xSMGR, CFG_ENTRY_GLOBAL, ::comphelper::ConfigurationHelper::E_ALL_LOCALES ), + css::uno::UNO_QUERY ); + XCUBasedAcceleratorConfiguration::reload(); + } + else if ( sConfig.equalsAscii("Modules") ) + { + m_xCfg = css::uno::Reference< css::container::XNameAccess > ( + ::comphelper::ConfigurationHelper::openConfig( m_xSMGR, CFG_ENTRY_MODULES, ::comphelper::ConfigurationHelper::E_ALL_LOCALES ), + css::uno::UNO_QUERY ); + XCUBasedAcceleratorConfiguration::reload(); + } +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::addResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/) + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XCUBasedAcceleratorConfiguration::addResetListener()", "TODO implement me") +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::removeResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/) + throw(css::uno::RuntimeException) +{ + LOG_WARNING("XCUBasedAcceleratorConfiguration::removeResetListener()", "TODO implement me") +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::changesOccurred(const css::util::ChangesEvent& aEvent) + throw(css::uno::RuntimeException) +{ + RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "XCUBasedAcceleratorConfiguration::changesOccurred()" ); + + css::uno::Reference< css::container::XHierarchicalNameAccess > xHAccess; + aEvent.Base >>= xHAccess; + if (! xHAccess.is ()) + return; + + css::util::ChangesEvent aReceivedEvents( aEvent ); + const sal_Int32 c = aReceivedEvents.Changes.getLength(); + sal_Int32 i = 0; + for (i=0; i<c; ++i) + { + const css::util::ElementChange& aChange = aReceivedEvents.Changes[i]; + + // Only path of form "PrimaryKeys/Modules/Module['<module_name>']/Key['<command_url>']/Command[<locale>]" will + // be interesting for use. Sometimes short path values are given also by the broadcaster ... but they must be ignored :-) + // So we try to split the path into 3 parts (module isnt important here, because we already know it ... because + // these instance is bound to a specific module configuration ... or it''s the global configuration where no module is given at all. + + ::rtl::OUString sOrgPath ; + ::rtl::OUString sPath ; + ::rtl::OUString sKey; + + aChange.Accessor >>= sOrgPath; + sPath = sOrgPath; + ::rtl::OUString sPrimarySecondary = ::utl::extractFirstFromConfigurationPath(sPath, &sPath); + ::rtl::OUString sGlobalModules = ::utl::extractFirstFromConfigurationPath(sPath, &sPath); + + if ( sGlobalModules.equals(CFG_ENTRY_GLOBAL) ) + { + ::rtl::OUString sModule; + sKey = ::utl::extractFirstFromConfigurationPath(sPath, &sPath); + if (( sKey.getLength() > 0 ) && ( sPath.getLength() > 0 )) + reloadChanged(sPrimarySecondary, sGlobalModules, sModule, sKey); + } + else if ( sGlobalModules.equals(CFG_ENTRY_MODULES) ) + { + ::rtl::OUString sModule = ::utl::extractFirstFromConfigurationPath(sPath, &sPath); + sKey = ::utl::extractFirstFromConfigurationPath(sPath, &sPath); + + if (( sKey.getLength() > 0 ) && ( sPath.getLength() > 0 )) + { + reloadChanged(sPrimarySecondary, sGlobalModules, sModule, sKey); + } + } + } +} + +//----------------------------------------------- +void SAL_CALL XCUBasedAcceleratorConfiguration::disposing(const css::lang::EventObject& /*aSource*/) + throw(css::uno::RuntimeException) +{ +} + +//----------------------------------------------- +void XCUBasedAcceleratorConfiguration::impl_ts_load( sal_Bool bPreferred, const css::uno::Reference< css::container::XNameAccess >& xCfg ) +{ + AcceleratorCache aReadCache = AcceleratorCache(); + css::uno::Reference< css::container::XNameAccess > xAccess; + if (m_sGlobalOrModules.equalsAscii("Global")) + xCfg->getByName(CFG_ENTRY_GLOBAL) >>= xAccess; + else if (m_sGlobalOrModules.equalsAscii("Modules")) + { + css::uno::Reference< css::container::XNameAccess > xModules; + xCfg->getByName(CFG_ENTRY_MODULES) >>= xModules; + xModules->getByName(m_sModuleCFG) >>= xAccess; + } + + const ::rtl::OUString sIsoLang = impl_ts_getLocale().toISO(); + const ::rtl::OUString sDefaultLocale = ::rtl::OUString::createFromAscii("en-US"); + + css::uno::Reference< css::container::XNameAccess > xKey; + css::uno::Reference< css::container::XNameAccess > xCommand; + if (xAccess.is()) + { + css::uno::Sequence< ::rtl::OUString > lKeys = xAccess->getElementNames(); + sal_Int32 nKeys = lKeys.getLength(); + for ( sal_Int32 i=0; i<nKeys; ++i ) + { + ::rtl::OUString sKey = lKeys[i]; + xAccess->getByName(sKey) >>= xKey; + xKey->getByName(CFG_PROP_COMMAND) >>= xCommand; + + css::uno::Sequence< ::rtl::OUString > lLocales = xCommand->getElementNames(); + sal_Int32 nLocales = lLocales.getLength(); + ::std::vector< ::rtl::OUString > aLocales; + for ( sal_Int32 j=0; j<nLocales; ++j ) + aLocales.push_back(lLocales[j]); + + ::std::vector< ::rtl::OUString >::const_iterator pFound; + for ( pFound = aLocales.begin(); pFound != aLocales.end(); ++pFound ) + { + if ( *pFound == sIsoLang ) + break; + } + + if ( pFound == aLocales.end() ) + { + for ( pFound = aLocales.begin(); pFound != aLocales.end(); ++pFound ) + { + if ( *pFound == sDefaultLocale ) + break; + } + + if ( pFound == aLocales.end() ) + continue; + } + + ::rtl::OUString sLocale = *pFound; + ::rtl::OUString sCommand; + xCommand->getByName(sLocale) >>= sCommand; + if (sCommand.getLength()<1) + continue; + + css::awt::KeyEvent aKeyEvent; + + sal_Int32 nIndex = 0; + ::rtl::OUString sKeyCommand = sKey.getToken(0, '_', nIndex); + ::rtl::OUString sPrefix = ::rtl::OUString::createFromAscii("KEY_"); + aKeyEvent.KeyCode = m_rKeyMapping->mapIdentifierToCode(sPrefix + sKeyCommand); + + css::uno::Sequence< ::rtl::OUString > sToken(4); + const sal_Int32 nToken = 4; + sal_Bool bValid = sal_True; + sal_Int32 k; + for (k=0; k<nToken; ++k) + { + if (nIndex < 0) + break; + + sToken[k] = sKey.getToken(0, '_', nIndex); + ::rtl::OUString sTest = sToken[k]; + if (sToken[k].getLength() < 1) + { + bValid = sal_False; + break; + } + + if (sToken[k].equalsAscii("SHIFT")) + aKeyEvent.Modifiers |= css::awt::KeyModifier::SHIFT; + else if (sToken[k].equalsAscii("MOD1")) + aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD1; + else if (sToken[k].equalsAscii("MOD2")) + aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD2; + else if (sToken[k].equalsAscii("MOD3")) + aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD3; + else + { + bValid = sal_False; + break; + } + } + + if ( !aReadCache.hasKey(aKeyEvent) && bValid && k<nToken) + aReadCache.setKeyCommandPair(aKeyEvent, sCommand); + } + } + + if (bPreferred) + m_aPrimaryReadCache.takeOver(aReadCache); + else + m_aSecondaryReadCache.takeOver(aReadCache); +} + +//----------------------------------------------- +void XCUBasedAcceleratorConfiguration::impl_ts_save(sal_Bool bPreferred, const css::uno::Reference< css::container::XNameAccess >& /*xCfg*/) +{ + if (bPreferred) + { + AcceleratorCache::TKeyList::const_iterator pIt; + AcceleratorCache::TKeyList lPrimaryReadKeys = m_aPrimaryReadCache.getAllKeys(); + AcceleratorCache::TKeyList lPrimaryWriteKeys = m_pPrimaryWriteCache->getAllKeys(); + + for ( pIt = lPrimaryReadKeys.begin(); pIt != lPrimaryReadKeys.end(); ++pIt ) + { + if (!m_pPrimaryWriteCache->hasKey(*pIt)) + removeKeyFromConfiguration(*pIt, sal_True); + } + + for ( pIt = lPrimaryWriteKeys.begin(); pIt != lPrimaryWriteKeys.end(); ++pIt ) + { + ::rtl::OUString sCommand = m_pPrimaryWriteCache->getCommandByKey(*pIt); + if (!m_aPrimaryReadCache.hasKey(*pIt)) + { + insertKeyToConfiguration(*pIt, sCommand, sal_True); + } + else + { + ::rtl::OUString sReadCommand = m_aPrimaryReadCache.getCommandByKey(*pIt); + if (sReadCommand != sCommand) + insertKeyToConfiguration(*pIt, sCommand, sal_True); + } + } + + // take over all changes into the original container + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + if (m_pPrimaryWriteCache) + { + m_aPrimaryReadCache.takeOver(*m_pPrimaryWriteCache); + AcceleratorCache* pTemp = m_pPrimaryWriteCache; + m_pPrimaryWriteCache = 0; + delete pTemp; + } + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + } + + else + { + AcceleratorCache::TKeyList::const_iterator pIt; + AcceleratorCache::TKeyList lSecondaryReadKeys = m_aSecondaryReadCache.getAllKeys(); + AcceleratorCache::TKeyList lSecondaryWriteKeys = m_pSecondaryWriteCache->getAllKeys(); + + for ( pIt = lSecondaryReadKeys.begin(); pIt != lSecondaryReadKeys.end(); ++pIt) + { + if (!m_pSecondaryWriteCache->hasKey(*pIt)) + removeKeyFromConfiguration(*pIt, sal_False); + } + + + for ( pIt = lSecondaryWriteKeys.begin(); pIt != lSecondaryWriteKeys.end(); ++pIt ) + { + ::rtl::OUString sCommand = m_pSecondaryWriteCache->getCommandByKey(*pIt); + if (!m_aSecondaryReadCache.hasKey(*pIt)) + { + insertKeyToConfiguration(*pIt, sCommand, sal_False); + } + else + { + ::rtl::OUString sReadCommand = m_aSecondaryReadCache.getCommandByKey(*pIt); + if (sReadCommand != sCommand) + insertKeyToConfiguration(*pIt, sCommand, sal_False); + } + } + + // take over all changes into the original container + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + if (m_pSecondaryWriteCache) + { + m_aSecondaryReadCache.takeOver(*m_pSecondaryWriteCache); + AcceleratorCache* pTemp = m_pSecondaryWriteCache; + m_pSecondaryWriteCache = 0; + delete pTemp; + } + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + } + + ::comphelper::ConfigurationHelper::flush(m_xCfg); +} + +//----------------------------------------------- +void XCUBasedAcceleratorConfiguration::insertKeyToConfiguration( const css::awt::KeyEvent& aKeyEvent, const ::rtl::OUString& sCommand, const sal_Bool bPreferred ) +{ + css::uno::Reference< css::container::XNameAccess > xAccess; + css::uno::Reference< css::container::XNameContainer > xContainer; + css::uno::Reference< css::lang::XSingleServiceFactory > xFac; + css::uno::Reference< css::uno::XInterface > xInst; + + if ( bPreferred ) + m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess; + else + m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess; + + if ( m_sGlobalOrModules.equals(CFG_ENTRY_GLOBAL) ) + xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer; + else if ( m_sGlobalOrModules.equals(CFG_ENTRY_MODULES) ) + { + css::uno::Reference< css::container::XNameContainer > xModules; + xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules; + if ( !xModules->hasByName(m_sModuleCFG) ) + { + xFac = css::uno::Reference< css::lang::XSingleServiceFactory >(xModules, css::uno::UNO_QUERY); + xInst = xFac->createInstance(); + xModules->insertByName(m_sModuleCFG, css::uno::makeAny(xInst)); + } + xModules->getByName(m_sModuleCFG) >>= xContainer; + } + + const ::rtl::OUString sKey = lcl_getKeyString(m_rKeyMapping,aKeyEvent); + css::uno::Reference< css::container::XNameAccess > xKey; + css::uno::Reference< css::container::XNameContainer > xCommand; + if ( !xContainer->hasByName(sKey) ) + { + xFac = css::uno::Reference< css::lang::XSingleServiceFactory >(xContainer, css::uno::UNO_QUERY); + xInst = xFac->createInstance(); + xContainer->insertByName(sKey, css::uno::makeAny(xInst)); + } + xContainer->getByName(sKey) >>= xKey; + + xKey->getByName(CFG_PROP_COMMAND) >>= xCommand; + ::rtl::OUString sLocale = impl_ts_getLocale().toISO(); + if ( !xCommand->hasByName(sLocale) ) + xCommand->insertByName(sLocale, css::uno::makeAny(sCommand)); + else + xCommand->replaceByName(sLocale, css::uno::makeAny(sCommand)); +} + +//----------------------------------------------- +void XCUBasedAcceleratorConfiguration::removeKeyFromConfiguration( const css::awt::KeyEvent& aKeyEvent, const sal_Bool bPreferred ) +{ + css::uno::Reference< css::container::XNameAccess > xAccess; + css::uno::Reference< css::container::XNameContainer > xContainer; + + if ( bPreferred ) + m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess; + else + m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess; + + if ( m_sGlobalOrModules.equals(CFG_ENTRY_GLOBAL) ) + xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer; + else if ( m_sGlobalOrModules.equals(CFG_ENTRY_MODULES) ) + { + css::uno::Reference< css::container::XNameAccess > xModules; + xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules; + if ( !xModules->hasByName(m_sModuleCFG) ) + return; + xModules->getByName(m_sModuleCFG) >>= xContainer; + } + + const ::rtl::OUString sKey = lcl_getKeyString(m_rKeyMapping,aKeyEvent); + xContainer->removeByName(sKey); +} + +//----------------------------------------------- +void XCUBasedAcceleratorConfiguration::reloadChanged( const ::rtl::OUString& sPrimarySecondary, const ::rtl::OUString& sGlobalModules, const ::rtl::OUString& sModule, const ::rtl::OUString& sKey ) +{ + css::uno::Reference< css::container::XNameAccess > xAccess; + css::uno::Reference< css::container::XNameContainer > xContainer; + + m_xCfg->getByName(sPrimarySecondary) >>= xAccess; + if ( sGlobalModules.equals(CFG_ENTRY_GLOBAL) ) + xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer; + else + { + css::uno::Reference< css::container::XNameAccess > xModules; + xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules; + if ( !xModules->hasByName(sModule) ) + return; + xModules->getByName(sModule) >>= xContainer; + } + + css::awt::KeyEvent aKeyEvent; + ::rtl::OUString sKeyIdentifier; + + sal_Int32 nIndex = 0; + sKeyIdentifier = sKey.getToken(0, '_', nIndex); + aKeyEvent.KeyCode = m_rKeyMapping->mapIdentifierToCode(::rtl::OUString::createFromAscii("KEY_")+sKeyIdentifier); + + css::uno::Sequence< ::rtl::OUString > sToken(3); + const sal_Int32 nToken = 3; + for (sal_Int32 i=0; i<nToken; ++i) + { + if ( nIndex < 0 ) + break; + + sToken[i] = sKey.getToken(0, '_', nIndex); + if (sToken[i].equalsAscii("SHIFT")) + aKeyEvent.Modifiers |= css::awt::KeyModifier::SHIFT; + else if (sToken[i].equalsAscii("MOD1")) + aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD1; + else if (sToken[i].equalsAscii("MOD2")) + aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD2; + else if (sToken[i].equalsAscii("MOD3")) + aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD3; + } + + css::uno::Reference< css::container::XNameAccess > xKey; + css::uno::Reference< css::container::XNameAccess > xCommand; + ::rtl::OUString sCommand; + + if (xContainer->hasByName(sKey)) + { + ::rtl::OUString sLocale = impl_ts_getLocale().toISO(); + xContainer->getByName(sKey) >>= xKey; + xKey->getByName(CFG_PROP_COMMAND) >>= xCommand; + xCommand->getByName(sLocale) >>= sCommand; + } + + if (sPrimarySecondary.equals(CFG_ENTRY_PRIMARY)) + { + if (sCommand.getLength() ==0) + m_aPrimaryReadCache.removeKey(aKeyEvent); + else + m_aPrimaryReadCache.setKeyCommandPair(aKeyEvent, sCommand); + } + else if (sPrimarySecondary.equals(CFG_ENTRY_SECONDARY)) + { + if (sCommand.getLength() ==0) + m_aSecondaryReadCache.removeKey(aKeyEvent); + else + m_aSecondaryReadCache.setKeyCommandPair(aKeyEvent, sCommand); + } +} + +//----------------------------------------------- +AcceleratorCache& XCUBasedAcceleratorConfiguration::impl_getCFG(sal_Bool bPreferred, sal_Bool bWriteAccessRequested) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + if (bPreferred) + { + //create copy of our readonly-cache, if write access is forced ... but + //not still possible! + if ( + (bWriteAccessRequested) && + (!m_pPrimaryWriteCache ) + ) + { + m_pPrimaryWriteCache = new AcceleratorCache(m_aPrimaryReadCache); + } + + // in case, we have a writeable cache, we use it for reading too! + // Otherwhise the API user cant find its own changes ... + if (m_pPrimaryWriteCache) + return *m_pPrimaryWriteCache; + else + return m_aPrimaryReadCache; + } + + else + { + //create copy of our readonly-cache, if write access is forced ... but + //not still possible! + if ( + (bWriteAccessRequested) && + (!m_pSecondaryWriteCache ) + ) + { + m_pSecondaryWriteCache = new AcceleratorCache(m_aSecondaryReadCache); + } + + // in case, we have a writeable cache, we use it for reading too! + // Otherwhise the API user cant find its own changes ... + if (m_pSecondaryWriteCache) + return *m_pSecondaryWriteCache; + else + return m_aSecondaryReadCache; + } + + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +::comphelper::Locale XCUBasedAcceleratorConfiguration::impl_ts_getLocale() const +{ + static ::rtl::OUString LOCALE_PACKAGE = ::rtl::OUString::createFromAscii("/org.openoffice.Setup"); + static ::rtl::OUString LOCALE_PATH = ::rtl::OUString::createFromAscii("L10N" ); + static ::rtl::OUString LOCALE_KEY = ::rtl::OUString::createFromAscii("ooLocale" ); + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::uno::XInterface > xCFG = fpc::ConfigurationHelper::openConfig(xSMGR, LOCALE_PACKAGE, LOCALE_PATH, fpc::ConfigurationHelper::E_READONLY); + css::uno::Reference< css::beans::XPropertySet > xProp (xCFG, css::uno::UNO_QUERY_THROW); + ::rtl::OUString sISOLocale; + xProp->getPropertyValue(LOCALE_KEY) >>= sISOLocale; + + if (!sISOLocale.getLength()) + return ::comphelper::Locale::EN_US(); + return ::comphelper::Locale(sISOLocale); +} + +} // namespace framework diff --git a/framework/source/accelerators/acceleratorexecute.cxx b/framework/source/accelerators/acceleratorexecute.cxx new file mode 100644 index 000000000000..98fe7bb7630b --- /dev/null +++ b/framework/source/accelerators/acceleratorexecute.cxx @@ -0,0 +1,382 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include "acceleratorexecute.hxx" + +//=============================================== +// includes + +#ifndef __COM_SUN_STAR_FRAME_XMODULEMANAGER_HPP_ +#include <com/sun/star/frame/XModuleManager.hpp> +#endif + +#ifndef __COM_SUN_STAR_UI_XUICONFIGURATIONMANAGER_HPP_ +#include <com/sun/star/ui/XUIConfigurationManager.hpp> +#endif + +#ifndef __COM_SUN_STAR_UI_XMODULEUICONFIGURATIONMANAGERSUPPLIER_HPP_ +#include <com/sun/star/ui/XModuleUIConfigurationManagerSupplier.hpp> +#endif + +#ifndef __COM_SUN_STAR_UI_XUICONFIGURATIONMANAGERSUPPLIER_HPP_ +#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> +#endif + +#ifndef __COM_SUN_STAR_AWT_KEYMODIFIER_HPP_ +#include <com/sun/star/awt/KeyModifier.hpp> +#endif + +#ifndef __COM_SUN_STAR_UNO_SEQUENCE_HXX_ +#include <com/sun/star/uno/Sequence.hxx> +#endif + +#ifndef __COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_ +#include <com/sun/star/beans/PropertyValue.hpp> +#endif + +//=============================================== +// namespace + +namespace svt +{ + +namespace css = ::com::sun::star; + +//=============================================== +// definitions + +//----------------------------------------------- +AcceleratorExecute::AcceleratorExecute() + : TMutexInit ( ) + , m_aAsyncCallback(LINK(this, AcceleratorExecute, impl_ts_asyncCallback)) +{ +} + +//----------------------------------------------- +AcceleratorExecute::AcceleratorExecute(const AcceleratorExecute& rCopy) + : TMutexInit ( ) + , m_aAsyncCallback(LINK(this, AcceleratorExecute, impl_ts_asyncCallback)) +{ + // copy construction sint supported in real ... + // but we need this ctor to init our async callback ... +} + +//----------------------------------------------- +AcceleratorExecute::~AcceleratorExecute() +{ + // does nothing real +} + +//----------------------------------------------- +AcceleratorExecute* AcceleratorExecute::createAcceleratorHelper() +{ + AcceleratorExecute* pNew = new AcceleratorExecute(); + return pNew; +} + +//----------------------------------------------- +void AcceleratorExecute::init(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR, + const css::uno::Reference< css::frame::XFrame >& xEnv ) +{ + // SAFE -> ---------------------------------- + ::osl::ResettableMutexGuard aLock(m_aLock); + + // take over the uno service manager + m_xSMGR = xSMGR; + + // specify our internal dispatch provider + // frame or desktop?! => document or global config. + sal_Bool bDesktopIsUsed = sal_False; + m_xDispatcher = css::uno::Reference< css::frame::XDispatchProvider >(xEnv, css::uno::UNO_QUERY); + if (!m_xDispatcher.is()) + { + aLock.clear(); + // <- SAFE ------------------------------ + + css::uno::Reference< css::frame::XDispatchProvider > xDispatcher( + xSMGR->createInstance(SERVICENAME_DESKTOP), + css::uno::UNO_QUERY_THROW); + + // SAFE -> ------------------------------ + aLock.reset(); + + m_xDispatcher = xDispatcher; + bDesktopIsUsed = sal_True; + } + + aLock.clear(); + // <- SAFE ---------------------------------- + + // open all needed configuration objects + css::uno::Reference< css::ui::XAcceleratorConfiguration > xGlobalCfg; + css::uno::Reference< css::ui::XAcceleratorConfiguration > xModuleCfg; + css::uno::Reference< css::ui::XAcceleratorConfiguration > xDocCfg ; + + // global cfg + xGlobalCfg = AcceleratorExecute::impl_st_openGlobalConfig(xSMGR); + if (!bDesktopIsUsed) + { + // module cfg + xModuleCfg = AcceleratorExecute::impl_st_openModuleConfig(xSMGR, xEnv); + + // doc cfg + css::uno::Reference< css::frame::XController > xController; + css::uno::Reference< css::frame::XModel > xModel; + xController = xEnv->getController(); + if (xController.is()) + xModel = xController->getModel(); + if (xModel.is()) + xDocCfg = AcceleratorExecute::impl_st_openDocConfig(xModel); + } + + // SAFE -> ------------------------------ + aLock.reset(); + + m_xGlobalCfg = xGlobalCfg; + m_xModuleCfg = xModuleCfg; + m_xDocCfg = xDocCfg ; + + aLock.clear(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void AcceleratorExecute::execute(const KeyCode& aVCLKey) +{ + css::awt::KeyEvent aAWTKey = AcceleratorExecute::st_VCLKey2AWTKey(aVCLKey); + execute(aAWTKey); +} + +//----------------------------------------------- +void AcceleratorExecute::execute(const css::awt::KeyEvent& aAWTKey) +{ + ::rtl::OUString sCommand = impl_ts_findCommand(aAWTKey); + + // No Command found? Do nothing! User isnt interested on any error handling .-) + if (!sCommand.getLength()) + return; + + // SAFE -> ---------------------------------- + ::osl::ResettableMutexGuard aLock(m_aLock); + + m_lCommandQueue.push_back(sCommand); + m_aAsyncCallback.Post(0); + + aLock.clear(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +css::awt::KeyEvent AcceleratorExecute::st_VCLKey2AWTKey(const KeyCode& aVCLKey) +{ + css::awt::KeyEvent aAWTKey; + aAWTKey.Modifiers = 0; + aAWTKey.KeyCode = (sal_Int16)aVCLKey.GetCode(); + + if (aVCLKey.IsShift()) + aAWTKey.Modifiers |= css::awt::KeyModifier::SHIFT; + if (aVCLKey.IsMod1()) + aAWTKey.Modifiers |= css::awt::KeyModifier::MOD1; + if (aVCLKey.IsMod2()) + aAWTKey.Modifiers |= css::awt::KeyModifier::MOD2; + if (aVCLKey.IsMod3()) + aAWTKey.Modifiers |= css::awt::KeyModifier::MOD3; + + return aAWTKey; +} + +/* +ViewFrame->GetObjectShell +ObjectShell->GetStyleSheetPool +*/ + +//----------------------------------------------- +KeyCode AcceleratorExecute::st_AWTKey2VCLKey(const css::awt::KeyEvent& aAWTKey) +{ + sal_Bool bShift = ((aAWTKey.Modifiers & css::awt::KeyModifier::SHIFT) == css::awt::KeyModifier::SHIFT ); + sal_Bool bMod1 = ((aAWTKey.Modifiers & css::awt::KeyModifier::MOD1 ) == css::awt::KeyModifier::MOD1 ); + sal_Bool bMod2 = ((aAWTKey.Modifiers & css::awt::KeyModifier::MOD2 ) == css::awt::KeyModifier::MOD2 ); + sal_Bool bMod3 = ((aAWTKey.Modifiers & css::awt::KeyModifier::MOD3 ) == css::awt::KeyModifier::MOD3 ); + USHORT nKey = (USHORT)aAWTKey.KeyCode; + + return KeyCode(nKey, bShift, bMod1, bMod2, bMod3); +} + +//----------------------------------------------- +::rtl::OUString AcceleratorExecute::impl_ts_findCommand(const css::awt::KeyEvent& aKey) +{ + // SAFE -> ---------------------------------- + ::osl::ResettableMutexGuard aLock(m_aLock); + + css::uno::Reference< css::ui::XAcceleratorConfiguration > xGlobalCfg = m_xGlobalCfg; + css::uno::Reference< css::ui::XAcceleratorConfiguration > xModuleCfg = m_xModuleCfg; + css::uno::Reference< css::ui::XAcceleratorConfiguration > xDocCfg = m_xDocCfg ; + + aLock.clear(); + // <- SAFE ---------------------------------- + + ::rtl::OUString sCommand; + try + { + if (xDocCfg.is()) + sCommand = xDocCfg->getCommandByKeyEvent(aKey); + } + catch(const css::container::NoSuchElementException&) + { + try + { + if (xModuleCfg.is()) + sCommand = xModuleCfg->getCommandByKeyEvent(aKey); + } + catch(const css::container::NoSuchElementException&) + { + try + { + if (xGlobalCfg.is()) + sCommand = xGlobalCfg->getCommandByKeyEvent(aKey); + } + catch(const css::container::NoSuchElementException&) + {} + } + } + + return sCommand; +} + +//----------------------------------------------- +css::uno::Reference< css::ui::XAcceleratorConfiguration > AcceleratorExecute::impl_st_openGlobalConfig(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR) +{ + css::uno::Reference< css::ui::XAcceleratorConfiguration > xAccCfg( + xSMGR->createInstance(SERVICENAME_GLOBALACCELERATORCONFIGURATION), + css::uno::UNO_QUERY_THROW); + return xAccCfg; +} + +//----------------------------------------------- +css::uno::Reference< css::ui::XAcceleratorConfiguration > AcceleratorExecute::impl_st_openModuleConfig(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR , + const css::uno::Reference< css::frame::XFrame >& xFrame) +{ + css::uno::Reference< css::frame::XModuleManager > xModuleDetection( + xSMGR->createInstance(SERVICENAME_MODULEMANAGER), + css::uno::UNO_QUERY_THROW); + + ::rtl::OUString sModule; + try + { + sModule = xModuleDetection->identify(xFrame); + } + catch(const css::uno::RuntimeException& exRuntime) + { throw exRuntime; } + catch(const css::uno::Exception&) + { return css::uno::Reference< css::ui::XAcceleratorConfiguration >(); } + + css::uno::Reference< css::ui::XModuleUIConfigurationManagerSupplier > xUISupplier( + xSMGR->createInstance(SERVICENAME_MODULEUICONFIGURATIONMANAGERSUPPLIER), + css::uno::UNO_QUERY_THROW); + + css::uno::Reference< css::ui::XUIConfigurationManager > xUIManager = xUISupplier->getUIConfigurationManager(sModule); + css::uno::Reference< css::ui::XAcceleratorConfiguration > xAccCfg (xUIManager->getShortCutManager(), css::uno::UNO_QUERY_THROW); + return xAccCfg; +} + +//----------------------------------------------- +css::uno::Reference< css::ui::XAcceleratorConfiguration > AcceleratorExecute::impl_st_openDocConfig(const css::uno::Reference< css::frame::XModel >& xModel) +{ + css::uno::Reference< css::ui::XUIConfigurationManagerSupplier > xUISupplier(xModel, css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::ui::XUIConfigurationManager > xUIManager = xUISupplier->getUIConfigurationManager(); + css::uno::Reference< css::ui::XAcceleratorConfiguration > xAccCfg (xUIManager->getShortCutManager(), css::uno::UNO_QUERY_THROW); + return xAccCfg; +} + +//----------------------------------------------- +css::uno::Reference< css::util::XURLTransformer > AcceleratorExecute::impl_ts_getURLParser() +{ + // SAFE -> ---------------------------------- + ::osl::ResettableMutexGuard aLock(m_aLock); + + if (m_xURLParser.is()) + return m_xURLParser; + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + + aLock.clear(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::util::XURLTransformer > xParser( + xSMGR->createInstance(SERVICENAME_URLTRANSFORMER), + css::uno::UNO_QUERY_THROW); + + // SAFE -> ---------------------------------- + aLock.reset(); + m_xURLParser = xParser; + aLock.clear(); + // <- SAFE ---------------------------------- + + return xParser; +} + +//----------------------------------------------- +IMPL_LINK(AcceleratorExecute, impl_ts_asyncCallback, void*, pVoid) +{ + // SAFE -> ---------------------------------- + ::osl::ResettableMutexGuard aLock(m_aLock); + + TCommandQueue::iterator pIt = m_lCommandQueue.begin(); + if (pIt == m_lCommandQueue.end()) + return 0; + ::rtl::OUString sCommand = *pIt; + m_lCommandQueue.erase(pIt); + + css::uno::Reference< css::frame::XDispatchProvider > xProvider = m_xDispatcher; + + aLock.clear(); + // <- SAFE ---------------------------------- + + // convert command in URL structure + css::uno::Reference< css::util::XURLTransformer > xParser = impl_ts_getURLParser(); + css::util::URL aURL; + aURL.Complete = sCommand; + xParser->parseStrict(aURL); + + // ask for dispatch object + css::uno::Reference< css::frame::XDispatch > xDispatch = xProvider->queryDispatch(aURL, ::rtl::OUString(), 0); + css::uno::Sequence< css::beans::PropertyValue> aArgs; + if (xDispatch.is()) + { + if(::comphelper::UiEventsLogger::isEnabled()) //#i88653# + { + Sequence<css::beans::PropertyValue> source; + ::comphelper::UiEventsLogger::appendDispatchOrigin(OUString::createFromAscii("AcceleratorExecute")); + ::comphelper::UiEventsLogger::logDispatch(aURL, source); + } + xDispatch->dispatch(aURL, css::uno::Sequence< css::beans::PropertyValue >()); + } + return 0; +} + +} // namespace svt diff --git a/framework/source/accelerators/acceleratorexecute.hxx b/framework/source/accelerators/acceleratorexecute.hxx new file mode 100644 index 000000000000..07f6348184e2 --- /dev/null +++ b/framework/source/accelerators/acceleratorexecute.hxx @@ -0,0 +1,255 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_SVTOOLS_ACCELERATOREXECUTE_HXX +#define INCLUDED_SVTOOLS_ACCELERATOREXECUTE_HXX + +//=============================================== +// includes + +#include <vector> + +#ifndef __COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_ +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#endif + +#ifndef __COM_SUN_STAR_FRAME_XFRAME_HPP_ +#include <com/sun/star/frame/XFrame.hpp> +#endif + +#ifndef __COM_SUN_STAR_FRAME_XDISPATCHPROVIDER_HPP_ +#include <com/sun/star/frame/XDispatchProvider.hpp> +#endif + +#ifndef __COM_SUN_STAR_UI_XACCELERATORCONFIGURATION_HPP_ +#include <com/sun/star/ui/XAcceleratorConfiguration.hpp> +#endif + +#ifndef __COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_ +#include <com/sun/star/util/XURLTransformer.hpp> +#endif + +#ifndef __COM_SUN_STAR_AWT_KEYEVENT_HPP_ +#include <com/sun/star/awt/KeyEvent.hpp> +#endif +#include <vcl/keycod.hxx> +#include <vcl/evntpost.hxx> +#include <osl/mutex.h> + +//=============================================== +// namespace + +namespace svt +{ + +#ifdef css + #error "Who define css? I need it as namespace alias." +#else + #define css ::com::sun::star +#endif + +//=============================================== +// definitions + +struct TMutexInit +{ + ::osl::Mutex m_aLock; +}; + +//=============================================== +/** + @descr implements a helper, which can be used to + convert vcl key codes into awt key codes ... + and reverse. + + Further such key code can be triggered. + Doing so different accelerator + configurations are merged together; a suitable + command registered for the given key code is searched + and will be dispatched. + + @attention + + Because exceution of an accelerator command can be dangerous + (in case it force an office shutdown for key "ALT+F4"!) + all internal dispatches are done asynchronous. + Menas that the trigger call doesnt wait till the dispatch + is finished. You can call very often. All requests will be + queued internal and dispatched ASAP. + + Of course this queue will be stopped if the environment + will be destructed ... + */ +class AcceleratorExecute : private TMutexInit +{ + //------------------------------------------- + // const, types + private: + + /** TODO document me */ + typedef ::std::vector< ::rtl::OUString > TCommandQueue; + + //------------------------------------------- + // member + private: + + /** TODO document me */ + css::uno::Reference< css::lang::XMultiServiceFactory > m_xSMGR; + + /** TODO document me */ + css::uno::Reference< css::util::XURLTransformer > m_xURLParser; + + /** TODO document me */ + css::uno::Reference< css::frame::XDispatchProvider > m_xDispatcher; + + /** TODO document me */ + css::uno::Reference< css::ui::XAcceleratorConfiguration > m_xGlobalCfg; + css::uno::Reference< css::ui::XAcceleratorConfiguration > m_xModuleCfg; + css::uno::Reference< css::ui::XAcceleratorConfiguration > m_xDocCfg; + + /** TODO document me */ + TCommandQueue m_lCommandQueue; + + /** TODO document me */ + ::vcl::EventPoster m_aAsyncCallback; + + //------------------------------------------- + // interface + public: + + //--------------------------------------- + /** @short factory method to create new accelerator + helper instance. + + @descr Such helper instance must be initialized at first. + So it can know its environment (global/module or + document specific). + + Afterwards it can be used to execute incoming + accelerator requests. + + The "end of life" of such helper can be reached as follow: + + - delete the object + => If it stands currently in its execute method, they will + be finished. All further queued requests will be removed + and further not executed! + + Other modes are possible and will be implemented ASAP :-) + */ + static AcceleratorExecute* createAcceleratorHelper(); + + //--------------------------------------- + /** @short fight against inlining ... */ + virtual ~AcceleratorExecute(); + + //--------------------------------------- + /** @short init this instance. + + @descr It must be called as first method after creation. + And further it can be called more then once ... + but at least its should be used one times only. + Otherwhise nobody can say, which asynchronous + executions will be used inside the old and which one + will be used inside the new environment. + + @param xSMGR + reference to an uno service manager. + + @param xEnv + if it points to a valid frame it will be used + to execute the dispatch there. Further the frame + is used to locate the right module configuration + and use it merged together with the document and + the global configuration. + + If this parameter is set to NULL, the global configuration + is used only. Further the global Desktop instance is + used for dispatch. + */ + virtual void init(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR, + const css::uno::Reference< css::frame::XFrame >& xEnv ); + + //--------------------------------------- + /** @short trigger this accelerator. + + @descr The internal configuartions are used to find + as suitable command for this key code. + This command will be queued and executed later + asynchronous. + + @param aKey + specify the accelerator for execute. + */ + virtual void execute(const KeyCode& aKey); + virtual void execute(const css::awt::KeyEvent& aKey); + + //--------------------------------------- + /** TODO document me */ + static css::awt::KeyEvent st_VCLKey2AWTKey(const KeyCode& aKey); + static KeyCode st_AWTKey2VCLKey(const css::awt::KeyEvent& aKey); + + //------------------------------------------- + // internal + private: + + //--------------------------------------- + /** @short allow creation of instances of this class + by using our factory only! + */ + AcceleratorExecute(); + AcceleratorExecute(const AcceleratorExecute& rCopy); + void operator=(const AcceleratorExecute& rCopy) {}; + + //--------------------------------------- + /** TODO document me */ + css::uno::Reference< css::ui::XAcceleratorConfiguration > impl_st_openGlobalConfig(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR); + + css::uno::Reference< css::ui::XAcceleratorConfiguration > impl_st_openModuleConfig(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR , + const css::uno::Reference< css::frame::XFrame >& xFrame); + + css::uno::Reference< css::ui::XAcceleratorConfiguration > impl_st_openDocConfig(const css::uno::Reference< css::frame::XModel >& xModel); + + //--------------------------------------- + /** TODO document me */ + ::rtl::OUString impl_ts_findCommand(const css::awt::KeyEvent& aKey); + + //--------------------------------------- + /** TODO document me */ + css::uno::Reference< css::util::XURLTransformer > impl_ts_getURLParser(); + + //--------------------------------------- + /** TODO document me */ + DECL_LINK(impl_ts_asyncCallback, void*); +}; + +#undef css +#undef css + +} // namespace svt + +#endif // INCLUDED_SVTOOLS_ACCELERATOREXECUTE_HXX diff --git a/framework/source/accelerators/documentacceleratorconfiguration.cxx b/framework/source/accelerators/documentacceleratorconfiguration.cxx new file mode 100644 index 000000000000..81edb165653c --- /dev/null +++ b/framework/source/accelerators/documentacceleratorconfiguration.cxx @@ -0,0 +1,240 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include <accelerators/documentacceleratorconfiguration.hxx> + +#ifndef __FRAMEWORK_XML_ACCELERATORCONFIGURATIONREADER_HXX_ +#include <xml/acceleratorconfigurationreader.hxx> +#endif + +#ifndef __FRAMEWORK_XML_ACCELERATORCONFIGURATIONWRITER_HXX_ +#include <xml/acceleratorconfigurationwriter.hxx> +#endif + +#ifndef __FRAMEWORK_XML_SAXNAMESPACEFILTER_HXX_ +#include <xml/saxnamespacefilter.hxx> +#endif + +//_______________________________________________ +// own includes +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> + +#ifndef __FRAMEWORK_ACCELERATORCONST_H_ +#include <acceleratorconst.h> +#endif +#include <services.h> + +//_______________________________________________ +// interface includes + +#ifndef _COM_SUN_STAR_IO_XACTIVEDATASOURCE_HPP_ +#include <com/sun/star/io/XActiveDataSource.hpp> +#endif + +#ifndef _COM_SUN_STAR_IO_XSEEKABLE_HPP_ +#include <com/sun/star/io/XSeekable.hpp> +#endif + +#ifndef _COM_SUN_STAR_IO_XTRUNCATE_HPP_ +#include <com/sun/star/io/XTruncate.hpp> +#endif + +#ifndef _COM_SUN_STAR_EMBED_ELEMENTMODES_HPP_ +#include <com/sun/star/embed/ElementModes.hpp> +#endif + +#ifndef _COM_SUN_STAR_XML_SAX_INPUTSOURCE_HPP_ +#include <com/sun/star/xml/sax/InputSource.hpp> +#endif + +#ifndef _COM_SUN_STAR_XML_SAX_XPARSER_HPP_ +#include <com/sun/star/xml/sax/XParser.hpp> +#endif + +//_______________________________________________ +// other includes + +#ifndef _COMPHELPER_SEQUENCEASHASHMAP_HXX +#include <comphelper/sequenceashashmap.hxx> +#endif + +//_______________________________________________ +// const + +namespace framework +{ + +//----------------------------------------------- +// XInterface, XTypeProvider, XServiceInfo +DEFINE_XINTERFACE_2(DocumentAcceleratorConfiguration , + XMLBasedAcceleratorConfiguration , + DIRECT_INTERFACE(css::lang::XServiceInfo) , + DIRECT_INTERFACE(css::lang::XInitialization)) +// DIRECT_INTERFACE(css::ui::XUIConfigurationStorage)) + +DEFINE_XTYPEPROVIDER_2_WITH_BASECLASS(DocumentAcceleratorConfiguration , + XMLBasedAcceleratorConfiguration , + css::lang::XServiceInfo , + css::lang::XInitialization) +// css::ui::XUIConfigurationStorage) + +DEFINE_XSERVICEINFO_MULTISERVICE(DocumentAcceleratorConfiguration , + ::cppu::OWeakObject , + SERVICENAME_DOCUMENTACCELERATORCONFIGURATION , + IMPLEMENTATIONNAME_DOCUMENTACCELERATORCONFIGURATION) + +DEFINE_INIT_SERVICE(DocumentAcceleratorConfiguration, + { + /*Attention + I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance() + to create a new instance of this class by our own supported service factory. + see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations! + */ + } + ) + +//----------------------------------------------- +DocumentAcceleratorConfiguration::DocumentAcceleratorConfiguration(const css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR) + : XMLBasedAcceleratorConfiguration(xSMGR) +{ +} + +//----------------------------------------------- +DocumentAcceleratorConfiguration::~DocumentAcceleratorConfiguration() +{ + m_aPresetHandler.removeStorageListener(this); +} + +//----------------------------------------------- +void SAL_CALL DocumentAcceleratorConfiguration::initialize(const css::uno::Sequence< css::uno::Any >& lArguments) + throw(css::uno::Exception , + css::uno::RuntimeException) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + ::comphelper::SequenceAsHashMap lArgs(lArguments); + m_xDocumentRoot = lArgs.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii("DocumentRoot"), + css::uno::Reference< css::embed::XStorage >()); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + impl_ts_fillCache(); +} + +//----------------------------------------------- +void SAL_CALL DocumentAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& xStorage) + throw(css::uno::RuntimeException) +{ + // Attention! xStorage must be accepted too, if it's NULL ! + + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + sal_Bool bForgetOldStorages = m_xDocumentRoot.is(); + m_xDocumentRoot = xStorage; + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + if (bForgetOldStorages) + impl_ts_clearCache(); + + if (xStorage.is()) + impl_ts_fillCache(); +} + +//----------------------------------------------- +sal_Bool SAL_CALL DocumentAcceleratorConfiguration::hasStorage() + throw(css::uno::RuntimeException) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + return m_xDocumentRoot.is(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void DocumentAcceleratorConfiguration::impl_ts_fillCache() +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::embed::XStorage > xDocumentRoot = m_xDocumentRoot; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + // Sometimes we must live without a document root. + // E.g. if the document is readonly ... + if (!xDocumentRoot.is()) + return; + + // get current office locale ... but dont cache it. + // Otherwise we must be listener on the configuration layer + // which seems to superflous for this small implementation .-) + ::comphelper::Locale aLocale = impl_ts_getLocale(); + + // May be the current document does not contain any + // accelerator config? Handle it gracefully :-) + try + { + // Note: The used preset class is threadsafe by itself ... and live if we live! + // We do not need any mutex here. + + // open the folder, where the configuration exists + m_aPresetHandler.connectToResource( + PresetHandler::E_DOCUMENT, + PresetHandler::RESOURCETYPE_ACCELERATOR(), + ::rtl::OUString(), + xDocumentRoot, + aLocale); + + DocumentAcceleratorConfiguration::reload(); + m_aPresetHandler.addStorageListener(this); + } + /* + + Sometimes the configuration seams to be corrupted .. + So it would be nice if we dont crash the office then .-) + #121559# + + catch(const css::uno::RuntimeException& exRun) + { throw exRun; } + */ + catch(const css::uno::Exception&) + {} +} + +//----------------------------------------------- +void DocumentAcceleratorConfiguration::impl_ts_clearCache() +{ + m_aPresetHandler.forgetCachedStorages(); +} + +} // namespace framework diff --git a/framework/source/accelerators/globalacceleratorconfiguration.cxx b/framework/source/accelerators/globalacceleratorconfiguration.cxx new file mode 100644 index 000000000000..dc040479d854 --- /dev/null +++ b/framework/source/accelerators/globalacceleratorconfiguration.cxx @@ -0,0 +1,127 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include <accelerators/globalacceleratorconfiguration.hxx> + +//_______________________________________________ +// own includes +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> + +#include <acceleratorconst.h> +#include <services.h> + +//_______________________________________________ +// interface includes +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/util/XChangesNotifier.hpp> + +//_______________________________________________ +// other includes +#include <vcl/svapp.hxx> +#include <comphelper/locale.hxx> +#include <comphelper/configurationhelper.hxx> + +//_______________________________________________ +// const + +namespace framework +{ + +//----------------------------------------------- +// XInterface, XTypeProvider, XServiceInfo +DEFINE_XINTERFACE_2(GlobalAcceleratorConfiguration , + XCUBasedAcceleratorConfiguration , + DIRECT_INTERFACE(css::lang::XServiceInfo), + DIRECT_INTERFACE(css::lang::XInitialization)) +DEFINE_XTYPEPROVIDER_2_WITH_BASECLASS(GlobalAcceleratorConfiguration, + XCUBasedAcceleratorConfiguration , + css::lang::XServiceInfo , + css::lang::XInitialization) + +DEFINE_XSERVICEINFO_MULTISERVICE(GlobalAcceleratorConfiguration , + ::cppu::OWeakObject , + SERVICENAME_GLOBALACCELERATORCONFIGURATION , + IMPLEMENTATIONNAME_GLOBALACCELERATORCONFIGURATION) + +DEFINE_INIT_SERVICE(GlobalAcceleratorConfiguration, + { + /*Attention + I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance() + to create a new instance of this class by our own supported service factory. + see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations! + */ + impl_ts_fillCache(); + } + ) + +//----------------------------------------------- +GlobalAcceleratorConfiguration::GlobalAcceleratorConfiguration(const css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR) + : XCUBasedAcceleratorConfiguration(xSMGR) +{ +} + +//----------------------------------------------- +GlobalAcceleratorConfiguration::~GlobalAcceleratorConfiguration() +{ +} + +void SAL_CALL GlobalAcceleratorConfiguration::initialize(const css::uno::Sequence< css::uno::Any >& /*lArguments*/) + throw(css::uno::Exception , + css::uno::RuntimeException) +{ +} + +//----------------------------------------------- +void GlobalAcceleratorConfiguration::impl_ts_fillCache() +{ + // get current office locale ... but dont cache it. + // Otherwise we must be listener on the configuration layer + // which seems to superflous for this small implementation .-) + ::comphelper::Locale aLocale = ::comphelper::Locale(m_sLocale); + + // May be there exists no accelerator config? Handle it gracefully :-) + try + { + m_sGlobalOrModules = CFG_ENTRY_GLOBAL; + XCUBasedAcceleratorConfiguration::reload(); + + css::uno::Reference< css::util::XChangesNotifier > xBroadcaster(m_xCfg, css::uno::UNO_QUERY_THROW); + xBroadcaster->addChangesListener(static_cast< css::util::XChangesListener* >(this)); + } + catch(const css::uno::RuntimeException& exRun) + { throw exRun; } + catch(const css::uno::Exception&) + {} +} + +} // namespace framework diff --git a/framework/source/accelerators/keymapping.cxx b/framework/source/accelerators/keymapping.cxx new file mode 100644 index 000000000000..7d4054014524 --- /dev/null +++ b/framework/source/accelerators/keymapping.cxx @@ -0,0 +1,229 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include <accelerators/keymapping.hxx> + +//_______________________________________________ +// own includes + +#include <macros/generic.hxx> + +//_______________________________________________ +// interface includes +#include <com/sun/star/awt/Key.hpp> + +//_______________________________________________ +// other includes + +//_______________________________________________ +// namespace + +namespace framework +{ + +//_______________________________________________ +// helper + +KeyMapping::KeyIdentifierInfo KeyMapping::KeyIdentifierMap[] = +{ + {css::awt::Key::NUM0 , "KEY_0" }, + {css::awt::Key::NUM1 , "KEY_1" }, + {css::awt::Key::NUM2 , "KEY_2" }, + {css::awt::Key::NUM3 , "KEY_3" }, + {css::awt::Key::NUM4 , "KEY_4" }, + {css::awt::Key::NUM5 , "KEY_5" }, + {css::awt::Key::NUM6 , "KEY_6" }, + {css::awt::Key::NUM7 , "KEY_7" }, + {css::awt::Key::NUM8 , "KEY_8" }, + {css::awt::Key::NUM9 , "KEY_9" }, + {css::awt::Key::A , "KEY_A" }, + {css::awt::Key::B , "KEY_B" }, + {css::awt::Key::C , "KEY_C" }, + {css::awt::Key::D , "KEY_D" }, + {css::awt::Key::E , "KEY_E" }, + {css::awt::Key::F , "KEY_F" }, + {css::awt::Key::G , "KEY_G" }, + {css::awt::Key::H , "KEY_H" }, + {css::awt::Key::I , "KEY_I" }, + {css::awt::Key::J , "KEY_J" }, + {css::awt::Key::K , "KEY_K" }, + {css::awt::Key::L , "KEY_L" }, + {css::awt::Key::M , "KEY_M" }, + {css::awt::Key::N , "KEY_N" }, + {css::awt::Key::O , "KEY_O" }, + {css::awt::Key::P , "KEY_P" }, + {css::awt::Key::Q , "KEY_Q" }, + {css::awt::Key::R , "KEY_R" }, + {css::awt::Key::S , "KEY_S" }, + {css::awt::Key::T , "KEY_T" }, + {css::awt::Key::U , "KEY_U" }, + {css::awt::Key::V , "KEY_V" }, + {css::awt::Key::W , "KEY_W" }, + {css::awt::Key::X , "KEY_X" }, + {css::awt::Key::Y , "KEY_Y" }, + {css::awt::Key::Z , "KEY_Z" }, + {css::awt::Key::F1 , "KEY_F1" }, + {css::awt::Key::F2 , "KEY_F2" }, + {css::awt::Key::F3 , "KEY_F3" }, + {css::awt::Key::F4 , "KEY_F4" }, + {css::awt::Key::F5 , "KEY_F5" }, + {css::awt::Key::F6 , "KEY_F6" }, + {css::awt::Key::F7 , "KEY_F7" }, + {css::awt::Key::F8 , "KEY_F8" }, + {css::awt::Key::F9 , "KEY_F9" }, + {css::awt::Key::F10 , "KEY_F10" }, + {css::awt::Key::F11 , "KEY_F11" }, + {css::awt::Key::F12 , "KEY_F12" }, + {css::awt::Key::F13 , "KEY_F13" }, + {css::awt::Key::F14 , "KEY_F14" }, + {css::awt::Key::F15 , "KEY_F15" }, + {css::awt::Key::F16 , "KEY_F16" }, + {css::awt::Key::F17 , "KEY_F17" }, + {css::awt::Key::F18 , "KEY_F18" }, + {css::awt::Key::F19 , "KEY_F19" }, + {css::awt::Key::F20 , "KEY_F20" }, + {css::awt::Key::F21 , "KEY_F21" }, + {css::awt::Key::F22 , "KEY_F22" }, + {css::awt::Key::F23 , "KEY_F23" }, + {css::awt::Key::F24 , "KEY_F24" }, + {css::awt::Key::F25 , "KEY_F25" }, + {css::awt::Key::F26 , "KEY_F26" }, + {css::awt::Key::DOWN , "KEY_DOWN" }, + {css::awt::Key::UP , "KEY_UP" }, + {css::awt::Key::LEFT , "KEY_LEFT" }, + {css::awt::Key::RIGHT , "KEY_RIGHT" }, + {css::awt::Key::HOME , "KEY_HOME" }, + {css::awt::Key::END , "KEY_END" }, + {css::awt::Key::PAGEUP , "KEY_PAGEUP" }, + {css::awt::Key::PAGEDOWN , "KEY_PAGEDOWN" }, + {css::awt::Key::RETURN , "KEY_RETURN" }, + {css::awt::Key::ESCAPE , "KEY_ESCAPE" }, + {css::awt::Key::TAB , "KEY_TAB" }, + {css::awt::Key::BACKSPACE , "KEY_BACKSPACE" }, + {css::awt::Key::SPACE , "KEY_SPACE" }, + {css::awt::Key::INSERT , "KEY_INSERT" }, + {css::awt::Key::DELETE , "KEY_DELETE" }, + {css::awt::Key::ADD , "KEY_ADD" }, + {css::awt::Key::SUBTRACT , "KEY_SUBTRACT" }, + {css::awt::Key::MULTIPLY , "KEY_MULTIPLY" }, + {css::awt::Key::DIVIDE , "KEY_DIVIDE" }, + {css::awt::Key::POINT , "KEY_POINT" }, + {css::awt::Key::COMMA , "KEY_COMMA" }, + {css::awt::Key::LESS , "KEY_LESS" }, + {css::awt::Key::GREATER , "KEY_GREATER" }, + {css::awt::Key::EQUAL , "KEY_EQUAL" }, + {css::awt::Key::OPEN , "KEY_OPEN" }, + {css::awt::Key::CUT , "KEY_CUT" }, + {css::awt::Key::COPY , "KEY_COPY" }, + {css::awt::Key::PASTE , "KEY_PASTE" }, + {css::awt::Key::UNDO , "KEY_UNDO" }, + {css::awt::Key::REPEAT , "KEY_REPEAT" }, + {css::awt::Key::FIND , "KEY_FIND" }, + {css::awt::Key::PROPERTIES , "KEY_PROPERTIES" }, + {css::awt::Key::FRONT , "KEY_FRONT" }, + {css::awt::Key::CONTEXTMENU , "KEY_CONTEXTMENU"}, + {css::awt::Key::HELP , "KEY_HELP" }, + {css::awt::Key::MENU , "KEY_MENU" }, + {css::awt::Key::HANGUL_HANJA , "KEY_HANGUL_HANJA"}, + {css::awt::Key::DECIMAL , "KEY_DECIMAL" }, + {css::awt::Key::TILDE , "KEY_TILDE" }, + {css::awt::Key::QUOTELEFT , "KEY_QUOTELEFT" }, + {0 , "" } // mark the end of this array! +}; + +//----------------------------------------------- +KeyMapping::KeyMapping() +{ + sal_Int32 i = 0; + while(KeyIdentifierMap[i].Code != 0) + { + ::rtl::OUString sIdentifier = ::rtl::OUString::createFromAscii(KeyIdentifierMap[i].Identifier); + sal_Int16 nCode = KeyIdentifierMap[i].Code; + + m_lIdentifierHash[sIdentifier] = nCode ; + m_lCodeHash [nCode] = sIdentifier; + + ++i; + } +} + +//----------------------------------------------- +KeyMapping::~KeyMapping() +{ +} + +//----------------------------------------------- +sal_uInt16 KeyMapping::mapIdentifierToCode(const ::rtl::OUString& sIdentifier) + throw(css::lang::IllegalArgumentException) +{ + Identifier2CodeHash::const_iterator pIt = m_lIdentifierHash.find(sIdentifier); + if (pIt != m_lIdentifierHash.end()) + return pIt->second; + + // Its not well known identifier - but may be a pure key code formated as string ... + // Check and convert it! + sal_uInt16 nCode = 0; + if (!KeyMapping::impl_st_interpretIdentifierAsPureKeyCode(sIdentifier, nCode)) + throw css::lang::IllegalArgumentException( + DECLARE_ASCII("Cant map given identifier to a valid key code value."), + css::uno::Reference< css::uno::XInterface >(), + 0); + + return (sal_uInt16)nCode; +} + +//----------------------------------------------- +::rtl::OUString KeyMapping::mapCodeToIdentifier(sal_uInt16 nCode) +{ + Code2IdentifierHash::const_iterator pIt = m_lCodeHash.find(nCode); + if (pIt != m_lCodeHash.end()) + return pIt->second; + + // If we have no well known identifier - use the pure code value! + return ::rtl::OUString::valueOf((sal_Int32)nCode); +} + +//----------------------------------------------- +sal_Bool KeyMapping::impl_st_interpretIdentifierAsPureKeyCode(const ::rtl::OUString& sIdentifier, + sal_uInt16& rCode ) +{ + sal_Int32 nCode = sIdentifier.toInt32(); + if (nCode > 0) + { + rCode = (sal_uInt16)nCode; + return sal_True; + } + + // 0 is normaly an error of the called method toInt32() ... + // But we must be aware, that the identifier is "0"! + rCode = 0; + return sIdentifier.equalsAscii("0"); +} + +} // namespace framework diff --git a/framework/source/accelerators/makefile.mk b/framework/source/accelerators/makefile.mk new file mode 100644 index 000000000000..23a60dd1870e --- /dev/null +++ b/framework/source/accelerators/makefile.mk @@ -0,0 +1,52 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=..$/.. + +PRJNAME= framework +TARGET= fwk_accelerators +ENABLE_EXCEPTIONS= TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Generate ----------------------------------------------------- + +SLOFILES= \ + $(SLO)$/keymapping.obj \ + $(SLO)$/storageholder.obj \ + $(SLO)$/presethandler.obj \ + $(SLO)$/acceleratorcache.obj \ + $(SLO)$/acceleratorconfiguration.obj \ + $(SLO)$/globalacceleratorconfiguration.obj \ + $(SLO)$/moduleacceleratorconfiguration.obj \ + $(SLO)$/documentacceleratorconfiguration.obj + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + diff --git a/framework/source/accelerators/moduleacceleratorconfiguration.cxx b/framework/source/accelerators/moduleacceleratorconfiguration.cxx new file mode 100644 index 000000000000..566311d6f5be --- /dev/null +++ b/framework/source/accelerators/moduleacceleratorconfiguration.cxx @@ -0,0 +1,175 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include <accelerators/moduleacceleratorconfiguration.hxx> + +//_______________________________________________ +// own includes +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> + +#ifndef __FRAMEWORK_ACCELERATORCONST_H_ +#include <acceleratorconst.h> +#endif +#include <services.h> + +//_______________________________________________ +// interface includes +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/embed/ElementModes.hpp> + +//_______________________________________________ +// other includes + +#ifndef _COMPHELPER_SEQUENCEASHASHMAP_HXX +#include <comphelper/sequenceashashmap.hxx> +#endif +#include <vcl/svapp.hxx> + +#ifndef _COMPHELPER_CONFIGURATIONHELPER_HXX_ +#include <comphelper/configurationhelper.hxx> +#endif + +#ifndef _COM_SUN_STAR_UTIL_XCHANGESNOTIFIER_HPP_ +#include <com/sun/star/util/XChangesNotifier.hpp> +#endif + +#ifndef _RTL_LOGFILE_HXX_ +#include <rtl/logfile.hxx> +#endif + +#ifndef _RTL_LOGFILE_HXX_ +#include <rtl/logfile.h> +#endif + +//_______________________________________________ +// const + +namespace framework +{ + +//----------------------------------------------- +// XInterface, XTypeProvider, XServiceInfo +DEFINE_XINTERFACE_2(ModuleAcceleratorConfiguration , + XCUBasedAcceleratorConfiguration , + DIRECT_INTERFACE(css::lang::XServiceInfo) , + DIRECT_INTERFACE(css::lang::XInitialization)) + +DEFINE_XTYPEPROVIDER_2_WITH_BASECLASS(ModuleAcceleratorConfiguration, + XCUBasedAcceleratorConfiguration , + css::lang::XServiceInfo , + css::lang::XInitialization ) + +DEFINE_XSERVICEINFO_MULTISERVICE(ModuleAcceleratorConfiguration , + ::cppu::OWeakObject , + SERVICENAME_MODULEACCELERATORCONFIGURATION , + IMPLEMENTATIONNAME_MODULEACCELERATORCONFIGURATION) + +DEFINE_INIT_SERVICE(ModuleAcceleratorConfiguration, + { + /*Attention + I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance() + to create a new instance of this class by our own supported service factory. + see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations! + */ + } + ) + +//----------------------------------------------- +ModuleAcceleratorConfiguration::ModuleAcceleratorConfiguration(const css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR) + : XCUBasedAcceleratorConfiguration(xSMGR) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ModuleAcceleratorConfiguration::ModuleAcceleratorConfiguration" ); +} + +//----------------------------------------------- +ModuleAcceleratorConfiguration::~ModuleAcceleratorConfiguration() +{ + // m_aPresetHandler.removeStorageListener(this); +} + +//----------------------------------------------- +void SAL_CALL ModuleAcceleratorConfiguration::initialize(const css::uno::Sequence< css::uno::Any >& lArguments) + throw(css::uno::Exception , + css::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ModuleAcceleratorConfiguration::initialize" ); + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + ::comphelper::SequenceAsHashMap lArgs(lArguments); + m_sModule = lArgs.getUnpackedValueOrDefault(::rtl::OUString::createFromAscii("ModuleIdentifier"), ::rtl::OUString()); + m_sLocale = lArgs.getUnpackedValueOrDefault(::rtl::OUString::createFromAscii("Locale") , ::rtl::OUString::createFromAscii("x-default")); + + if (!m_sModule.getLength()) + throw css::uno::RuntimeException( + ::rtl::OUString::createFromAscii("The module dependend accelerator configuration service was initialized with an empty module identifier!"), + static_cast< ::cppu::OWeakObject* >(this)); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + impl_ts_fillCache(); +} + +//----------------------------------------------- +void ModuleAcceleratorConfiguration::impl_ts_fillCache() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ModuleAcceleratorConfiguration::impl_ts_fillCache" ); + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + ::rtl::OUString sModule = m_sModule; + m_sModuleCFG = m_sModule; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + // get current office locale ... but dont cache it. + // Otherwise we must be listener on the configuration layer + // which seems to superflous for this small implementation .-) + ::comphelper::Locale aLocale = ::comphelper::Locale(m_sLocale); + + // May be the current app module does not have any + // accelerator config? Handle it gracefully :-) + try + { + m_sGlobalOrModules = CFG_ENTRY_MODULES; + XCUBasedAcceleratorConfiguration::reload(); + + css::uno::Reference< css::util::XChangesNotifier > xBroadcaster(m_xCfg, css::uno::UNO_QUERY_THROW); + xBroadcaster->addChangesListener(static_cast< css::util::XChangesListener* >(this)); + } + catch(const css::uno::RuntimeException& exRun) + { throw exRun; } + catch(const css::uno::Exception&) + {} +} + +} // namespace framework + diff --git a/framework/source/accelerators/presethandler.cxx b/framework/source/accelerators/presethandler.cxx new file mode 100644 index 000000000000..ecfe6d2a0a5f --- /dev/null +++ b/framework/source/accelerators/presethandler.cxx @@ -0,0 +1,937 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include <accelerators/presethandler.hxx> + +//_______________________________________________ +// own includes +#include <classes/fwkresid.hxx> + +#include "classes/resource.hrc" +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> +#include <services.h> + +//_______________________________________________ +// interface includes + +#ifndef __COM_SUN_STAR_CONFIGURATION_CORRUPTEDUICONFIGURATIONEXCEPTION_HPP_ +#include <com/sun/star/configuration/CorruptedUIConfigurationException.hpp> +#endif + +#ifndef __COM_SUN_STAR_CONTAINER_NOSUCHELEMENTEXCEPTION_HPP_ +#include <com/sun/star/container/NoSuchElementException.hpp> +#endif + +#ifndef __COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_ +#include <com/sun/star/container/XNameAccess.hpp> +#endif + +#ifndef __COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_ +#include <com/sun/star/beans/XPropertySet.hpp> +#endif + +#ifndef __COM_SUN_STAR_EMBED_ELEMENTMODES_HPP_ +#include <com/sun/star/embed/ElementModes.hpp> +#endif + +#ifndef __COM_SUN_STAR_EMBED_XTRANSACTEDOBJECT_HPP_ +#include <com/sun/star/embed/XTransactedObject.hpp> +#endif + +#ifndef __COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_ +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#endif + +//_______________________________________________ +// other includes +#include <vcl/svapp.hxx> + +#ifndef _RTL_USTRBUF_HXX +#include <rtl/ustrbuf.hxx> +#endif + +//_______________________________________________ +// const + +#define SUBSTORAGE_GLOBAL DECLARE_ASCII("global" ) +#define SUBSTORAGE_MODULES DECLARE_ASCII("modules") + +#define BASEPATH_SHARE_LAYER DECLARE_ASCII("UIConfig" ) +#define BASEPATH_USER_LAYER DECLARE_ASCII("UserConfig") + +#define RELPATH_SHARE_LAYER DECLARE_ASCII("soffice.cfg") +#define RELPATH_USER_LAYER DECLARE_ASCII("soffice.cfg") +// #define RELPATH_SHARE_LAYER DECLARE_ASCII("soffice.cfg/uiconfig.zip") +// #define RELPATH_USER_LAYER DECLARE_ASCII("soffice.cfg/uiconfig.zip") + +#define FILE_EXTENSION DECLARE_ASCII(".xml") + +#define PATH_SEPERATOR DECLARE_ASCII("/") + +static const ::sal_Int32 ID_CORRUPT_UICONFIG_SHARE = 1; +static const ::sal_Int32 ID_CORRUPT_UICONFIG_USER = 2; +static const ::sal_Int32 ID_CORRUPT_UICONFIG_GENERAL = 3; + +//_______________________________________________ +// namespace + +namespace framework +{ + +//----------------------------------------------- +::rtl::OUString PresetHandler::PRESET_DEFAULT() +{ + static ::rtl::OUString RSTYPE = DECLARE_ASCII("default"); + return RSTYPE; +} + +//----------------------------------------------- +::rtl::OUString PresetHandler::TARGET_CURRENT() +{ + static ::rtl::OUString RSTYPE = DECLARE_ASCII("current"); + return RSTYPE; +} + +//----------------------------------------------- +::rtl::OUString PresetHandler::RESOURCETYPE_MENUBAR() +{ + static ::rtl::OUString RSTYPE = DECLARE_ASCII("menubar"); + return RSTYPE; +} + +//----------------------------------------------- +::rtl::OUString PresetHandler::RESOURCETYPE_TOOLBAR() +{ + static ::rtl::OUString RSTYPE = DECLARE_ASCII("toolbar"); + return RSTYPE; +} + +//----------------------------------------------- +::rtl::OUString PresetHandler::RESOURCETYPE_ACCELERATOR() +{ + static ::rtl::OUString RSTYPE = DECLARE_ASCII("accelerator"); + return RSTYPE; +} + +//----------------------------------------------- +::rtl::OUString PresetHandler::RESOURCETYPE_STATUSBAR() +{ + static ::rtl::OUString RSTYPE = DECLARE_ASCII("statusbar"); + return RSTYPE; +} + +//----------------------------------------------- +PresetHandler::PresetHandler(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR) + : ThreadHelpBase (&Application::GetSolarMutex() ) + , m_xSMGR (xSMGR ) + , m_aSharedStorages ( ) + , m_lDocumentStorages(xSMGR ) + , m_aLocale (::comphelper::Locale::X_NOTRANSLATE()) +{ +} + +//----------------------------------------------- +PresetHandler::PresetHandler(const PresetHandler& rCopy) + : ThreadHelpBase (&Application::GetSolarMutex() ) +{ + m_xSMGR = rCopy.m_xSMGR; + m_eConfigType = rCopy.m_eConfigType; + m_sResourceType = rCopy.m_sResourceType; + m_sModule = rCopy.m_sModule; + m_aSharedStorages = rCopy.m_aSharedStorages; + m_xWorkingStorageShare = rCopy.m_xWorkingStorageShare; + m_xWorkingStorageNoLang = rCopy.m_xWorkingStorageNoLang; + m_xWorkingStorageUser = rCopy.m_xWorkingStorageUser; + m_lPresets = rCopy.m_lPresets; + m_lTargets = rCopy.m_lTargets; + m_aLocale = rCopy.m_aLocale; + m_lDocumentStorages = rCopy.m_lDocumentStorages; + m_sRelPathShare = rCopy.m_sRelPathShare; + m_sRelPathNoLang = rCopy.m_sRelPathNoLang; + m_sRelPathUser = rCopy.m_sRelPathUser; +} + +//----------------------------------------------- +PresetHandler::~PresetHandler() +{ + m_xWorkingStorageShare.clear(); + m_xWorkingStorageNoLang.clear(); + m_xWorkingStorageUser.clear(); + + /* #i46497# + Dont call forgetCachedStorages() here for shared storages. + Because we opened different sub storages by using openPath(). + And every already open path was reused and referenced (means it's + ref count was increased!) + So now we have to release our ref counts to these shared storages + only ... and not to free all used storages. + Otherwise we will disconnect all other open configuration access + objects which base on these storages. + */ + m_aSharedStorages->m_lStoragesShare.closePath(m_sRelPathShare); + m_aSharedStorages->m_lStoragesUser.closePath (m_sRelPathUser ); + + /* On the other side closePath() is not needed for our special handled + document storage. Because it's not shared with others ... so we can + free it. + */ + m_lDocumentStorages.forgetCachedStorages(); +} + +//----------------------------------------------- +void PresetHandler::forgetCachedStorages() +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + if (m_eConfigType == E_DOCUMENT) + { + m_xWorkingStorageShare.clear(); + m_xWorkingStorageNoLang.clear(); + m_xWorkingStorageUser.clear(); + } + + m_lDocumentStorages.forgetCachedStorages(); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +::rtl::OUString lcl_getLocalizedMessage(::sal_Int32 nID) +{ + ::rtl::OUString sMessage = ::rtl::OUString::createFromAscii("Unknown error."); + + switch(nID) + { + case ID_CORRUPT_UICONFIG_SHARE : + sMessage = ::rtl::OUString( String( FwkResId( STR_CORRUPT_UICFG_SHARE ))); + break; + + case ID_CORRUPT_UICONFIG_USER : + sMessage = ::rtl::OUString( String( FwkResId( STR_CORRUPT_UICFG_USER ))); + break; + + case ID_CORRUPT_UICONFIG_GENERAL : + sMessage = ::rtl::OUString( String( FwkResId( STR_CORRUPT_UICFG_GENERAL ))); + break; + } + + return sMessage; +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > PresetHandler::getOrCreateRootStorageShare() +{ + css::uno::Reference< css::embed::XStorage > xRoot = m_aSharedStorages->m_lStoragesShare.getRootStorage(); + if (xRoot.is()) + return xRoot; + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::beans::XPropertySet > xPathSettings( + xSMGR->createInstance(SERVICENAME_PATHSETTINGS), + css::uno::UNO_QUERY_THROW); + + ::rtl::OUString sShareLayer; + xPathSettings->getPropertyValue(BASEPATH_SHARE_LAYER) >>= sShareLayer; + + // "UIConfig" is a "multi path" ... use first part only here! + sal_Int32 nPos = sShareLayer.indexOf(';'); + if (nPos > 0) + sShareLayer = sShareLayer.copy(0, nPos); + + // Note: May be an user uses URLs without a final slash! Check it ... + nPos = sShareLayer.lastIndexOf('/'); + if (nPos != sShareLayer.getLength()-1) + sShareLayer += ::rtl::OUString::createFromAscii("/"); + + sShareLayer += RELPATH_SHARE_LAYER; // folder + /* + // TODO remove me! + // Attention: This is temp. workaround ... We create a temp. storage file + // based of a sytem directory. This must be used so, till the storage implementation + // can work on directories too. + */ + css::uno::Sequence< css::uno::Any > lArgs(2); + lArgs[0] <<= sShareLayer; + lArgs[1] <<= css::embed::ElementModes::READ | css::embed::ElementModes::NOCREATE; + + css::uno::Reference< css::lang::XSingleServiceFactory > xStorageFactory(xSMGR->createInstance(SERVICENAME_FILESYSTEMSTORAGEFACTORY) , css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::embed::XStorage > xStorage; + + try + { + xStorage = css::uno::Reference< css::embed::XStorage >(xStorageFactory->createInstanceWithArguments(lArgs), css::uno::UNO_QUERY_THROW); + } + catch(const css::uno::Exception& ex) + { + throw css::configuration::CorruptedUIConfigurationException( + lcl_getLocalizedMessage(ID_CORRUPT_UICONFIG_SHARE), + css::uno::Reference< css::uno::XInterface >(), + ex.Message); + } + + m_aSharedStorages->m_lStoragesShare.setRootStorage(xStorage); + + return xStorage; +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > PresetHandler::getOrCreateRootStorageUser() +{ + css::uno::Reference< css::embed::XStorage > xRoot = m_aSharedStorages->m_lStoragesUser.getRootStorage(); + if (xRoot.is()) + return xRoot; + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::beans::XPropertySet > xPathSettings( + xSMGR->createInstance(SERVICENAME_PATHSETTINGS), + css::uno::UNO_QUERY_THROW); + + ::rtl::OUString sUserLayer; + xPathSettings->getPropertyValue(BASEPATH_USER_LAYER) >>= sUserLayer ; + + // Note: May be an user uses URLs without a final slash! Check it ... + sal_Int32 nPos = sUserLayer.lastIndexOf('/'); + if (nPos != sUserLayer.getLength()-1) + sUserLayer += ::rtl::OUString::createFromAscii("/"); + + sUserLayer += RELPATH_USER_LAYER; // storage file + + css::uno::Sequence< css::uno::Any > lArgs(2); + lArgs[0] <<= sUserLayer; + lArgs[1] <<= css::embed::ElementModes::READWRITE; + + css::uno::Reference< css::lang::XSingleServiceFactory > xStorageFactory(xSMGR->createInstance(SERVICENAME_FILESYSTEMSTORAGEFACTORY) , css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::embed::XStorage > xStorage; + + try + { + xStorage = css::uno::Reference< css::embed::XStorage >(xStorageFactory->createInstanceWithArguments(lArgs), css::uno::UNO_QUERY_THROW); + } + catch(const css::uno::Exception& ex) + { + throw css::configuration::CorruptedUIConfigurationException( + lcl_getLocalizedMessage(ID_CORRUPT_UICONFIG_USER), + css::uno::Reference< css::uno::XInterface >(), + ex.Message); + } + + m_aSharedStorages->m_lStoragesUser.setRootStorage(xStorage); + + return xStorage; +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > PresetHandler::getWorkingStorageShare() +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + return m_xWorkingStorageShare; + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > PresetHandler::getWorkingStorageUser() +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + return m_xWorkingStorageUser; + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > PresetHandler::getParentStorageShare(const css::uno::Reference< css::embed::XStorage >& /*xChild*/) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::embed::XStorage > xWorking = m_xWorkingStorageShare; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + return m_aSharedStorages->m_lStoragesShare.getParentStorage(xWorking); +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > PresetHandler::getParentStorageUser(const css::uno::Reference< css::embed::XStorage >& /*xChild*/) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::embed::XStorage > xWorking = m_xWorkingStorageUser; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + return m_aSharedStorages->m_lStoragesUser.getParentStorage(xWorking); +} + +//----------------------------------------------- +void PresetHandler::connectToResource( PresetHandler::EConfigType eConfigType , + const ::rtl::OUString& sResource , + const ::rtl::OUString& sModule , + const css::uno::Reference< css::embed::XStorage >& xDocumentRoot, + const ::comphelper::Locale& aLocale ) +{ + // TODO free all current open storages! + + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + m_eConfigType = eConfigType ; + m_sResourceType = sResource ; + m_sModule = sModule ; + m_aLocale = aLocale ; + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::embed::XStorage > xShare; + css::uno::Reference< css::embed::XStorage > xNoLang; + css::uno::Reference< css::embed::XStorage > xUser; + + // special case for documents + // use outside root storage, if we run in E_DOCUMENT mode! + if (eConfigType == E_DOCUMENT) + { + if (!xDocumentRoot.is()) + throw css::uno::RuntimeException( + ::rtl::OUString::createFromAscii("There is valid root storage, where the UI configuration can work on."), + css::uno::Reference< css::uno::XInterface >()); + m_lDocumentStorages.setRootStorage(xDocumentRoot); + xShare = xDocumentRoot; + xUser = xDocumentRoot; + } + else + { + xShare = getOrCreateRootStorageShare(); + xUser = getOrCreateRootStorageUser(); + } + + // #...# + try + { + + // a) inside share layer we should not create any new structures ... We jave to use + // existing ones only! + // b) inside user layer we can (SOFT mode!) but sometimes we shouldnt (HARD mode!) + // create new empty structures. We should preferr using of any existing structure. + sal_Int32 eShareMode = (css::embed::ElementModes::READ | css::embed::ElementModes::NOCREATE); + sal_Int32 eUserMode = (css::embed::ElementModes::READWRITE ); + + ::rtl::OUStringBuffer sRelPathBuf(1024); + ::rtl::OUString sRelPathShare; + ::rtl::OUString sRelPathNoLang; + ::rtl::OUString sRelPathUser; + switch(eConfigType) + { + case E_GLOBAL : + { + sRelPathBuf.append(SUBSTORAGE_GLOBAL); + sRelPathBuf.append(PATH_SEPERATOR ); + sRelPathBuf.append(sResource ); + sRelPathShare = sRelPathBuf.makeStringAndClear(); + sRelPathUser = sRelPathShare; + + xShare = impl_openPathIgnoringErrors(sRelPathShare, eShareMode, sal_True ); + xUser = impl_openPathIgnoringErrors(sRelPathUser , eUserMode , sal_False); + } + break; + + case E_MODULES : + { + sRelPathBuf.append(SUBSTORAGE_MODULES); + sRelPathBuf.append(PATH_SEPERATOR ); + sRelPathBuf.append(sModule ); + sRelPathBuf.append(PATH_SEPERATOR ); + sRelPathBuf.append(sResource ); + sRelPathShare = sRelPathBuf.makeStringAndClear(); + sRelPathUser = sRelPathShare; + + xShare = impl_openPathIgnoringErrors(sRelPathShare, eShareMode, sal_True ); + xUser = impl_openPathIgnoringErrors(sRelPathUser , eUserMode , sal_False); + } + break; + + case E_DOCUMENT : + { + // A document does not have a share layer in real. + // It has one layer only, and this one should be opened READ_WRITE. + // So we open the user layer here only and set the share layer equals to it .-) + + sRelPathBuf.append(sResource); + sRelPathUser = sRelPathBuf.makeStringAndClear(); + sRelPathShare = sRelPathUser; + + try + { + xUser = m_lDocumentStorages.openPath(sRelPathUser , eUserMode ); + xShare = xUser; + } + catch(const css::uno::RuntimeException& exRun) + { throw exRun; } + catch(const css::uno::Exception&) + { xShare.clear(); xUser.clear(); } + } + break; + } + + // Non-localized global share + xNoLang = xShare; + sRelPathNoLang = sRelPathShare; + + if ( + (aLocale != ::comphelper::Locale::X_NOTRANSLATE()) && // localized level? + (eConfigType != E_DOCUMENT ) // no localization in document mode! + ) + { + // First try to find the right localized set inside share layer. + // Fallbacks are allowed there. + ::comphelper::Locale aShareLocale = aLocale ; + ::rtl::OUString sLocalizedSharePath(sRelPathShare); + sal_Bool bAllowFallbacks = sal_True ; + xShare = impl_openLocalizedPathIgnoringErrors(sLocalizedSharePath, eShareMode, sal_True , aShareLocale, bAllowFallbacks); + + // The try to locate the right sub dir inside user layer ... without using fallbacks! + // Normaly the corresponding sub dir should be created matching the specified locale. + // Because we allow creation of storages inside user layer by default. + ::comphelper::Locale aUserLocale = aLocale ; + ::rtl::OUString sLocalizedUserPath(sRelPathUser); + bAllowFallbacks = sal_False ; + xUser = impl_openLocalizedPathIgnoringErrors(sLocalizedUserPath, eUserMode , sal_False, aUserLocale, bAllowFallbacks); + + sRelPathShare = sLocalizedSharePath; + sRelPathUser = sLocalizedUserPath ; + } + + // read content of level 3 (presets, targets) + css::uno::Reference< css::container::XNameAccess > xAccess ; + css::uno::Sequence< ::rtl::OUString > lNames ; + const ::rtl::OUString* pNames ; + sal_Int32 c ; + sal_Int32 i ; + OUStringList lPresets; + OUStringList lTargets; + + // read preset names of share layer + xAccess = css::uno::Reference< css::container::XNameAccess >(xShare, css::uno::UNO_QUERY); + if (xAccess.is()) + { + lNames = xAccess->getElementNames(); + pNames = lNames.getConstArray(); + c = lNames.getLength(); + + for (i=0; i<c; ++i) + { + ::rtl::OUString sTemp = pNames[i]; + sal_Int32 nPos = sTemp.indexOf(FILE_EXTENSION); + if (nPos > -1) + sTemp = sTemp.copy(0,nPos); + lPresets.push_back(sTemp); + } + } + + // read preset names of user layer + xAccess = css::uno::Reference< css::container::XNameAccess >(xUser, css::uno::UNO_QUERY); + if (xAccess.is()) + { + lNames = xAccess->getElementNames(); + pNames = lNames.getConstArray(); + c = lNames.getLength(); + + for (i=0; i<c; ++i) + { + ::rtl::OUString sTemp = pNames[i]; + sal_Int32 nPos = sTemp.indexOf(FILE_EXTENSION); + if (nPos > -1) + sTemp = sTemp.copy(0,nPos); + lTargets.push_back(sTemp); + } + } + + // SAFE -> ---------------------------------- + aWriteLock.lock(); + + m_xWorkingStorageShare = xShare ; + m_xWorkingStorageNoLang= xNoLang; + m_xWorkingStorageUser = xUser ; + m_lPresets = lPresets; + m_lTargets = lTargets; + m_sRelPathShare = sRelPathShare; + m_sRelPathNoLang = sRelPathNoLang; + m_sRelPathUser = sRelPathUser; + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + } + catch(const css::uno::Exception& ex) + { + throw css::configuration::CorruptedUIConfigurationException( + lcl_getLocalizedMessage(ID_CORRUPT_UICONFIG_GENERAL), + css::uno::Reference< css::uno::XInterface >(), + ex.Message); + } +} + +//----------------------------------------------- +void PresetHandler::copyPresetToTarget(const ::rtl::OUString& sPreset, + const ::rtl::OUString& sTarget) +{ + // dont check our preset list, if element exists + // We try to open it and forward all errors to the user! + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::embed::XStorage > xWorkingShare = m_xWorkingStorageShare; + css::uno::Reference< css::embed::XStorage > xWorkingNoLang= m_xWorkingStorageNoLang; + css::uno::Reference< css::embed::XStorage > xWorkingUser = m_xWorkingStorageUser ; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + // e.g. module without any config data ?! + if ( + (!xWorkingShare.is()) || + (!xWorkingUser.is() ) + ) + { + return; + } + + ::rtl::OUString sPresetFile(sPreset); + sPresetFile += FILE_EXTENSION; + + ::rtl::OUString sTargetFile(sTarget); + sTargetFile += FILE_EXTENSION; + + // remove existing elements before you try to copy the preset to that location ... + // Otherwise w will get an ElementExistException inside copyElementTo()! + css::uno::Reference< css::container::XNameAccess > xCheckingUser(xWorkingUser, css::uno::UNO_QUERY_THROW); + if (xCheckingUser->hasByName(sTargetFile)) + xWorkingUser->removeElement(sTargetFile); + + xWorkingShare->copyElementTo(sPresetFile, xWorkingUser, sTargetFile); + + // If our storages work in transacted mode, we have + // to commit all changes from bottom to top! + commitUserChanges(); +} + +//----------------------------------------------- +css::uno::Reference< css::io::XStream > PresetHandler::openPreset(const ::rtl::OUString& sPreset, + sal_Bool bUseNoLangGlobal) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::embed::XStorage > xFolder = bUseNoLangGlobal? m_xWorkingStorageNoLang: m_xWorkingStorageShare; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + // e.g. module without any config data ?! + if (!xFolder.is()) + return css::uno::Reference< css::io::XStream >(); + + ::rtl::OUString sFile(sPreset); + sFile += FILE_EXTENSION; + + // inform user about errors (use original exceptions!) + css::uno::Reference< css::io::XStream > xStream = xFolder->openStreamElement(sFile, css::embed::ElementModes::READ); + return xStream; +} + +//----------------------------------------------- +css::uno::Reference< css::io::XStream > PresetHandler::openTarget(const ::rtl::OUString& sTarget , + sal_Bool bCreateIfMissing) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::embed::XStorage > xFolder = m_xWorkingStorageUser; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + // e.g. module without any config data ?! + if (!xFolder.is()) + return css::uno::Reference< css::io::XStream >(); + + ::rtl::OUString sFile(sTarget); + sFile += FILE_EXTENSION; + + sal_Int32 nOpenMode = css::embed::ElementModes::READWRITE; + if (!bCreateIfMissing) + nOpenMode |= css::embed::ElementModes::NOCREATE; + + // try it in read/write mode first and ignore errors. + css::uno::Reference< css::io::XStream > xStream; + try + { + xStream = xFolder->openStreamElement(sFile, nOpenMode); + return xStream; + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { xStream.clear(); } + + // try it readonly if it failed before. + // inform user about errors (use original exceptions!) + nOpenMode &= ~css::embed::ElementModes::WRITE; + xStream = xFolder->openStreamElement(sFile, nOpenMode); + + return xStream; +} + +//----------------------------------------------- +void PresetHandler::commitUserChanges() +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::embed::XStorage > xWorking = m_xWorkingStorageUser; + EConfigType eCfgType = m_eConfigType; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + // e.g. module without any config data ?! + if (!xWorking.is()) + return; + + ::rtl::OUString sPath; + + switch(eCfgType) + { + case E_GLOBAL : + case E_MODULES : + { + sPath = m_aSharedStorages->m_lStoragesUser.getPathOfStorage(xWorking); + m_aSharedStorages->m_lStoragesUser.commitPath(sPath); + m_aSharedStorages->m_lStoragesUser.notifyPath(sPath); + } + break; + + case E_DOCUMENT : + { + sPath = m_lDocumentStorages.getPathOfStorage(xWorking); + m_lDocumentStorages.commitPath(sPath); + m_lDocumentStorages.notifyPath(sPath); + } + break; + } +} + +//----------------------------------------------- +void PresetHandler::addStorageListener(IStorageListener* pListener) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + ::rtl::OUString sRelPath = m_sRelPathUser; // use user path ... because we dont work directly on the share layer! + EConfigType eCfgType = m_eConfigType; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + if (!sRelPath.getLength()) + return; + + switch(eCfgType) + { + case E_GLOBAL : + case E_MODULES : + { + m_aSharedStorages->m_lStoragesUser.addStorageListener(pListener, sRelPath); + } + break; + + case E_DOCUMENT : + { + m_lDocumentStorages.addStorageListener(pListener, sRelPath); + } + break; + } +} + +//----------------------------------------------- +void PresetHandler::removeStorageListener(IStorageListener* pListener) +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + ::rtl::OUString sRelPath = m_sRelPathUser; // use user path ... because we dont work directly on the share layer! + EConfigType eCfgType = m_eConfigType; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + if (!sRelPath.getLength()) + return; + + switch(eCfgType) + { + case E_GLOBAL : + case E_MODULES : + { + m_aSharedStorages->m_lStoragesUser.removeStorageListener(pListener, sRelPath); + } + break; + + case E_DOCUMENT : + { + m_lDocumentStorages.removeStorageListener(pListener, sRelPath); + } + break; + } +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > PresetHandler::impl_openPathIgnoringErrors(const ::rtl::OUString& sPath , + sal_Int32 eMode , + sal_Bool bShare) +{ + css::uno::Reference< css::embed::XStorage > xPath; + try + { + if (bShare) + xPath = m_aSharedStorages->m_lStoragesShare.openPath(sPath, eMode); + else + xPath = m_aSharedStorages->m_lStoragesUser.openPath(sPath, eMode); + } + catch(const css::uno::RuntimeException& exRun) + { throw exRun; } + catch(const css::uno::Exception&) + { xPath.clear(); } + return xPath; +} + +//----------------------------------------------- +::std::vector< ::rtl::OUString >::const_iterator PresetHandler::impl_findMatchingLocalizedValue(const ::std::vector< ::rtl::OUString >& lLocalizedValues, + ::comphelper::Locale& aLocale , + sal_Bool bAllowFallbacks ) +{ + ::std::vector< ::rtl::OUString >::const_iterator pFound = lLocalizedValues.end(); + if (bAllowFallbacks) + { + pFound = ::comphelper::Locale::getFallback(lLocalizedValues, aLocale.toISO()); + } + else + { + for ( pFound = lLocalizedValues.begin(); + pFound != lLocalizedValues.end() ; + ++pFound ) + { + const ::rtl::OUString& sCheckISO = *pFound; + ::comphelper::Locale aCheckLocale(sCheckISO); + if (aCheckLocale.equals(aLocale)) + break; + } + } + + // if we found a valid locale ... take it over to our in/out parameter aLocale + if (pFound != lLocalizedValues.end()) + { + const ::rtl::OUString& sISOLocale = *pFound; + aLocale.fromISO(sISOLocale); + } + + return pFound; +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > PresetHandler::impl_openLocalizedPathIgnoringErrors(::rtl::OUString& sPath , + sal_Int32 eMode , + sal_Bool bShare , + ::comphelper::Locale& aLocale , + sal_Bool bAllowFallback) +{ + css::uno::Reference< css::embed::XStorage > xPath = impl_openPathIgnoringErrors(sPath, eMode, bShare); + ::std::vector< ::rtl::OUString > lSubFolders = impl_getSubFolderNames(xPath); + ::std::vector< ::rtl::OUString >::const_iterator pLocaleFolder = impl_findMatchingLocalizedValue(lSubFolders, aLocale, bAllowFallback); + + // no fallback ... creation not allowed => no storage + if ( + (pLocaleFolder == lSubFolders.end() ) && + ((eMode & css::embed::ElementModes::NOCREATE) == css::embed::ElementModes::NOCREATE) + ) + return css::uno::Reference< css::embed::XStorage >(); + + // it doesnt matter, if there is a locale fallback or not + // If creation of storages is allowed, we do it anyway. + // Otherwhise we have no acc config at all, which can make other trouble. + ::rtl::OUString sLocalizedPath; + sLocalizedPath = sPath; + sLocalizedPath += PATH_SEPERATOR; + if (pLocaleFolder != lSubFolders.end()) + sLocalizedPath += *pLocaleFolder; + else + sLocalizedPath += aLocale.toISO(); + + css::uno::Reference< css::embed::XStorage > xLocalePath = impl_openPathIgnoringErrors(sLocalizedPath, eMode, bShare); + + if (xLocalePath.is()) + sPath = sLocalizedPath; + else + sPath = ::rtl::OUString(); + + return xLocalePath; +} + +//----------------------------------------------- +::std::vector< ::rtl::OUString > PresetHandler::impl_getSubFolderNames(const css::uno::Reference< css::embed::XStorage >& xFolder) +{ + css::uno::Reference< css::container::XNameAccess > xAccess(xFolder, css::uno::UNO_QUERY); + if (!xAccess.is()) + return ::std::vector< ::rtl::OUString >(); + + ::std::vector< ::rtl::OUString > lSubFolders; + const css::uno::Sequence< ::rtl::OUString > lNames = xAccess->getElementNames(); + const ::rtl::OUString* pNames = lNames.getConstArray(); + sal_Int32 c = lNames.getLength(); + sal_Int32 i = 0; + + for (i=0; i<c; ++i) + { + try + { + if (xFolder->isStorageElement(pNames[i])) + lSubFolders.push_back(pNames[i]); + } + catch(const css::uno::RuntimeException& exRun) + { throw exRun; } + catch(const css::uno::Exception&) + {} + } + + return lSubFolders; +} + +//----------------------------------------------- +} // namespace framework diff --git a/framework/source/accelerators/storageholder.cxx b/framework/source/accelerators/storageholder.cxx new file mode 100644 index 000000000000..33776d8c7fc1 --- /dev/null +++ b/framework/source/accelerators/storageholder.cxx @@ -0,0 +1,637 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include <accelerators/storageholder.hxx> + +//=============================================== +// own includes +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> +#include <services.h> + +//=============================================== +// interface includes + +#ifndef __COM_SUN_STAR_CONTAINER_NOSUCHELEMENTEXCEPTION_HPP_ +#include <com/sun/star/container/NoSuchElementException.hpp> +#endif + +#ifndef __COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_ +#include <com/sun/star/container/XNameAccess.hpp> +#endif + +#ifndef __COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_ +#include <com/sun/star/beans/XPropertySet.hpp> +#endif + +#ifndef __COM_SUN_STAR_EMBED_ELEMENTMODES_HPP_ +#include <com/sun/star/embed/ElementModes.hpp> +#endif + +#ifndef __COM_SUN_STAR_EMBED_XTRANSACTEDOBJECT_HPP_ +#include <com/sun/star/embed/XTransactedObject.hpp> +#endif + +#ifndef __COM_SUN_STAR_EMBED_XPACKAGESTRUCTURECREATOR_HPP_ +#include <com/sun/star/embed/XPackageStructureCreator.hpp> +#endif + +#ifndef __COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_ +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#endif + +#ifndef __COM_SUN_STAR_IO_XSEEKABLE_HPP_ +#include <com/sun/star/io/XSeekable.hpp> +#endif + +//=============================================== +// other includes +#include <comphelper/processfactory.hxx> + +//=============================================== +// const + +#define PATH_SEPERATOR_ASCII "/" +#define PATH_SEPERATOR_UNICODE ((sal_Unicode)'/') +#define PATH_SEPERATOR ::rtl::OUString::createFromAscii(PATH_SEPERATOR_ASCII) + +//=============================================== +// namespace + +namespace framework +{ + +namespace css = ::com::sun::star; + +//----------------------------------------------- +StorageHolder::StorageHolder() + : ThreadHelpBase( ) + , m_xSMGR (::comphelper::getProcessServiceFactory()) +{ +} + +//----------------------------------------------- +StorageHolder::StorageHolder(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR) + : ThreadHelpBase( ) + , m_xSMGR (xSMGR) +{ +} + +//----------------------------------------------- +StorageHolder::~StorageHolder() +{ + // TODO implement me + // dispose/clear etcpp. +} + +//----------------------------------------------- +void StorageHolder::forgetCachedStorages() +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + TPath2StorageInfo::iterator pIt; + for ( pIt = m_lStorages.begin(); + pIt != m_lStorages.end() ; + ++pIt ) + { + TStorageInfo& rInfo = pIt->second; + // TODO think about listener ! + rInfo.Storage.clear(); + } + m_lStorages.clear(); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +void StorageHolder::setRootStorage(const css::uno::Reference< css::embed::XStorage >& xRoot) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + m_xRoot = xRoot; + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > StorageHolder::getRootStorage() const +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + return m_xRoot; + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > StorageHolder::openPath(const ::rtl::OUString& sPath , + sal_Int32 nOpenMode) +{ + ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath); + OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath); + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::embed::XStorage > xParent = m_xRoot; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::embed::XStorage > xChild ; + ::rtl::OUString sRelPath; + OUStringList::const_iterator pIt ; + + for ( pIt = lFolders.begin(); + pIt != lFolders.end() ; + ++pIt ) + { + const ::rtl::OUString& sChild = *pIt; + ::rtl::OUString sCheckPath (sRelPath); + sCheckPath += sChild; + sCheckPath += PATH_SEPERATOR; + + // SAFE -> ------------------------------ + aReadLock.lock(); + + // If we found an already open storage ... we must increase + // its use count. Otherwhise it will may be closed to early :-) + TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath); + TStorageInfo* pInfo = 0; + if (pCheck != m_lStorages.end()) + { + pInfo = &(pCheck->second); + ++(pInfo->UseCount); + xChild = pInfo->Storage; + } + else + { + aReadLock.unlock(); + // <- SAFE ------------------------------ + + try + { + xChild = StorageHolder::openSubStorageWithFallback(xParent, sChild, nOpenMode, sal_True); // TODO think about delegating fallback decision to our own calli! + } + catch(const css::uno::RuntimeException& exRun) + { throw exRun; } + catch(const css::uno::Exception& exAny) + { + /* TODO URGENT! + in case we found some "already existing storages" on the path before and increased its UseCount ... + and now we will get an exception on creating a new sub storage ... + we must decrease all UseCounts, which was touched before. Otherwise these storages cant be closed! + + Idea: Using of another structure member "PossibleUseCount" as vector of unique numbers. + Every thread use another unique number to identify all "owned candidates". + A flush method with the same unique number force increasing of the "UseCount" variable then + inside a synchronized block ... + */ + throw exAny; + } + + // SAFE -> ------------------------------ + WriteGuard aWriteLock(m_aLock); + pInfo = &(m_lStorages[sCheckPath]); + pInfo->Storage = xChild; + pInfo->UseCount = 1; + aWriteLock.unlock(); + // <- SAFE ------------------------------ + } + + xParent = xChild; + sRelPath += sChild; + sRelPath += PATH_SEPERATOR; + } + + // TODO think about return last storage as working storage ... but dont caching it inside this holder! + // => otherwhise the same storage is may be commit more then once. + + return xChild; +} + +//----------------------------------------------- +StorageHolder::TStorageList StorageHolder::getAllPathStorages(const ::rtl::OUString& sPath) +{ + ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath); + OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath); + + StorageHolder::TStorageList lStoragesOfPath; + ::rtl::OUString sRelPath ; + OUStringList::const_iterator pIt ; + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + for ( pIt = lFolders.begin(); + pIt != lFolders.end() ; + ++pIt ) + { + const ::rtl::OUString& sChild = *pIt; + ::rtl::OUString sCheckPath (sRelPath); + sCheckPath += sChild; + sCheckPath += PATH_SEPERATOR; + + TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath); + if (pCheck == m_lStorages.end()) + { + // at least one path element was not found + // Seems that this path isnt open ... + lStoragesOfPath.clear(); + return lStoragesOfPath; + } + + TStorageInfo& rInfo = pCheck->second; + lStoragesOfPath.push_back(rInfo.Storage); + + sRelPath += sChild; + sRelPath += PATH_SEPERATOR; + } + + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + return lStoragesOfPath; +} + +//----------------------------------------------- +void StorageHolder::commitPath(const ::rtl::OUString& sPath) +{ + StorageHolder::TStorageList lStorages = getAllPathStorages(sPath); + + css::uno::Reference< css::embed::XTransactedObject > xCommit; + StorageHolder::TStorageList::reverse_iterator pIt; + for ( pIt = lStorages.rbegin(); // order of commit is important ... otherwhise changes are not recognized! + pIt != lStorages.rend() ; + ++pIt ) + { + xCommit = css::uno::Reference< css::embed::XTransactedObject >(*pIt, css::uno::UNO_QUERY); + if (!xCommit.is()) + continue; + xCommit->commit(); + } + + // SAFE -> ------------------------------ + ReadGuard aReadLock(m_aLock); + xCommit = css::uno::Reference< css::embed::XTransactedObject >(m_xRoot, css::uno::UNO_QUERY); + aReadLock.unlock(); + // <- SAFE ------------------------------ + + if (xCommit.is()) + xCommit->commit(); +} + +//----------------------------------------------- +void StorageHolder::closePath(const ::rtl::OUString& rPath) +{ + ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(rPath); + OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath); + + /* convert list of pathes in the following way: + [0] = "path_1" => "path_1 + [1] = "path_2" => "path_1/path_2" + [2] = "path_3" => "path_1/path_2/path_3" + */ + OUStringList::iterator pIt1 ; + ::rtl::OUString sParentPath; + for ( pIt1 = lFolders.begin(); + pIt1 != lFolders.end() ; + ++pIt1 ) + { + ::rtl::OUString sCurrentRelPath = sParentPath; + sCurrentRelPath += *pIt1; + sCurrentRelPath += PATH_SEPERATOR; + *pIt1 = sCurrentRelPath; + sParentPath = sCurrentRelPath; + } + + // SAFE -> ------------------------------ + ReadGuard aReadLock(m_aLock); + + OUStringList::reverse_iterator pIt2; + for ( pIt2 = lFolders.rbegin(); + pIt2 != lFolders.rend() ; + ++pIt2 ) + { + ::rtl::OUString sPath = *pIt2; + TPath2StorageInfo::iterator pPath = m_lStorages.find(sPath); + if (pPath == m_lStorages.end()) + continue; // ??? + + TStorageInfo& rInfo = pPath->second; + --rInfo.UseCount; + if (rInfo.UseCount < 1) + { + rInfo.Storage.clear(); + m_lStorages.erase(pPath); + } + } + + aReadLock.unlock(); + // <- SAFE ------------------------------ +} + +//----------------------------------------------- +void StorageHolder::notifyPath(const ::rtl::OUString& sPath) +{ + ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath); + + // SAFE -> ------------------------------ + ReadGuard aReadLock(m_aLock); + + TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath); + if (pIt1 == m_lStorages.end()) + return; + + TStorageInfo& rInfo = pIt1->second; + TStorageListenerList::iterator pIt2; + for ( pIt2 = rInfo.Listener.begin(); + pIt2 != rInfo.Listener.end() ; + ++pIt2 ) + { + IStorageListener* pListener = *pIt2; + if (pListener) + pListener->changesOccured(sNormedPath); + } + + aReadLock.unlock(); + // <- SAFE ------------------------------ +} + +//----------------------------------------------- +void StorageHolder::addStorageListener( IStorageListener* pListener, + const ::rtl::OUString& sPath ) +{ + ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath); + + // SAFE -> ------------------------------ + ReadGuard aReadLock(m_aLock); + + TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath); + if (pIt1 == m_lStorages.end()) + return; + + TStorageInfo& rInfo = pIt1->second; + TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener); + if (pIt2 == rInfo.Listener.end()) + rInfo.Listener.push_back(pListener); + + aReadLock.unlock(); + // <- SAFE ------------------------------ +} + +//----------------------------------------------- +void StorageHolder::removeStorageListener( IStorageListener* pListener, + const ::rtl::OUString& sPath ) +{ + ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath); + + // SAFE -> ------------------------------ + ReadGuard aReadLock(m_aLock); + + TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath); + if (pIt1 == m_lStorages.end()) + return; + + TStorageInfo& rInfo = pIt1->second; + TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener); + if (pIt2 != rInfo.Listener.end()) + rInfo.Listener.erase(pIt2); + + aReadLock.unlock(); + // <- SAFE ------------------------------ +} + +//----------------------------------------------- +::rtl::OUString StorageHolder::getPathOfStorage(const css::uno::Reference< css::embed::XStorage >& xStorage) +{ + // SAFE -> ------------------------------ + ReadGuard aReadLock(m_aLock); + + TPath2StorageInfo::const_iterator pIt; + for ( pIt = m_lStorages.begin(); + pIt != m_lStorages.end() ; + ++pIt ) + { + const TStorageInfo& rInfo = pIt->second; + if (rInfo.Storage == xStorage) + break; + } + + if (pIt == m_lStorages.end()) + return ::rtl::OUString(); + + return pIt->first; + + // <- SAFE ------------------------------ +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const css::uno::Reference< css::embed::XStorage >& xChild) +{ + ::rtl::OUString sChildPath = getPathOfStorage(xChild); + return getParentStorage(sChildPath); +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const ::rtl::OUString& sChildPath) +{ + // normed path = "a/b/c/" ... we search for "a/b/" + ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sChildPath); + OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath); + sal_Int32 c = lFolders.size(); + + // a) "" => - => no parent + // b) "a/b/c/" => "a/b/" => return storage "a/b/" + // c) "a/" => "" => return root ! + + // a) + if (c < 1) + return css::uno::Reference< css::embed::XStorage >(); + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + // b) + if (c < 2) + return m_xRoot; + + // c) + ::rtl::OUString sParentPath; + sal_Int32 i = 0; + for (i=0; i<c-1; ++i) + { + sParentPath += lFolders[i]; + sParentPath += PATH_SEPERATOR; + } + + TPath2StorageInfo::const_iterator pParent = m_lStorages.find(sParentPath); + if (pParent != m_lStorages.end()) + return pParent->second.Storage; + + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + // ? + LOG_WARNING("StorageHolder::getParentStorage()", "Unexpected situation. Cached storage item seems to be wrong.") + return css::uno::Reference< css::embed::XStorage >(); +} + +//----------------------------------------------- +void StorageHolder::operator=(const StorageHolder& rCopy) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + m_xSMGR = rCopy.m_xSMGR; // ??? + m_xRoot = rCopy.m_xRoot; + m_lStorages = rCopy.m_lStorages; + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- +} + +//----------------------------------------------- +css::uno::Reference< css::embed::XStorage > StorageHolder::openSubStorageWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage , + const ::rtl::OUString& sSubStorage , + sal_Int32 eOpenMode , + sal_Bool bAllowFallback) +{ + // a) try it first with user specified open mode + // ignore errors ... but save it for later use! + css::uno::Exception exResult; + try + { + css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eOpenMode); + if (xSubStorage.is()) + return xSubStorage; + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception& ex) + { exResult = ex; } + + // b) readonly already tried? => forward last error! + if ( + (!bAllowFallback ) || // fallback allowed ? + ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE) // fallback possible ? + ) + throw exResult; + + // c) try it readonly + // dont catch exception here! Outside code whish to know, if operation failed or not. + // Otherwhise they work on NULL references ... + sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE); + css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eNewMode); + if (xSubStorage.is()) + return xSubStorage; + + // d) no chance! + LOG_WARNING("openSubStorageWithFallback()", "Unexpected situation! Got no exception for missing storage ...") + return css::uno::Reference< css::embed::XStorage >(); +} + +//----------------------------------------------- +css::uno::Reference< css::io::XStream > StorageHolder::openSubStreamWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage , + const ::rtl::OUString& sSubStream , + sal_Int32 eOpenMode , + sal_Bool bAllowFallback) +{ + // a) try it first with user specified open mode + // ignore errors ... but save it for later use! + css::uno::Exception exResult; + try + { + css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eOpenMode); + if (xSubStream.is()) + return xSubStream; + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception& ex) + { exResult = ex; } + + // b) readonly already tried? => forward last error! + if ( + (!bAllowFallback ) || // fallback allowed ? + ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE) // fallback possible ? + ) + throw exResult; + + // c) try it readonly + // dont catch exception here! Outside code whish to know, if operation failed or not. + // Otherwhise they work on NULL references ... + sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE); + css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eNewMode); + if (xSubStream.is()) + return xSubStream; + + // d) no chance! + LOG_WARNING("openSubStreamWithFallbacks()", "Unexpected situation! Got no exception for missing stream ...") + return css::uno::Reference< css::io::XStream >(); +} + +//----------------------------------------------- +::rtl::OUString StorageHolder::impl_st_normPath(const ::rtl::OUString& sPath) +{ + // path must start without "/" but end with "/"! + + ::rtl::OUString sNormedPath = sPath; + + // "/bla" => "bla" && "/" => "" (!) + if (sNormedPath.indexOf(PATH_SEPERATOR) == 0) + sNormedPath += sNormedPath.copy(1); + + // "/" => "" || "" => "" ? + if (sNormedPath.getLength() < 1) + return ::rtl::OUString(); + + // "bla" => "bla/" + if (sNormedPath.lastIndexOf(PATH_SEPERATOR) != (sNormedPath.getLength()-1)) + sNormedPath += PATH_SEPERATOR; + + return sNormedPath; +} + +//----------------------------------------------- +OUStringList StorageHolder::impl_st_parsePath(const ::rtl::OUString& sPath) +{ + OUStringList lToken; + sal_Int32 i = 0; + while (sal_True) + { + ::rtl::OUString sToken = sPath.getToken(0, PATH_SEPERATOR_UNICODE, i); + if (i < 0) + break; + lToken.push_back(sToken); + } + return lToken; +} + +//=============================================== +} // namespace framework |