/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ #include #include #include #include "migration.hxx" #include "migration_impl.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace osl; using namespace std; using namespace com::sun::star::task; using namespace com::sun::star::lang; using namespace com::sun::star::beans; using namespace com::sun::star::util; using namespace com::sun::star::container; using com::sun::star::uno::Exception; using namespace com::sun::star; using ::rtl::OUString; using ::rtl::OString; namespace desktop { static const char ITEM_DESCRIPTOR_COMMANDURL[] = "CommandURL"; static const char ITEM_DESCRIPTOR_CONTAINER[] = "ItemDescriptorContainer"; static const char ITEM_DESCRIPTOR_LABEL[] = "Label"; static const char XDG_CONFIG_PART[] = "/.config"; ::rtl::OUString retrieveLabelFromCommand(const ::rtl::OUString& sCommand, const ::rtl::OUString& sModuleIdentifier) { ::rtl::OUString sLabel; uno::Reference< container::XNameAccess > xUICommands; uno::Reference< container::XNameAccess > xNameAccess( ::comphelper::getProcessServiceFactory()->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.UICommandDescription")) ), uno::UNO_QUERY ); if ( xNameAccess.is() ) { uno::Any a = xNameAccess->getByName( sModuleIdentifier ); a >>= xUICommands; } if (xUICommands.is()) { if ( !sCommand.isEmpty() ) { rtl::OUString aStr; ::uno::Sequence< beans::PropertyValue > aPropSeq; try { uno::Any a( xUICommands->getByName( sCommand )); if ( a >>= aPropSeq ) { for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ ) { if ( aPropSeq[i].Name == "Label" ) { aPropSeq[i].Value >>= aStr; break; } } } sLabel = aStr; } catch (const container::NoSuchElementException&) { sLabel = sCommand; sal_Int32 nIndex = sLabel.indexOf(':'); if (nIndex>=0 && nIndex <= sLabel.getLength()-1) sLabel = sLabel.copy(nIndex+1); } } } return sLabel; } ::rtl::OUString mapModuleShortNameToIdentifier(const ::rtl::OUString& sShortName) { ::rtl::OUString sIdentifier; if ( sShortName == "StartModule" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.StartModule")); else if ( sShortName == "swriter" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.TextDocument")); else if ( sShortName == "scalc" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sheet.SpreadsheetDocument")); else if ( sShortName == "sdraw" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.DrawingDocument")); else if ( sShortName == "simpress" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.presentation.PresentationDocument")); else if ( sShortName == "smath" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.formula.FormulaProperties")); else if ( sShortName == "schart" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.chart2.ChartDocument")); else if ( sShortName == "BasicIDE" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.script.BasicIDE")); else if ( sShortName == "dbapp" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdb.OfficeDatabaseDocument")); else if ( sShortName == "sglobal" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.GlobalDocument")); else if ( sShortName == "sweb" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.WebDocument")); else if ( sShortName == "swxform" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xforms.XMLFormDocument")); else if ( sShortName == "sbibliography" ) sIdentifier = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Bibliography")); return sIdentifier; } bool MigrationImpl::alreadyMigrated() { rtl::OUString MIGRATION_STAMP_NAME(RTL_CONSTASCII_USTRINGPARAM("/MIGRATED")); rtl::OUString aStr = m_aInfo.userdata + MIGRATION_STAMP_NAME; File aFile(aStr); // create migration stamp, and/or check its existence bool bRet = aFile.open (osl_File_OpenFlag_Write | osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock) == FileBase::E_EXIST; OSL_TRACE( "File '%s' exists? %d\n", rtl::OUStringToOString(aStr, RTL_TEXTENCODING_ASCII_US).getStr(), bRet ); return bRet; } bool MigrationImpl::initializeMigration() { bool bRet = false; if (!checkMigrationCompleted()) { readAvailableMigrations(m_vMigrationsAvailable); sal_Int32 nIndex = findPreferedMigrationProcess(m_vMigrationsAvailable); // m_aInfo is now set to the preferred migration source if ( nIndex >= 0 ) { if (alreadyMigrated()) return false; m_vrMigrations = readMigrationSteps(m_vMigrationsAvailable[nIndex].name); } bRet = !m_aInfo.userdata.isEmpty(); } OSL_TRACE( "Migration %s", bRet ? "needed" : "not required" ); return bRet; } void Migration::migrateSettingsIfNecessary() { MigrationImpl aImpl( comphelper::getProcessServiceFactory() ); if (! aImpl.initializeMigration() ) return; sal_Bool bResult = sal_False; try { bResult = aImpl.doMigration(); } catch (const Exception& e) { OString aMsg("doMigration() exception: "); aMsg += OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US); OSL_FAIL(aMsg.getStr()); } OSL_ENSURE(bResult, "Migration has not been successfull"); (void)bResult; } MigrationImpl::MigrationImpl(const uno::Reference< XMultiServiceFactory >& xFactory) : m_vrVersions(new strings_v) , m_xFactory(xFactory) { } MigrationImpl::~MigrationImpl() { } // The main entry point for migrating settings sal_Bool MigrationImpl::doMigration() { // compile file list for migration m_vrFileList = compileFileList(); sal_Bool result = sal_False; try { NewVersionUIInfo aNewVersionUIInfo; ::std::vector< MigrationModuleInfo > vModulesInfo = dectectUIChangesForAllModules(); aNewVersionUIInfo.init(vModulesInfo); copyFiles(); const ::rtl::OUString sMenubarResourceURL(RTL_CONSTASCII_USTRINGPARAM("private:resource/menubar/menubar")); const ::rtl::OUString sToolbarResourcePre(RTL_CONSTASCII_USTRINGPARAM("private:resource/toolbar/")); for (sal_uInt32 i=0; i lArgs(2); ::rtl::OUString aOldCfgDataPath = m_aInfo.userdata + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/user/config/soffice.cfg/modules/")); lArgs[0] <<= aOldCfgDataPath + vModulesInfo[i].sModuleShortName; lArgs[1] <<= embed::ElementModes::READ; uno::Reference< lang::XSingleServiceFactory > xStorageFactory( embed::FileSystemStorageFactory::create(comphelper::ComponentContext(m_xFactory).getUNOContext())); uno::Reference< embed::XStorage > xModules(xStorageFactory->createInstanceWithArguments(lArgs), uno::UNO_QUERY); uno::Reference< ui::XUIConfigurationManager > xOldCfgManager( m_xFactory->createInstance( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ui.UIConfigurationManager"))), uno::UNO_QUERY ); uno::Reference< ui::XUIConfigurationStorage > xOldCfgStorage( xOldCfgManager, uno::UNO_QUERY ); uno::Reference< ui::XUIConfigurationPersistence > xOldCfgPersistence( xOldCfgManager, uno::UNO_QUERY ); if ( xOldCfgStorage.is() && xOldCfgPersistence.is() && xModules.is() ) { xOldCfgStorage->setStorage( xModules ); xOldCfgPersistence->reload(); } uno::Reference< ui::XUIConfigurationManager > xCfgManager = aNewVersionUIInfo.getConfigManager(vModulesInfo[i].sModuleShortName); if (vModulesInfo[i].bHasMenubar) { uno::Reference< container::XIndexContainer > xOldVersionMenuSettings = uno::Reference< container::XIndexContainer >(xOldCfgManager->getSettings(sMenubarResourceURL, sal_True), uno::UNO_QUERY); uno::Reference< container::XIndexContainer > xNewVersionMenuSettings = aNewVersionUIInfo.getNewMenubarSettings(vModulesInfo[i].sModuleShortName); ::rtl::OUString sParent; compareOldAndNewConfig(sParent, xOldVersionMenuSettings, xNewVersionMenuSettings, sMenubarResourceURL); mergeOldToNewVersion(xCfgManager, xNewVersionMenuSettings, sModuleIdentifier, sMenubarResourceURL); } sal_Int32 nToolbars = vModulesInfo[i].m_vToolbars.size(); if (nToolbars >0) { for (sal_Int32 j=0; j xOldVersionToolbarSettings = uno::Reference< container::XIndexContainer >(xOldCfgManager->getSettings(sToolbarResourceURL, sal_True), uno::UNO_QUERY); uno::Reference< container::XIndexContainer > xNewVersionToolbarSettings = aNewVersionUIInfo.getNewToolbarSettings(vModulesInfo[i].sModuleShortName, sToolbarName); ::rtl::OUString sParent; compareOldAndNewConfig(sParent, xOldVersionToolbarSettings, xNewVersionToolbarSettings, sToolbarResourceURL); mergeOldToNewVersion(xCfgManager, xNewVersionToolbarSettings, sModuleIdentifier, sToolbarResourceURL); } } m_aOldVersionItemsHashMap.clear(); m_aNewVersionItemsHashMap.clear(); } // execute the migration items from Setup.xcu copyConfig(); // execute custom migration services from Setup.xcu // and refresh the cache runServices(); refresh(); result = sal_True; } catch (...) { OString aMsg("An unexpected exception was thrown during migration"); aMsg += "\nOldVersion: " + OUStringToOString(m_aInfo.productname, RTL_TEXTENCODING_ASCII_US); aMsg += "\nDataPath : " + OUStringToOString(m_aInfo.userdata, RTL_TEXTENCODING_ASCII_US); OSL_FAIL(aMsg.getStr()); } // prevent running the migration multiple times setMigrationCompleted(); return result; } void MigrationImpl::refresh() { uno::Reference< XRefreshable >( configuration::theDefaultProvider::get( comphelper::getComponentContext(m_xFactory)), uno::UNO_QUERY_THROW)->refresh(); } void MigrationImpl::setMigrationCompleted() { try { uno::Reference< XPropertySet > aPropertySet(getConfigAccess("org.openoffice.Setup/Office", true), uno::UNO_QUERY_THROW); aPropertySet->setPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("MigrationCompleted")), uno::makeAny(sal_True)); uno::Reference< XChangesBatch >(aPropertySet, uno::UNO_QUERY_THROW)->commitChanges(); } catch (...) { // fail silently } } bool MigrationImpl::checkMigrationCompleted() { sal_Bool bMigrationCompleted = sal_False; try { uno::Reference< XPropertySet > aPropertySet( getConfigAccess("org.openoffice.Setup/Office"), uno::UNO_QUERY_THROW); aPropertySet->getPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM("MigrationCompleted"))) >>= bMigrationCompleted; if( !bMigrationCompleted && getenv("SAL_DISABLE_USERMIGRATION" ) ) { // migration prevented - fake it's success setMigrationCompleted(); bMigrationCompleted = sal_True; } } catch (const Exception&) { // just return false... } OSL_TRACE( "Migration %s", bMigrationCompleted ? "already completed" : "not done" ); return bMigrationCompleted; } static void insertSorted(migrations_available& rAvailableMigrations, supported_migration& aSupportedMigration) { bool bInserted( false ); migrations_available::iterator pIter = rAvailableMigrations.begin(); while ( !bInserted && pIter != rAvailableMigrations.end()) { if ( pIter->nPriority < aSupportedMigration.nPriority ) { rAvailableMigrations.insert(pIter, aSupportedMigration ); bInserted = true; break; // i111193: insert invalidates iterator! } ++pIter; } if ( !bInserted ) rAvailableMigrations.push_back( aSupportedMigration ); } bool MigrationImpl::readAvailableMigrations(migrations_available& rAvailableMigrations) { // get supported version names uno::Reference< XNameAccess > aMigrationAccess(getConfigAccess("org.openoffice.Setup/Migration/SupportedVersions"), uno::UNO_QUERY_THROW); uno::Sequence< OUString > seqSupportedVersions = aMigrationAccess->getElementNames(); const OUString aVersionIdentifiers( RTL_CONSTASCII_USTRINGPARAM( "VersionIdentifiers" )); const OUString aPriorityIdentifier( RTL_CONSTASCII_USTRINGPARAM( "Priority" )); for (sal_Int32 i=0; i seqVersions; uno::Reference< XNameAccess > xMigrationData( aMigrationAccess->getByName(seqSupportedVersions[i]), uno::UNO_QUERY_THROW ); xMigrationData->getByName( aVersionIdentifiers ) >>= seqVersions; xMigrationData->getByName( aPriorityIdentifier ) >>= nPriority; supported_migration aSupportedMigration; aSupportedMigration.name = seqSupportedVersions[i]; aSupportedMigration.nPriority = nPriority; for (sal_Int32 j=0; j aMigrationAccess(getConfigAccess("org.openoffice.Setup/Migration/SupportedVersions"), uno::UNO_QUERY_THROW); uno::Reference< XNameAccess > xMigrationData( aMigrationAccess->getByName(rMigrationName), uno::UNO_QUERY_THROW ); // get migration description from from org.openoffice.Setup/Migration // and build vector of migration steps OUString aMigrationSteps( RTL_CONSTASCII_USTRINGPARAM( "MigrationSteps" )); uno::Reference< XNameAccess > theNameAccess(xMigrationData->getByName(aMigrationSteps), uno::UNO_QUERY_THROW); uno::Sequence< OUString > seqMigrations = theNameAccess->getElementNames(); uno::Reference< XNameAccess > tmpAccess; uno::Reference< XNameAccess > tmpAccess2; uno::Sequence< OUString > tmpSeq; migrations_vr vrMigrations(new migrations_v); for (sal_Int32 i = 0; i < seqMigrations.getLength(); i++) { // get current migration step theNameAccess->getByName(seqMigrations[i]) >>= tmpAccess; migration_step tmpStep; tmpStep.name = seqMigrations[i]; // read included files from current step description ::rtl::OUString aSeqEntry; if (tmpAccess->getByName(OUString(RTL_CONSTASCII_USTRINGPARAM("IncludedFiles"))) >>= tmpSeq) { for (sal_Int32 j=0; jgetByName(OUString(RTL_CONSTASCII_USTRINGPARAM("ExcludedFiles"))) >>= tmpSeq) { for (sal_Int32 j=0; jgetByName(OUString(RTL_CONSTASCII_USTRINGPARAM("IncludedNodes"))) >>= tmpSeq) { for (sal_Int32 j=0; jgetByName(OUString(RTL_CONSTASCII_USTRINGPARAM("ExcludedNodes"))) >>= tmpSeq) { for (sal_Int32 j=0; jgetByName(OUString(RTL_CONSTASCII_USTRINGPARAM("IncludedExtensions"))) >>= tmpSeq) { for (sal_Int32 j=0; jgetByName(OUString(RTL_CONSTASCII_USTRINGPARAM("ExcludedExtensions"))) >>= tmpSeq) { for (sal_Int32 j=0; jgetByName(OUString(RTL_CONSTASCII_USTRINGPARAM("MigrationService"))) >>= tmpStep.service; vrMigrations->push_back(tmpStep); } return vrMigrations; } static FileBase::RC _checkAndCreateDirectory(INetURLObject& dirURL) { FileBase::RC result = Directory::create(dirURL.GetMainURL(INetURLObject::DECODE_TO_IURI)); if (result == FileBase::E_NOENT) { INetURLObject baseURL(dirURL); baseURL.removeSegment(); _checkAndCreateDirectory(baseURL); return Directory::create(dirURL.GetMainURL(INetURLObject::DECODE_TO_IURI)); } else return result; } install_info MigrationImpl::findInstallation(const strings_v& rVersions) { install_info aInfo; strings_v::const_iterator i_ver = rVersions.begin(); while (i_ver != rVersions.end()) { ::rtl::OUString aVersion, aProfileName; sal_Int32 nSeparatorIndex = (*i_ver).indexOf('='); if ( nSeparatorIndex != -1 ) { aVersion = (*i_ver).copy( 0, nSeparatorIndex ); aProfileName = (*i_ver).copy( nSeparatorIndex+1 ); } if ( !aVersion.isEmpty() && !aProfileName.isEmpty() && ( aInfo.userdata.isEmpty() || aProfileName.equalsIgnoreAsciiCase( utl::ConfigManager::getProductName() ) ) ) { ::rtl::OUString aUserInst; osl::Security().getConfigDir( aUserInst ); #if defined UNX && ! defined MACOSX const char* pXDGCfgHome = getenv("XDG_CONFIG_HOME"); // 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 && aUserInst.endsWithAsciiL( XDG_CONFIG_PART, sizeof( XDG_CONFIG_PART ) - 1 ) ) aUserInst = aUserInst.copy( 0, aUserInst.getLength() - sizeof( XDG_CONFIG_PART ) + 2 ); // remove trailing '.config' ( but leave the terminating '/' ) #endif if ( !aUserInst.isEmpty() && aUserInst[ aUserInst.getLength()-1 ] != '/' ) aUserInst += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")); #if defined UNX && ! defined MACOSX // tribute to whoever had the "great" idea to use different names on Windows and Unix aUserInst += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".")); #endif aUserInst += aProfileName; rtl::OUString url( INetURLObject(aUserInst).GetMainURL(INetURLObject::NO_DECODE)); osl::DirectoryItem item; osl::FileStatus stat(osl_FileStatus_Mask_Type); if (osl::DirectoryItem::get(url, item) == osl::FileBase::E_None && item.getFileStatus(stat) == osl::FileBase::E_None && stat.getFileType() == osl::FileStatus::Directory) { aInfo.userdata = url; aInfo.productname = aVersion; } } ++i_ver; } return aInfo; } sal_Int32 MigrationImpl::findPreferedMigrationProcess(const migrations_available& rAvailableMigrations) { sal_Int32 nIndex( -1 ); sal_Int32 i( 0 ); migrations_available::const_iterator rIter = rAvailableMigrations.begin(); while ( rIter != rAvailableMigrations.end() ) { install_info aInstallInfo = findInstallation(rIter->supported_versions); if (!aInstallInfo.productname.isEmpty() ) { m_aInfo = aInstallInfo; nIndex = i; break; } ++i; ++rIter; } OSL_TRACE( " preferred migration is from product '%s'\n", rtl::OUStringToOString( m_aInfo.productname, RTL_TEXTENCODING_ASCII_US ).getStr() ); OSL_TRACE( " and settings directory '%s'\n", rtl::OUStringToOString( m_aInfo.userdata, RTL_TEXTENCODING_ASCII_US ).getStr() ); return nIndex; } strings_vr MigrationImpl::applyPatterns(const strings_v& vSet, const strings_v& vPatterns) const { using namespace utl; strings_vr vrResult(new strings_v); strings_v::const_iterator i_set; strings_v::const_iterator i_pat = vPatterns.begin(); while (i_pat != vPatterns.end()) { // find matches for this pattern in input set // and copy them to the result SearchParam param(*i_pat, SearchParam::SRCH_REGEXP); TextSearch ts(param, LANGUAGE_DONTKNOW); i_set = vSet.begin(); xub_StrLen start = 0; xub_StrLen end = 0; while (i_set != vSet.end()) { end = (xub_StrLen)(i_set->getLength()); if (ts.SearchFrwrd(*i_set, &start, &end)) vrResult->push_back(*i_set); ++i_set; } ++i_pat; } return vrResult; } strings_vr MigrationImpl::getAllFiles(const OUString& baseURL) const { using namespace osl; strings_vr vrResult(new strings_v); // get sub dirs Directory dir(baseURL); if (dir.open() == FileBase::E_None) { strings_v vSubDirs; strings_vr vrSubResult; // work through directory contents... DirectoryItem item; FileStatus fs(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL); while (dir.getNextItem(item) == FileBase::E_None) { if (item.getFileStatus(fs) == FileBase::E_None) { if (fs.getFileType() == FileStatus::Directory) vSubDirs.push_back(fs.getFileURL()); else vrResult->push_back(fs.getFileURL()); } } // recurse subfolders strings_v::const_iterator i = vSubDirs.begin(); while (i != vSubDirs.end()) { vrSubResult = getAllFiles(*i); vrResult->insert(vrResult->end(), vrSubResult->begin(), vrSubResult->end()); ++i; } } return vrResult; } strings_vr MigrationImpl::compileFileList() { strings_vr vrResult(new strings_v); strings_vr vrInclude; strings_vr vrExclude; // get a list of all files: strings_vr vrFiles = getAllFiles(m_aInfo.userdata); // get a file list result for each migration step migrations_v::const_iterator i_migr = m_vrMigrations->begin(); while (i_migr != m_vrMigrations->end()) { vrInclude = applyPatterns(*vrFiles, i_migr->includeFiles); vrExclude = applyPatterns(*vrFiles, i_migr->excludeFiles); subtract(*vrInclude, *vrExclude); vrResult->insert(vrResult->end(), vrInclude->begin(), vrInclude->end()); ++i_migr; } return vrResult; } namespace { struct componentParts { std::set< rtl::OUString > includedPaths; std::set< rtl::OUString > excludedPaths; }; typedef std::map< rtl::OUString, componentParts > Components; bool getComponent(rtl::OUString const & path, rtl::OUString * component) { OSL_ASSERT(component != 0); if (path.isEmpty() || path[0] != '/') { OSL_TRACE( ("configuration migration in/exclude path %s ignored (does not" " start with slash)"), rtl::OUStringToOString(path, RTL_TEXTENCODING_UTF8).getStr()); return false; } sal_Int32 i = path.indexOf('/', 1); *component = i < 0 ? path.copy(1) : path.copy(1, i - 1); return true; } uno::Sequence< rtl::OUString > setToSeq(std::set< rtl::OUString > const & set) { std::set< rtl::OUString >::size_type n = set.size(); if (n > SAL_MAX_INT32) { throw std::bad_alloc(); } uno::Sequence< rtl::OUString > seq(static_cast< sal_Int32 >(n)); sal_Int32 i = 0; for (std::set< rtl::OUString >::const_iterator j(set.begin()); j != set.end(); ++j) { seq[i++] = *j; } return seq; } } void MigrationImpl::copyConfig() { Components comps; for (migrations_v::const_iterator i(m_vrMigrations->begin()); i != m_vrMigrations->end(); ++i) { for (strings_v::const_iterator j(i->includeConfig.begin()); j != i->includeConfig.end(); ++j) { rtl::OUString comp; if (getComponent(*j, &comp)) { comps[comp].includedPaths.insert(*j); } } for (strings_v::const_iterator j(i->excludeConfig.begin()); j != i->excludeConfig.end(); ++j) { rtl::OUString comp; if (getComponent(*j, &comp)) { comps[comp].excludedPaths.insert(*j); } } } // check if the shared registrymodifications.xcu file exists bool bRegistryModificationsXcuExists = false; rtl::OUString regFilePath(m_aInfo.userdata); regFilePath += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/user/registrymodifications.xcu")); File regFile(regFilePath); ::osl::FileBase::RC nError = regFile.open(osl_File_OpenFlag_Read); if ( nError == ::osl::FileBase::E_None ) { bRegistryModificationsXcuExists = true; regFile.close(); } for (Components::const_iterator i(comps.begin()); i != comps.end(); ++i) { if (!i->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 rtl::OUStringBuffer buf(m_aInfo.userdata); buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("/user/registry/data")); sal_Int32 n = 0; do { rtl::OUString seg(i->first.getToken(0, '.', n)); rtl::OUString enc( rtl::Uri::encode( seg, rtl_UriCharClassPchar, rtl_UriEncodeStrict, RTL_TEXTENCODING_UTF8)); if (enc.isEmpty() && !seg.isEmpty()) { OSL_TRACE( ("configuration migration component %s ignored (cannot" " be encoded as file path)"), rtl::OUStringToOString( i->first, RTL_TEXTENCODING_UTF8).getStr()); goto next; } buf.append(sal_Unicode('/')); buf.append(enc); } while (n >= 0); buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(".xcu")); regFilePath = buf.toString(); } configuration::Update::get( comphelper::getProcessComponentContext())-> insertModificationXcuFile( regFilePath, setToSeq(i->second.includedPaths), setToSeq(i->second.excludedPaths)); } else { OSL_TRACE( ("configuration migration component %s ignored (only excludes," " no includes)"), rtl::OUStringToOString( i->first, RTL_TEXTENCODING_UTF8).getStr()); } next:; } } // removes elements of vector 2 in vector 1 void MigrationImpl::subtract(strings_v& va, const strings_v& vb_c) const { strings_v vb(vb_c); // ensure uniqueness of entries sort(va.begin(), va.end()); sort(vb.begin(), vb.end()); unique(va.begin(), va.end()); unique(vb.begin(), vb.end()); strings_v::const_iterator i_ex = vb.begin(); strings_v::iterator i_in; strings_v::iterator i_next; while (i_ex != vb.end()) { i_in = va.begin(); while (i_in != va.end()) { if ( *i_in == *i_ex) { i_next = i_in+1; va.erase(i_in); i_in = i_next; // we can only find one match since we // ensured uniquness of the entries. ergo: break; } else ++i_in; } ++i_ex; } } uno::Reference< XNameAccess > MigrationImpl::getConfigAccess(const sal_Char* pPath, sal_Bool bUpdate) { uno::Reference< XNameAccess > xNameAccess; try{ OUString sAccessSrvc; if (bUpdate) sAccessSrvc = OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.ConfigurationUpdateAccess")); else sAccessSrvc = OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.ConfigurationAccess")); OUString sConfigURL = OUString::createFromAscii(pPath); uno::Reference< XMultiServiceFactory > theConfigProvider( configuration::theDefaultProvider::get( comphelper::getProcessComponentContext())); // access the provider uno::Sequence< uno::Any > theArgs(1); theArgs[ 0 ] <<= sConfigURL; xNameAccess = uno::Reference< XNameAccess > ( theConfigProvider->createInstanceWithArguments( sAccessSrvc, theArgs ), uno::UNO_QUERY_THROW ); } catch (const com::sun::star::uno::Exception& e) { OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US); OSL_FAIL(aMsg.getStr()); } return xNameAccess; } void MigrationImpl::copyFiles() { strings_v::const_iterator i_file = m_vrFileList->begin(); OUString localName; OUString destName; OUString userInstall; utl::Bootstrap::PathStatus aStatus; aStatus = utl::Bootstrap::locateUserInstallation(userInstall); if (aStatus == utl::Bootstrap::PATH_EXISTS) { while (i_file != m_vrFileList->end()) { // remove installation prefix from file localName = i_file->copy(m_aInfo.userdata.getLength()); destName = userInstall + localName; INetURLObject aURL(destName); // check whether destination directory exists aURL.removeSegment(); _checkAndCreateDirectory(aURL); FileBase::RC copyResult = File::copy(*i_file, destName); if (copyResult != FileBase::E_None) { OString msg("Cannot copy "); msg += OUStringToOString(*i_file, RTL_TEXTENCODING_UTF8) + " to " + OUStringToOString(destName, RTL_TEXTENCODING_UTF8); OSL_FAIL(msg.getStr()); } ++i_file; } } else { OSL_FAIL("copyFiles: UserInstall does not exist"); } } void MigrationImpl::runServices() { // Build argument array uno::Sequence< uno::Any > seqArguments(3); seqArguments[0] = uno::makeAny(NamedValue( OUString(RTL_CONSTASCII_USTRINGPARAM("Productname")), uno::makeAny(m_aInfo.productname))); seqArguments[1] = uno::makeAny(NamedValue( OUString(RTL_CONSTASCII_USTRINGPARAM("UserData")), uno::makeAny(m_aInfo.userdata))); // create an instance of every migration service // and execute the migration job uno::Reference< XJob > xMigrationJob; migrations_v::const_iterator i_mig = m_vrMigrations->begin(); while (i_mig != m_vrMigrations->end()) { if( !i_mig->service.isEmpty()) { try { // set black list for extension migration uno::Sequence< rtl::OUString > seqExtBlackList; sal_uInt32 nSize = i_mig->excludeExtensions.size(); if ( nSize > 0 ) seqExtBlackList = comphelper::arrayToSequence< ::rtl::OUString >( &i_mig->excludeExtensions[0], nSize ); seqArguments[2] = uno::makeAny(NamedValue( OUString(RTL_CONSTASCII_USTRINGPARAM("ExtensionBlackList")), uno::makeAny( seqExtBlackList ))); xMigrationJob = uno::Reference< XJob >(m_xFactory->createInstanceWithArguments( i_mig->service, seqArguments), uno::UNO_QUERY_THROW); xMigrationJob->execute(uno::Sequence< NamedValue >()); } catch (const Exception& e) { OString aMsg("Execution of migration service failed (Exception caught).\nService: "); aMsg += OUStringToOString(i_mig->service, RTL_TEXTENCODING_ASCII_US) + "\nMessage: "; aMsg += OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US); OSL_FAIL(aMsg.getStr()); } catch (...) { OString aMsg("Execution of migration service failed (Exception caught).\nService: "); aMsg += OUStringToOString(i_mig->service, RTL_TEXTENCODING_ASCII_US) + "\nNo message available"; OSL_FAIL(aMsg.getStr()); } } ++i_mig; } } ::std::vector< MigrationModuleInfo > MigrationImpl::dectectUIChangesForAllModules() const { ::std::vector< MigrationModuleInfo > vModulesInfo; const ::rtl::OUString MENUBAR(RTL_CONSTASCII_USTRINGPARAM("menubar")); const ::rtl::OUString TOOLBAR(RTL_CONSTASCII_USTRINGPARAM("toolbar")); uno::Sequence< uno::Any > lArgs(2); lArgs[0] <<= m_aInfo.userdata + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/user/config/soffice.cfg/modules")); lArgs[1] <<= embed::ElementModes::READ; uno::Reference< lang::XSingleServiceFactory > xStorageFactory( embed::FileSystemStorageFactory::create(comphelper::ComponentContext(m_xFactory).getUNOContext())); uno::Reference< embed::XStorage > xModules; xModules = uno::Reference< embed::XStorage >(xStorageFactory->createInstanceWithArguments(lArgs), uno::UNO_QUERY); if (!xModules.is()) return vModulesInfo; uno::Reference< container::XNameAccess > xAccess = uno::Reference< container::XNameAccess >(xModules, uno::UNO_QUERY); uno::Sequence< ::rtl::OUString > lNames = xAccess->getElementNames(); sal_Int32 nLength = lNames.getLength(); for (sal_Int32 i=0; i xModule = xModules->openStorageElement(sModuleShortName, embed::ElementModes::READ); if (xModule.is()) { MigrationModuleInfo aModuleInfo; uno::Reference< embed::XStorage > xMenubar = xModule->openStorageElement(MENUBAR, embed::ElementModes::READ); if (xMenubar.is()) { uno::Reference< container::XNameAccess > xNameAccess = uno::Reference< container::XNameAccess >(xMenubar, uno::UNO_QUERY); if (xNameAccess->getElementNames().getLength() > 0) { aModuleInfo.sModuleShortName = sModuleShortName; aModuleInfo.bHasMenubar = sal_True; } } uno::Reference< embed::XStorage > xToolbar = xModule->openStorageElement(TOOLBAR, embed::ElementModes::READ); if (xToolbar.is()) { const ::rtl::OUString RESOURCEURL_CUSTOM_ELEMENT(RTL_CONSTASCII_USTRINGPARAM("custom_")); sal_Int32 nCustomLen = 7; uno::Reference< container::XNameAccess > xNameAccess = uno::Reference< container::XNameAccess >(xToolbar, uno::UNO_QUERY); ::uno::Sequence< ::rtl::OUString > lToolbars = xNameAccess->getElementNames(); for (sal_Int32 j=0; j=nCustomLen && sToolbarName.copy(0, nCustomLen).equals(RESOURCEURL_CUSTOM_ELEMENT)) continue; aModuleInfo.sModuleShortName = sModuleShortName; sal_Int32 nIndex = sToolbarName.lastIndexOf('.'); if (nIndex > 0) { ::rtl::OUString sExtension(sToolbarName.copy(nIndex)); ::rtl::OUString sToolbarResourceName(sToolbarName.copy(0, nIndex)); if (!sToolbarResourceName.isEmpty() && sExtension.equalsAsciiL(".xml", 4)) aModuleInfo.m_vToolbars.push_back(sToolbarResourceName); } } } if (!aModuleInfo.sModuleShortName.isEmpty()) vModulesInfo.push_back(aModuleInfo); } } return vModulesInfo; } void MigrationImpl::compareOldAndNewConfig(const ::rtl::OUString& sParent, const uno::Reference< container::XIndexContainer >& xIndexOld, const uno::Reference< container::XIndexContainer >& xIndexNew, const ::rtl::OUString& sResourceURL) { const ::rtl::OUString MENU_SEPERATOR(RTL_CONSTASCII_USTRINGPARAM(" | ")); ::std::vector< MigrationItem > vOldItems; ::std::vector< MigrationItem > vNewItems; uno::Sequence< beans::PropertyValue > aProp; sal_Int32 nOldCount = xIndexOld->getCount(); sal_Int32 nNewCount = xIndexNew->getCount(); for (int n=0; ngetByIndex(n) >>= aProp) { for(int i=0; i>= aMigrationItem.m_sCommandURL; else if ( aProp[i].Name == ITEM_DESCRIPTOR_CONTAINER ) aProp[i].Value >>= aMigrationItem.m_xPopupMenu; } if (!aMigrationItem.m_sCommandURL.isEmpty()) vOldItems.push_back(aMigrationItem); } } for (int n=0; ngetByIndex(n) >>= aProp) { for(int i=0; i>= aMigrationItem.m_sCommandURL; else if ( aProp[i].Name == ITEM_DESCRIPTOR_CONTAINER ) aProp[i].Value >>= aMigrationItem.m_xPopupMenu; } if (!aMigrationItem.m_sCommandURL.isEmpty()) vNewItems.push_back(aMigrationItem); } } ::std::vector< MigrationItem >::iterator it; ::rtl::OUString sSibling; for (it = vOldItems.begin(); it!=vOldItems.end(); ++it) { ::std::vector< MigrationItem >::iterator pFound = ::std::find(vNewItems.begin(), vNewItems.end(), *it); if (pFound != vNewItems.end() && it->m_xPopupMenu.is()) { ::rtl::OUString sName; if (!sParent.isEmpty()) sName = sParent + MENU_SEPERATOR + it->m_sCommandURL; else sName = it->m_sCommandURL; compareOldAndNewConfig(sName, it->m_xPopupMenu, pFound->m_xPopupMenu, sResourceURL); } else if (pFound == vNewItems.end()) { MigrationItem aMigrationItem(sParent, sSibling, it->m_sCommandURL, it->m_xPopupMenu); if (m_aOldVersionItemsHashMap.find(sResourceURL)==m_aOldVersionItemsHashMap.end()) { ::std::vector< MigrationItem > vMigrationItems; m_aOldVersionItemsHashMap.insert(MigrationHashMap::value_type(sResourceURL, vMigrationItems)); m_aOldVersionItemsHashMap[sResourceURL].push_back(aMigrationItem); } else { if (::std::find(m_aOldVersionItemsHashMap[sResourceURL].begin(), m_aOldVersionItemsHashMap[sResourceURL].end(), aMigrationItem)==m_aOldVersionItemsHashMap[sResourceURL].end()) m_aOldVersionItemsHashMap[sResourceURL].push_back(aMigrationItem); } } sSibling = it->m_sCommandURL; } uno::Reference< container::XIndexContainer > xPopup; for (it = vNewItems.begin(); it!=vNewItems.end(); ++it) { ::std::vector< MigrationItem >::iterator pFound = ::std::find(vOldItems.begin(), vOldItems.end(), *it); if (pFound != vOldItems.end() && it->m_xPopupMenu.is()) { ::rtl::OUString sName; if (!sParent.isEmpty()) sName = sParent + MENU_SEPERATOR + it->m_sCommandURL; else sName = it->m_sCommandURL; compareOldAndNewConfig(sName, pFound->m_xPopupMenu, it->m_xPopupMenu, sResourceURL); } else if (::std::find(vOldItems.begin(), vOldItems.end(), *it) == vOldItems.end()) { MigrationItem aMigrationItem(sParent, sSibling, it->m_sCommandURL, it->m_xPopupMenu); if (m_aNewVersionItemsHashMap.find(sResourceURL)==m_aNewVersionItemsHashMap.end()) { ::std::vector< MigrationItem > vMigrationItems; m_aNewVersionItemsHashMap.insert(MigrationHashMap::value_type(sResourceURL, vMigrationItems)); m_aNewVersionItemsHashMap[sResourceURL].push_back(aMigrationItem); } else { if (::std::find(m_aNewVersionItemsHashMap[sResourceURL].begin(), m_aNewVersionItemsHashMap[sResourceURL].end(), aMigrationItem)==m_aNewVersionItemsHashMap[sResourceURL].end()) m_aNewVersionItemsHashMap[sResourceURL].push_back(aMigrationItem); } } } } void MigrationImpl::mergeOldToNewVersion(const uno::Reference< ui::XUIConfigurationManager >& xCfgManager, const uno::Reference< container::XIndexContainer>& xIndexContainer, const ::rtl::OUString& sModuleIdentifier, const ::rtl::OUString& sResourceURL) { MigrationHashMap::iterator pFound = m_aOldVersionItemsHashMap.find(sResourceURL); if (pFound==m_aOldVersionItemsHashMap.end()) return; ::std::vector< MigrationItem >::iterator it; for (it=pFound->second.begin(); it!=pFound->second.end(); ++it) { uno::Reference< container::XIndexContainer > xTemp = xIndexContainer; ::rtl::OUString sParentNodeName = it->m_sParentNodeName; sal_Int32 nIndex = 0; do { ::rtl::OUString sToken = sParentNodeName.getToken(0, '|', nIndex).trim(); if (sToken.isEmpty()) break; sal_Int32 nCount = xTemp->getCount(); for (sal_Int32 i=0; i xChild; uno::Sequence< beans::PropertyValue > aPropSeq; xTemp->getByIndex(i) >>= aPropSeq; for (sal_Int32 j=0; j>= sCommandURL; else if ( sPropName == ITEM_DESCRIPTOR_LABEL ) aPropSeq[j].Value >>= sLabel; else if ( sPropName == ITEM_DESCRIPTOR_CONTAINER ) aPropSeq[j].Value >>= xChild; } if (sCommandURL == sToken) { xTemp = xChild; break; } } } while (nIndex>=0); if (nIndex == -1) { uno::Sequence< beans::PropertyValue > aPropSeq(3); aPropSeq[0].Name = rtl::OUString(ITEM_DESCRIPTOR_COMMANDURL); aPropSeq[0].Value <<= it->m_sCommandURL; aPropSeq[1].Name = rtl::OUString(ITEM_DESCRIPTOR_LABEL); aPropSeq[1].Value <<= retrieveLabelFromCommand(it->m_sCommandURL, sModuleIdentifier); aPropSeq[2].Name = rtl::OUString(ITEM_DESCRIPTOR_CONTAINER); aPropSeq[2].Value <<= it->m_xPopupMenu; if (it->m_sPrevSibling.isEmpty()) xTemp->insertByIndex(0, uno::makeAny(aPropSeq)); else if (!it->m_sPrevSibling.isEmpty()) { sal_Int32 nCount = xTemp->getCount(); sal_Int32 i = 0; for (; i aTempPropSeq; xTemp->getByIndex(i) >>= aTempPropSeq; for (sal_Int32 j=0; j>= sCmd; break; } } if (sCmd.equals(it->m_sPrevSibling)) break; } xTemp->insertByIndex(i+1, uno::makeAny(aPropSeq)); } } } uno::Reference< container::XIndexAccess > xIndexAccess(xIndexContainer, uno::UNO_QUERY); if (xIndexAccess.is()) xCfgManager->replaceSettings(sResourceURL, xIndexAccess); uno::Reference< ui::XUIConfigurationPersistence > xUIConfigurationPersistence(xCfgManager, uno::UNO_QUERY); if (xUIConfigurationPersistence.is()) xUIConfigurationPersistence->store(); } uno::Reference< ui::XUIConfigurationManager > NewVersionUIInfo::getConfigManager(const ::rtl::OUString& sModuleShortName) const { uno::Reference< ui::XUIConfigurationManager > xCfgManager; for (sal_Int32 i=0; i>= xCfgManager; break; } } return xCfgManager; } uno::Reference< container::XIndexContainer > NewVersionUIInfo::getNewMenubarSettings(const ::rtl::OUString& sModuleShortName) const { uno::Reference< container::XIndexContainer > xNewMenuSettings; for (sal_Int32 i=0; i>= xNewMenuSettings; break; } } return xNewMenuSettings; } uno::Reference< container::XIndexContainer > NewVersionUIInfo::getNewToolbarSettings(const ::rtl::OUString& sModuleShortName, const ::rtl::OUString& sToolbarName) const { uno::Reference< container::XIndexContainer > xNewToolbarSettings; for (sal_Int32 i=0; i lToolbarSettingsSeq; m_lNewVersionToolbarSettingsSeq[i].Value >>= lToolbarSettingsSeq; for (sal_Int32 j=0; j>= xNewToolbarSettings; break; } } break; } } return xNewToolbarSettings; } void NewVersionUIInfo::init(const ::std::vector< MigrationModuleInfo >& vModulesInfo) { m_lCfgManagerSeq.realloc(vModulesInfo.size()); m_lNewVersionMenubarSettingsSeq.realloc(vModulesInfo.size()); m_lNewVersionToolbarSettingsSeq.realloc(vModulesInfo.size()); const ::rtl::OUString sModuleCfgSupplier(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ui.ModuleUIConfigurationManagerSupplier")); const ::rtl::OUString sMenubarResourceURL(RTL_CONSTASCII_USTRINGPARAM("private:resource/menubar/menubar")); const ::rtl::OUString sToolbarResourcePre(RTL_CONSTASCII_USTRINGPARAM("private:resource/toolbar/")); uno::Reference< ui::XModuleUIConfigurationManagerSupplier > xModuleCfgSupplier = uno::Reference< ui::XModuleUIConfigurationManagerSupplier >(::comphelper::getProcessServiceFactory()->createInstance(sModuleCfgSupplier), uno::UNO_QUERY); for (sal_uInt32 i=0; i xCfgManager = xModuleCfgSupplier->getUIConfigurationManager(sModuleIdentifier); m_lCfgManagerSeq[i].Name = vModulesInfo[i].sModuleShortName; m_lCfgManagerSeq[i].Value <<= xCfgManager; if (vModulesInfo[i].bHasMenubar) { m_lNewVersionMenubarSettingsSeq[i].Name = vModulesInfo[i].sModuleShortName; m_lNewVersionMenubarSettingsSeq[i].Value <<= xCfgManager->getSettings(sMenubarResourceURL, sal_True); } sal_Int32 nToolbars = vModulesInfo[i].m_vToolbars.size(); if (nToolbars > 0) { uno::Sequence< beans::PropertyValue > lPropSeq(nToolbars); for (sal_Int32 j=0; jgetSettings(sToolbarResourceURL, sal_True); } m_lNewVersionToolbarSettingsSeq[i].Name = vModulesInfo[i].sModuleShortName; m_lNewVersionToolbarSettingsSeq[i].Value <<= lPropSeq; } } } } } // namespace desktop /* vim:set shiftwidth=4 softtabstop=4 expandtab: */