/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
if (!checkMigrationCompleted()) {
readAvailableMigrations(m_vMigrationsAvailable);
sal_Int32 nIndex = findPreferredMigrationProcess(m_vMigrationsAvailable); // m_aInfo is now set to the preferred migration source if ( nIndex >= 0 ) { if (alreadyMigrated()) returnfalse;
m_vrMigrations = readMigrationSteps(m_vMigrationsAvailable[nIndex].name);
}
bool bResult = false; try {
bResult = aImpl.doMigration();
} catch (const Exception&) {
TOOLS_WARN_EXCEPTION( "desktop", "doMigration()");
}
OSL_ENSURE(bResult, "Migration has not been successful");
}
MigrationImpl::MigrationImpl()
{
}
MigrationImpl::~MigrationImpl()
{
}
// The main entry point for migrating settings bool MigrationImpl::doMigration()
{ // compile file list for migration
m_vrFileList = compileFileList();
// get migration description from org.openoffice.Setup/Migration // and build vector of migration steps
uno::Reference< XNameAccess > theNameAccess(xMigrationData->getByName(u"MigrationSteps"_ustr), uno::UNO_QUERY_THROW);
uno::Reference< XNameAccess > tmpAccess;
uno::Sequence< OUString > tmpSeq;
migrations_vr vrMigrations(new migrations_v); const css::uno::Sequence<OUString> aMigrationSteps = theNameAccess->getElementNames(); for (const OUString& rMigrationStep : aMigrationSteps) { // get current migration step
theNameAccess->getByName(rMigrationStep) >>= tmpAccess;
migration_step tmpStep;
// read included files from current step description if (tmpAccess->getByName(u"IncludedFiles"_ustr) >>= tmpSeq) {
tmpStep.includeFiles.insert(tmpStep.includeFiles.end(), tmpSeq.begin(), tmpSeq.end());
}
// cater for XDG_CONFIG_HOME change // If XDG_CONFIG_HOME is set then we; // assume the user knows what they are doing ( room for improvement here, we could // of course search the default config dir etc. also - but this is more complex, // we would need to weigh results from the current config dir against matches in // the 'old' config dir etc. ) - currently we just use the returned config dir. // If XDG_CONFIG_HOME is NOT set; // assume then we should now using the default $HOME/.config config location for // our user profiles, however *all* previous libreoffice and openoffice.org // configurations will be in the 'old' config directory and that's where we need // to search - we convert the returned config dir to the 'old' dir if ( !pXDGCfgHome && rConfigDir.endsWith( XDG_CONFIG_PART ) ) // remove trailing '.config/' but leave the terminating '/'
aPreXDGConfigPath = rConfigDir.copy( 0, rConfigDir.getLength() - sizeof( XDG_CONFIG_PART ) + 2 ); else
aPreXDGConfigPath = rConfigDir;
// the application-specific config dir is no longer prefixed by '.' because it is hidden under ".config" // we have to add the '.' for the pre-XDG directory names
aPreXDGConfigPath += ".";
SAL_INFO( "desktop.migration", " preferred migration is from product '" << m_aInfo.productname << "'");
SAL_INFO( "desktop.migration", " and settings directory '" << m_aInfo.userdata << "'");
return nIndex;
}
strings_vr MigrationImpl::applyPatterns(const strings_v& vSet, const strings_v& vPatterns)
{ usingnamespace utl;
strings_vr vrResult(new strings_v); for (autoconst& pattern : vPatterns)
{ // find matches for this pattern in input set // and copy them to the result
SearchParam param(pattern, SearchParam::SearchType::Regexp);
TextSearch ts(param, LANGUAGE_DONTKNOW);
sal_Int32 start = 0;
sal_Int32 end = 0; for (autoconst& elem : vSet)
{
end = elem.getLength(); if (ts.SearchForward(elem, &start, &end))
vrResult->push_back(elem);
}
} return vrResult;
}
bool getComponent(OUString const & path, OUString * component)
{
OSL_ASSERT(component != nullptr); if (path.isEmpty() || path[0] != '/') {
SAL_INFO( "desktop.migration", "configuration migration in/exclude path " << path << " ignored (does not start with slash)" ); returnfalse;
}
sal_Int32 i = path.indexOf('/', 1);
*component = i < 0 ? path.copy(1) : path.copy(1, i - 1); returntrue;
}
void renameMigratedSetElementTo(
css::uno::Reference<css::container::XNameContainer> const & set, OUString const & currentName,
OUString const & migratedName)
{ // To avoid unexpected data loss, the code is careful to only rename from currentName to // migratedName in the expected case where the currentName element exists and the migratedName // element doesn't exist: boolconst hasCurrent = set->hasByName(currentName); boolconst hasMigrated = set->hasByName(migratedName); if (hasCurrent && !hasMigrated) { autoconst elem = set->getByName(currentName);
set->removeByName(currentName);
set->insertByName(migratedName, elem);
} else {
SAL_INFO_IF(!hasCurrent, "desktop.migration", "unexpectedly missing " << currentName);
SAL_INFO_IF(hasMigrated, "desktop.migration", "unexpectedly present " << migratedName);
}
}
void renameMigratedSetElementBack(
css::uno::Reference<css::container::XNameContainer> const & set, OUString const & currentName,
OUString const & migratedName)
{ // To avoid unexpected data loss, the code is careful to ensure that in the end a currentName // element exists, creating it from a template if the migratedName element had unexpectedly gone // missing: boolconst hasMigrated = set->hasByName(migratedName);
css::uno::Any elem; if (hasMigrated) {
elem = set->getByName(migratedName);
set->removeByName(migratedName);
} else {
SAL_INFO("desktop.migration", "unexpected loss of " << migratedName);
elem <<= css::uno::Reference<css::lang::XSingleServiceFactory>(
set, css::uno::UNO_QUERY_THROW)->createInstance();
} if (set->hasByName(currentName)) {
SAL_INFO("desktop.migration", "unexpected reappearance of " << currentName); if (hasMigrated) {
SAL_INFO( "desktop.migration", "reappeared " << currentName << " overwritten with " << migratedName);
set->replaceByName(currentName, elem);
}
} else {
set->insertByName(currentName, elem);
}
}
}
void MigrationImpl::copyConfig()
{
Components comps; for (autoconst& rMigrationStep : *m_vrMigrations) { for (const OUString& rIncludePath : rMigrationStep.includeConfig) {
OUString comp; if (getComponent(rIncludePath, &comp)) {
comps[comp].includedPaths.insert(rIncludePath);
}
} for (const OUString& rExcludePath : rMigrationStep.excludeConfig) {
OUString comp; if (getComponent(rExcludePath, &comp)) {
comps[comp].excludedPaths.insert(rExcludePath);
}
}
}
// If the to-be-migrated data contains modifications of // /org.openoffice.Office.UI/ColorScheme/ColorSchemes set elements named after the migrated // product name, those modifications must instead be made to the corresponding set elements // named after the current product name. However, if the current configuration data does not // contain those old-named set elements at all, their modification data would silently be // ignored by css.configuration.XUpdate::insertModificationXcuFile. So temporarily rename any // new-named set elements to their old-named counterparts here, and rename them back again down // below after importing the migrated data:
OUString sProductName = utl::ConfigManager::getProductName();
OUString sProductNameDark = sProductName + " Dark";
OUString sMigratedProductName = m_aInfo.productname; // remove version number from the end of product name if there’s one if (isdigit(sMigratedProductName[sMigratedProductName.getLength() - 1]))
sMigratedProductName = (sMigratedProductName.copy(0, m_aInfo.productname.getLength() - 1)).trim();
OUString sMigratedProductNameDark = sMigratedProductName + " Dark"; autoconst tempRename = sMigratedProductName != sProductName; if (tempRename) { autoconst batch = comphelper::ConfigurationChanges::create(); autoconst schemes = officecfg::Office::UI::ColorScheme::ColorSchemes::get(batch);
renameMigratedSetElementTo(schemes, sProductName, sMigratedProductName);
renameMigratedSetElementTo(schemes, sProductNameDark, sMigratedProductNameDark);
batch->commit();
}
for (autoconst& comp : comps)
{ if (!comp.second.includedPaths.empty()) { if (!bRegistryModificationsXcuExists) { // shared registrymodifications.xcu does not exists // the configuration is split in many registry files // determine the file names from the first element in included paths
OUStringBuffer buf(m_aInfo.userdata
+ "/user/registry/data");
sal_Int32 n = 0; do {
OUString seg(comp.first.getToken(0, '.', n));
OUString enc(
rtl::Uri::encode(
seg, rtl_UriCharClassPchar, rtl_UriEncodeStrict,
RTL_TEXTENCODING_UTF8)); if (enc.isEmpty() && !seg.isEmpty()) {
SAL_INFO( "desktop.migration", "configuration migration component " << comp.first << " ignored (cannot be encoded as file path)" ); goto next;
}
buf.append("/" + enc);
} while (n >= 0);
buf.append(".xcu");
regFilePath = buf.makeStringAndClear();
}
configuration::Update::get(
comphelper::getProcessComponentContext())->
insertModificationXcuFile(
regFilePath,
comphelper::containerToSequence(comp.second.includedPaths),
comphelper::containerToSequence(comp.second.excludedPaths));
} else {
SAL_INFO( "desktop.migration", "configuration migration component " << comp.first << " ignored (only excludes, no includes)" );
}
next:
;
} if (tempRename) { autoconst batch = comphelper::ConfigurationChanges::create(); autoconst schemes = officecfg::Office::UI::ColorScheme::ColorSchemes::get(batch);
renameMigratedSetElementBack(schemes, sProductName, sMigratedProductName);
renameMigratedSetElementBack(schemes, sProductNameDark, sMigratedProductNameDark);
batch->commit();
} // checking the migrated (product name related) color scheme name, and replace it to the current version scheme name try
{
OUString sMigratedColorScheme;
uno::Reference<XPropertySet> aPropertySet(
getConfigAccess("org.openoffice.Office.UI/ColorScheme", true), uno::UNO_QUERY_THROW); if (aPropertySet->getPropertyValue(u"CurrentColorScheme"_ustr) >>= sMigratedColorScheme)
{ if (sMigratedColorScheme.equals(sMigratedProductName))
{
aPropertySet->setPropertyValue(u"CurrentColorScheme"_ustr,
uno::Any(sProductName));
uno::Reference<XChangesBatch>(aPropertySet, uno::UNO_QUERY_THROW)->commitChanges();
} elseif (sMigratedColorScheme.equals(sMigratedProductNameDark))
{
aPropertySet->setPropertyValue(u"CurrentColorScheme"_ustr,
uno::Any(sProductNameDark));
uno::Reference<XChangesBatch>(aPropertySet, uno::UNO_QUERY_THROW)->commitChanges();
}
}
} catch (const Exception&) { // fail silently...
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.