1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
27 #include <migration.hxx>
28 #include "migration_impl.hxx"
30 #include <sal/log.hxx>
31 #include <unotools/textsearch.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/sequence.hxx>
34 #include <unotools/bootstrap.hxx>
35 #include <rtl/uri.hxx>
36 #include <i18nlangtag/lang.h>
37 #include <comphelper/diagnose_ex.hxx>
38 #include <tools/urlobj.hxx>
39 #include <officecfg/Office/UI.hxx>
40 #include <osl/file.hxx>
41 #include <osl/security.hxx>
42 #include <unotools/configmgr.hxx>
44 #include <com/sun/star/configuration/Update.hpp>
45 #include <com/sun/star/configuration/theDefaultProvider.hpp>
46 #include <com/sun/star/container/XNameContainer.hpp>
47 #include <com/sun/star/task/XJob.hpp>
48 #include <com/sun/star/beans/NamedValue.hpp>
49 #include <com/sun/star/beans/XPropertySet.hpp>
50 #include <com/sun/star/util/XRefreshable.hpp>
51 #include <com/sun/star/util/XChangesBatch.hpp>
52 #include <com/sun/star/embed/ElementModes.hpp>
53 #include <com/sun/star/embed/FileSystemStorageFactory.hpp>
54 #include <com/sun/star/embed/XStorage.hpp>
55 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
56 #include <com/sun/star/ui/UIConfigurationManager.hpp>
57 #include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
58 #include <vcl/commandinfoprovider.hxx>
61 using namespace com::sun::star::task
;
62 using namespace com::sun::star::lang
;
63 using namespace com::sun::star::beans
;
64 using namespace com::sun::star::util
;
65 using namespace com::sun::star::container
;
66 using com::sun::star::uno::Exception
;
67 using namespace com::sun::star
;
73 constexpr OUString ITEM_DESCRIPTOR_COMMANDURL
= u
"CommandURL"_ustr
;
74 constexpr OUString ITEM_DESCRIPTOR_CONTAINER
= u
"ItemDescriptorContainer"_ustr
;
75 constexpr OUString ITEM_DESCRIPTOR_LABEL
= u
"Label"_ustr
;
77 static OUString
mapModuleShortNameToIdentifier(std::u16string_view sShortName
)
81 if ( sShortName
== u
"StartModule" )
82 sIdentifier
= "com.sun.star.frame.StartModule";
84 else if ( sShortName
== u
"swriter" )
85 sIdentifier
= "com.sun.star.text.TextDocument";
87 else if ( sShortName
== u
"scalc" )
88 sIdentifier
= "com.sun.star.sheet.SpreadsheetDocument";
90 else if ( sShortName
== u
"sdraw" )
91 sIdentifier
= "com.sun.star.drawing.DrawingDocument";
93 else if ( sShortName
== u
"simpress" )
94 sIdentifier
= "com.sun.star.presentation.PresentationDocument";
96 else if ( sShortName
== u
"smath" )
97 sIdentifier
= "com.sun.star.formula.FormulaProperties";
99 else if ( sShortName
== u
"schart" )
100 sIdentifier
= "com.sun.star.chart2.ChartDocument";
102 else if ( sShortName
== u
"BasicIDE" )
103 sIdentifier
= "com.sun.star.script.BasicIDE";
105 else if ( sShortName
== u
"dbapp" )
106 sIdentifier
= "com.sun.star.sdb.OfficeDatabaseDocument";
108 else if ( sShortName
== u
"sglobal" )
109 sIdentifier
= "com.sun.star.text.GlobalDocument";
111 else if ( sShortName
== u
"sweb" )
112 sIdentifier
= "com.sun.star.text.WebDocument";
114 else if ( sShortName
== u
"swxform" )
115 sIdentifier
= "com.sun.star.xforms.XMLFormDocument";
117 else if ( sShortName
== u
"sbibliography" )
118 sIdentifier
= "com.sun.star.frame.Bibliography";
123 bool MigrationImpl::alreadyMigrated()
125 OUString aStr
= m_aInfo
.userdata
+ "/MIGRATED4";
127 // create migration stamp, and/or check its existence
128 bool bRet
= aFile
.open (osl_File_OpenFlag_Write
| osl_File_OpenFlag_Create
| osl_File_OpenFlag_NoLock
) == FileBase::E_EXIST
;
129 SAL_INFO( "desktop.migration", "File '" << aStr
<< "' exists? " << bRet
);
133 bool MigrationImpl::initializeMigration()
137 if (!checkMigrationCompleted()) {
138 readAvailableMigrations(m_vMigrationsAvailable
);
139 sal_Int32 nIndex
= findPreferredMigrationProcess(m_vMigrationsAvailable
);
140 // m_aInfo is now set to the preferred migration source
142 if (alreadyMigrated())
144 m_vrMigrations
= readMigrationSteps(m_vMigrationsAvailable
[nIndex
].name
);
147 bRet
= !m_aInfo
.userdata
.isEmpty();
150 SAL_INFO( "desktop.migration", "Migration " << ( bRet
? "needed" : "not required" ) );
155 void Migration::migrateSettingsIfNecessary()
159 if (! aImpl
.initializeMigration() )
162 bool bResult
= false;
164 bResult
= aImpl
.doMigration();
165 } catch (const Exception
&) {
166 TOOLS_WARN_EXCEPTION( "desktop", "doMigration()");
168 OSL_ENSURE(bResult
, "Migration has not been successful");
171 MigrationImpl::MigrationImpl()
175 MigrationImpl::~MigrationImpl()
179 // The main entry point for migrating settings
180 bool MigrationImpl::doMigration()
182 // compile file list for migration
183 m_vrFileList
= compileFileList();
187 NewVersionUIInfo aNewVersionUIInfo
;
188 std::vector
< MigrationModuleInfo
> vModulesInfo
= detectUIChangesForAllModules();
189 aNewVersionUIInfo
.init(vModulesInfo
);
193 static constexpr OUString
sMenubarResourceURL(u
"private:resource/menubar/menubar"_ustr
);
194 static constexpr OUStringLiteral
sToolbarResourcePre(u
"private:resource/toolbar/");
195 for (MigrationModuleInfo
& i
: vModulesInfo
) {
196 OUString sModuleIdentifier
= mapModuleShortNameToIdentifier(i
.sModuleShortName
);
197 if (sModuleIdentifier
.isEmpty())
201 OUString aOldCfgDataPath
= m_aInfo
.userdata
+ "/user/config/soffice.cfg/modules/" + i
.sModuleShortName
;
202 uno::Sequence
< uno::Any
> lArgs
{uno::Any(aOldCfgDataPath
), uno::Any(embed::ElementModes::READ
)};
204 const uno::Reference
< uno::XComponentContext
>& xContext(comphelper::getProcessComponentContext());
205 uno::Reference
< lang::XSingleServiceFactory
> xStorageFactory(embed::FileSystemStorageFactory::create(xContext
));
206 uno::Reference
< embed::XStorage
> xModules(xStorageFactory
->createInstanceWithArguments(lArgs
), uno::UNO_QUERY
);
207 uno::Reference
< ui::XUIConfigurationManager2
> xOldCfgManager
= ui::UIConfigurationManager::create(xContext
);
209 if ( xModules
.is() ) {
210 xOldCfgManager
->setStorage( xModules
);
211 xOldCfgManager
->reload();
214 uno::Reference
< ui::XUIConfigurationManager
> xCfgManager
= aNewVersionUIInfo
.getConfigManager(i
.sModuleShortName
);
217 uno::Reference
< container::XIndexContainer
> xOldVersionMenuSettings(xOldCfgManager
->getSettings(sMenubarResourceURL
, true), uno::UNO_QUERY
);
218 uno::Reference
< container::XIndexContainer
> xNewVersionMenuSettings
= aNewVersionUIInfo
.getNewMenubarSettings(i
.sModuleShortName
);
219 compareOldAndNewConfig(OUString(), xOldVersionMenuSettings
, xNewVersionMenuSettings
, sMenubarResourceURL
);
220 mergeOldToNewVersion(xCfgManager
, xNewVersionMenuSettings
, sModuleIdentifier
, sMenubarResourceURL
);
223 sal_Int32 nToolbars
= i
.m_vToolbars
.size();
225 for (sal_Int32 j
=0; j
<nToolbars
; ++j
) {
226 OUString sToolbarName
= i
.m_vToolbars
[j
];
227 OUString sToolbarResourceURL
= sToolbarResourcePre
+ sToolbarName
;
229 uno::Reference
< container::XIndexContainer
> xOldVersionToolbarSettings(xOldCfgManager
->getSettings(sToolbarResourceURL
, true), uno::UNO_QUERY
);
230 uno::Reference
< container::XIndexContainer
> xNewVersionToolbarSettings
= aNewVersionUIInfo
.getNewToolbarSettings(i
.sModuleShortName
, sToolbarName
);
231 compareOldAndNewConfig(OUString(), xOldVersionToolbarSettings
, xNewVersionToolbarSettings
, sToolbarResourceURL
);
232 mergeOldToNewVersion(xCfgManager
, xNewVersionToolbarSettings
, sModuleIdentifier
, sToolbarResourceURL
);
236 m_aOldVersionItemsHashMap
.clear();
239 // execute the migration items from Setup.xcu
242 // execute custom migration services from Setup.xcu
243 // and refresh the cache
245 uno::Reference
< XRefreshable
>(
246 configuration::theDefaultProvider::get(comphelper::getProcessComponentContext()),
247 uno::UNO_QUERY_THROW
)->refresh();
250 } catch (const css::uno::Exception
&) {
251 TOOLS_WARN_EXCEPTION(
253 "ignored Exception while migrating from version \"" << m_aInfo
.productname
254 << "\" data \"" << m_aInfo
.userdata
<< "\"");
257 // prevent running the migration multiple times
258 setMigrationCompleted();
262 void MigrationImpl::setMigrationCompleted()
265 uno::Reference
< XPropertySet
> aPropertySet(getConfigAccess("org.openoffice.Setup/Office", true), uno::UNO_QUERY_THROW
);
266 aPropertySet
->setPropertyValue(u
"MigrationCompleted"_ustr
, uno::Any(true));
267 uno::Reference
< XChangesBatch
>(aPropertySet
, uno::UNO_QUERY_THROW
)->commitChanges();
273 bool MigrationImpl::checkMigrationCompleted()
275 bool bMigrationCompleted
= false;
277 uno::Reference
< XPropertySet
> aPropertySet(
278 getConfigAccess("org.openoffice.Setup/Office"), uno::UNO_QUERY_THROW
);
279 aPropertySet
->getPropertyValue(u
"MigrationCompleted"_ustr
) >>= bMigrationCompleted
;
281 if( !bMigrationCompleted
&& getenv("SAL_DISABLE_USERMIGRATION" ) ) {
282 // migration prevented - fake its success
283 setMigrationCompleted();
284 bMigrationCompleted
= true;
286 } catch (const Exception
&) {
287 // just return false...
289 SAL_INFO( "desktop.migration", "Migration " << ( bMigrationCompleted
? "already completed" : "not done" ) );
291 return bMigrationCompleted
;
294 static void insertSorted(migrations_available
& rAvailableMigrations
, supported_migration
const & aSupportedMigration
)
296 migrations_available::iterator pIter
= std::find_if(rAvailableMigrations
.begin(), rAvailableMigrations
.end(),
297 [&aSupportedMigration
](const supported_migration
& rMigration
) { return rMigration
.nPriority
< aSupportedMigration
.nPriority
; });
298 if (pIter
!= rAvailableMigrations
.end())
299 rAvailableMigrations
.insert(pIter
, aSupportedMigration
);
301 rAvailableMigrations
.push_back( aSupportedMigration
);
304 void MigrationImpl::readAvailableMigrations(migrations_available
& rAvailableMigrations
)
306 // get supported version names
307 uno::Reference
< XNameAccess
> aMigrationAccess(getConfigAccess("org.openoffice.Setup/Migration/SupportedVersions"), uno::UNO_SET_THROW
);
308 const uno::Sequence
< OUString
> seqSupportedVersions
= aMigrationAccess
->getElementNames();
310 static constexpr OUStringLiteral
aVersionIdentifiers( u
"VersionIdentifiers" );
311 static constexpr OUStringLiteral
aPriorityIdentifier( u
"Priority" );
313 for (OUString
const & supportedVersion
:seqSupportedVersions
) {
314 sal_Int32
nPriority( 0 );
315 uno::Sequence
< OUString
> seqVersions
;
316 uno::Reference
< XNameAccess
> xMigrationData( aMigrationAccess
->getByName(supportedVersion
), uno::UNO_QUERY_THROW
);
317 xMigrationData
->getByName( aVersionIdentifiers
) >>= seqVersions
;
318 xMigrationData
->getByName( aPriorityIdentifier
) >>= nPriority
;
320 supported_migration aSupportedMigration
;
321 aSupportedMigration
.name
= supportedVersion
;
322 aSupportedMigration
.nPriority
= nPriority
;
323 for (OUString
const& s
: seqVersions
)
324 aSupportedMigration
.supported_versions
.push_back(s
.trim());
325 insertSorted( rAvailableMigrations
, aSupportedMigration
);
326 SAL_INFO( "desktop.migration", " available migration '" << aSupportedMigration
.name
<< "'" );
330 migrations_vr
MigrationImpl::readMigrationSteps(const OUString
& rMigrationName
)
332 // get migration access
333 uno::Reference
< XNameAccess
> aMigrationAccess(getConfigAccess("org.openoffice.Setup/Migration/SupportedVersions"), uno::UNO_SET_THROW
);
334 uno::Reference
< XNameAccess
> xMigrationData( aMigrationAccess
->getByName(rMigrationName
), uno::UNO_QUERY_THROW
);
336 // get migration description from org.openoffice.Setup/Migration
337 // and build vector of migration steps
338 uno::Reference
< XNameAccess
> theNameAccess(xMigrationData
->getByName(u
"MigrationSteps"_ustr
), uno::UNO_QUERY_THROW
);
339 uno::Reference
< XNameAccess
> tmpAccess
;
340 uno::Sequence
< OUString
> tmpSeq
;
341 migrations_vr
vrMigrations(new migrations_v
);
342 const css::uno::Sequence
<OUString
> aMigrationSteps
= theNameAccess
->getElementNames();
343 for (const OUString
& rMigrationStep
: aMigrationSteps
) {
344 // get current migration step
345 theNameAccess
->getByName(rMigrationStep
) >>= tmpAccess
;
346 migration_step tmpStep
;
348 // read included files from current step description
349 if (tmpAccess
->getByName(u
"IncludedFiles"_ustr
) >>= tmpSeq
) {
350 for (const OUString
& rSeqEntry
: tmpSeq
)
351 tmpStep
.includeFiles
.push_back(rSeqEntry
);
355 if (tmpAccess
->getByName(u
"ExcludedFiles"_ustr
) >>= tmpSeq
) {
356 for (const OUString
& rSeqEntry
: tmpSeq
)
357 tmpStep
.excludeFiles
.push_back(rSeqEntry
);
361 if (tmpAccess
->getByName(u
"IncludedNodes"_ustr
) >>= tmpSeq
) {
362 for (const OUString
& rSeqEntry
: tmpSeq
)
363 tmpStep
.includeConfig
.push_back(rSeqEntry
);
367 if (tmpAccess
->getByName(u
"ExcludedNodes"_ustr
) >>= tmpSeq
) {
368 for (const OUString
& rSeqEntry
: tmpSeq
)
369 tmpStep
.excludeConfig
.push_back(rSeqEntry
);
372 // excluded extensions...
373 if (tmpAccess
->getByName(u
"ExcludedExtensions"_ustr
) >>= tmpSeq
) {
374 for (const OUString
& rSeqEntry
: tmpSeq
)
375 tmpStep
.excludeExtensions
.push_back(rSeqEntry
);
379 tmpAccess
->getByName(u
"MigrationService"_ustr
) >>= tmpStep
.service
;
381 vrMigrations
->push_back(tmpStep
);
386 static FileBase::RC
_checkAndCreateDirectory(INetURLObject
const & dirURL
)
388 FileBase::RC result
= Directory::create(dirURL
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
));
389 if (result
== FileBase::E_NOENT
) {
390 INetURLObject
baseURL(dirURL
);
391 baseURL
.removeSegment();
392 _checkAndCreateDirectory(baseURL
);
393 return Directory::create(dirURL
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
));
398 #if defined UNX && ! defined MACOSX
400 const char XDG_CONFIG_PART
[] = "/.config/";
402 OUString
MigrationImpl::preXDGConfigDir(const OUString
& rConfigDir
)
404 OUString aPreXDGConfigPath
;
405 const char* pXDGCfgHome
= getenv("XDG_CONFIG_HOME");
407 // cater for XDG_CONFIG_HOME change
408 // If XDG_CONFIG_HOME is set then we;
409 // assume the user knows what they are doing ( room for improvement here, we could
410 // of course search the default config dir etc. also - but this is more complex,
411 // we would need to weigh results from the current config dir against matches in
412 // the 'old' config dir etc. ) - currently we just use the returned config dir.
413 // If XDG_CONFIG_HOME is NOT set;
414 // assume then we should now using the default $HOME/.config config location for
415 // our user profiles, however *all* previous libreoffice and openoffice.org
416 // configurations will be in the 'old' config directory and that's where we need
417 // to search - we convert the returned config dir to the 'old' dir
418 if ( !pXDGCfgHome
&& rConfigDir
.endsWith( XDG_CONFIG_PART
) )
419 // remove trailing '.config/' but leave the terminating '/'
420 aPreXDGConfigPath
= rConfigDir
.copy( 0, rConfigDir
.getLength() - sizeof( XDG_CONFIG_PART
) + 2 );
422 aPreXDGConfigPath
= rConfigDir
;
424 // the application-specific config dir is no longer prefixed by '.' because it is hidden under ".config"
425 // we have to add the '.' for the pre-XDG directory names
426 aPreXDGConfigPath
+= ".";
428 return aPreXDGConfigPath
;
432 void MigrationImpl::setInstallInfoIfExist(
434 std::u16string_view rConfigDir
,
435 const OUString
& rVersion
)
437 OUString
url(INetURLObject(rConfigDir
).GetMainURL(INetURLObject::DecodeMechanism::NONE
));
438 osl::DirectoryItem item
;
439 osl::FileStatus
stat(osl_FileStatus_Mask_Type
);
441 if (osl::DirectoryItem::get(url
, item
) == osl::FileBase::E_None
442 && item
.getFileStatus(stat
) == osl::FileBase::E_None
443 && stat
.getFileType() == osl::FileStatus::Directory
) {
444 aInfo
.userdata
= url
;
445 aInfo
.productname
= rVersion
;
449 install_info
MigrationImpl::findInstallation(const strings_v
& rVersions
)
452 OUString aTopConfigDir
;
453 osl::Security().getConfigDir( aTopConfigDir
);
454 if ( !aTopConfigDir
.isEmpty() && aTopConfigDir
[ aTopConfigDir
.getLength()-1 ] != '/' )
455 aTopConfigDir
+= "/";
457 #if defined UNX && ! defined MACOSX
458 OUString aPreXDGTopConfigDir
= preXDGConfigDir(aTopConfigDir
);
462 for (auto const& elem
: rVersions
)
464 OUString aVersion
, aProfileName
;
465 sal_Int32 nSeparatorIndex
= elem
.indexOf('=');
466 if ( nSeparatorIndex
!= -1 ) {
467 aVersion
= elem
.copy( 0, nSeparatorIndex
);
468 aProfileName
= elem
.copy( nSeparatorIndex
+1 );
471 if ( !aVersion
.isEmpty() && !aProfileName
.isEmpty() &&
472 ( aInfo
.userdata
.isEmpty() ||
473 aProfileName
.equalsIgnoreAsciiCase(
474 utl::ConfigManager::getProductName() ) ) ) {
475 setInstallInfoIfExist(aInfo
, Concat2View(aTopConfigDir
+ aProfileName
), aVersion
);
476 #if defined UNX && ! defined MACOSX
477 //try preXDG path if the new one does not exist
478 if ( aInfo
.userdata
.isEmpty())
479 setInstallInfoIfExist(aInfo
, Concat2View(aPreXDGTopConfigDir
+ aProfileName
), aVersion
);
487 sal_Int32
MigrationImpl::findPreferredMigrationProcess(const migrations_available
& rAvailableMigrations
)
489 sal_Int32
nIndex( -1 );
492 for (auto const& availableMigration
: rAvailableMigrations
)
494 install_info aInstallInfo
= findInstallation(availableMigration
.supported_versions
);
495 if (!aInstallInfo
.productname
.isEmpty() ) {
496 m_aInfo
= std::move(aInstallInfo
);
503 SAL_INFO( "desktop.migration", " preferred migration is from product '" << m_aInfo
.productname
<< "'");
504 SAL_INFO( "desktop.migration", " and settings directory '" << m_aInfo
.userdata
<< "'");
509 strings_vr
MigrationImpl::applyPatterns(const strings_v
& vSet
, const strings_v
& vPatterns
)
512 strings_vr
vrResult(new strings_v
);
513 for (auto const& pattern
: vPatterns
)
515 // find matches for this pattern in input set
516 // and copy them to the result
517 SearchParam
param(pattern
, SearchParam::SearchType::Regexp
);
518 TextSearch
ts(param
, LANGUAGE_DONTKNOW
);
521 for (auto const& elem
: vSet
)
523 end
= elem
.getLength();
524 if (ts
.SearchForward(elem
, &start
, &end
))
525 vrResult
->push_back(elem
);
531 strings_vr
MigrationImpl::getAllFiles(const OUString
& baseURL
) const
533 strings_vr
vrResult(new strings_v
);
536 Directory
dir(baseURL
);
537 if (dir
.open() == FileBase::E_None
) {
539 strings_vr vrSubResult
;
541 // work through directory contents...
543 FileStatus
fs(osl_FileStatus_Mask_Type
| osl_FileStatus_Mask_FileURL
);
544 while (dir
.getNextItem(item
) == FileBase::E_None
) {
545 if (item
.getFileStatus(fs
) == FileBase::E_None
) {
546 if (fs
.getFileType() == FileStatus::Directory
)
547 vSubDirs
.push_back(fs
.getFileURL());
549 vrResult
->push_back(fs
.getFileURL());
553 // recurse subfolders
554 for (auto const& subDir
: vSubDirs
)
556 vrSubResult
= getAllFiles(subDir
);
557 vrResult
->insert(vrResult
->end(), vrSubResult
->begin(), vrSubResult
->end());
566 // removes elements of vector 2 in vector 1
567 strings_v
subtract(strings_v
&& a
, strings_v
&& b
)
569 std::sort(a
.begin(), a
.end());
570 strings_v::iterator
ae(std::unique(a
.begin(), a
.end()));
571 std::sort(b
.begin(), b
.end());
572 strings_v::iterator
be(std::unique(b
.begin(), b
.end()));
574 std::set_difference(a
.begin(), ae
, b
.begin(), be
, std::back_inserter(c
));
580 strings_vr
MigrationImpl::compileFileList()
583 strings_vr
vrResult(new strings_v
);
585 // get a list of all files:
586 strings_vr vrFiles
= getAllFiles(m_aInfo
.userdata
);
588 // get a file list result for each migration step
589 for (auto const& rMigration
: *m_vrMigrations
)
591 strings_vr vrInclude
= applyPatterns(*vrFiles
, rMigration
.includeFiles
);
592 strings_vr vrExclude
= applyPatterns(*vrFiles
, rMigration
.excludeFiles
);
593 strings_v
sub(subtract(std::move(*vrInclude
), std::move(*vrExclude
)));
594 vrResult
->insert(vrResult
->end(), sub
.begin(), sub
.end());
602 struct componentParts
{
603 std::set
< OUString
> includedPaths
;
604 std::set
< OUString
> excludedPaths
;
607 typedef std::map
< OUString
, componentParts
> Components
;
609 bool getComponent(OUString
const & path
, OUString
* component
)
611 OSL_ASSERT(component
!= nullptr);
612 if (path
.isEmpty() || path
[0] != '/') {
613 SAL_INFO( "desktop.migration", "configuration migration in/exclude path " << path
<< " ignored (does not start with slash)" );
616 sal_Int32 i
= path
.indexOf('/', 1);
617 *component
= i
< 0 ? path
.copy(1) : path
.copy(1, i
- 1);
621 void renameMigratedSetElementTo(
622 css::uno::Reference
<css::container::XNameContainer
> const & set
, OUString
const & currentName
,
623 OUString
const & migratedName
)
625 // To avoid unexpected data loss, the code is careful to only rename from currentName to
626 // migratedName in the expected case where the currentName element exists and the migratedName
627 // element doesn't exist:
628 bool const hasCurrent
= set
->hasByName(currentName
);
629 bool const hasMigrated
= set
->hasByName(migratedName
);
630 if (hasCurrent
&& !hasMigrated
) {
631 auto const elem
= set
->getByName(currentName
);
632 set
->removeByName(currentName
);
633 set
->insertByName(migratedName
, elem
);
635 SAL_INFO_IF(!hasCurrent
, "desktop.migration", "unexpectedly missing " << currentName
);
636 SAL_INFO_IF(hasMigrated
, "desktop.migration", "unexpectedly present " << migratedName
);
640 void renameMigratedSetElementBack(
641 css::uno::Reference
<css::container::XNameContainer
> const & set
, OUString
const & currentName
,
642 OUString
const & migratedName
)
644 // To avoid unexpected data loss, the code is careful to ensure that in the end a currentName
645 // element exists, creating it from a template if the migratedName element had unexpectedly gone
647 bool const hasMigrated
= set
->hasByName(migratedName
);
650 elem
= set
->getByName(migratedName
);
651 set
->removeByName(migratedName
);
653 SAL_INFO("desktop.migration", "unexpected loss of " << migratedName
);
654 elem
<<= css::uno::Reference
<css::lang::XSingleServiceFactory
>(
655 set
, css::uno::UNO_QUERY_THROW
)->createInstance();
657 if (set
->hasByName(currentName
)) {
658 SAL_INFO("desktop.migration", "unexpected reappearance of " << currentName
);
662 "reappeared " << currentName
<< " overwritten with " << migratedName
);
663 set
->replaceByName(currentName
, elem
);
666 set
->insertByName(currentName
, elem
);
672 void MigrationImpl::copyConfig()
675 for (auto const& rMigrationStep
: *m_vrMigrations
) {
676 for (const OUString
& rIncludePath
: rMigrationStep
.includeConfig
) {
678 if (getComponent(rIncludePath
, &comp
)) {
679 comps
[comp
].includedPaths
.insert(rIncludePath
);
682 for (const OUString
& rExcludePath
: rMigrationStep
.excludeConfig
) {
684 if (getComponent(rExcludePath
, &comp
)) {
685 comps
[comp
].excludedPaths
.insert(rExcludePath
);
690 // check if the shared registrymodifications.xcu file exists
691 bool bRegistryModificationsXcuExists
= false;
692 OUString regFilePath
= m_aInfo
.userdata
+ "/user/registrymodifications.xcu";
693 File
regFile(regFilePath
);
694 ::osl::FileBase::RC nError
= regFile
.open(osl_File_OpenFlag_Read
);
695 if ( nError
== ::osl::FileBase::E_None
) {
696 bRegistryModificationsXcuExists
= true;
700 // If the to-be-migrated data contains modifications of
701 // /org.openoffice.Office.UI/ColorScheme/ColorSchemes set elements named after the migrated
702 // product name, those modifications must instead be made to the corresponding set elements
703 // named after the current product name. However, if the current configuration data does not
704 // contain those old-named set elements at all, their modification data would silently be
705 // ignored by css.configuration.XUpdate::insertModificationXcuFile. So temporarily rename any
706 // new-named set elements to their old-named counterparts here, and rename them back again down
707 // below after importing the migrated data:
708 OUString sProductName
= utl::ConfigManager::getProductName();
709 OUString sProductNameDark
= sProductName
+ " Dark";
710 OUString sMigratedProductName
= m_aInfo
.productname
;
711 // remove version number from the end of product name if there’s one
712 if (isdigit(sMigratedProductName
[sMigratedProductName
.getLength() - 1]))
713 sMigratedProductName
= (sMigratedProductName
.copy(0, m_aInfo
.productname
.getLength() - 1)).trim();
714 OUString sMigratedProductNameDark
= sMigratedProductName
+ " Dark";
715 auto const tempRename
= sMigratedProductName
!= sProductName
;
717 auto const batch
= comphelper::ConfigurationChanges::create();
718 auto const schemes
= officecfg::Office::UI::ColorScheme::ColorSchemes::get(batch
);
719 renameMigratedSetElementTo(schemes
, sProductName
, sMigratedProductName
);
720 renameMigratedSetElementTo(schemes
, sProductNameDark
, sMigratedProductNameDark
);
724 for (auto const& comp
: comps
)
726 if (!comp
.second
.includedPaths
.empty()) {
727 if (!bRegistryModificationsXcuExists
) {
728 // shared registrymodifications.xcu does not exists
729 // the configuration is split in many registry files
730 // determine the file names from the first element in included paths
731 OUStringBuffer
buf(m_aInfo
.userdata
732 + "/user/registry/data");
735 OUString
seg(comp
.first
.getToken(0, '.', n
));
738 seg
, rtl_UriCharClassPchar
, rtl_UriEncodeStrict
,
739 RTL_TEXTENCODING_UTF8
));
740 if (enc
.isEmpty() && !seg
.isEmpty()) {
741 SAL_INFO( "desktop.migration", "configuration migration component " << comp
.first
<< " ignored (cannot be encoded as file path)" );
744 buf
.append("/" + enc
);
747 regFilePath
= buf
.makeStringAndClear();
749 configuration::Update::get(
750 comphelper::getProcessComponentContext())->
751 insertModificationXcuFile(
753 comphelper::containerToSequence(comp
.second
.includedPaths
),
754 comphelper::containerToSequence(comp
.second
.excludedPaths
));
757 SAL_INFO( "desktop.migration", "configuration migration component " << comp
.first
<< " ignored (only excludes, no includes)" );
763 auto const batch
= comphelper::ConfigurationChanges::create();
764 auto const schemes
= officecfg::Office::UI::ColorScheme::ColorSchemes::get(batch
);
765 renameMigratedSetElementBack(schemes
, sProductName
, sMigratedProductName
);
766 renameMigratedSetElementBack(schemes
, sProductNameDark
, sMigratedProductNameDark
);
769 // checking the migrated (product name related) color scheme name, and replace it to the current version scheme name
772 OUString sMigratedColorScheme
;
773 uno::Reference
<XPropertySet
> aPropertySet(
774 getConfigAccess("org.openoffice.Office.UI/ColorScheme", true), uno::UNO_QUERY_THROW
);
775 if (aPropertySet
->getPropertyValue(u
"CurrentColorScheme"_ustr
) >>= sMigratedColorScheme
)
777 if (sMigratedColorScheme
.equals(sMigratedProductName
))
779 aPropertySet
->setPropertyValue(u
"CurrentColorScheme"_ustr
,
780 uno::Any(sProductName
));
781 uno::Reference
<XChangesBatch
>(aPropertySet
, uno::UNO_QUERY_THROW
)->commitChanges();
783 else if (sMigratedColorScheme
.equals(sMigratedProductNameDark
))
785 aPropertySet
->setPropertyValue(u
"CurrentColorScheme"_ustr
,
786 uno::Any(sProductNameDark
));
787 uno::Reference
<XChangesBatch
>(aPropertySet
, uno::UNO_QUERY_THROW
)->commitChanges();
790 } catch (const Exception
&) {
795 uno::Reference
< XNameAccess
> MigrationImpl::getConfigAccess(const char* pPath
, bool bUpdate
)
797 uno::Reference
< XNameAccess
> xNameAccess
;
799 OUString sAccessSrvc
;
801 sAccessSrvc
= "com.sun.star.configuration.ConfigurationUpdateAccess";
803 sAccessSrvc
= "com.sun.star.configuration.ConfigurationAccess";
805 OUString sConfigURL
= OUString::createFromAscii(pPath
);
807 uno::Reference
< XMultiServiceFactory
> theConfigProvider(
808 configuration::theDefaultProvider::get(
809 comphelper::getProcessComponentContext()));
811 // access the provider
812 uno::Sequence
< uno::Any
> theArgs
{uno::Any(sConfigURL
)};
814 theConfigProvider
->createInstanceWithArguments(
815 sAccessSrvc
, theArgs
), uno::UNO_QUERY_THROW
);
816 } catch (const css::uno::Exception
&) {
817 TOOLS_WARN_EXCEPTION("desktop.migration", "ignoring");
822 void MigrationImpl::copyFiles()
826 OUString userInstall
;
827 utl::Bootstrap::PathStatus aStatus
;
828 aStatus
= utl::Bootstrap::locateUserInstallation(userInstall
);
829 if (aStatus
== utl::Bootstrap::PATH_EXISTS
) {
830 for (auto const& rFile
: *m_vrFileList
)
832 // remove installation prefix from file
833 localName
= rFile
.copy(m_aInfo
.userdata
.getLength());
834 if (localName
.endsWith( "/autocorr/acor_.dat")) {
835 // Previous versions used an empty language tag for
836 // LANGUAGE_DONTKNOW with the "[All]" autocorrection entry.
837 // As of LibreOffice 4.0 it is 'und' for LANGUAGE_UNDETERMINED
838 // so the file name is "acor_und.dat".
839 localName
= OUString::Concat(localName
.subView( 0, localName
.getLength() - 4)) + "und.dat";
841 destName
= userInstall
+ localName
;
842 INetURLObject
aURL(destName
);
843 // check whether destination directory exists
844 aURL
.removeSegment();
845 _checkAndCreateDirectory(aURL
);
846 FileBase::RC copyResult
= File::copy(rFile
, destName
);
847 if (copyResult
!= FileBase::E_None
) {
848 SAL_WARN( "desktop", "Cannot copy " << rFile
<< " to " << destName
);
852 OSL_FAIL("copyFiles: UserInstall does not exist");
856 void MigrationImpl::runServices()
858 // Build argument array
859 uno::Sequence
< uno::Any
> seqArguments(3);
860 auto pseqArguments
= seqArguments
.getArray();
861 pseqArguments
[0] <<= NamedValue(u
"Productname"_ustr
,
862 uno::Any(m_aInfo
.productname
));
863 pseqArguments
[1] <<= NamedValue(u
"UserData"_ustr
,
864 uno::Any(m_aInfo
.userdata
));
867 // create an instance of every migration service
868 // and execute the migration job
869 uno::Reference
< XJob
> xMigrationJob
;
871 const uno::Reference
< uno::XComponentContext
>& xContext(comphelper::getProcessComponentContext());
872 for (auto const& rMigration
: *m_vrMigrations
)
874 if( !rMigration
.service
.isEmpty()) {
877 // set black list for extension migration
878 uno::Sequence
< OUString
> seqExtDenyList
;
879 sal_uInt32 nSize
= rMigration
.excludeExtensions
.size();
881 seqExtDenyList
= comphelper::arrayToSequence
< OUString
>(
882 rMigration
.excludeExtensions
.data(), nSize
);
883 pseqArguments
[2] <<= NamedValue(u
"ExtensionDenyList"_ustr
,
884 uno::Any( seqExtDenyList
));
887 xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(rMigration
.service
, seqArguments
, xContext
),
888 uno::UNO_QUERY_THROW
);
890 xMigrationJob
->execute(uno::Sequence
< NamedValue
>());
893 } catch (const Exception
&) {
894 TOOLS_WARN_EXCEPTION( "desktop", "Execution of migration service failed. Service: "
895 << rMigration
.service
);
897 SAL_WARN( "desktop", "Execution of migration service failed (Exception caught).\nService: "
898 << rMigration
.service
<< "\nNo message available");
905 std::vector
< MigrationModuleInfo
> MigrationImpl::detectUIChangesForAllModules() const
907 std::vector
< MigrationModuleInfo
> vModulesInfo
;
908 static constexpr OUStringLiteral
MENUBAR(u
"menubar");
909 static constexpr OUStringLiteral
TOOLBAR(u
"toolbar");
911 uno::Sequence
< uno::Any
> lArgs
{uno::Any(m_aInfo
.userdata
+ "/user/config/soffice.cfg/modules"),
912 uno::Any(embed::ElementModes::READ
)};
914 uno::Reference
< lang::XSingleServiceFactory
> xStorageFactory(
915 embed::FileSystemStorageFactory::create(comphelper::getProcessComponentContext()));
916 uno::Reference
< embed::XStorage
> xModules
;
918 xModules
.set(xStorageFactory
->createInstanceWithArguments(lArgs
), uno::UNO_QUERY
);
922 uno::Sequence
< OUString
> lNames
= xModules
->getElementNames();
923 sal_Int32 nLength
= lNames
.getLength();
924 for (sal_Int32 i
=0; i
<nLength
; ++i
) {
925 const OUString
& sModuleShortName
= lNames
[i
];
926 uno::Reference
< embed::XStorage
> xModule
= xModules
->openStorageElement(sModuleShortName
, embed::ElementModes::READ
);
928 MigrationModuleInfo aModuleInfo
;
930 uno::Reference
< embed::XStorage
> xMenubar
= xModule
->openStorageElement(MENUBAR
, embed::ElementModes::READ
);
932 if (xMenubar
->getElementNames().hasElements()) {
933 aModuleInfo
.sModuleShortName
= sModuleShortName
;
934 aModuleInfo
.bHasMenubar
= true;
938 uno::Reference
< embed::XStorage
> xToolbar
= xModule
->openStorageElement(TOOLBAR
, embed::ElementModes::READ
);
940 const ::uno::Sequence
< OUString
> lToolbars
= xToolbar
->getElementNames();
941 for (OUString
const & sToolbarName
: lToolbars
) {
942 if (sToolbarName
.startsWith("custom_"))
945 aModuleInfo
.sModuleShortName
= sModuleShortName
;
946 sal_Int32 nIndex
= sToolbarName
.lastIndexOf('.');
948 std::u16string_view
sExtension(sToolbarName
.subView(nIndex
));
949 OUString
sToolbarResourceName(sToolbarName
.copy(0, nIndex
));
950 if (!sToolbarResourceName
.isEmpty() && sExtension
== u
".xml")
951 aModuleInfo
.m_vToolbars
.push_back(sToolbarResourceName
);
956 if (!aModuleInfo
.sModuleShortName
.isEmpty())
957 vModulesInfo
.push_back(aModuleInfo
);
964 void MigrationImpl::compareOldAndNewConfig(const OUString
& sParent
,
965 const uno::Reference
< container::XIndexContainer
>& xIndexOld
,
966 const uno::Reference
< container::XIndexContainer
>& xIndexNew
,
967 const OUString
& sResourceURL
)
969 static constexpr OUStringLiteral
MENU_SEPARATOR(u
" | ");
971 std::vector
< MigrationItem
> vOldItems
;
972 std::vector
< MigrationItem
> vNewItems
;
973 uno::Sequence
< beans::PropertyValue
> aProps
;
974 sal_Int32 nOldCount
= xIndexOld
->getCount();
975 sal_Int32 nNewCount
= xIndexNew
->getCount();
977 for (int n
=0; n
<nOldCount
; ++n
) {
978 MigrationItem aMigrationItem
;
979 if (xIndexOld
->getByIndex(n
) >>= aProps
) {
980 for(beans::PropertyValue
const & prop
: aProps
) {
981 if ( prop
.Name
== ITEM_DESCRIPTOR_COMMANDURL
)
982 prop
.Value
>>= aMigrationItem
.m_sCommandURL
;
983 else if ( prop
.Name
== ITEM_DESCRIPTOR_CONTAINER
)
984 prop
.Value
>>= aMigrationItem
.m_xPopupMenu
;
987 if (!aMigrationItem
.m_sCommandURL
.isEmpty())
988 vOldItems
.push_back(aMigrationItem
);
992 for (int n
=0; n
<nNewCount
; ++n
) {
993 MigrationItem aMigrationItem
;
994 if (xIndexNew
->getByIndex(n
) >>= aProps
) {
995 for(beans::PropertyValue
const & prop
: aProps
) {
996 if ( prop
.Name
== ITEM_DESCRIPTOR_COMMANDURL
)
997 prop
.Value
>>= aMigrationItem
.m_sCommandURL
;
998 else if ( prop
.Name
== ITEM_DESCRIPTOR_CONTAINER
)
999 prop
.Value
>>= aMigrationItem
.m_xPopupMenu
;
1002 if (!aMigrationItem
.m_sCommandURL
.isEmpty())
1003 vNewItems
.push_back(aMigrationItem
);
1008 for (auto const& oldItem
: vOldItems
)
1010 std::vector
< MigrationItem
>::iterator pFound
= std::find(vNewItems
.begin(), vNewItems
.end(), oldItem
);
1011 if (pFound
!= vNewItems
.end() && oldItem
.m_xPopupMenu
.is()) {
1013 if (!sParent
.isEmpty())
1014 sName
= sParent
+ MENU_SEPARATOR
+ oldItem
.m_sCommandURL
;
1016 sName
= oldItem
.m_sCommandURL
;
1017 compareOldAndNewConfig(sName
, oldItem
.m_xPopupMenu
, pFound
->m_xPopupMenu
, sResourceURL
);
1018 } else if (pFound
== vNewItems
.end()) {
1019 MigrationItem
aMigrationItem(sParent
, sSibling
, oldItem
.m_sCommandURL
, oldItem
.m_xPopupMenu
);
1020 if (m_aOldVersionItemsHashMap
.find(sResourceURL
)==m_aOldVersionItemsHashMap
.end()) {
1021 std::vector
< MigrationItem
> vMigrationItems
;
1022 m_aOldVersionItemsHashMap
.emplace(sResourceURL
, vMigrationItems
);
1023 m_aOldVersionItemsHashMap
[sResourceURL
].push_back(aMigrationItem
);
1025 if (std::find(m_aOldVersionItemsHashMap
[sResourceURL
].begin(), m_aOldVersionItemsHashMap
[sResourceURL
].end(), aMigrationItem
)==m_aOldVersionItemsHashMap
[sResourceURL
].end())
1026 m_aOldVersionItemsHashMap
[sResourceURL
].push_back(aMigrationItem
);
1030 sSibling
= oldItem
.m_sCommandURL
;
1034 void MigrationImpl::mergeOldToNewVersion(const uno::Reference
< ui::XUIConfigurationManager
>& xCfgManager
,
1035 const uno::Reference
< container::XIndexContainer
>& xIndexContainer
,
1036 const OUString
& sModuleIdentifier
,
1037 const OUString
& sResourceURL
)
1039 MigrationHashMap::iterator pFound
= m_aOldVersionItemsHashMap
.find(sResourceURL
);
1040 if (pFound
==m_aOldVersionItemsHashMap
.end())
1043 for (auto const& elem
: pFound
->second
)
1045 uno::Reference
< container::XIndexContainer
> xTemp
= xIndexContainer
;
1047 OUString sParentNodeName
= elem
.m_sParentNodeName
;
1048 sal_Int32 nIndex
= 0;
1050 std::u16string_view
sToken( o3tl::trim(o3tl::getToken(sParentNodeName
, 0, '|', nIndex
)) );
1054 sal_Int32 nCount
= xTemp
->getCount();
1055 for (sal_Int32 i
=0; i
<nCount
; ++i
) {
1056 OUString sCommandURL
;
1058 uno::Reference
< container::XIndexContainer
> xChild
;
1060 uno::Sequence
< beans::PropertyValue
> aPropSeq
;
1061 xTemp
->getByIndex(i
) >>= aPropSeq
;
1062 for (beans::PropertyValue
const & prop
: aPropSeq
) {
1063 OUString sPropName
= prop
.Name
;
1064 if ( sPropName
== ITEM_DESCRIPTOR_COMMANDURL
)
1065 prop
.Value
>>= sCommandURL
;
1066 else if ( sPropName
== ITEM_DESCRIPTOR_LABEL
)
1067 prop
.Value
>>= sLabel
;
1068 else if ( sPropName
== ITEM_DESCRIPTOR_CONTAINER
)
1069 prop
.Value
>>= xChild
;
1072 if (sCommandURL
== sToken
) {
1073 xTemp
= std::move(xChild
);
1078 } while (nIndex
>= 0);
1081 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(elem
.m_sCommandURL
, sModuleIdentifier
);
1082 uno::Sequence
< beans::PropertyValue
> aPropSeq
{
1083 beans::PropertyValue(ITEM_DESCRIPTOR_COMMANDURL
, 0, uno::Any(elem
.m_sCommandURL
), beans::PropertyState_DIRECT_VALUE
),
1084 beans::PropertyValue(ITEM_DESCRIPTOR_LABEL
, 0, uno::Any(vcl::CommandInfoProvider::GetLabelForCommand(aProperties
)), beans::PropertyState_DIRECT_VALUE
),
1085 beans::PropertyValue(ITEM_DESCRIPTOR_CONTAINER
, 0, uno::Any(elem
.m_xPopupMenu
), beans::PropertyState_DIRECT_VALUE
)
1088 if (elem
.m_sPrevSibling
.isEmpty())
1089 xTemp
->insertByIndex(0, uno::Any(aPropSeq
));
1091 sal_Int32 nCount
= xTemp
->getCount();
1093 for (; i
<nCount
; ++i
) {
1095 uno::Sequence
< beans::PropertyValue
> aTempPropSeq
;
1096 xTemp
->getByIndex(i
) >>= aTempPropSeq
;
1097 for (beans::PropertyValue
const & prop
: aTempPropSeq
) {
1098 if ( prop
.Name
== ITEM_DESCRIPTOR_COMMANDURL
) {
1099 prop
.Value
>>= sCmd
;
1104 if (sCmd
== elem
.m_sPrevSibling
)
1108 xTemp
->insertByIndex(i
+1, uno::Any(aPropSeq
));
1113 if (xIndexContainer
.is())
1114 xCfgManager
->replaceSettings(sResourceURL
, xIndexContainer
);
1116 uno::Reference
< ui::XUIConfigurationPersistence
> xUIConfigurationPersistence(xCfgManager
, uno::UNO_QUERY
);
1117 if (xUIConfigurationPersistence
.is())
1118 xUIConfigurationPersistence
->store();
1121 uno::Reference
< ui::XUIConfigurationManager
> NewVersionUIInfo::getConfigManager(std::u16string_view sModuleShortName
) const
1123 uno::Reference
< ui::XUIConfigurationManager
> xCfgManager
;
1125 for ( const css::beans::PropertyValue
& rProp
: m_lCfgManagerSeq
) {
1126 if (rProp
.Name
== sModuleShortName
) {
1127 rProp
.Value
>>= xCfgManager
;
1135 uno::Reference
< container::XIndexContainer
> NewVersionUIInfo::getNewMenubarSettings(std::u16string_view sModuleShortName
) const
1137 uno::Reference
< container::XIndexContainer
> xNewMenuSettings
;
1139 for (auto const & prop
: m_lNewVersionMenubarSettingsSeq
) {
1140 if (prop
.Name
== sModuleShortName
) {
1141 prop
.Value
>>= xNewMenuSettings
;
1146 return xNewMenuSettings
;
1149 uno::Reference
< container::XIndexContainer
> NewVersionUIInfo::getNewToolbarSettings(std::u16string_view sModuleShortName
, std::u16string_view sToolbarName
) const
1151 uno::Reference
< container::XIndexContainer
> xNewToolbarSettings
;
1153 for (auto const & newProp
: m_lNewVersionToolbarSettingsSeq
) {
1154 if (newProp
.Name
== sModuleShortName
) {
1155 uno::Sequence
< beans::PropertyValue
> lToolbarSettingsSeq
;
1156 newProp
.Value
>>= lToolbarSettingsSeq
;
1157 for (auto const & prop
: lToolbarSettingsSeq
) {
1158 if (prop
.Name
== sToolbarName
) {
1159 prop
.Value
>>= xNewToolbarSettings
;
1168 return xNewToolbarSettings
;
1171 void NewVersionUIInfo::init(const std::vector
< MigrationModuleInfo
>& vModulesInfo
)
1173 m_lCfgManagerSeq
.resize(vModulesInfo
.size());
1174 m_lNewVersionMenubarSettingsSeq
.realloc(vModulesInfo
.size());
1175 auto p_lNewVersionMenubarSettingsSeq
= m_lNewVersionMenubarSettingsSeq
.getArray();
1176 m_lNewVersionToolbarSettingsSeq
.realloc(vModulesInfo
.size());
1177 auto p_lNewVersionToolbarSettingsSeq
= m_lNewVersionToolbarSettingsSeq
.getArray();
1179 static constexpr OUStringLiteral
sMenubarResourceURL(u
"private:resource/menubar/menubar");
1180 static constexpr OUStringLiteral
sToolbarResourcePre(u
"private:resource/toolbar/");
1182 uno::Reference
< ui::XModuleUIConfigurationManagerSupplier
> xModuleCfgSupplier
= ui::theModuleUIConfigurationManagerSupplier::get( ::comphelper::getProcessComponentContext() );
1184 for (size_t i
=0; i
<vModulesInfo
.size(); ++i
) {
1185 OUString sModuleIdentifier
= mapModuleShortNameToIdentifier(vModulesInfo
[i
].sModuleShortName
);
1186 if (!sModuleIdentifier
.isEmpty()) {
1187 uno::Reference
< ui::XUIConfigurationManager
> xCfgManager
= xModuleCfgSupplier
->getUIConfigurationManager(sModuleIdentifier
);
1188 m_lCfgManagerSeq
[i
].Name
= vModulesInfo
[i
].sModuleShortName
;
1189 m_lCfgManagerSeq
[i
].Value
<<= xCfgManager
;
1191 if (vModulesInfo
[i
].bHasMenubar
) {
1192 p_lNewVersionMenubarSettingsSeq
[i
].Name
= vModulesInfo
[i
].sModuleShortName
;
1193 p_lNewVersionMenubarSettingsSeq
[i
].Value
<<= xCfgManager
->getSettings(sMenubarResourceURL
, true);
1196 sal_Int32 nToolbars
= vModulesInfo
[i
].m_vToolbars
.size();
1197 if (nToolbars
> 0) {
1198 uno::Sequence
< beans::PropertyValue
> lPropSeq(nToolbars
);
1199 auto plPropSeq
= lPropSeq
.getArray();
1200 for (sal_Int32 j
=0; j
<nToolbars
; ++j
) {
1201 OUString sToolbarName
= vModulesInfo
[i
].m_vToolbars
[j
];
1202 OUString sToolbarResourceURL
= sToolbarResourcePre
+ sToolbarName
;
1204 plPropSeq
[j
].Name
= sToolbarName
;
1205 plPropSeq
[j
].Value
<<= xCfgManager
->getSettings(sToolbarResourceURL
, true);
1208 p_lNewVersionToolbarSettingsSeq
[i
].Name
= vModulesInfo
[i
].sModuleShortName
;
1209 p_lNewVersionToolbarSettingsSeq
[i
].Value
<<= lPropSeq
;
1215 } // namespace desktop
1217 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */