Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "sal/config.h"
21 :
22 : #include <algorithm>
23 : #include <iterator>
24 : #include <map>
25 : #include <new>
26 : #include <set>
27 :
28 : #include "migration.hxx"
29 : #include "migration_impl.hxx"
30 :
31 : #include <unotools/textsearch.hxx>
32 : #include <comphelper/processfactory.hxx>
33 : #include <comphelper/sequence.hxx>
34 : #include <unotools/bootstrap.hxx>
35 : #include <rtl/bootstrap.hxx>
36 : #include <rtl/uri.hxx>
37 : #include <i18nlangtag/lang.h>
38 : #include <tools/urlobj.hxx>
39 : #include <osl/file.hxx>
40 : #include <osl/mutex.hxx>
41 : #include <osl/security.hxx>
42 : #include <unotools/configmgr.hxx>
43 :
44 : #include <com/sun/star/configuration/Update.hpp>
45 : #include <com/sun/star/configuration/theDefaultProvider.hpp>
46 : #include <com/sun/star/lang/XInitialization.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/util/XStringSubstitution.hpp>
53 : #include <com/sun/star/embed/ElementModes.hpp>
54 : #include <com/sun/star/embed/FileSystemStorageFactory.hpp>
55 : #include <com/sun/star/embed/XStorage.hpp>
56 : #include <com/sun/star/ui/ModuleUIConfigurationManagerSupplier.hpp>
57 : #include <com/sun/star/frame/UICommandDescription.hpp>
58 : #include <com/sun/star/ui/UIConfigurationManager.hpp>
59 : #include <com/sun/star/ui/XUIConfiguration.hpp>
60 : #include <com/sun/star/ui/XUIConfigurationStorage.hpp>
61 : #include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
62 :
63 : using namespace osl;
64 : using namespace std;
65 : using namespace com::sun::star::task;
66 : using namespace com::sun::star::lang;
67 : using namespace com::sun::star::beans;
68 : using namespace com::sun::star::util;
69 : using namespace com::sun::star::container;
70 : using com::sun::star::uno::Exception;
71 : using namespace com::sun::star;
72 :
73 :
74 : namespace desktop {
75 :
76 : static const char ITEM_DESCRIPTOR_COMMANDURL[] = "CommandURL";
77 : static const char ITEM_DESCRIPTOR_CONTAINER[] = "ItemDescriptorContainer";
78 : static const char ITEM_DESCRIPTOR_LABEL[] = "Label";
79 :
80 0 : OUString retrieveLabelFromCommand(const OUString& sCommand, const OUString& sModuleIdentifier)
81 : {
82 0 : OUString sLabel;
83 :
84 0 : uno::Reference< container::XNameAccess > xUICommands;
85 : uno::Reference< container::XNameAccess > const xNameAccess(
86 : frame::UICommandDescription::create(
87 0 : ::comphelper::getProcessComponentContext()) );
88 0 : xNameAccess->getByName( sModuleIdentifier ) >>= xUICommands;
89 0 : if (xUICommands.is())
90 : {
91 0 : if ( !sCommand.isEmpty() )
92 : {
93 0 : OUString aStr;
94 0 : ::uno::Sequence< beans::PropertyValue > aPropSeq;
95 : try
96 : {
97 0 : uno::Any a( xUICommands->getByName( sCommand ));
98 0 : if ( a >>= aPropSeq )
99 : {
100 0 : for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ )
101 : {
102 0 : if ( aPropSeq[i].Name == "Label" )
103 : {
104 0 : aPropSeq[i].Value >>= aStr;
105 0 : break;
106 : }
107 : }
108 : }
109 :
110 0 : sLabel = aStr;
111 : }
112 0 : catch (const container::NoSuchElementException&)
113 : {
114 0 : sLabel = sCommand;
115 0 : sal_Int32 nIndex = sLabel.indexOf(':');
116 0 : if (nIndex>=0 && nIndex <= sLabel.getLength()-1)
117 0 : sLabel = sLabel.copy(nIndex+1);
118 0 : }
119 :
120 : }
121 : }
122 :
123 0 : return sLabel;
124 : }
125 :
126 0 : OUString mapModuleShortNameToIdentifier(const OUString& sShortName)
127 : {
128 0 : OUString sIdentifier;
129 :
130 0 : if ( sShortName == "StartModule" )
131 0 : sIdentifier = "com.sun.star.frame.StartModule";
132 :
133 0 : else if ( sShortName == "swriter" )
134 0 : sIdentifier = "com.sun.star.text.TextDocument";
135 :
136 0 : else if ( sShortName == "scalc" )
137 0 : sIdentifier = "com.sun.star.sheet.SpreadsheetDocument";
138 :
139 0 : else if ( sShortName == "sdraw" )
140 0 : sIdentifier = "com.sun.star.drawing.DrawingDocument";
141 :
142 0 : else if ( sShortName == "simpress" )
143 0 : sIdentifier = "com.sun.star.presentation.PresentationDocument";
144 :
145 0 : else if ( sShortName == "smath" )
146 0 : sIdentifier = "com.sun.star.formula.FormulaProperties";
147 :
148 0 : else if ( sShortName == "schart" )
149 0 : sIdentifier = "com.sun.star.chart2.ChartDocument";
150 :
151 0 : else if ( sShortName == "BasicIDE" )
152 0 : sIdentifier = "com.sun.star.script.BasicIDE";
153 :
154 0 : else if ( sShortName == "dbapp" )
155 0 : sIdentifier = "com.sun.star.sdb.OfficeDatabaseDocument";
156 :
157 0 : else if ( sShortName == "sglobal" )
158 0 : sIdentifier = "com.sun.star.text.GlobalDocument";
159 :
160 0 : else if ( sShortName == "sweb" )
161 0 : sIdentifier = "com.sun.star.text.WebDocument";
162 :
163 0 : else if ( sShortName == "swxform" )
164 0 : sIdentifier = "com.sun.star.xforms.XMLFormDocument";
165 :
166 0 : else if ( sShortName == "sbibliography" )
167 0 : sIdentifier = "com.sun.star.frame.Bibliography";
168 :
169 0 : return sIdentifier;
170 : }
171 :
172 0 : bool MigrationImpl::alreadyMigrated()
173 : {
174 0 : OUString MIGRATION_STAMP_NAME("/MIGRATED4");
175 0 : OUString aStr = m_aInfo.userdata + MIGRATION_STAMP_NAME;
176 0 : File aFile(aStr);
177 : // create migration stamp, and/or check its existence
178 0 : bool bRet = aFile.open (osl_File_OpenFlag_Write | osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock) == FileBase::E_EXIST;
179 : OSL_TRACE( "File '%s' exists? %d\n",
180 : OUStringToOString(aStr, RTL_TEXTENCODING_ASCII_US).getStr(),
181 : bRet );
182 0 : return bRet;
183 : }
184 :
185 32 : bool MigrationImpl::initializeMigration()
186 : {
187 32 : bool bRet = false;
188 :
189 32 : if (!checkMigrationCompleted()) {
190 32 : readAvailableMigrations(m_vMigrationsAvailable);
191 32 : sal_Int32 nIndex = findPreferedMigrationProcess(m_vMigrationsAvailable);
192 : // m_aInfo is now set to the preferred migration source
193 32 : if ( nIndex >= 0 ) {
194 0 : if (alreadyMigrated())
195 0 : return false;
196 0 : m_vrMigrations = readMigrationSteps(m_vMigrationsAvailable[nIndex].name);
197 : }
198 :
199 32 : bRet = !m_aInfo.userdata.isEmpty();
200 : }
201 :
202 : OSL_TRACE( "Migration %s", bRet ? "needed" : "not required" );
203 :
204 32 : return bRet;
205 : }
206 :
207 32 : void Migration::migrateSettingsIfNecessary()
208 : {
209 32 : MigrationImpl aImpl;
210 :
211 32 : if (! aImpl.initializeMigration() )
212 64 : return;
213 :
214 0 : sal_Bool bResult = sal_False;
215 : try
216 : {
217 0 : bResult = aImpl.doMigration();
218 : }
219 0 : catch (const Exception& e)
220 : {
221 0 : OString aMsg("doMigration() exception: ");
222 0 : aMsg += OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US);
223 0 : OSL_FAIL(aMsg.getStr());
224 : }
225 : OSL_ENSURE(bResult, "Migration has not been successful");
226 0 : (void)bResult;
227 : }
228 :
229 32 : MigrationImpl::MigrationImpl()
230 32 : : m_vrVersions(new strings_v)
231 : {
232 32 : }
233 :
234 32 : MigrationImpl::~MigrationImpl()
235 : {
236 32 : }
237 :
238 : // The main entry point for migrating settings
239 0 : sal_Bool MigrationImpl::doMigration()
240 : {
241 : // compile file list for migration
242 0 : m_vrFileList = compileFileList();
243 :
244 0 : sal_Bool result = sal_False;
245 : try
246 : {
247 0 : NewVersionUIInfo aNewVersionUIInfo;
248 0 : ::std::vector< MigrationModuleInfo > vModulesInfo = dectectUIChangesForAllModules();
249 0 : aNewVersionUIInfo.init(vModulesInfo);
250 :
251 0 : copyFiles();
252 :
253 0 : const OUString sMenubarResourceURL("private:resource/menubar/menubar");
254 0 : const OUString sToolbarResourcePre("private:resource/toolbar/");
255 0 : for (sal_uInt32 i=0; i<vModulesInfo.size(); ++i)
256 : {
257 0 : OUString sModuleIdentifier = mapModuleShortNameToIdentifier(vModulesInfo[i].sModuleShortName);
258 0 : if (sModuleIdentifier.isEmpty())
259 0 : continue;
260 :
261 0 : uno::Sequence< uno::Any > lArgs(2);
262 0 : OUString aOldCfgDataPath = m_aInfo.userdata + OUString("/user/config/soffice.cfg/modules/");
263 0 : lArgs[0] <<= aOldCfgDataPath + vModulesInfo[i].sModuleShortName;
264 0 : lArgs[1] <<= embed::ElementModes::READ;
265 :
266 0 : uno::Reference< uno::XComponentContext > xContext(comphelper::getProcessComponentContext());
267 0 : uno::Reference< lang::XSingleServiceFactory > xStorageFactory(embed::FileSystemStorageFactory::create(xContext));
268 0 : uno::Reference< embed::XStorage > xModules(xStorageFactory->createInstanceWithArguments(lArgs), uno::UNO_QUERY);
269 0 : uno::Reference< ui::XUIConfigurationManager2 > xOldCfgManager = ui::UIConfigurationManager::create(xContext);
270 :
271 0 : if ( xModules.is() )
272 : {
273 0 : xOldCfgManager->setStorage( xModules );
274 0 : xOldCfgManager->reload();
275 : }
276 :
277 0 : uno::Reference< ui::XUIConfigurationManager > xCfgManager = aNewVersionUIInfo.getConfigManager(vModulesInfo[i].sModuleShortName);
278 :
279 0 : if (vModulesInfo[i].bHasMenubar)
280 : {
281 0 : uno::Reference< container::XIndexContainer > xOldVersionMenuSettings = uno::Reference< container::XIndexContainer >(xOldCfgManager->getSettings(sMenubarResourceURL, sal_True), uno::UNO_QUERY);
282 0 : uno::Reference< container::XIndexContainer > xNewVersionMenuSettings = aNewVersionUIInfo.getNewMenubarSettings(vModulesInfo[i].sModuleShortName);
283 0 : OUString sParent;
284 0 : compareOldAndNewConfig(sParent, xOldVersionMenuSettings, xNewVersionMenuSettings, sMenubarResourceURL);
285 0 : mergeOldToNewVersion(xCfgManager, xNewVersionMenuSettings, sModuleIdentifier, sMenubarResourceURL);
286 : }
287 :
288 0 : sal_Int32 nToolbars = vModulesInfo[i].m_vToolbars.size();
289 0 : if (nToolbars >0)
290 : {
291 0 : for (sal_Int32 j=0; j<nToolbars; ++j)
292 : {
293 0 : OUString sToolbarName = vModulesInfo[i].m_vToolbars[j];
294 0 : OUString sToolbarResourceURL = sToolbarResourcePre + sToolbarName;
295 :
296 0 : uno::Reference< container::XIndexContainer > xOldVersionToolbarSettings = uno::Reference< container::XIndexContainer >(xOldCfgManager->getSettings(sToolbarResourceURL, sal_True), uno::UNO_QUERY);
297 0 : uno::Reference< container::XIndexContainer > xNewVersionToolbarSettings = aNewVersionUIInfo.getNewToolbarSettings(vModulesInfo[i].sModuleShortName, sToolbarName);
298 0 : OUString sParent;
299 0 : compareOldAndNewConfig(sParent, xOldVersionToolbarSettings, xNewVersionToolbarSettings, sToolbarResourceURL);
300 0 : mergeOldToNewVersion(xCfgManager, xNewVersionToolbarSettings, sModuleIdentifier, sToolbarResourceURL);
301 0 : }
302 : }
303 :
304 0 : m_aOldVersionItemsHashMap.clear();
305 0 : m_aNewVersionItemsHashMap.clear();
306 0 : }
307 :
308 : // execute the migration items from Setup.xcu
309 0 : copyConfig();
310 :
311 : // execute custom migration services from Setup.xcu
312 : // and refresh the cache
313 0 : runServices();
314 0 : refresh();
315 :
316 0 : result = sal_True;
317 : }
318 0 : catch (css::uno::Exception & e)
319 : {
320 : SAL_WARN(
321 : "desktop.migration",
322 : "ignored Exception \"" << e.Message
323 : << "\" while migrating from version \"" << m_aInfo.productname
324 : << "\" data \"" << m_aInfo.userdata << "\"");
325 : }
326 :
327 : // prevent running the migration multiple times
328 0 : setMigrationCompleted();
329 0 : return result;
330 : }
331 :
332 0 : void MigrationImpl::refresh()
333 : {
334 : uno::Reference< XRefreshable >(
335 : configuration::theDefaultProvider::get(comphelper::getProcessComponentContext()),
336 0 : uno::UNO_QUERY_THROW)->refresh();
337 0 : }
338 :
339 0 : void MigrationImpl::setMigrationCompleted()
340 : {
341 : try
342 : {
343 0 : uno::Reference< XPropertySet > aPropertySet(getConfigAccess("org.openoffice.Setup/Office", true), uno::UNO_QUERY_THROW);
344 0 : aPropertySet->setPropertyValue("MigrationCompleted", uno::makeAny(sal_True));
345 0 : uno::Reference< XChangesBatch >(aPropertySet, uno::UNO_QUERY_THROW)->commitChanges();
346 : }
347 0 : catch (...)
348 : {
349 : // fail silently
350 : }
351 0 : }
352 :
353 32 : bool MigrationImpl::checkMigrationCompleted()
354 : {
355 32 : sal_Bool bMigrationCompleted = sal_False;
356 : try {
357 : uno::Reference< XPropertySet > aPropertySet(
358 32 : getConfigAccess("org.openoffice.Setup/Office"), uno::UNO_QUERY_THROW);
359 32 : aPropertySet->getPropertyValue("MigrationCompleted") >>= bMigrationCompleted;
360 :
361 32 : if( !bMigrationCompleted && getenv("SAL_DISABLE_USERMIGRATION" ) )
362 : {
363 : // migration prevented - fake it's success
364 0 : setMigrationCompleted();
365 0 : bMigrationCompleted = sal_True;
366 32 : }
367 : }
368 0 : catch (const Exception&)
369 : {
370 : // just return false...
371 : }
372 : OSL_TRACE( "Migration %s", bMigrationCompleted ? "already completed" : "not done" );
373 :
374 32 : return bMigrationCompleted;
375 : }
376 :
377 32 : static void insertSorted(migrations_available& rAvailableMigrations, supported_migration& aSupportedMigration)
378 : {
379 32 : bool bInserted( false );
380 32 : migrations_available::iterator pIter = rAvailableMigrations.begin();
381 64 : while ( !bInserted && pIter != rAvailableMigrations.end())
382 : {
383 0 : if ( pIter->nPriority < aSupportedMigration.nPriority )
384 : {
385 0 : rAvailableMigrations.insert(pIter, aSupportedMigration );
386 0 : bInserted = true;
387 0 : break; // i111193: insert invalidates iterator!
388 : }
389 0 : ++pIter;
390 : }
391 32 : if ( !bInserted )
392 32 : rAvailableMigrations.push_back( aSupportedMigration );
393 32 : }
394 :
395 32 : bool MigrationImpl::readAvailableMigrations(migrations_available& rAvailableMigrations)
396 : {
397 : // get supported version names
398 32 : uno::Reference< XNameAccess > aMigrationAccess(getConfigAccess("org.openoffice.Setup/Migration/SupportedVersions"), uno::UNO_QUERY_THROW);
399 64 : uno::Sequence< OUString > seqSupportedVersions = aMigrationAccess->getElementNames();
400 :
401 64 : const OUString aVersionIdentifiers( "VersionIdentifiers" );
402 64 : const OUString aPriorityIdentifier( "Priority" );
403 :
404 64 : for (sal_Int32 i=0; i<seqSupportedVersions.getLength(); i++)
405 : {
406 32 : sal_Int32 nPriority( 0 );
407 32 : uno::Sequence< OUString > seqVersions;
408 64 : uno::Reference< XNameAccess > xMigrationData( aMigrationAccess->getByName(seqSupportedVersions[i]), uno::UNO_QUERY_THROW );
409 32 : xMigrationData->getByName( aVersionIdentifiers ) >>= seqVersions;
410 32 : xMigrationData->getByName( aPriorityIdentifier ) >>= nPriority;
411 :
412 64 : supported_migration aSupportedMigration;
413 32 : aSupportedMigration.name = seqSupportedVersions[i];
414 32 : aSupportedMigration.nPriority = nPriority;
415 192 : for (sal_Int32 j=0; j<seqVersions.getLength(); j++)
416 160 : aSupportedMigration.supported_versions.push_back(seqVersions[j].trim());
417 32 : insertSorted( rAvailableMigrations, aSupportedMigration );
418 : OSL_TRACE( " available migration '%s'\n",
419 : OUStringToOString( aSupportedMigration.name, RTL_TEXTENCODING_ASCII_US ).getStr() );
420 32 : }
421 :
422 64 : return true;
423 : }
424 :
425 0 : migrations_vr MigrationImpl::readMigrationSteps(const OUString& rMigrationName)
426 : {
427 : // get migration access
428 0 : uno::Reference< XNameAccess > aMigrationAccess(getConfigAccess("org.openoffice.Setup/Migration/SupportedVersions"), uno::UNO_QUERY_THROW);
429 0 : uno::Reference< XNameAccess > xMigrationData( aMigrationAccess->getByName(rMigrationName), uno::UNO_QUERY_THROW );
430 :
431 : // get migration description from from org.openoffice.Setup/Migration
432 : // and build vector of migration steps
433 0 : OUString aMigrationSteps( "MigrationSteps" );
434 0 : uno::Reference< XNameAccess > theNameAccess(xMigrationData->getByName(aMigrationSteps), uno::UNO_QUERY_THROW);
435 0 : uno::Sequence< OUString > seqMigrations = theNameAccess->getElementNames();
436 0 : uno::Reference< XNameAccess > tmpAccess;
437 0 : uno::Reference< XNameAccess > tmpAccess2;
438 0 : uno::Sequence< OUString > tmpSeq;
439 0 : migrations_vr vrMigrations(new migrations_v);
440 0 : for (sal_Int32 i = 0; i < seqMigrations.getLength(); i++)
441 : {
442 : // get current migration step
443 0 : theNameAccess->getByName(seqMigrations[i]) >>= tmpAccess;
444 0 : migration_step tmpStep;
445 0 : tmpStep.name = seqMigrations[i];
446 :
447 : // read included files from current step description
448 0 : OUString aSeqEntry;
449 0 : if (tmpAccess->getByName("IncludedFiles") >>= tmpSeq)
450 : {
451 0 : for (sal_Int32 j=0; j<tmpSeq.getLength(); j++)
452 : {
453 0 : aSeqEntry = tmpSeq[j];
454 0 : tmpStep.includeFiles.push_back(aSeqEntry);
455 : }
456 : }
457 :
458 : // exluded files...
459 0 : if (tmpAccess->getByName("ExcludedFiles") >>= tmpSeq)
460 : {
461 0 : for (sal_Int32 j=0; j<tmpSeq.getLength(); j++)
462 0 : tmpStep.excludeFiles.push_back(tmpSeq[j]);
463 : }
464 :
465 : // included nodes...
466 0 : if (tmpAccess->getByName("IncludedNodes") >>= tmpSeq)
467 : {
468 0 : for (sal_Int32 j=0; j<tmpSeq.getLength(); j++)
469 0 : tmpStep.includeConfig.push_back(tmpSeq[j]);
470 : }
471 :
472 : // excluded nodes...
473 0 : if (tmpAccess->getByName("ExcludedNodes") >>= tmpSeq)
474 : {
475 0 : for (sal_Int32 j=0; j<tmpSeq.getLength(); j++)
476 0 : tmpStep.excludeConfig.push_back(tmpSeq[j]);
477 : }
478 :
479 : // included extensions...
480 0 : if (tmpAccess->getByName("IncludedExtensions") >>= tmpSeq)
481 : {
482 0 : for (sal_Int32 j=0; j<tmpSeq.getLength(); j++)
483 0 : tmpStep.includeExtensions.push_back(tmpSeq[j]);
484 : }
485 :
486 : // excluded extensions...
487 0 : if (tmpAccess->getByName("ExcludedExtensions") >>= tmpSeq)
488 : {
489 0 : for (sal_Int32 j=0; j<tmpSeq.getLength(); j++)
490 : {
491 0 : aSeqEntry = tmpSeq[j];
492 0 : tmpStep.excludeExtensions.push_back(aSeqEntry);
493 : }
494 : }
495 :
496 : // generic service
497 0 : tmpAccess->getByName("MigrationService") >>= tmpStep.service;
498 :
499 0 : vrMigrations->push_back(tmpStep);
500 0 : }
501 0 : return vrMigrations;
502 : }
503 :
504 0 : static FileBase::RC _checkAndCreateDirectory(INetURLObject& dirURL)
505 : {
506 0 : FileBase::RC result = Directory::create(dirURL.GetMainURL(INetURLObject::DECODE_TO_IURI));
507 0 : if (result == FileBase::E_NOENT)
508 : {
509 0 : INetURLObject baseURL(dirURL);
510 0 : baseURL.removeSegment();
511 0 : _checkAndCreateDirectory(baseURL);
512 0 : return Directory::create(dirURL.GetMainURL(INetURLObject::DECODE_TO_IURI));
513 : } else
514 0 : return result;
515 : }
516 :
517 : static const char XDG_CONFIG_PART[] = "/.config/";
518 :
519 : #if defined UNX && ! defined MACOSX
520 32 : OUString MigrationImpl::preXDGConfigDir(const OUString& rConfigDir)
521 : {
522 32 : OUString aPreXDGConfigPath;
523 32 : const char* pXDGCfgHome = getenv("XDG_CONFIG_HOME");
524 :
525 : // cater for XDG_CONFIG_HOME change
526 : // If XDG_CONFIG_HOME is set then we;
527 : // assume the user knows what they are doing ( room for improvement here, we could
528 : // of course search the default config dir etc. also - but this is more complex,
529 : // we would need to weigh results from the current config dir against matches in
530 : // the 'old' config dir etc. ) - currently we just use the returned config dir.
531 : // If XDG_CONFIG_HOME is NOT set;
532 : // assume then we should now using the default $HOME/,config config location for
533 : // our user profiles, however *all* previous libreoffice and openoffice.org
534 : // configurations will be in the 'old' config directory and that's where we need
535 : // to search - we convert the returned config dir to the 'old' dir
536 32 : if ( !pXDGCfgHome && rConfigDir.endsWithAsciiL( XDG_CONFIG_PART, sizeof( XDG_CONFIG_PART ) - 1 ) )
537 : // remove trailing '.config/' but leave the terminating '/'
538 0 : aPreXDGConfigPath = rConfigDir.copy( 0, rConfigDir.getLength() - sizeof( XDG_CONFIG_PART ) + 2 );
539 : else
540 32 : aPreXDGConfigPath = rConfigDir;
541 :
542 : // the application-specific config dir is not longer prefixed by '.' because it is hidden under ".config"
543 : // we have to add the '.' for the pre-XDG directory names
544 32 : aPreXDGConfigPath += ".";
545 :
546 32 : return aPreXDGConfigPath;
547 : }
548 : #endif
549 :
550 320 : void MigrationImpl::setInstallInfoIfExist(
551 : install_info& aInfo,
552 : const OUString& rConfigDir,
553 : const OUString& rVersion)
554 : {
555 320 : OUString url(INetURLObject(rConfigDir).GetMainURL(INetURLObject::NO_DECODE));
556 640 : osl::DirectoryItem item;
557 640 : osl::FileStatus stat(osl_FileStatus_Mask_Type);
558 :
559 640 : if (osl::DirectoryItem::get(url, item) == osl::FileBase::E_None
560 0 : && item.getFileStatus(stat) == osl::FileBase::E_None
561 320 : && stat.getFileType() == osl::FileStatus::Directory)
562 : {
563 0 : aInfo.userdata = url;
564 0 : aInfo.productname = rVersion;
565 320 : }
566 320 : }
567 :
568 32 : install_info MigrationImpl::findInstallation(const strings_v& rVersions)
569 : {
570 :
571 32 : OUString aTopConfigDir;
572 32 : osl::Security().getConfigDir( aTopConfigDir );
573 32 : if ( !aTopConfigDir.isEmpty() && aTopConfigDir[ aTopConfigDir.getLength()-1 ] != '/' )
574 32 : aTopConfigDir += "/";
575 :
576 : #if defined UNX && ! defined MACOSX
577 64 : OUString aPreXDGTopConfigDir = preXDGConfigDir(aTopConfigDir);
578 : #endif
579 :
580 32 : install_info aInfo;
581 32 : strings_v::const_iterator i_ver = rVersions.begin();
582 224 : while (i_ver != rVersions.end())
583 : {
584 320 : OUString aVersion, aProfileName;
585 160 : sal_Int32 nSeparatorIndex = (*i_ver).indexOf('=');
586 160 : if ( nSeparatorIndex != -1 )
587 : {
588 160 : aVersion = (*i_ver).copy( 0, nSeparatorIndex );
589 160 : aProfileName = (*i_ver).copy( nSeparatorIndex+1 );
590 : }
591 :
592 800 : if ( !aVersion.isEmpty() && !aProfileName.isEmpty() &&
593 160 : ( aInfo.userdata.isEmpty() ||
594 : aProfileName.equalsIgnoreAsciiCase(
595 160 : utl::ConfigManager::getProductName() ) ) )
596 : {
597 160 : setInstallInfoIfExist(aInfo, aTopConfigDir + aProfileName, aVersion);
598 : #if defined UNX && ! defined MACOSX
599 : //try preXDG path if the new one does not exist
600 160 : if ( aInfo.userdata.isEmpty())
601 160 : setInstallInfoIfExist(aInfo, aPreXDGTopConfigDir + aProfileName, aVersion);
602 : #endif
603 : }
604 160 : ++i_ver;
605 160 : }
606 :
607 64 : return aInfo;
608 : }
609 :
610 32 : sal_Int32 MigrationImpl::findPreferedMigrationProcess(const migrations_available& rAvailableMigrations)
611 : {
612 32 : sal_Int32 nIndex( -1 );
613 32 : sal_Int32 i( 0 );
614 :
615 32 : migrations_available::const_iterator rIter = rAvailableMigrations.begin();
616 32 : while ( rIter != rAvailableMigrations.end() )
617 : {
618 32 : install_info aInstallInfo = findInstallation(rIter->supported_versions);
619 32 : if (!aInstallInfo.productname.isEmpty() )
620 : {
621 0 : m_aInfo = aInstallInfo;
622 0 : nIndex = i;
623 0 : break;
624 : }
625 32 : ++i;
626 32 : ++rIter;
627 32 : }
628 :
629 : OSL_TRACE( " preferred migration is from product '%s'\n",
630 : OUStringToOString( m_aInfo.productname, RTL_TEXTENCODING_ASCII_US ).getStr() );
631 : OSL_TRACE( " and settings directory '%s'\n",
632 : OUStringToOString( m_aInfo.userdata, RTL_TEXTENCODING_ASCII_US ).getStr() );
633 :
634 32 : return nIndex;
635 : }
636 :
637 0 : strings_vr MigrationImpl::applyPatterns(const strings_v& vSet, const strings_v& vPatterns) const
638 : {
639 : using namespace utl;
640 0 : strings_vr vrResult(new strings_v);
641 0 : strings_v::const_iterator i_set;
642 0 : strings_v::const_iterator i_pat = vPatterns.begin();
643 0 : while (i_pat != vPatterns.end())
644 : {
645 : // find matches for this pattern in input set
646 : // and copy them to the result
647 0 : SearchParam param(*i_pat, SearchParam::SRCH_REGEXP);
648 0 : TextSearch ts(param, LANGUAGE_DONTKNOW);
649 0 : i_set = vSet.begin();
650 0 : sal_Int32 start = 0;
651 0 : sal_Int32 end = 0;
652 0 : while (i_set != vSet.end())
653 : {
654 0 : end = i_set->getLength();
655 0 : if (ts.SearchForward(*i_set, &start, &end))
656 0 : vrResult->push_back(*i_set);
657 0 : ++i_set;
658 : }
659 0 : ++i_pat;
660 0 : }
661 0 : return vrResult;
662 : }
663 :
664 0 : strings_vr MigrationImpl::getAllFiles(const OUString& baseURL) const
665 : {
666 : using namespace osl;
667 0 : strings_vr vrResult(new strings_v);
668 :
669 : // get sub dirs
670 0 : Directory dir(baseURL);
671 0 : if (dir.open() == FileBase::E_None)
672 : {
673 0 : strings_v vSubDirs;
674 0 : strings_vr vrSubResult;
675 :
676 : // work through directory contents...
677 0 : DirectoryItem item;
678 0 : FileStatus fs(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL);
679 0 : while (dir.getNextItem(item) == FileBase::E_None)
680 : {
681 0 : if (item.getFileStatus(fs) == FileBase::E_None)
682 : {
683 0 : if (fs.getFileType() == FileStatus::Directory)
684 0 : vSubDirs.push_back(fs.getFileURL());
685 : else
686 0 : vrResult->push_back(fs.getFileURL());
687 : }
688 : }
689 :
690 : // recurse subfolders
691 0 : strings_v::const_iterator i = vSubDirs.begin();
692 0 : while (i != vSubDirs.end())
693 : {
694 0 : vrSubResult = getAllFiles(*i);
695 0 : vrResult->insert(vrResult->end(), vrSubResult->begin(), vrSubResult->end());
696 0 : ++i;
697 0 : }
698 : }
699 0 : return vrResult;
700 : }
701 :
702 : namespace {
703 :
704 : // removes elements of vector 2 in vector 1
705 0 : strings_v subtract(strings_v const & va, strings_v const & vb) {
706 0 : strings_v a(va);
707 0 : std::sort(a.begin(), a.end());
708 0 : strings_v::iterator ae(std::unique(a.begin(), a.end()));
709 0 : strings_v b(vb);
710 0 : std::sort(b.begin(), b.end());
711 0 : strings_v::iterator be(std::unique(b.begin(), b.end()));
712 0 : strings_v c;
713 0 : std::set_difference(a.begin(), ae, b.begin(), be, std::back_inserter(c));
714 0 : return c;
715 : }
716 :
717 : }
718 :
719 0 : strings_vr MigrationImpl::compileFileList()
720 : {
721 :
722 0 : strings_vr vrResult(new strings_v);
723 0 : strings_vr vrInclude;
724 0 : strings_vr vrExclude;
725 :
726 : // get a list of all files:
727 0 : strings_vr vrFiles = getAllFiles(m_aInfo.userdata);
728 :
729 : // get a file list result for each migration step
730 0 : migrations_v::const_iterator i_migr = m_vrMigrations->begin();
731 0 : while (i_migr != m_vrMigrations->end())
732 : {
733 0 : vrInclude = applyPatterns(*vrFiles, i_migr->includeFiles);
734 0 : vrExclude = applyPatterns(*vrFiles, i_migr->excludeFiles);
735 0 : strings_v sub(subtract(*vrInclude, *vrExclude));
736 0 : vrResult->insert(vrResult->end(), sub.begin(), sub.end());
737 0 : ++i_migr;
738 0 : }
739 0 : return vrResult;
740 : }
741 :
742 : namespace {
743 :
744 0 : struct componentParts {
745 : std::set< OUString > includedPaths;
746 : std::set< OUString > excludedPaths;
747 : };
748 :
749 : typedef std::map< OUString, componentParts > Components;
750 :
751 0 : bool getComponent(OUString const & path, OUString * component) {
752 : OSL_ASSERT(component != 0);
753 0 : if (path.isEmpty() || path[0] != '/') {
754 : OSL_TRACE(
755 : ("configuration migration in/exclude path %s ignored (does not"
756 : " start with slash)"),
757 : OUStringToOString(path, RTL_TEXTENCODING_UTF8).getStr());
758 0 : return false;
759 : }
760 0 : sal_Int32 i = path.indexOf('/', 1);
761 0 : *component = i < 0 ? path.copy(1) : path.copy(1, i - 1);
762 0 : return true;
763 : }
764 :
765 0 : uno::Sequence< OUString > setToSeq(std::set< OUString > const & set) {
766 0 : std::set< OUString >::size_type n = set.size();
767 0 : if (n > SAL_MAX_INT32) {
768 0 : throw std::bad_alloc();
769 : }
770 0 : uno::Sequence< OUString > seq(static_cast< sal_Int32 >(n));
771 0 : sal_Int32 i = 0;
772 0 : for (std::set< OUString >::const_iterator j(set.begin());
773 0 : j != set.end(); ++j)
774 : {
775 0 : seq[i++] = *j;
776 : }
777 0 : return seq;
778 : }
779 :
780 : }
781 :
782 0 : void MigrationImpl::copyConfig() {
783 0 : Components comps;
784 0 : for (migrations_v::const_iterator i(m_vrMigrations->begin());
785 0 : i != m_vrMigrations->end(); ++i)
786 : {
787 0 : for (strings_v::const_iterator j(i->includeConfig.begin());
788 0 : j != i->includeConfig.end(); ++j)
789 : {
790 0 : OUString comp;
791 0 : if (getComponent(*j, &comp)) {
792 0 : comps[comp].includedPaths.insert(*j);
793 : }
794 0 : }
795 0 : for (strings_v::const_iterator j(i->excludeConfig.begin());
796 0 : j != i->excludeConfig.end(); ++j)
797 : {
798 0 : OUString comp;
799 0 : if (getComponent(*j, &comp)) {
800 0 : comps[comp].excludedPaths.insert(*j);
801 : }
802 0 : }
803 : }
804 :
805 : // check if the shared registrymodifications.xcu file exists
806 0 : bool bRegistryModificationsXcuExists = false;
807 0 : OUString regFilePath(m_aInfo.userdata);
808 0 : regFilePath += "/user/registrymodifications.xcu";
809 0 : File regFile(regFilePath);
810 0 : ::osl::FileBase::RC nError = regFile.open(osl_File_OpenFlag_Read);
811 0 : if ( nError == ::osl::FileBase::E_None ) {
812 0 : bRegistryModificationsXcuExists = true;
813 0 : regFile.close();
814 : }
815 :
816 0 : for (Components::const_iterator i(comps.begin()); i != comps.end(); ++i) {
817 0 : if (!i->second.includedPaths.empty()) {
818 0 : if (!bRegistryModificationsXcuExists) {
819 : // shared registrymodifications.xcu does not exists
820 : // the configuration is split in many registry files
821 : // determine the file names from the first element in included paths
822 0 : OUStringBuffer buf(m_aInfo.userdata);
823 0 : buf.appendAscii("/user/registry/data");
824 0 : sal_Int32 n = 0;
825 0 : do {
826 0 : OUString seg(i->first.getToken(0, '.', n));
827 : OUString enc(
828 : rtl::Uri::encode(
829 : seg, rtl_UriCharClassPchar, rtl_UriEncodeStrict,
830 0 : RTL_TEXTENCODING_UTF8));
831 0 : if (enc.isEmpty() && !seg.isEmpty()) {
832 : OSL_TRACE(
833 : ("configuration migration component %s ignored (cannot"
834 : " be encoded as file path)"),
835 : OUStringToOString(
836 : i->first, RTL_TEXTENCODING_UTF8).getStr());
837 0 : goto next;
838 : }
839 0 : buf.append(sal_Unicode('/'));
840 0 : buf.append(enc);
841 0 : } while (n >= 0);
842 0 : buf.appendAscii(".xcu");
843 0 : regFilePath = buf.toString();
844 : }
845 : configuration::Update::get(
846 0 : comphelper::getProcessComponentContext())->
847 : insertModificationXcuFile(
848 0 : regFilePath, setToSeq(i->second.includedPaths),
849 0 : setToSeq(i->second.excludedPaths));
850 : } else {
851 : OSL_TRACE(
852 : ("configuration migration component %s ignored (only excludes,"
853 : " no includes)"),
854 : OUStringToOString(
855 : i->first, RTL_TEXTENCODING_UTF8).getStr());
856 : }
857 : next:;
858 0 : }
859 0 : }
860 :
861 64 : uno::Reference< XNameAccess > MigrationImpl::getConfigAccess(const sal_Char* pPath, sal_Bool bUpdate)
862 : {
863 64 : uno::Reference< XNameAccess > xNameAccess;
864 : try{
865 64 : OUString sAccessSrvc;
866 64 : if (bUpdate)
867 0 : sAccessSrvc = "com.sun.star.configuration.ConfigurationUpdateAccess";
868 : else
869 64 : sAccessSrvc = "com.sun.star.configuration.ConfigurationAccess";
870 :
871 128 : OUString sConfigURL = OUString::createFromAscii(pPath);
872 :
873 : uno::Reference< XMultiServiceFactory > theConfigProvider(
874 : configuration::theDefaultProvider::get(
875 128 : comphelper::getProcessComponentContext()));
876 :
877 : // access the provider
878 128 : uno::Sequence< uno::Any > theArgs(1);
879 64 : theArgs[ 0 ] <<= sConfigURL;
880 128 : xNameAccess = uno::Reference< XNameAccess > (
881 64 : theConfigProvider->createInstanceWithArguments(
882 192 : sAccessSrvc, theArgs ), uno::UNO_QUERY_THROW );
883 : }
884 0 : catch (const com::sun::star::uno::Exception& e)
885 : {
886 0 : OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US);
887 0 : OSL_FAIL(aMsg.getStr());
888 : }
889 64 : return xNameAccess;
890 : }
891 :
892 0 : void MigrationImpl::copyFiles()
893 : {
894 0 : strings_v::const_iterator i_file = m_vrFileList->begin();
895 0 : OUString localName;
896 0 : OUString destName;
897 0 : OUString userInstall;
898 : utl::Bootstrap::PathStatus aStatus;
899 0 : aStatus = utl::Bootstrap::locateUserInstallation(userInstall);
900 0 : if (aStatus == utl::Bootstrap::PATH_EXISTS)
901 : {
902 0 : while (i_file != m_vrFileList->end())
903 : {
904 : // remove installation prefix from file
905 0 : localName = i_file->copy(m_aInfo.userdata.getLength());
906 0 : if (localName.endsWith( "/autocorr/acor_.dat"))
907 : {
908 : // Previous versions used an empty language tag for
909 : // LANGUAGE_DONTKNOW with the "[All]" autocorrection entry.
910 : // As of LibreOffice 4.0 it is 'und' for LANGUAGE_UNDETERMINED
911 : // so the file name is "acor_und.dat".
912 0 : localName = localName.copy( 0, localName.getLength() - 4) + "und.dat";
913 : }
914 0 : destName = userInstall + localName;
915 0 : INetURLObject aURL(destName);
916 : // check whether destination directory exists
917 0 : aURL.removeSegment();
918 0 : _checkAndCreateDirectory(aURL);
919 0 : FileBase::RC copyResult = File::copy(*i_file, destName);
920 0 : if (copyResult != FileBase::E_None)
921 : {
922 0 : OString msg("Cannot copy ");
923 0 : msg += OUStringToOString(*i_file, RTL_TEXTENCODING_UTF8) + " to "
924 0 : + OUStringToOString(destName, RTL_TEXTENCODING_UTF8);
925 0 : OSL_FAIL(msg.getStr());
926 : }
927 0 : ++i_file;
928 0 : }
929 : }
930 : else
931 : {
932 : OSL_FAIL("copyFiles: UserInstall does not exist");
933 0 : }
934 0 : }
935 :
936 0 : void MigrationImpl::runServices()
937 : {
938 : // Build argument array
939 0 : uno::Sequence< uno::Any > seqArguments(3);
940 0 : seqArguments[0] = uno::makeAny(NamedValue("Productname",
941 0 : uno::makeAny(m_aInfo.productname)));
942 0 : seqArguments[1] = uno::makeAny(NamedValue("UserData",
943 0 : uno::makeAny(m_aInfo.userdata)));
944 :
945 :
946 : // create an instance of every migration service
947 : // and execute the migration job
948 0 : uno::Reference< XJob > xMigrationJob;
949 :
950 0 : uno::Reference< uno::XComponentContext > xContext(comphelper::getProcessComponentContext());
951 0 : migrations_v::const_iterator i_mig = m_vrMigrations->begin();
952 0 : while (i_mig != m_vrMigrations->end())
953 : {
954 0 : if( !i_mig->service.isEmpty())
955 : {
956 :
957 : try
958 : {
959 : // set black list for extension migration
960 0 : uno::Sequence< OUString > seqExtBlackList;
961 0 : sal_uInt32 nSize = i_mig->excludeExtensions.size();
962 0 : if ( nSize > 0 )
963 0 : seqExtBlackList = comphelper::arrayToSequence< OUString >(
964 0 : &i_mig->excludeExtensions[0], nSize );
965 0 : seqArguments[2] = uno::makeAny(NamedValue("ExtensionBlackList",
966 0 : uno::makeAny( seqExtBlackList )));
967 :
968 0 : xMigrationJob = uno::Reference< XJob >(
969 0 : xContext->getServiceManager()->createInstanceWithArgumentsAndContext(i_mig->service, seqArguments, xContext),
970 0 : uno::UNO_QUERY_THROW);
971 :
972 0 : xMigrationJob->execute(uno::Sequence< NamedValue >());
973 :
974 :
975 : }
976 0 : catch (const Exception& e)
977 : {
978 0 : OString aMsg("Execution of migration service failed (Exception caught).\nService: ");
979 0 : aMsg += OUStringToOString(i_mig->service, RTL_TEXTENCODING_ASCII_US) + "\nMessage: ";
980 0 : aMsg += OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US);
981 0 : OSL_FAIL(aMsg.getStr());
982 : }
983 0 : catch (...)
984 : {
985 0 : OString aMsg("Execution of migration service failed (Exception caught).\nService: ");
986 0 : aMsg += OUStringToOString(i_mig->service, RTL_TEXTENCODING_ASCII_US) +
987 0 : "\nNo message available";
988 0 : OSL_FAIL(aMsg.getStr());
989 : }
990 :
991 : }
992 0 : ++i_mig;
993 0 : }
994 0 : }
995 :
996 0 : ::std::vector< MigrationModuleInfo > MigrationImpl::dectectUIChangesForAllModules() const
997 : {
998 0 : ::std::vector< MigrationModuleInfo > vModulesInfo;
999 0 : const OUString MENUBAR("menubar");
1000 0 : const OUString TOOLBAR("toolbar");
1001 :
1002 0 : uno::Sequence< uno::Any > lArgs(2);
1003 0 : lArgs[0] <<= m_aInfo.userdata + "/user/config/soffice.cfg/modules";
1004 0 : lArgs[1] <<= embed::ElementModes::READ;
1005 :
1006 : uno::Reference< lang::XSingleServiceFactory > xStorageFactory(
1007 0 : embed::FileSystemStorageFactory::create(comphelper::getProcessComponentContext()));
1008 0 : uno::Reference< embed::XStorage > xModules;
1009 :
1010 0 : xModules = uno::Reference< embed::XStorage >(xStorageFactory->createInstanceWithArguments(lArgs), uno::UNO_QUERY);
1011 0 : if (!xModules.is())
1012 0 : return vModulesInfo;
1013 :
1014 0 : uno::Reference< container::XNameAccess > xAccess = uno::Reference< container::XNameAccess >(xModules, uno::UNO_QUERY);
1015 0 : uno::Sequence< OUString > lNames = xAccess->getElementNames();
1016 0 : sal_Int32 nLength = lNames.getLength();
1017 0 : for (sal_Int32 i=0; i<nLength; ++i)
1018 : {
1019 0 : OUString sModuleShortName = lNames[i];
1020 0 : uno::Reference< embed::XStorage > xModule = xModules->openStorageElement(sModuleShortName, embed::ElementModes::READ);
1021 0 : if (xModule.is())
1022 : {
1023 0 : MigrationModuleInfo aModuleInfo;
1024 :
1025 0 : uno::Reference< embed::XStorage > xMenubar = xModule->openStorageElement(MENUBAR, embed::ElementModes::READ);
1026 0 : if (xMenubar.is())
1027 : {
1028 0 : uno::Reference< container::XNameAccess > xNameAccess = uno::Reference< container::XNameAccess >(xMenubar, uno::UNO_QUERY);
1029 0 : if (xNameAccess->getElementNames().getLength() > 0)
1030 : {
1031 0 : aModuleInfo.sModuleShortName = sModuleShortName;
1032 0 : aModuleInfo.bHasMenubar = sal_True;
1033 0 : }
1034 : }
1035 :
1036 0 : uno::Reference< embed::XStorage > xToolbar = xModule->openStorageElement(TOOLBAR, embed::ElementModes::READ);
1037 0 : if (xToolbar.is())
1038 : {
1039 0 : const OUString RESOURCEURL_CUSTOM_ELEMENT("custom_");
1040 0 : sal_Int32 nCustomLen = 7;
1041 :
1042 0 : uno::Reference< container::XNameAccess > xNameAccess = uno::Reference< container::XNameAccess >(xToolbar, uno::UNO_QUERY);
1043 0 : ::uno::Sequence< OUString > lToolbars = xNameAccess->getElementNames();
1044 0 : for (sal_Int32 j=0; j<lToolbars.getLength(); ++j)
1045 : {
1046 0 : OUString sToolbarName = lToolbars[j];
1047 0 : if (sToolbarName.getLength()>=nCustomLen &&
1048 0 : sToolbarName.copy(0, nCustomLen).equals(RESOURCEURL_CUSTOM_ELEMENT))
1049 0 : continue;
1050 :
1051 0 : aModuleInfo.sModuleShortName = sModuleShortName;
1052 0 : sal_Int32 nIndex = sToolbarName.lastIndexOf('.');
1053 0 : if (nIndex > 0)
1054 : {
1055 0 : OUString sExtension(sToolbarName.copy(nIndex));
1056 0 : OUString sToolbarResourceName(sToolbarName.copy(0, nIndex));
1057 0 : if (!sToolbarResourceName.isEmpty() && sExtension.equalsAsciiL(".xml", 4))
1058 0 : aModuleInfo.m_vToolbars.push_back(sToolbarResourceName);
1059 : }
1060 0 : }
1061 : }
1062 :
1063 0 : if (!aModuleInfo.sModuleShortName.isEmpty())
1064 0 : vModulesInfo.push_back(aModuleInfo);
1065 : }
1066 0 : }
1067 :
1068 0 : return vModulesInfo;
1069 : }
1070 :
1071 0 : void MigrationImpl::compareOldAndNewConfig(const OUString& sParent,
1072 : const uno::Reference< container::XIndexContainer >& xIndexOld,
1073 : const uno::Reference< container::XIndexContainer >& xIndexNew,
1074 : const OUString& sResourceURL)
1075 : {
1076 0 : const OUString MENU_SEPARATOR(" | ");
1077 :
1078 0 : ::std::vector< MigrationItem > vOldItems;
1079 0 : ::std::vector< MigrationItem > vNewItems;
1080 0 : uno::Sequence< beans::PropertyValue > aProp;
1081 0 : sal_Int32 nOldCount = xIndexOld->getCount();
1082 0 : sal_Int32 nNewCount = xIndexNew->getCount();
1083 :
1084 0 : for (int n=0; n<nOldCount; ++n)
1085 : {
1086 0 : MigrationItem aMigrationItem;
1087 0 : if (xIndexOld->getByIndex(n) >>= aProp)
1088 : {
1089 0 : for(int i=0; i<aProp.getLength(); ++i)
1090 : {
1091 0 : if ( aProp[i].Name == ITEM_DESCRIPTOR_COMMANDURL )
1092 0 : aProp[i].Value >>= aMigrationItem.m_sCommandURL;
1093 0 : else if ( aProp[i].Name == ITEM_DESCRIPTOR_CONTAINER )
1094 0 : aProp[i].Value >>= aMigrationItem.m_xPopupMenu;
1095 : }
1096 :
1097 0 : if (!aMigrationItem.m_sCommandURL.isEmpty())
1098 0 : vOldItems.push_back(aMigrationItem);
1099 : }
1100 0 : }
1101 :
1102 0 : for (int n=0; n<nNewCount; ++n)
1103 : {
1104 0 : MigrationItem aMigrationItem;
1105 0 : if (xIndexNew->getByIndex(n) >>= aProp)
1106 : {
1107 0 : for(int i=0; i<aProp.getLength(); ++i)
1108 : {
1109 0 : if ( aProp[i].Name == ITEM_DESCRIPTOR_COMMANDURL )
1110 0 : aProp[i].Value >>= aMigrationItem.m_sCommandURL;
1111 0 : else if ( aProp[i].Name == ITEM_DESCRIPTOR_CONTAINER )
1112 0 : aProp[i].Value >>= aMigrationItem.m_xPopupMenu;
1113 : }
1114 :
1115 0 : if (!aMigrationItem.m_sCommandURL.isEmpty())
1116 0 : vNewItems.push_back(aMigrationItem);
1117 : }
1118 0 : }
1119 :
1120 0 : ::std::vector< MigrationItem >::iterator it;
1121 :
1122 0 : OUString sSibling;
1123 0 : for (it = vOldItems.begin(); it!=vOldItems.end(); ++it)
1124 : {
1125 0 : ::std::vector< MigrationItem >::iterator pFound = ::std::find(vNewItems.begin(), vNewItems.end(), *it);
1126 0 : if (pFound != vNewItems.end() && it->m_xPopupMenu.is())
1127 : {
1128 0 : OUString sName;
1129 0 : if (!sParent.isEmpty())
1130 0 : sName = sParent + MENU_SEPARATOR + it->m_sCommandURL;
1131 : else
1132 0 : sName = it->m_sCommandURL;
1133 0 : compareOldAndNewConfig(sName, it->m_xPopupMenu, pFound->m_xPopupMenu, sResourceURL);
1134 : }
1135 0 : else if (pFound == vNewItems.end())
1136 : {
1137 0 : MigrationItem aMigrationItem(sParent, sSibling, it->m_sCommandURL, it->m_xPopupMenu);
1138 0 : if (m_aOldVersionItemsHashMap.find(sResourceURL)==m_aOldVersionItemsHashMap.end())
1139 : {
1140 0 : ::std::vector< MigrationItem > vMigrationItems;
1141 0 : m_aOldVersionItemsHashMap.insert(MigrationHashMap::value_type(sResourceURL, vMigrationItems));
1142 0 : m_aOldVersionItemsHashMap[sResourceURL].push_back(aMigrationItem);
1143 : }
1144 : else
1145 : {
1146 0 : if (::std::find(m_aOldVersionItemsHashMap[sResourceURL].begin(), m_aOldVersionItemsHashMap[sResourceURL].end(), aMigrationItem)==m_aOldVersionItemsHashMap[sResourceURL].end())
1147 0 : m_aOldVersionItemsHashMap[sResourceURL].push_back(aMigrationItem);
1148 0 : }
1149 : }
1150 :
1151 0 : sSibling = it->m_sCommandURL;
1152 : }
1153 :
1154 0 : uno::Reference< container::XIndexContainer > xPopup;
1155 0 : for (it = vNewItems.begin(); it!=vNewItems.end(); ++it)
1156 : {
1157 0 : ::std::vector< MigrationItem >::iterator pFound = ::std::find(vOldItems.begin(), vOldItems.end(), *it);
1158 0 : if (pFound != vOldItems.end() && it->m_xPopupMenu.is())
1159 : {
1160 0 : OUString sName;
1161 0 : if (!sParent.isEmpty())
1162 0 : sName = sParent + MENU_SEPARATOR + it->m_sCommandURL;
1163 : else
1164 0 : sName = it->m_sCommandURL;
1165 0 : compareOldAndNewConfig(sName, pFound->m_xPopupMenu, it->m_xPopupMenu, sResourceURL);
1166 : }
1167 0 : else if (::std::find(vOldItems.begin(), vOldItems.end(), *it) == vOldItems.end())
1168 : {
1169 0 : MigrationItem aMigrationItem(sParent, sSibling, it->m_sCommandURL, it->m_xPopupMenu);
1170 0 : if (m_aNewVersionItemsHashMap.find(sResourceURL)==m_aNewVersionItemsHashMap.end())
1171 : {
1172 0 : ::std::vector< MigrationItem > vMigrationItems;
1173 0 : m_aNewVersionItemsHashMap.insert(MigrationHashMap::value_type(sResourceURL, vMigrationItems));
1174 0 : m_aNewVersionItemsHashMap[sResourceURL].push_back(aMigrationItem);
1175 : }
1176 : else
1177 : {
1178 0 : if (::std::find(m_aNewVersionItemsHashMap[sResourceURL].begin(), m_aNewVersionItemsHashMap[sResourceURL].end(), aMigrationItem)==m_aNewVersionItemsHashMap[sResourceURL].end())
1179 0 : m_aNewVersionItemsHashMap[sResourceURL].push_back(aMigrationItem);
1180 0 : }
1181 : }
1182 0 : }
1183 0 : }
1184 :
1185 0 : void MigrationImpl::mergeOldToNewVersion(const uno::Reference< ui::XUIConfigurationManager >& xCfgManager,
1186 : const uno::Reference< container::XIndexContainer>& xIndexContainer,
1187 : const OUString& sModuleIdentifier,
1188 : const OUString& sResourceURL)
1189 : {
1190 0 : MigrationHashMap::iterator pFound = m_aOldVersionItemsHashMap.find(sResourceURL);
1191 0 : if (pFound==m_aOldVersionItemsHashMap.end())
1192 0 : return;
1193 :
1194 0 : ::std::vector< MigrationItem >::iterator it;
1195 0 : for (it=pFound->second.begin(); it!=pFound->second.end(); ++it)
1196 : {
1197 0 : uno::Reference< container::XIndexContainer > xTemp = xIndexContainer;
1198 :
1199 0 : OUString sParentNodeName = it->m_sParentNodeName;
1200 0 : sal_Int32 nIndex = 0;
1201 0 : do
1202 : {
1203 0 : OUString sToken = sParentNodeName.getToken(0, '|', nIndex).trim();
1204 0 : if (sToken.isEmpty())
1205 0 : break;
1206 :
1207 0 : sal_Int32 nCount = xTemp->getCount();
1208 0 : for (sal_Int32 i=0; i<nCount; ++i)
1209 : {
1210 0 : OUString sCommandURL;
1211 0 : OUString sLabel;
1212 0 : uno::Reference< container::XIndexContainer > xChild;
1213 :
1214 0 : uno::Sequence< beans::PropertyValue > aPropSeq;
1215 0 : xTemp->getByIndex(i) >>= aPropSeq;
1216 0 : for (sal_Int32 j=0; j<aPropSeq.getLength(); ++j)
1217 : {
1218 0 : OUString sPropName = aPropSeq[j].Name;
1219 0 : if ( sPropName == ITEM_DESCRIPTOR_COMMANDURL )
1220 0 : aPropSeq[j].Value >>= sCommandURL;
1221 0 : else if ( sPropName == ITEM_DESCRIPTOR_LABEL )
1222 0 : aPropSeq[j].Value >>= sLabel;
1223 0 : else if ( sPropName == ITEM_DESCRIPTOR_CONTAINER )
1224 0 : aPropSeq[j].Value >>= xChild;
1225 0 : }
1226 :
1227 0 : if (sCommandURL == sToken)
1228 : {
1229 0 : xTemp = xChild;
1230 0 : break;
1231 : }
1232 0 : }
1233 :
1234 0 : } while (nIndex>=0);
1235 :
1236 0 : if (nIndex == -1)
1237 : {
1238 0 : uno::Sequence< beans::PropertyValue > aPropSeq(3);
1239 :
1240 0 : aPropSeq[0].Name = OUString(ITEM_DESCRIPTOR_COMMANDURL);
1241 0 : aPropSeq[0].Value <<= it->m_sCommandURL;
1242 0 : aPropSeq[1].Name = OUString(ITEM_DESCRIPTOR_LABEL);
1243 0 : aPropSeq[1].Value <<= retrieveLabelFromCommand(it->m_sCommandURL, sModuleIdentifier);
1244 0 : aPropSeq[2].Name = OUString(ITEM_DESCRIPTOR_CONTAINER);
1245 0 : aPropSeq[2].Value <<= it->m_xPopupMenu;
1246 :
1247 0 : if (it->m_sPrevSibling.isEmpty())
1248 0 : xTemp->insertByIndex(0, uno::makeAny(aPropSeq));
1249 0 : else if (!it->m_sPrevSibling.isEmpty())
1250 : {
1251 0 : sal_Int32 nCount = xTemp->getCount();
1252 0 : sal_Int32 i = 0;
1253 0 : for (; i<nCount; ++i)
1254 : {
1255 0 : OUString sCmd;
1256 0 : uno::Sequence< beans::PropertyValue > aTempPropSeq;
1257 0 : xTemp->getByIndex(i) >>= aTempPropSeq;
1258 0 : for (sal_Int32 j=0; j<aTempPropSeq.getLength(); ++j)
1259 : {
1260 0 : if ( aTempPropSeq[j].Name == ITEM_DESCRIPTOR_COMMANDURL )
1261 : {
1262 0 : aTempPropSeq[j].Value >>= sCmd;
1263 0 : break;
1264 : }
1265 : }
1266 :
1267 0 : if (sCmd.equals(it->m_sPrevSibling))
1268 0 : break;
1269 0 : }
1270 :
1271 0 : xTemp->insertByIndex(i+1, uno::makeAny(aPropSeq));
1272 0 : }
1273 : }
1274 0 : }
1275 :
1276 0 : uno::Reference< container::XIndexAccess > xIndexAccess(xIndexContainer, uno::UNO_QUERY);
1277 0 : if (xIndexAccess.is())
1278 0 : xCfgManager->replaceSettings(sResourceURL, xIndexAccess);
1279 :
1280 0 : uno::Reference< ui::XUIConfigurationPersistence > xUIConfigurationPersistence(xCfgManager, uno::UNO_QUERY);
1281 0 : if (xUIConfigurationPersistence.is())
1282 0 : xUIConfigurationPersistence->store();
1283 : }
1284 :
1285 0 : uno::Reference< ui::XUIConfigurationManager > NewVersionUIInfo::getConfigManager(const OUString& sModuleShortName) const
1286 : {
1287 0 : uno::Reference< ui::XUIConfigurationManager > xCfgManager;
1288 :
1289 0 : for (sal_Int32 i=0; i<m_lCfgManagerSeq.getLength(); ++i)
1290 : {
1291 0 : if (m_lCfgManagerSeq[i].Name.equals(sModuleShortName))
1292 : {
1293 0 : m_lCfgManagerSeq[i].Value >>= xCfgManager;
1294 0 : break;
1295 : }
1296 : }
1297 :
1298 0 : return xCfgManager;
1299 : }
1300 :
1301 0 : uno::Reference< container::XIndexContainer > NewVersionUIInfo::getNewMenubarSettings(const OUString& sModuleShortName) const
1302 : {
1303 0 : uno::Reference< container::XIndexContainer > xNewMenuSettings;
1304 :
1305 0 : for (sal_Int32 i=0; i<m_lNewVersionMenubarSettingsSeq.getLength(); ++i)
1306 : {
1307 0 : if (m_lNewVersionMenubarSettingsSeq[i].Name.equals(sModuleShortName))
1308 : {
1309 0 : m_lNewVersionMenubarSettingsSeq[i].Value >>= xNewMenuSettings;
1310 0 : break;
1311 : }
1312 : }
1313 :
1314 0 : return xNewMenuSettings;
1315 : }
1316 :
1317 0 : uno::Reference< container::XIndexContainer > NewVersionUIInfo::getNewToolbarSettings(const OUString& sModuleShortName, const OUString& sToolbarName) const
1318 : {
1319 0 : uno::Reference< container::XIndexContainer > xNewToolbarSettings;
1320 :
1321 0 : for (sal_Int32 i=0; i<m_lNewVersionToolbarSettingsSeq.getLength(); ++i)
1322 : {
1323 0 : if (m_lNewVersionToolbarSettingsSeq[i].Name.equals(sModuleShortName))
1324 : {
1325 0 : uno::Sequence< beans::PropertyValue > lToolbarSettingsSeq;
1326 0 : m_lNewVersionToolbarSettingsSeq[i].Value >>= lToolbarSettingsSeq;
1327 0 : for (sal_Int32 j=0; j<lToolbarSettingsSeq.getLength(); ++j)
1328 : {
1329 0 : if (lToolbarSettingsSeq[j].Name.equals(sToolbarName))
1330 : {
1331 0 : lToolbarSettingsSeq[j].Value >>= xNewToolbarSettings;
1332 0 : break;
1333 : }
1334 : }
1335 :
1336 0 : break;
1337 : }
1338 : }
1339 :
1340 0 : return xNewToolbarSettings;
1341 : }
1342 :
1343 0 : void NewVersionUIInfo::init(const ::std::vector< MigrationModuleInfo >& vModulesInfo)
1344 : {
1345 0 : m_lCfgManagerSeq.realloc(vModulesInfo.size());
1346 0 : m_lNewVersionMenubarSettingsSeq.realloc(vModulesInfo.size());
1347 0 : m_lNewVersionToolbarSettingsSeq.realloc(vModulesInfo.size());
1348 :
1349 0 : const OUString sMenubarResourceURL("private:resource/menubar/menubar");
1350 0 : const OUString sToolbarResourcePre("private:resource/toolbar/");
1351 :
1352 0 : uno::Reference< ui::XModuleUIConfigurationManagerSupplier > xModuleCfgSupplier = ui::ModuleUIConfigurationManagerSupplier::create( ::comphelper::getProcessComponentContext() );
1353 :
1354 0 : for (sal_uInt32 i=0; i<vModulesInfo.size(); ++i)
1355 : {
1356 0 : OUString sModuleIdentifier = mapModuleShortNameToIdentifier(vModulesInfo[i].sModuleShortName);
1357 0 : if (!sModuleIdentifier.isEmpty())
1358 : {
1359 0 : uno::Reference< ui::XUIConfigurationManager > xCfgManager = xModuleCfgSupplier->getUIConfigurationManager(sModuleIdentifier);
1360 0 : m_lCfgManagerSeq[i].Name = vModulesInfo[i].sModuleShortName;
1361 0 : m_lCfgManagerSeq[i].Value <<= xCfgManager;
1362 :
1363 0 : if (vModulesInfo[i].bHasMenubar)
1364 : {
1365 0 : m_lNewVersionMenubarSettingsSeq[i].Name = vModulesInfo[i].sModuleShortName;
1366 0 : m_lNewVersionMenubarSettingsSeq[i].Value <<= xCfgManager->getSettings(sMenubarResourceURL, sal_True);
1367 : }
1368 :
1369 0 : sal_Int32 nToolbars = vModulesInfo[i].m_vToolbars.size();
1370 0 : if (nToolbars > 0)
1371 : {
1372 0 : uno::Sequence< beans::PropertyValue > lPropSeq(nToolbars);
1373 0 : for (sal_Int32 j=0; j<nToolbars; ++j)
1374 : {
1375 0 : OUString sToolbarName = vModulesInfo[i].m_vToolbars[j];
1376 0 : OUString sToolbarResourceURL = sToolbarResourcePre + sToolbarName;
1377 :
1378 0 : lPropSeq[j].Name = sToolbarName;
1379 0 : lPropSeq[j].Value <<= xCfgManager->getSettings(sToolbarResourceURL, sal_True);
1380 0 : }
1381 :
1382 0 : m_lNewVersionToolbarSettingsSeq[i].Name = vModulesInfo[i].sModuleShortName;
1383 0 : m_lNewVersionToolbarSettingsSeq[i].Value <<= lPropSeq;
1384 0 : }
1385 : }
1386 0 : }
1387 0 : }
1388 :
1389 : } // namespace desktop
1390 :
1391 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|