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 :
21 : #include "services/autorecovery.hxx"
22 : #include <loadenv/loadenv.hxx>
23 :
24 : #include <loadenv/targethelper.hxx>
25 : #include <pattern/frame.hxx>
26 : #include <threadhelp/readguard.hxx>
27 : #include <threadhelp/writeguard.hxx>
28 :
29 : #include <classes/resource.hrc>
30 : #include <classes/fwkresid.hxx>
31 : #include <protocols.h>
32 : #include <properties.h>
33 : #include <services.h>
34 :
35 : #include "helper/mischelper.hxx"
36 :
37 : #include <com/sun/star/ucb/NameClash.hpp>
38 : #include <com/sun/star/container/XNameAccess.hpp>
39 : #include <com/sun/star/frame/Desktop.hpp>
40 : #include <com/sun/star/frame/GlobalEventBroadcaster.hpp>
41 : #include <com/sun/star/frame/XLoadable.hpp>
42 : #include <com/sun/star/frame/XModel2.hpp>
43 : #include <com/sun/star/frame/ModuleManager.hpp>
44 : #include <com/sun/star/frame/XTitle.hpp>
45 : #include <com/sun/star/frame/XFrame.hpp>
46 : #include <com/sun/star/frame/XDispatchProvider.hpp>
47 : #include <com/sun/star/frame/DispatchResultState.hpp>
48 : #include <com/sun/star/frame/XNotifyingDispatch.hpp>
49 : #include <com/sun/star/frame/XController.hpp>
50 : #include <com/sun/star/frame/XModel.hpp>
51 : #include <com/sun/star/frame/XStorable.hpp>
52 : #include <com/sun/star/util/XModifiable.hpp>
53 : #include <com/sun/star/util/URLTransformer.hpp>
54 : #include <com/sun/star/util/XURLTransformer.hpp>
55 : #include <com/sun/star/frame/XDesktop.hpp>
56 : #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
57 : #include <com/sun/star/container/XNameContainer.hpp>
58 : #include <com/sun/star/util/XChangesNotifier.hpp>
59 : #include <com/sun/star/util/XChangesBatch.hpp>
60 : #include <com/sun/star/beans/XPropertySet.hpp>
61 : #include <com/sun/star/beans/PropertyAttribute.hpp>
62 : #include <com/sun/star/container/XContainerQuery.hpp>
63 : #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
64 : #include <com/sun/star/document/XDocumentRecovery.hpp>
65 : #include <com/sun/star/util/XCloseable.hpp>
66 : #include <com/sun/star/awt/XWindow2.hpp>
67 : #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
68 :
69 : #include <comphelper/configurationhelper.hxx>
70 : #include <comphelper/mediadescriptor.hxx>
71 : #include <comphelper/namedvaluecollection.hxx>
72 : #include <comphelper/processfactory.hxx>
73 : #include <vcl/svapp.hxx>
74 : #include <unotools/pathoptions.hxx>
75 : #include <tools/diagnose_ex.h>
76 : #include <unotools/tempfile.hxx>
77 : #include <ucbhelper/content.hxx>
78 :
79 : #include <osl/time.h>
80 : #include <vcl/msgbox.hxx>
81 : #include <osl/file.hxx>
82 : #include <unotools/bootstrap.hxx>
83 : #include <unotools/configmgr.hxx>
84 : #include <svl/documentlockfile.hxx>
85 : #include <cppuhelper/exc_hlp.hxx>
86 :
87 : #include <tools/urlobj.hxx>
88 :
89 : #include <fwkdllapi.h>
90 :
91 : //_______________________________________________
92 : // namespaces
93 :
94 : using ::com::sun::star::uno::Sequence;
95 : using ::com::sun::star::uno::UNO_QUERY;
96 : using ::com::sun::star::uno::UNO_QUERY_THROW;
97 : using ::com::sun::star::uno::UNO_SET_THROW;
98 : using ::com::sun::star::uno::Reference;
99 : using ::com::sun::star::uno::Any;
100 : using ::com::sun::star::beans::PropertyValue;
101 : using ::com::sun::star::container::XEnumeration;
102 : using ::com::sun::star::document::XDocumentRecovery;
103 : using ::com::sun::star::frame::ModuleManager;
104 : using ::com::sun::star::frame::XModel2;
105 : using ::com::sun::star::frame::XModel;
106 : using ::com::sun::star::frame::XFrame;
107 : using ::com::sun::star::frame::XController2;
108 : using ::com::sun::star::frame::XLoadable;
109 : using ::com::sun::star::frame::XStorable;
110 : using ::com::sun::star::lang::XComponent;
111 :
112 :
113 : namespace framework
114 : {
115 :
116 : //-----------------------------------------------
117 : // recovery.xcu
118 : static const char CFG_PACKAGE_RECOVERY[] = "org.openoffice.Office.Recovery/";
119 : static const char CFG_ENTRY_RECOVERYLIST[] = "RecoveryList";
120 : static const char CFG_PATH_RECOVERYINFO[] = "RecoveryInfo";
121 : static const char CFG_ENTRY_CRASHED[] = "Crashed";
122 : static const char CFG_ENTRY_SESSIONDATA[] = "SessionData";
123 :
124 : static const char CFG_ENTRY_AUTOSAVE_ENABLED[] = "AutoSave/Enabled";
125 : static const char CFG_ENTRY_AUTOSAVE_TIMEINTERVALL[] = "AutoSave/TimeIntervall"; //sic!
126 :
127 : static const char CFG_PATH_AUTOSAVE[] = "AutoSave";
128 : static const char CFG_ENTRY_MINSPACE_DOCSAVE[] = "MinSpaceDocSave";
129 : static const char CFG_ENTRY_MINSPACE_CONFIGSAVE[] = "MinSpaceConfigSave";
130 :
131 : static const char CFG_PACKAGE_MODULES[] = "org.openoffice.Setup/Office/Factories";
132 : static const char CFG_ENTRY_REALDEFAULTFILTER[] = "ooSetupFactoryActualFilter";
133 :
134 : static const char CFG_ENTRY_PROP_TEMPURL[] = "TempURL";
135 : static const char CFG_ENTRY_PROP_ORIGINALURL[] = "OriginalURL";
136 : static const char CFG_ENTRY_PROP_TEMPLATEURL[] = "TemplateURL";
137 : static const char CFG_ENTRY_PROP_FACTORYURL[] = "FactoryURL";
138 : static const char CFG_ENTRY_PROP_MODULE[] = "Module";
139 : static const char CFG_ENTRY_PROP_DOCUMENTSTATE[] = "DocumentState";
140 : static const char CFG_ENTRY_PROP_FILTER[] = "Filter";
141 : static const char CFG_ENTRY_PROP_TITLE[] = "Title";
142 : static const char CFG_ENTRY_PROP_ID[] = "ID";
143 : static const char CFG_ENTRY_PROP_VIEWNAMES[] = "ViewNames";
144 :
145 : static const char FILTER_PROP_TYPE[] = "Type";
146 : static const char TYPE_PROP_EXTENSIONS[] = "Extensions";
147 :
148 : // setup.xcu
149 : static const char CFG_ENTRY_PROP_EMPTYDOCUMENTURL[] = "ooSetupFactoryEmptyDocumentURL";
150 : static const char CFG_ENTRY_PROP_FACTORYSERVICE[] = "ooSetupFactoryDocumentService";
151 :
152 : static const char EVENT_ON_NEW[] = "OnNew";
153 : static const char EVENT_ON_LOAD[] = "OnLoad";
154 : static const char EVENT_ON_UNLOAD[] = "OnUnload";
155 : static const char EVENT_ON_MODIFYCHANGED[] = "OnModifyChanged";
156 : static const char EVENT_ON_SAVE[] = "OnSave";
157 : static const char EVENT_ON_SAVEAS[] = "OnSaveAs";
158 : static const char EVENT_ON_SAVETO[] = "OnCopyTo";
159 : static const char EVENT_ON_SAVEDONE[] = "OnSaveDone";
160 : static const char EVENT_ON_SAVEASDONE[] = "OnSaveAsDone";
161 : static const char EVENT_ON_SAVETODONE[] = "OnCopyToDone";
162 : static const char EVENT_ON_SAVEFAILED[] = "OnSaveFailed";
163 : static const char EVENT_ON_SAVEASFAILED[] = "OnSaveAsFailed";
164 : static const char EVENT_ON_SAVETOFAILED[] = "OnCopyToFailed";
165 :
166 : static const char RECOVERY_ITEM_BASE_IDENTIFIER[] = "recovery_item_";
167 :
168 : static const char CMD_PROTOCOL[] = "vnd.sun.star.autorecovery:";
169 :
170 : static const char CMD_DO_AUTO_SAVE[] = "/doAutoSave"; // force AutoSave ignoring the AutoSave timer
171 : static const char CMD_DO_PREPARE_EMERGENCY_SAVE[] = "/doPrepareEmergencySave"; // prepare the office for the following EmergencySave step (hide windows etcpp.)
172 : static const char CMD_DO_EMERGENCY_SAVE[] = "/doEmergencySave"; // do EmergencySave on crash
173 : static const char CMD_DO_RECOVERY[] = "/doAutoRecovery"; // recover all crashed documents
174 : static const char CMD_DO_ENTRY_BACKUP[] = "/doEntryBackup"; // try to store a temp or original file to a user defined location
175 : static const char CMD_DO_ENTRY_CLEANUP[] = "/doEntryCleanUp"; // remove the specified entry from the recovery cache
176 : static const char CMD_DO_SESSION_SAVE[] = "/doSessionSave"; // save all open documents if e.g. a window manager closes an user session
177 : static const char CMD_DO_SESSION_QUIET_QUIT[] = "/doSessionQuietQuit"; // let the current session be quietly closed ( the saving should be done using doSessionSave previously ) if e.g. a window manager closes an user session
178 : static const char CMD_DO_SESSION_RESTORE[] = "/doSessionRestore"; // restore a saved user session from disc
179 : static const char CMD_DO_DISABLE_RECOVERY[] = "/disableRecovery"; // disable recovery and auto save (!) temp. for this office session
180 : static const char CMD_DO_SET_AUTOSAVE_STATE[] = "/setAutoSaveState"; // disable/enable auto save (not crash save) for this office session
181 :
182 : static const char REFERRER_USER[] = "private:user";
183 :
184 : static const char PROP_DISPATCH_ASYNCHRON[] = "DispatchAsynchron";
185 : static const char PROP_PROGRESS[] = "StatusIndicator";
186 : static const char PROP_SAVEPATH[] = "SavePath";
187 : static const char PROP_ENTRY_ID[] = "EntryID";
188 : static const char PROP_AUTOSAVE_STATE[] = "AutoSaveState";
189 :
190 : static const char OPERATION_START[] = "start";
191 : static const char OPERATION_STOP[] = "stop";
192 : static const char OPERATION_UPDATE[] = "update";
193 :
194 : static const sal_Int32 MIN_DISCSPACE_DOCSAVE = 5; // [MB]
195 : static const sal_Int32 MIN_DISCSPACE_CONFIGSAVE = 1; // [MB]
196 : static const sal_Int32 RETRY_STORE_ON_FULL_DISC_FOREVER = 300; // not forever ... but often enough .-)
197 : static const sal_Int32 RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL = 3; // in case FULL DISC does not seam the real problem
198 : static const sal_Int32 GIVE_UP_RETRY = 1; // in case FULL DISC does not seam the real problem
199 :
200 : #define SAVE_IN_PROGRESS sal_True
201 : #define SAVE_FINISHED sal_False
202 :
203 : #define LOCK_FOR_CACHE_ADD_REMOVE sal_True
204 : #define LOCK_FOR_CACHE_USE sal_False
205 :
206 : #define MIN_TIME_FOR_USER_IDLE 10000 // 10s user idle
207 :
208 : // enable the following defines in case you whish to simulate a full disc for debug purposes .-)
209 :
210 : // this define throws everytime a document is stored or a configuration change
211 : // should be flushed an exception ... so the special error handler for this scenario is triggered
212 : // #define TRIGGER_FULL_DISC_CHECK
213 :
214 : // force "return sal_False" for the method impl_enoughDiscSpace().
215 : // #define SIMULATE_FULL_DISC
216 :
217 : //-----------------------------------------------
218 : // #define ENABLE_RECOVERY_LOGGING
219 : #undef ENABLE_RECOVERY_LOGGING
220 : #ifdef ENABLE_RECOVERY_LOGGING
221 : #define LOGFILE_RECOVERY "recovery.log"
222 :
223 : #define LOG_RECOVERY(MSG) \
224 : { \
225 : WRITE_LOGFILE(LOGFILE_RECOVERY, MSG) \
226 : WRITE_LOGFILE(LOGFILE_RECOVERY, "\n") \
227 : }
228 : #else
229 : #undef LOGFILE_RECOVERY
230 : #define LOG_RECOVERY(MSG)
231 : #endif
232 :
233 : //-----------------------------------------------
234 : class CacheLockGuard
235 : {
236 : private:
237 :
238 : // holds the outside calli alive, so it's shared resources
239 : // are valid everytimes
240 : css::uno::Reference< css::uno::XInterface > m_xOwner;
241 :
242 : // mutex shared with outside calli !
243 : LockHelper& m_rSharedMutex;
244 :
245 : // this variable knows the state of the "cache lock"
246 : sal_Int32& m_rCacheLock;
247 :
248 : // to prevent increasing/decreasing of m_rCacheLock more then ones
249 : // we must know if THIS guard has an actual lock set there !
250 : sal_Bool m_bLockedByThisGuard;
251 :
252 : public:
253 :
254 : CacheLockGuard(AutoRecovery* pOwner ,
255 : LockHelper& rMutex ,
256 : sal_Int32& rCacheLock ,
257 : sal_Bool bLockForAddRemoveVectorItems);
258 : ~CacheLockGuard();
259 :
260 : void lock(sal_Bool bLockForAddRemoveVectorItems);
261 : void unlock();
262 : };
263 :
264 : //-----------------------------------------------
265 0 : CacheLockGuard::CacheLockGuard(AutoRecovery* pOwner ,
266 : LockHelper& rMutex ,
267 : sal_Int32& rCacheLock ,
268 : sal_Bool bLockForAddRemoveVectorItems)
269 0 : : m_xOwner (static_cast< css::frame::XDispatch* >(pOwner))
270 : , m_rSharedMutex (rMutex )
271 : , m_rCacheLock (rCacheLock )
272 0 : , m_bLockedByThisGuard(sal_False )
273 : {
274 0 : lock(bLockForAddRemoveVectorItems);
275 0 : }
276 :
277 : //-----------------------------------------------
278 0 : CacheLockGuard::~CacheLockGuard()
279 : {
280 0 : unlock();
281 0 : m_xOwner.clear();
282 0 : }
283 :
284 : //-----------------------------------------------
285 0 : void CacheLockGuard::lock(sal_Bool bLockForAddRemoveVectorItems)
286 : {
287 : // SAFE -> ----------------------------------
288 0 : WriteGuard aWriteLock(m_rSharedMutex);
289 :
290 0 : if (m_bLockedByThisGuard)
291 0 : return;
292 :
293 : // This cache lock is needed only to prevent us from removing/adding
294 : // items from/into the recovery cache ... during it's used at another code place
295 : // for iterating .-)
296 :
297 : // Modifying of item properties is allowed and sometimes needed!
298 : // So we should detect only the dangerous state of concurrent add/remove
299 : // requests and throw an exception then ... which can of course break the whole
300 : // operation. On the other side a crash reasoned by an invalid stl iterator
301 : // will have the same effect .-)
302 :
303 0 : if (
304 : (m_rCacheLock > 0 ) &&
305 : (bLockForAddRemoveVectorItems)
306 : )
307 : {
308 : OSL_FAIL("Re-entrance problem detected. Using of an stl structure in combination with iteration, adding, removing of elements etcpp.");
309 : throw css::uno::RuntimeException(
310 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Re-entrance problem detected. Using of an stl structure in combination with iteration, adding, removing of elements etcpp.")),
311 0 : m_xOwner);
312 : }
313 :
314 0 : ++m_rCacheLock;
315 0 : m_bLockedByThisGuard = sal_True;
316 :
317 0 : aWriteLock.unlock();
318 : // <- SAFE ----------------------------------
319 : }
320 :
321 : //-----------------------------------------------
322 0 : void CacheLockGuard::unlock()
323 : {
324 : // SAFE -> ----------------------------------
325 0 : WriteGuard aWriteLock(m_rSharedMutex);
326 :
327 0 : if ( ! m_bLockedByThisGuard)
328 0 : return;
329 :
330 0 : --m_rCacheLock;
331 0 : m_bLockedByThisGuard = sal_False;
332 :
333 0 : if (m_rCacheLock < 0)
334 : {
335 : OSL_FAIL("Wrong using of member m_nDocCacheLock detected. A ref counted value shouldn't reach values <0 .-)");
336 : throw css::uno::RuntimeException(
337 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Wrong using of member m_nDocCacheLock detected. A ref counted value shouldn't reach values <0 .-)")),
338 0 : m_xOwner);
339 : }
340 0 : aWriteLock.unlock();
341 : // <- SAFE ----------------------------------
342 : }
343 :
344 : //-----------------------------------------------
345 0 : DispatchParams::DispatchParams()
346 0 : : m_nWorkingEntryID(-1)
347 : {
348 0 : };
349 :
350 : //-----------------------------------------------
351 0 : DispatchParams::DispatchParams(const ::comphelper::SequenceAsHashMap& lArgs ,
352 0 : const css::uno::Reference< css::uno::XInterface >& xOwner)
353 : {
354 0 : m_nWorkingEntryID = lArgs.getUnpackedValueOrDefault(PROP_ENTRY_ID, (sal_Int32)-1 );
355 0 : m_xProgress = lArgs.getUnpackedValueOrDefault(PROP_PROGRESS, css::uno::Reference< css::task::XStatusIndicator >());
356 0 : m_sSavePath = lArgs.getUnpackedValueOrDefault(PROP_SAVEPATH, ::rtl::OUString() );
357 0 : m_xHoldRefForAsyncOpAlive = xOwner;
358 0 : };
359 :
360 : //-----------------------------------------------
361 0 : DispatchParams::DispatchParams(const DispatchParams& rCopy)
362 : {
363 0 : m_xProgress = rCopy.m_xProgress;
364 0 : m_sSavePath = rCopy.m_sSavePath;
365 0 : m_nWorkingEntryID = rCopy.m_nWorkingEntryID;
366 0 : m_xHoldRefForAsyncOpAlive = rCopy.m_xHoldRefForAsyncOpAlive;
367 0 : };
368 :
369 : //-----------------------------------------------
370 0 : DispatchParams::~DispatchParams()
371 0 : {};
372 :
373 : //-----------------------------------------------
374 0 : DispatchParams& DispatchParams::operator=(const DispatchParams& rCopy)
375 : {
376 0 : m_xProgress = rCopy.m_xProgress;
377 0 : m_sSavePath = rCopy.m_sSavePath;
378 0 : m_nWorkingEntryID = rCopy.m_nWorkingEntryID;
379 0 : m_xHoldRefForAsyncOpAlive = rCopy.m_xHoldRefForAsyncOpAlive;
380 0 : return *this;
381 : }
382 :
383 : //-----------------------------------------------
384 0 : void DispatchParams::forget()
385 : {
386 0 : m_sSavePath = ::rtl::OUString();
387 0 : m_nWorkingEntryID = -1;
388 0 : m_xProgress.clear();
389 0 : m_xHoldRefForAsyncOpAlive.clear();
390 0 : };
391 :
392 : //-----------------------------------------------
393 0 : DEFINE_XINTERFACE_10(AutoRecovery ,
394 : OWeakObject ,
395 : DIRECT_INTERFACE (css::lang::XTypeProvider ),
396 : DIRECT_INTERFACE (css::lang::XServiceInfo ),
397 : DIRECT_INTERFACE (css::frame::XDispatch ),
398 : DIRECT_INTERFACE (css::beans::XMultiPropertySet ),
399 : DIRECT_INTERFACE (css::beans::XFastPropertySet ),
400 : DIRECT_INTERFACE (css::beans::XPropertySet ),
401 : DIRECT_INTERFACE (css::document::XEventListener ),
402 : DIRECT_INTERFACE (css::util::XChangesListener ),
403 : DIRECT_INTERFACE (css::util::XModifyListener ),
404 : DERIVED_INTERFACE(css::lang::XEventListener, css::document::XEventListener))
405 :
406 : //-----------------------------------------------
407 0 : DEFINE_XTYPEPROVIDER_6(AutoRecovery ,
408 : css::lang::XTypeProvider ,
409 : css::lang::XServiceInfo ,
410 : css::frame::XDispatch ,
411 : css::beans::XMultiPropertySet,
412 : css::beans::XFastPropertySet ,
413 : css::beans::XPropertySet )
414 :
415 : //-----------------------------------------------
416 72 : DEFINE_XSERVICEINFO_ONEINSTANCESERVICE(AutoRecovery ,
417 : ::cppu::OWeakObject ,
418 : "com.sun.star.frame.AutoRecovery",
419 : IMPLEMENTATIONNAME_AUTORECOVERY)
420 :
421 : //-----------------------------------------------
422 0 : DEFINE_INIT_SERVICE(
423 : AutoRecovery,
424 : {
425 : /*Attention
426 : I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
427 : to create a new instance of this class by our own supported service factory.
428 : see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
429 : */
430 :
431 : // read configuration to know if autosave/recovery is on/off etcpp...
432 : implts_readConfig();
433 :
434 : implts_startListening();
435 :
436 : // establish callback for our internal used timer.
437 : // Note: Its only active, if the timer will be started ...
438 : m_aTimer.SetTimeoutHdl(LINK(this, AutoRecovery, implts_timerExpired));
439 : }
440 : )
441 :
442 : //-----------------------------------------------
443 0 : AutoRecovery::AutoRecovery(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
444 0 : : ThreadHelpBase (&Application::GetSolarMutex() )
445 0 : , ::cppu::OBroadcastHelper ( m_aLock.getShareableOslMutex() )
446 : , ::cppu::OPropertySetHelper( *(static_cast< ::cppu::OBroadcastHelper* >(this)) )
447 : , ::cppu::OWeakObject ( )
448 : , m_xSMGR (xSMGR )
449 : , m_bListenForDocEvents (sal_False )
450 : , m_bListenForConfigChanges (sal_False )
451 : , m_nAutoSaveTimeIntervall (0 )
452 : , m_eJob (AutoRecovery::E_NO_JOB )
453 : , m_aAsyncDispatcher ( LINK( this, AutoRecovery, implts_asyncDispatch ) )
454 : , m_eTimerType (E_DONT_START_TIMER )
455 : , m_nIdPool (0 )
456 0 : , m_lListener (m_aLock.getShareableOslMutex() )
457 : , m_nDocCacheLock (0 )
458 : , m_nMinSpaceDocSave (MIN_DISCSPACE_DOCSAVE )
459 0 : , m_nMinSpaceConfigSave (MIN_DISCSPACE_CONFIGSAVE )
460 :
461 : #if OSL_DEBUG_LEVEL > 1
462 : , m_dbg_bMakeItFaster (sal_False )
463 : #endif
464 : {
465 0 : }
466 :
467 : //-----------------------------------------------
468 0 : AutoRecovery::~AutoRecovery()
469 : {
470 0 : implts_stopTimer();
471 0 : }
472 :
473 : //-----------------------------------------------
474 0 : void SAL_CALL AutoRecovery::dispatch(const css::util::URL& aURL ,
475 : const css::uno::Sequence< css::beans::PropertyValue >& lArguments)
476 : throw(css::uno::RuntimeException)
477 : {
478 : LOG_RECOVERY("AutoRecovery::dispatch() starts ...")
479 : LOG_RECOVERY(U2B(aURL.Complete).getStr())
480 :
481 : // valid request ?
482 0 : sal_Int32 eNewJob = AutoRecovery::implst_classifyJob(aURL);
483 0 : if (eNewJob == AutoRecovery::E_NO_JOB)
484 : return;
485 :
486 : // SAFE -> ----------------------------------
487 0 : WriteGuard aWriteLock(m_aLock);
488 :
489 : // still running operation ... ignoring AUTO_SAVE.
490 : // All other requests has higher prio!
491 0 : if (
492 : ( m_eJob != AutoRecovery::E_NO_JOB ) &&
493 : ((m_eJob & AutoRecovery::E_AUTO_SAVE ) != AutoRecovery::E_AUTO_SAVE)
494 : )
495 : {
496 : LOG_WARNING("AutoRecovery::dispatch()", "There is already an asynchronous dispatch() running. New request will be ignored!")
497 : return;
498 : }
499 :
500 0 : ::comphelper::SequenceAsHashMap lArgs(lArguments);
501 :
502 : // check if somewhere wish to disable recovery temp. for this office session
503 : // This can be done immediatly ... must not been done asynchronous.
504 0 : if ((eNewJob & AutoRecovery::E_DISABLE_AUTORECOVERY) == AutoRecovery::E_DISABLE_AUTORECOVERY)
505 : {
506 : // it's important to set a flag internaly, so AutoRecovery will be supressed - even if it's requested.
507 0 : m_eJob |= eNewJob;
508 0 : implts_stopTimer();
509 0 : implts_stopListening();
510 : return;
511 : }
512 :
513 : // disable/enable AutoSave for this office session only
514 : // independend from the configuration entry.
515 0 : if ((eNewJob & AutoRecovery::E_SET_AUTOSAVE_STATE) == AutoRecovery::E_SET_AUTOSAVE_STATE)
516 : {
517 0 : sal_Bool bOn = lArgs.getUnpackedValueOrDefault(PROP_AUTOSAVE_STATE, (sal_Bool)sal_True);
518 0 : if (bOn)
519 : {
520 : // dont enable AutoSave hardly !
521 : // reload configuration to know the current state.
522 0 : implts_readAutoSaveConfig();
523 0 : implts_updateTimer();
524 : // can it happen that might be the listener was stopped ? .-)
525 : // make sure it runs always ... even if AutoSave itself was disabled temporarly.
526 0 : implts_startListening();
527 : }
528 : else
529 : {
530 0 : implts_stopTimer();
531 0 : m_eJob &= ~AutoRecovery::E_AUTO_SAVE;
532 0 : m_eTimerType = AutoRecovery::E_DONT_START_TIMER;
533 : }
534 : return;
535 : }
536 :
537 0 : m_eJob |= eNewJob;
538 :
539 0 : sal_Bool bAsync = lArgs.getUnpackedValueOrDefault(PROP_DISPATCH_ASYNCHRON, (sal_Bool)sal_False);
540 0 : DispatchParams aParams (lArgs, static_cast< css::frame::XDispatch* >(this));
541 :
542 : // Hold this instance alive till the asynchronous operation will be finished.
543 0 : if (bAsync)
544 0 : m_aDispatchParams = aParams;
545 :
546 0 : aWriteLock.unlock();
547 : // <- SAFE ----------------------------------
548 :
549 0 : if (bAsync)
550 0 : m_aAsyncDispatcher.Post(0);
551 : else
552 0 : implts_dispatch(aParams);
553 : }
554 :
555 0 : void AutoRecovery::ListenerInformer::start()
556 : {
557 : m_rRecovery.implts_informListener(m_eJob,
558 0 : AutoRecovery::implst_createFeatureStateEvent(m_eJob, OPERATION_START, NULL));
559 0 : }
560 :
561 0 : void AutoRecovery::ListenerInformer::stop()
562 : {
563 0 : if (m_bStopped)
564 0 : return;
565 : m_rRecovery.implts_informListener(m_eJob,
566 0 : AutoRecovery::implst_createFeatureStateEvent(m_eJob, OPERATION_STOP, NULL));
567 0 : m_bStopped = true;
568 : }
569 :
570 : //-----------------------------------------------
571 0 : void AutoRecovery::implts_dispatch(const DispatchParams& aParams)
572 : {
573 : // SAFE -> ----------------------------------
574 0 : WriteGuard aWriteLock(m_aLock);
575 0 : sal_Int32 eJob = m_eJob;
576 0 : aWriteLock.unlock();
577 : // <- SAFE ----------------------------------
578 :
579 : // in case a new dispatch overwrites a may ba active AutoSave session
580 : // we must restore this session later. see below ...
581 0 : sal_Bool bWasAutoSaveActive = ((eJob & AutoRecovery::E_AUTO_SAVE) == AutoRecovery::E_AUTO_SAVE);
582 :
583 : // On the other side it make no sense to reactivate the AutoSave operation
584 : // if the new dispatch indicates a final decision ...
585 : // E.g. an EmergencySave/SessionSave indicates the end of life of the current office session.
586 : // It make no sense to reactivate an AutoSave then.
587 : // But a Recovery or SessionRestore should reactivate a may be already active AutoSave.
588 0 : sal_Bool bAllowAutoSaveReactivation = sal_True;
589 :
590 0 : implts_stopTimer();
591 0 : implts_stopListening();
592 :
593 0 : ListenerInformer aListenerInformer(*this, eJob);
594 0 : aListenerInformer.start();
595 :
596 : try
597 : {
598 : // Auto save is called from our internal timer ... not via dispatch() API !
599 : // else
600 0 : if (
601 : ((eJob & AutoRecovery::E_PREPARE_EMERGENCY_SAVE) == AutoRecovery::E_PREPARE_EMERGENCY_SAVE) &&
602 : ((eJob & AutoRecovery::E_DISABLE_AUTORECOVERY ) != AutoRecovery::E_DISABLE_AUTORECOVERY )
603 : )
604 : {
605 : LOG_RECOVERY("... prepare emergency save ...")
606 0 : bAllowAutoSaveReactivation = sal_False;
607 0 : implts_prepareEmergencySave();
608 : }
609 : else
610 0 : if (
611 : ((eJob & AutoRecovery::E_EMERGENCY_SAVE ) == AutoRecovery::E_EMERGENCY_SAVE ) &&
612 : ((eJob & AutoRecovery::E_DISABLE_AUTORECOVERY) != AutoRecovery::E_DISABLE_AUTORECOVERY)
613 : )
614 : {
615 : LOG_RECOVERY("... do emergency save ...")
616 0 : bAllowAutoSaveReactivation = sal_False;
617 0 : implts_doEmergencySave(aParams);
618 : }
619 : else
620 0 : if (
621 : ((eJob & AutoRecovery::E_RECOVERY ) == AutoRecovery::E_RECOVERY ) &&
622 : ((eJob & AutoRecovery::E_DISABLE_AUTORECOVERY) != AutoRecovery::E_DISABLE_AUTORECOVERY)
623 : )
624 : {
625 : LOG_RECOVERY("... do recovery ...")
626 0 : implts_doRecovery(aParams);
627 : }
628 : else
629 0 : if (
630 : ((eJob & AutoRecovery::E_SESSION_SAVE ) == AutoRecovery::E_SESSION_SAVE ) &&
631 : ((eJob & AutoRecovery::E_DISABLE_AUTORECOVERY) != AutoRecovery::E_DISABLE_AUTORECOVERY)
632 : )
633 : {
634 : LOG_RECOVERY("... do session save ...")
635 0 : bAllowAutoSaveReactivation = sal_False;
636 0 : implts_doSessionSave(aParams);
637 : }
638 : else
639 0 : if (
640 : ((eJob & AutoRecovery::E_SESSION_QUIET_QUIT ) == AutoRecovery::E_SESSION_QUIET_QUIT ) &&
641 : ((eJob & AutoRecovery::E_DISABLE_AUTORECOVERY) != AutoRecovery::E_DISABLE_AUTORECOVERY)
642 : )
643 : {
644 : LOG_RECOVERY("... do session quiet quit ...")
645 0 : bAllowAutoSaveReactivation = sal_False;
646 0 : implts_doSessionQuietQuit(aParams);
647 : }
648 : else
649 0 : if (
650 : ((eJob & AutoRecovery::E_SESSION_RESTORE ) == AutoRecovery::E_SESSION_RESTORE ) &&
651 : ((eJob & AutoRecovery::E_DISABLE_AUTORECOVERY) != AutoRecovery::E_DISABLE_AUTORECOVERY)
652 : )
653 : {
654 : LOG_RECOVERY("... do session restore ...")
655 0 : implts_doSessionRestore(aParams);
656 : }
657 : else
658 0 : if (
659 : ((eJob & AutoRecovery::E_ENTRY_BACKUP ) == AutoRecovery::E_ENTRY_BACKUP ) &&
660 : ((eJob & AutoRecovery::E_DISABLE_AUTORECOVERY) != AutoRecovery::E_DISABLE_AUTORECOVERY)
661 : )
662 0 : implts_backupWorkingEntry(aParams);
663 : else
664 0 : if (
665 : ((eJob & AutoRecovery::E_ENTRY_CLEANUP ) == AutoRecovery::E_ENTRY_CLEANUP ) &&
666 : ((eJob & AutoRecovery::E_DISABLE_AUTORECOVERY) != AutoRecovery::E_DISABLE_AUTORECOVERY)
667 : )
668 0 : implts_cleanUpWorkingEntry(aParams);
669 : }
670 0 : catch(const css::uno::RuntimeException&)
671 : {
672 0 : throw;
673 : }
674 0 : catch(const css::uno::Exception&)
675 : {
676 : // TODO better error handling
677 : }
678 :
679 0 : aListenerInformer.stop();
680 :
681 : // SAFE -> ----------------------------------
682 0 : aWriteLock.lock();
683 0 : m_eJob = E_NO_JOB;
684 0 : if (
685 : (bAllowAutoSaveReactivation) &&
686 : (bWasAutoSaveActive )
687 : )
688 : {
689 0 : m_eJob |= AutoRecovery::E_AUTO_SAVE;
690 : }
691 :
692 0 : aWriteLock.unlock();
693 : // <- SAFE ----------------------------------
694 :
695 : // depends on bAllowAutoSaveReactivation implicitly by looking on m_eJob=E_AUTO_SAVE! see before ...
696 0 : implts_updateTimer();
697 :
698 0 : if (bAllowAutoSaveReactivation)
699 0 : implts_startListening();
700 0 : }
701 :
702 : //-----------------------------------------------
703 0 : void SAL_CALL AutoRecovery::addStatusListener(const css::uno::Reference< css::frame::XStatusListener >& xListener,
704 : const css::util::URL& aURL )
705 : throw(css::uno::RuntimeException)
706 : {
707 0 : if (!xListener.is())
708 0 : throw css::uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Invalid listener reference.")), static_cast< css::frame::XDispatch* >(this));
709 : // container is threadsafe by using a shared mutex!
710 0 : m_lListener.addInterface(aURL.Complete, xListener);
711 :
712 : // REENTRANT !? -> --------------------------------
713 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
714 :
715 : // THREAD SAFE -> ----------------------------------
716 0 : ReadGuard aReadLock(m_aLock);
717 :
718 0 : AutoRecovery::TDocumentList::iterator pIt;
719 0 : for( pIt = m_lDocCache.begin();
720 0 : pIt != m_lDocCache.end() ;
721 : ++pIt )
722 : {
723 0 : AutoRecovery::TDocumentInfo& rInfo = *pIt;
724 0 : css::frame::FeatureStateEvent aEvent = AutoRecovery::implst_createFeatureStateEvent(m_eJob, OPERATION_UPDATE, &rInfo);
725 :
726 : // <- SAFE ------------------------------
727 0 : aReadLock.unlock();
728 0 : xListener->statusChanged(aEvent);
729 0 : aReadLock.lock();
730 : // SAFE -> ------------------------------
731 0 : }
732 :
733 0 : aReadLock.unlock();
734 : // <- SAFE ----------------------------------
735 0 : }
736 :
737 : //-----------------------------------------------
738 0 : void SAL_CALL AutoRecovery::removeStatusListener(const css::uno::Reference< css::frame::XStatusListener >& xListener,
739 : const css::util::URL& aURL )
740 : throw(css::uno::RuntimeException)
741 : {
742 0 : if (!xListener.is())
743 0 : throw css::uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Invalid listener reference.")), static_cast< css::frame::XDispatch* >(this));
744 : // container is threadsafe by using a shared mutex!
745 0 : m_lListener.removeInterface(aURL.Complete, xListener);
746 0 : }
747 :
748 : //-----------------------------------------------
749 0 : void SAL_CALL AutoRecovery::notifyEvent(const css::document::EventObject& aEvent)
750 : throw(css::uno::RuntimeException)
751 : {
752 0 : css::uno::Reference< css::frame::XModel > xDocument(aEvent.Source, css::uno::UNO_QUERY);
753 :
754 : // new document => put it into the internal list
755 0 : if (
756 0 : (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_NEW))) ||
757 0 : (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_LOAD)))
758 : )
759 : {
760 0 : implts_registerDocument(xDocument);
761 : }
762 : // document modified => set its modify state new (means modified against the original file!)
763 0 : else if ( aEvent.EventName == EVENT_ON_MODIFYCHANGED )
764 : {
765 0 : implts_updateModifiedState(xDocument);
766 : }
767 : /* at least one document starts saving process =>
768 : Our application code isnt ready for multiple save requests
769 : at the same time. So we have to supress our AutoSave feature
770 : for the moment, till this other save requests will be finished.
771 : */
772 0 : else if (
773 0 : (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_SAVE))) ||
774 0 : (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_SAVEAS))) ||
775 0 : (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_SAVETO)))
776 : )
777 : {
778 0 : implts_updateDocumentUsedForSavingState(xDocument, SAVE_IN_PROGRESS);
779 : }
780 : // document saved => remove tmp. files - but hold config entries alive!
781 0 : else if (
782 0 : (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_SAVEDONE))) ||
783 0 : (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_SAVEASDONE)))
784 : )
785 : {
786 0 : implts_markDocumentAsSaved(xDocument);
787 0 : implts_updateDocumentUsedForSavingState(xDocument, SAVE_FINISHED);
788 : }
789 : /* document saved as copy => mark it as "non used by concurrent save operation".
790 : so we can try to create a backup copy if next time AutoSave is started too.
791 : Dont remove temp. files or change the modified state of the document!
792 : It was not realy saved to the original file ...
793 : */
794 0 : else if ( aEvent.EventName == EVENT_ON_SAVETODONE )
795 : {
796 0 : implts_updateDocumentUsedForSavingState(xDocument, SAVE_FINISHED);
797 : }
798 : // If saving of a document failed by an error ... we have to save this document
799 : // by ourself next time AutoSave or EmergencySave is triggered.
800 : // But we can reset the state "used for other save requests". Otherwhise
801 : // these documents will never be saved!
802 0 : else if (
803 0 : (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_SAVEFAILED))) ||
804 0 : (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_SAVEASFAILED))) ||
805 0 : (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_SAVETOFAILED)))
806 : )
807 : {
808 0 : implts_updateDocumentUsedForSavingState(xDocument, SAVE_FINISHED);
809 : }
810 : // document closed => remove temp. files and configuration entries
811 0 : else if ( aEvent.EventName == EVENT_ON_UNLOAD )
812 : {
813 0 : implts_deregisterDocument(xDocument, sal_True); // sal_True => stop listening for disposing() !
814 0 : }
815 0 : }
816 :
817 : //-----------------------------------------------
818 0 : void SAL_CALL AutoRecovery::changesOccurred(const css::util::ChangesEvent& aEvent)
819 : throw(css::uno::RuntimeException)
820 : {
821 0 : const css::uno::Sequence< css::util::ElementChange > lChanges (aEvent.Changes);
822 0 : const css::util::ElementChange* pChanges = lChanges.getConstArray();
823 :
824 0 : sal_Int32 c = lChanges.getLength();
825 0 : sal_Int32 i = 0;
826 :
827 : // SAFE -> ----------------------------------
828 0 : WriteGuard aWriteLock(m_aLock);
829 :
830 : // Changes of the configuration must be ignored if AutoSave/Recovery was disabled for this
831 : // office session. That can happen if e.g. the command line arguments "--norestore" or "--headless"
832 : // was set.
833 0 : if ((m_eJob & AutoRecovery::E_DISABLE_AUTORECOVERY) == AutoRecovery::E_DISABLE_AUTORECOVERY)
834 0 : return;
835 :
836 0 : for (i=0; i<c; ++i)
837 : {
838 0 : ::rtl::OUString sPath;
839 0 : pChanges[i].Accessor >>= sPath;
840 :
841 0 : if ( sPath == CFG_ENTRY_AUTOSAVE_ENABLED )
842 : {
843 0 : sal_Bool bEnabled = sal_False;
844 0 : if (pChanges[i].Element >>= bEnabled)
845 : {
846 0 : if (bEnabled)
847 : {
848 0 : m_eJob |= AutoRecovery::E_AUTO_SAVE;
849 0 : m_eTimerType = AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL;
850 : }
851 : else
852 : {
853 0 : m_eJob &= ~AutoRecovery::E_AUTO_SAVE;
854 0 : m_eTimerType = AutoRecovery::E_DONT_START_TIMER;
855 : }
856 : }
857 : }
858 : else
859 0 : if ( sPath == CFG_ENTRY_AUTOSAVE_TIMEINTERVALL )
860 0 : pChanges[i].Element >>= m_nAutoSaveTimeIntervall;
861 0 : }
862 :
863 0 : aWriteLock.unlock();
864 : // <- SAFE ----------------------------------
865 :
866 : // Note: This call stops the timer and starts it again.
867 : // But it checks the different timer states internaly and
868 : // may be supress the restart!
869 0 : implts_updateTimer();
870 : }
871 :
872 : //-----------------------------------------------
873 0 : void SAL_CALL AutoRecovery::modified(const css::lang::EventObject& aEvent)
874 : throw(css::uno::RuntimeException)
875 : {
876 0 : css::uno::Reference< css::frame::XModel > xDocument(aEvent.Source, css::uno::UNO_QUERY);
877 0 : if (! xDocument.is())
878 0 : return;
879 :
880 0 : implts_markDocumentModifiedAgainstLastBackup(xDocument);
881 : }
882 :
883 : //-----------------------------------------------
884 0 : void SAL_CALL AutoRecovery::disposing(const css::lang::EventObject& aEvent)
885 : throw(css::uno::RuntimeException)
886 : {
887 : // SAFE -> ----------------------------------
888 0 : WriteGuard aWriteLock(m_aLock);
889 :
890 0 : if (aEvent.Source == m_xNewDocBroadcaster)
891 : {
892 0 : m_xNewDocBroadcaster.clear();
893 : return;
894 : }
895 :
896 0 : if (aEvent.Source == m_xRecoveryCFG)
897 : {
898 0 : m_xRecoveryCFG.clear();
899 : return;
900 : }
901 :
902 : // dispose from one of our cached documents ?
903 : // Normaly they should send a OnUnload message ...
904 : // But some stacktraces shows another possible use case .-)
905 0 : css::uno::Reference< css::frame::XModel > xDocument(aEvent.Source, css::uno::UNO_QUERY);
906 0 : if (xDocument.is())
907 : {
908 0 : implts_deregisterDocument(xDocument, sal_False); // sal_False => dont call removeEventListener() .. because it's not needed here
909 : return;
910 0 : }
911 :
912 : // <- SAFE ----------------------------------
913 : }
914 :
915 : //-----------------------------------------------
916 0 : css::uno::Reference< css::container::XNameAccess > AutoRecovery::implts_openConfig()
917 : {
918 : // SAFE -> ----------------------------------
919 0 : WriteGuard aWriteLock(m_aLock);
920 :
921 0 : if (m_xRecoveryCFG.is())
922 0 : return m_xRecoveryCFG;
923 0 : css::uno::Reference< css::uno::XComponentContext > xContext = comphelper::getComponentContext(m_xSMGR);
924 :
925 0 : aWriteLock.unlock();
926 : // <- SAFE ----------------------------------
927 :
928 0 : rtl::OUString sCFG_PACKAGE_RECOVERY(RTL_CONSTASCII_USTRINGPARAM(CFG_PACKAGE_RECOVERY));
929 : // throws a RuntimeException if an error occure!
930 : css::uno::Reference< css::container::XNameAccess > xCFG(
931 : ::comphelper::ConfigurationHelper::openConfig(xContext, sCFG_PACKAGE_RECOVERY, ::comphelper::ConfigurationHelper::E_STANDARD),
932 0 : css::uno::UNO_QUERY);
933 :
934 0 : sal_Int32 nMinSpaceDocSave = MIN_DISCSPACE_DOCSAVE;
935 0 : sal_Int32 nMinSpaceConfigSave = MIN_DISCSPACE_CONFIGSAVE;
936 :
937 : try
938 : {
939 0 : rtl::OUString sCFG_PATH_AUTOSAVE(CFG_PATH_AUTOSAVE);
940 : ::comphelper::ConfigurationHelper::readDirectKey(xContext,
941 : sCFG_PACKAGE_RECOVERY,
942 : sCFG_PATH_AUTOSAVE,
943 : rtl::OUString(CFG_ENTRY_MINSPACE_DOCSAVE),
944 0 : ::comphelper::ConfigurationHelper::E_STANDARD) >>= nMinSpaceDocSave;
945 :
946 : ::comphelper::ConfigurationHelper::readDirectKey(xContext,
947 : sCFG_PACKAGE_RECOVERY,
948 : sCFG_PATH_AUTOSAVE,
949 : rtl::OUString(CFG_ENTRY_MINSPACE_CONFIGSAVE),
950 0 : ::comphelper::ConfigurationHelper::E_STANDARD) >>= nMinSpaceConfigSave;
951 : }
952 0 : catch(const css::uno::Exception&)
953 : {
954 : // These config keys are not sooooo important, that
955 : // we are interested on errors here realy .-)
956 0 : nMinSpaceDocSave = MIN_DISCSPACE_DOCSAVE;
957 0 : nMinSpaceConfigSave = MIN_DISCSPACE_CONFIGSAVE;
958 : }
959 :
960 : // SAFE -> ----------------------------------
961 0 : aWriteLock.lock();
962 0 : m_xRecoveryCFG = xCFG;
963 0 : m_nMinSpaceDocSave = nMinSpaceDocSave;
964 0 : m_nMinSpaceConfigSave = nMinSpaceConfigSave;
965 0 : aWriteLock.unlock();
966 : // <- SAFE ----------------------------------
967 :
968 0 : return xCFG;
969 : }
970 :
971 : //-----------------------------------------------
972 0 : void AutoRecovery::implts_readAutoSaveConfig()
973 : {
974 0 : css::uno::Reference< css::container::XHierarchicalNameAccess > xCommonRegistry(implts_openConfig(), css::uno::UNO_QUERY);
975 :
976 : // AutoSave [bool]
977 0 : sal_Bool bEnabled = sal_False;
978 0 : xCommonRegistry->getByHierarchicalName(rtl::OUString(CFG_ENTRY_AUTOSAVE_ENABLED)) >>= bEnabled;
979 :
980 : // SAFE -> ------------------------------
981 0 : WriteGuard aWriteLock(m_aLock);
982 0 : if (bEnabled)
983 : {
984 0 : m_eJob |= AutoRecovery::E_AUTO_SAVE;
985 0 : m_eTimerType = AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL;
986 : }
987 : else
988 : {
989 0 : m_eJob &= ~AutoRecovery::E_AUTO_SAVE;
990 0 : m_eTimerType = AutoRecovery::E_DONT_START_TIMER;
991 : }
992 0 : aWriteLock.unlock();
993 : // <- SAFE ------------------------------
994 :
995 : // AutoSaveTimeIntervall [int] in min
996 0 : sal_Int32 nTimeIntervall = 15;
997 0 : xCommonRegistry->getByHierarchicalName(rtl::OUString(CFG_ENTRY_AUTOSAVE_TIMEINTERVALL)) >>= nTimeIntervall;
998 :
999 : // SAFE -> ----------------------------------
1000 0 : aWriteLock.lock();
1001 0 : m_nAutoSaveTimeIntervall = nTimeIntervall;
1002 0 : aWriteLock.unlock();
1003 : // <- SAFE ----------------------------------
1004 0 : }
1005 :
1006 : //-----------------------------------------------
1007 0 : void AutoRecovery::implts_readConfig()
1008 : {
1009 0 : implts_readAutoSaveConfig();
1010 :
1011 0 : css::uno::Reference< css::container::XHierarchicalNameAccess > xCommonRegistry(implts_openConfig(), css::uno::UNO_QUERY);
1012 :
1013 : // REENTRANT -> --------------------------------
1014 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_ADD_REMOVE);
1015 :
1016 : // THREADSAFE -> -------------------------------
1017 0 : WriteGuard aWriteLock(m_aLock);
1018 : // reset current cache load cache
1019 0 : m_lDocCache.clear();
1020 0 : m_nIdPool = 0;
1021 0 : aWriteLock.unlock();
1022 : // <- THREADSAFE -------------------------------
1023 :
1024 0 : aCacheLock.unlock();
1025 : // <- REENTRANT --------------------------------
1026 :
1027 0 : css::uno::Any aValue;
1028 :
1029 : // RecoveryList [set]
1030 0 : aValue = xCommonRegistry->getByHierarchicalName(rtl::OUString(CFG_ENTRY_RECOVERYLIST));
1031 0 : css::uno::Reference< css::container::XNameAccess > xList;
1032 0 : aValue >>= xList;
1033 0 : if (xList.is())
1034 : {
1035 0 : const rtl::OUString sRECOVERY_ITEM_BASE_IDENTIFIER(RECOVERY_ITEM_BASE_IDENTIFIER);
1036 0 : const css::uno::Sequence< ::rtl::OUString > lItems = xList->getElementNames();
1037 0 : const ::rtl::OUString* pItems = lItems.getConstArray();
1038 0 : sal_Int32 c = lItems.getLength();
1039 0 : sal_Int32 i = 0;
1040 :
1041 : // REENTRANT -> --------------------------
1042 0 : aCacheLock.lock(LOCK_FOR_CACHE_ADD_REMOVE);
1043 :
1044 0 : for (i=0; i<c; ++i)
1045 : {
1046 0 : css::uno::Reference< css::beans::XPropertySet > xItem;
1047 0 : xList->getByName(pItems[i]) >>= xItem;
1048 0 : if (!xItem.is())
1049 0 : continue;
1050 :
1051 0 : AutoRecovery::TDocumentInfo aInfo;
1052 0 : aInfo.NewTempURL = ::rtl::OUString();
1053 0 : aInfo.Document = css::uno::Reference< css::frame::XModel >();
1054 0 : xItem->getPropertyValue(rtl::OUString(CFG_ENTRY_PROP_ORIGINALURL)) >>= aInfo.OrgURL ;
1055 0 : xItem->getPropertyValue(rtl::OUString(CFG_ENTRY_PROP_TEMPURL)) >>= aInfo.OldTempURL ;
1056 0 : xItem->getPropertyValue(rtl::OUString(CFG_ENTRY_PROP_TEMPLATEURL)) >>= aInfo.TemplateURL ;
1057 0 : xItem->getPropertyValue(rtl::OUString(CFG_ENTRY_PROP_FILTER)) >>= aInfo.RealFilter ;
1058 0 : xItem->getPropertyValue(rtl::OUString(CFG_ENTRY_PROP_DOCUMENTSTATE)) >>= aInfo.DocumentState;
1059 0 : xItem->getPropertyValue(rtl::OUString(CFG_ENTRY_PROP_MODULE)) >>= aInfo.AppModule;
1060 0 : xItem->getPropertyValue(rtl::OUString(CFG_ENTRY_PROP_TITLE)) >>= aInfo.Title;
1061 0 : xItem->getPropertyValue(rtl::OUString(CFG_ENTRY_PROP_VIEWNAMES)) >>= aInfo.ViewNames;
1062 0 : implts_specifyAppModuleAndFactory(aInfo);
1063 0 : implts_specifyDefaultFilterAndExtension(aInfo);
1064 :
1065 0 : if (pItems[i].indexOf(sRECOVERY_ITEM_BASE_IDENTIFIER)==0)
1066 : {
1067 0 : ::rtl::OUString sID = pItems[i].copy(sRECOVERY_ITEM_BASE_IDENTIFIER.getLength());
1068 0 : aInfo.ID = sID.toInt32();
1069 : // SAFE -> ----------------------
1070 0 : aWriteLock.lock();
1071 0 : if (aInfo.ID > m_nIdPool)
1072 : {
1073 0 : m_nIdPool = aInfo.ID+1;
1074 : LOG_ASSERT(m_nIdPool>=0, "AutoRecovery::implts_readConfig()\nOverflow of IDPool detected!")
1075 : }
1076 0 : aWriteLock.unlock();
1077 : // <- SAFE ----------------------
1078 : }
1079 : #ifdef ENABLE_WARNINGS
1080 : else
1081 : LOG_WARNING("AutoRecovery::implts_readConfig()", "Who changed numbering of recovery items? Cache will be inconsistent then! I do not know, what will happen next time .-)")
1082 : #endif
1083 :
1084 : // THREADSAFE -> --------------------------
1085 0 : aWriteLock.lock();
1086 0 : m_lDocCache.push_back(aInfo);
1087 0 : aWriteLock.unlock();
1088 : // <- THREADSAFE --------------------------
1089 0 : }
1090 :
1091 0 : aCacheLock.unlock();
1092 : // <- REENTRANT --------------------------
1093 : }
1094 :
1095 0 : implts_updateTimer();
1096 0 : }
1097 :
1098 : //-----------------------------------------------
1099 0 : void AutoRecovery::implts_specifyDefaultFilterAndExtension(AutoRecovery::TDocumentInfo& rInfo)
1100 : {
1101 0 : if (rInfo.AppModule.isEmpty())
1102 : {
1103 : throw css::uno::RuntimeException(
1104 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Cant find out the default filter and its extension, if no application module is known!")),
1105 0 : static_cast< css::frame::XDispatch* >(this));
1106 : }
1107 :
1108 : // SAFE -> ----------------------------------
1109 0 : ReadGuard aReadLock(m_aLock);
1110 0 : css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1111 0 : css::uno::Reference< css::container::XNameAccess> xCFG = m_xModuleCFG;
1112 0 : aReadLock.unlock();
1113 : // <- SAFE ----------------------------------
1114 :
1115 : try
1116 : {
1117 0 : if (! xCFG.is())
1118 : {
1119 : // open module config on demand and cache the update access
1120 : xCFG = css::uno::Reference< css::container::XNameAccess >(
1121 : ::comphelper::ConfigurationHelper::openConfig(comphelper::getComponentContext(xSMGR), rtl::OUString(CFG_PACKAGE_MODULES),
1122 : ::comphelper::ConfigurationHelper::E_STANDARD),
1123 0 : css::uno::UNO_QUERY_THROW);
1124 :
1125 : // SAFE -> ----------------------------------
1126 0 : WriteGuard aWriteLock(m_aLock);
1127 0 : m_xModuleCFG = xCFG;
1128 0 : aWriteLock.unlock();
1129 : // <- SAFE ----------------------------------
1130 : }
1131 :
1132 : css::uno::Reference< css::container::XNameAccess > xModuleProps(
1133 0 : xCFG->getByName(rInfo.AppModule),
1134 0 : css::uno::UNO_QUERY_THROW);
1135 :
1136 0 : xModuleProps->getByName(rtl::OUString(CFG_ENTRY_REALDEFAULTFILTER)) >>= rInfo.DefaultFilter;
1137 :
1138 0 : css::uno::Reference< css::container::XNameAccess > xFilterCFG(xSMGR->createInstance(SERVICENAME_FILTERFACTORY), css::uno::UNO_QUERY_THROW);
1139 0 : css::uno::Reference< css::container::XNameAccess > xTypeCFG (xSMGR->createInstance(SERVICENAME_TYPEDETECTION), css::uno::UNO_QUERY_THROW);
1140 :
1141 0 : ::comphelper::SequenceAsHashMap lFilterProps (xFilterCFG->getByName(rInfo.DefaultFilter));
1142 0 : ::rtl::OUString sTypeRegistration = lFilterProps.getUnpackedValueOrDefault(rtl::OUString(FILTER_PROP_TYPE), ::rtl::OUString());
1143 0 : ::comphelper::SequenceAsHashMap lTypeProps (xTypeCFG->getByName(sTypeRegistration));
1144 0 : css::uno::Sequence< ::rtl::OUString > lExtensions = lTypeProps.getUnpackedValueOrDefault(rtl::OUString(TYPE_PROP_EXTENSIONS), css::uno::Sequence< ::rtl::OUString >());
1145 0 : if (lExtensions.getLength())
1146 : {
1147 0 : rInfo.Extension = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("."));
1148 0 : rInfo.Extension += lExtensions[0];
1149 : }
1150 : else
1151 0 : rInfo.Extension = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".unknown"));
1152 : }
1153 0 : catch(const css::uno::Exception&)
1154 : {
1155 0 : rInfo.DefaultFilter = ::rtl::OUString();
1156 0 : rInfo.Extension = ::rtl::OUString();
1157 0 : }
1158 0 : }
1159 :
1160 : //-----------------------------------------------
1161 0 : void AutoRecovery::implts_specifyAppModuleAndFactory(AutoRecovery::TDocumentInfo& rInfo)
1162 : {
1163 0 : ENSURE_OR_THROW2(
1164 : !rInfo.AppModule.isEmpty() || rInfo.Document.is(),
1165 : "Cant find out the application module nor its factory URL, if no application module (or a suitable) document is known!",
1166 : *this );
1167 :
1168 : // SAFE -> ----------------------------------
1169 0 : ReadGuard aReadLock(m_aLock);
1170 0 : css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1171 0 : aReadLock.unlock();
1172 : // <- SAFE ----------------------------------
1173 :
1174 0 : css::uno::Reference< css::frame::XModuleManager2 > xManager = ModuleManager::create( comphelper::getComponentContext(xSMGR) );
1175 :
1176 0 : if (rInfo.AppModule.isEmpty())
1177 0 : rInfo.AppModule = xManager->identify(rInfo.Document);
1178 :
1179 0 : ::comphelper::SequenceAsHashMap lModuleDescription(xManager->getByName(rInfo.AppModule));
1180 0 : lModuleDescription[rtl::OUString(CFG_ENTRY_PROP_EMPTYDOCUMENTURL)] >>= rInfo.FactoryURL;
1181 0 : lModuleDescription[rtl::OUString(CFG_ENTRY_PROP_FACTORYSERVICE)] >>= rInfo.FactoryService;
1182 0 : }
1183 :
1184 : //-----------------------------------------------
1185 0 : void AutoRecovery::implts_collectActiveViewNames( AutoRecovery::TDocumentInfo& i_rInfo )
1186 : {
1187 0 : ENSURE_OR_THROW2( i_rInfo.Document.is(), "need at document, at the very least", *this );
1188 :
1189 0 : i_rInfo.ViewNames.realloc(0);
1190 :
1191 : // obtain list of controllers of this document
1192 0 : ::std::vector< ::rtl::OUString > aViewNames;
1193 0 : const Reference< XModel2 > xModel( i_rInfo.Document, UNO_QUERY );
1194 0 : if ( xModel.is() )
1195 : {
1196 0 : const Reference< XEnumeration > xEnumControllers( xModel->getControllers() );
1197 0 : while ( xEnumControllers->hasMoreElements() )
1198 : {
1199 0 : const Reference< XController2 > xController( xEnumControllers->nextElement(), UNO_QUERY );
1200 0 : ::rtl::OUString sViewName;
1201 0 : if ( xController.is() )
1202 0 : sViewName = xController->getViewControllerName();
1203 : OSL_ENSURE( !sViewName.isEmpty(), "AutoRecovery::implts_collectActiveViewNames: (no XController2 ->) no view name -> no recovery of this view!" );
1204 :
1205 0 : if ( !sViewName.isEmpty() )
1206 0 : aViewNames.push_back( sViewName );
1207 0 : }
1208 : }
1209 : else
1210 : {
1211 0 : const Reference< XController2 > xController( xModel->getCurrentController(), UNO_QUERY );
1212 0 : ::rtl::OUString sViewName;
1213 0 : if ( xController.is() )
1214 0 : sViewName = xController->getViewControllerName();
1215 : OSL_ENSURE( !sViewName.isEmpty(), "AutoRecovery::implts_collectActiveViewNames: (no XController2 ->) no view name -> no recovery of this view!" );
1216 :
1217 0 : if ( !sViewName.isEmpty() )
1218 0 : aViewNames.push_back( sViewName );
1219 : }
1220 :
1221 0 : i_rInfo.ViewNames.realloc( aViewNames.size() );
1222 0 : ::std::copy( aViewNames.begin(), aViewNames.end(), i_rInfo.ViewNames.getArray() );
1223 0 : }
1224 :
1225 : //-----------------------------------------------
1226 0 : void AutoRecovery::implts_persistAllActiveViewNames()
1227 : {
1228 : // SAFE -> ----------------------------------
1229 0 : WriteGuard aWriteLock(m_aLock);
1230 :
1231 : // This list will be filled with every document
1232 0 : AutoRecovery::TDocumentList::iterator pIt;
1233 0 : for ( pIt = m_lDocCache.begin();
1234 0 : pIt != m_lDocCache.end() ;
1235 : ++pIt )
1236 : {
1237 0 : implts_collectActiveViewNames( *pIt );
1238 0 : implts_flushConfigItem( *pIt );
1239 0 : }
1240 0 : }
1241 :
1242 : //-----------------------------------------------
1243 0 : void AutoRecovery::implts_flushConfigItem(const AutoRecovery::TDocumentInfo& rInfo, sal_Bool bRemoveIt)
1244 : {
1245 0 : css::uno::Reference< css::container::XHierarchicalNameAccess > xCFG;
1246 :
1247 : try
1248 : {
1249 0 : xCFG = css::uno::Reference< css::container::XHierarchicalNameAccess >(implts_openConfig(), css::uno::UNO_QUERY_THROW);
1250 :
1251 0 : css::uno::Reference< css::container::XNameAccess > xCheck;
1252 0 : xCFG->getByHierarchicalName(rtl::OUString(CFG_ENTRY_RECOVERYLIST)) >>= xCheck;
1253 :
1254 0 : css::uno::Reference< css::container::XNameContainer > xModify(xCheck, css::uno::UNO_QUERY_THROW);
1255 0 : css::uno::Reference< css::lang::XSingleServiceFactory > xCreate(xCheck, css::uno::UNO_QUERY_THROW);
1256 :
1257 0 : ::rtl::OUStringBuffer sIDBuf;
1258 0 : sIDBuf.appendAscii(RTL_CONSTASCII_STRINGPARAM(RECOVERY_ITEM_BASE_IDENTIFIER));
1259 0 : sIDBuf.append((sal_Int32)rInfo.ID);
1260 0 : ::rtl::OUString sID = sIDBuf.makeStringAndClear();
1261 :
1262 : // remove
1263 0 : if (bRemoveIt)
1264 : {
1265 : // Catch NoSuchElementException.
1266 : // Its not a good idea inside multithreaded environments to call hasElement - removeElement.
1267 : // DO IT!
1268 : try
1269 : {
1270 0 : xModify->removeByName(sID);
1271 : }
1272 0 : catch(const css::container::NoSuchElementException&)
1273 : {
1274 0 : return;
1275 : }
1276 : }
1277 : else
1278 : {
1279 : // new/modify
1280 0 : css::uno::Reference< css::beans::XPropertySet > xSet;
1281 0 : sal_Bool bNew = (!xCheck->hasByName(sID));
1282 0 : if (bNew)
1283 0 : xSet = css::uno::Reference< css::beans::XPropertySet >(xCreate->createInstance(), css::uno::UNO_QUERY_THROW);
1284 : else
1285 0 : xCheck->getByName(sID) >>= xSet;
1286 :
1287 0 : xSet->setPropertyValue(rtl::OUString(CFG_ENTRY_PROP_ORIGINALURL), css::uno::makeAny(rInfo.OrgURL ));
1288 0 : xSet->setPropertyValue(rtl::OUString(CFG_ENTRY_PROP_TEMPURL), css::uno::makeAny(rInfo.OldTempURL ));
1289 0 : xSet->setPropertyValue(rtl::OUString(CFG_ENTRY_PROP_TEMPLATEURL), css::uno::makeAny(rInfo.TemplateURL ));
1290 0 : xSet->setPropertyValue(rtl::OUString(CFG_ENTRY_PROP_FILTER), css::uno::makeAny(rInfo.RealFilter));
1291 0 : xSet->setPropertyValue(rtl::OUString(CFG_ENTRY_PROP_DOCUMENTSTATE), css::uno::makeAny(rInfo.DocumentState));
1292 0 : xSet->setPropertyValue(rtl::OUString(CFG_ENTRY_PROP_MODULE), css::uno::makeAny(rInfo.AppModule));
1293 0 : xSet->setPropertyValue(rtl::OUString(CFG_ENTRY_PROP_TITLE), css::uno::makeAny(rInfo.Title));
1294 0 : xSet->setPropertyValue(rtl::OUString(CFG_ENTRY_PROP_VIEWNAMES), css::uno::makeAny(rInfo.ViewNames));
1295 :
1296 0 : if (bNew)
1297 0 : xModify->insertByName(sID, css::uno::makeAny(xSet));
1298 0 : }
1299 : }
1300 0 : catch(const css::uno::RuntimeException&)
1301 : {
1302 0 : throw;
1303 : }
1304 0 : catch(const css::uno::Exception&)
1305 : {
1306 : // ??? can it happen that a full disc let these set of operations fail too ???
1307 : }
1308 :
1309 0 : sal_Int32 nRetry = RETRY_STORE_ON_FULL_DISC_FOREVER;
1310 0 : do
1311 : {
1312 : try
1313 : {
1314 0 : css::uno::Reference< css::util::XChangesBatch > xFlush(xCFG, css::uno::UNO_QUERY_THROW);
1315 0 : xFlush->commitChanges();
1316 :
1317 : #ifdef TRIGGER_FULL_DISC_CHECK
1318 : throw css::uno::Exception();
1319 : #else // TRIGGER_FULL_DISC_CHECK
1320 0 : nRetry = 0;
1321 : #endif // TRIGGER_FULL_DISC_CHECK
1322 : }
1323 0 : catch(const css::uno::Exception&)
1324 : {
1325 : // a) FULL DISC seams to be the problem behind => show error and retry it forever (e.g. retry=300)
1326 : // b) unknown problem (may be locking problem) => reset RETRY value to more usefull value(!) (e.g. retry=3)
1327 : // c) unknown problem (may be locking problem) + 1..2 repeating operations => throw the original exception to force generation of a stacktrace !
1328 :
1329 : // SAFE ->
1330 0 : ReadGuard aReadLock(m_aLock);
1331 0 : sal_Int32 nMinSpaceConfigSave = m_nMinSpaceConfigSave;
1332 0 : aReadLock.unlock();
1333 : // <- SAFE
1334 :
1335 0 : if (! impl_enoughDiscSpace(nMinSpaceConfigSave))
1336 0 : AutoRecovery::impl_showFullDiscError();
1337 : else
1338 0 : if (nRetry > RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL)
1339 0 : nRetry = RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL;
1340 : else
1341 0 : if (nRetry <= GIVE_UP_RETRY)
1342 0 : throw; // force stacktrace to know if there exist might other reasons, why an AutoSave can fail !!!
1343 :
1344 0 : --nRetry;
1345 : }
1346 : }
1347 0 : while(nRetry>0);
1348 : }
1349 :
1350 : //-----------------------------------------------
1351 0 : void AutoRecovery::implts_startListening()
1352 : {
1353 : // SAFE -> ----------------------------------
1354 0 : ReadGuard aReadLock(m_aLock);
1355 0 : css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1356 0 : css::uno::Reference< css::util::XChangesNotifier > xCFG (m_xRecoveryCFG, css::uno::UNO_QUERY);
1357 0 : css::uno::Reference< css::frame::XGlobalEventBroadcaster > xBroadcaster = m_xNewDocBroadcaster;
1358 0 : sal_Bool bListenForDocEvents = m_bListenForDocEvents;
1359 0 : aReadLock.unlock();
1360 : // <- SAFE ----------------------------------
1361 :
1362 0 : if (
1363 0 : ( xCFG.is() ) &&
1364 0 : (! m_bListenForConfigChanges)
1365 : )
1366 : {
1367 0 : m_xRecoveryCFGListener = new WeakChangesListener(this);
1368 0 : xCFG->addChangesListener(m_xRecoveryCFGListener);
1369 0 : m_bListenForConfigChanges = sal_True;
1370 : }
1371 :
1372 0 : if (!xBroadcaster.is())
1373 : {
1374 0 : xBroadcaster = css::frame::GlobalEventBroadcaster::create( comphelper::getComponentContext(xSMGR) );
1375 : // SAFE -> ----------------------------------
1376 0 : WriteGuard aWriteLock(m_aLock);
1377 0 : m_xNewDocBroadcaster = xBroadcaster;
1378 0 : aWriteLock.unlock();
1379 : // <- SAFE ----------------------------------
1380 : }
1381 :
1382 0 : if (
1383 0 : ( xBroadcaster.is() ) &&
1384 : (! bListenForDocEvents)
1385 : )
1386 : {
1387 0 : m_xNewDocBroadcasterListener = new WeakDocumentEventListener(this);
1388 0 : xBroadcaster->addEventListener(m_xNewDocBroadcasterListener);
1389 : // SAFE ->
1390 0 : WriteGuard aWriteLock(m_aLock);
1391 0 : m_bListenForDocEvents = sal_True;
1392 0 : aWriteLock.unlock();
1393 : // <- SAFE
1394 0 : }
1395 0 : }
1396 :
1397 : //-----------------------------------------------
1398 0 : void AutoRecovery::implts_stopListening()
1399 : {
1400 : // SAFE -> ----------------------------------
1401 0 : ReadGuard aReadLock(m_aLock);
1402 : // Attention: Dont reset our internal members here too.
1403 : // May be we must work with our configuration, but dont wish to be informed
1404 : // about changes any longer. Needed e.g. during EMERGENCY_SAVE!
1405 0 : css::uno::Reference< css::util::XChangesNotifier > xCFG (m_xRecoveryCFG , css::uno::UNO_QUERY);
1406 0 : css::uno::Reference< css::document::XEventBroadcaster > xGlobalEventBroadcaster(m_xNewDocBroadcaster, css::uno::UNO_QUERY);
1407 0 : aReadLock.unlock();
1408 : // <- SAFE ----------------------------------
1409 :
1410 0 : if (
1411 0 : (xGlobalEventBroadcaster.is()) &&
1412 : (m_bListenForDocEvents )
1413 : )
1414 : {
1415 0 : xGlobalEventBroadcaster->removeEventListener(m_xNewDocBroadcasterListener);
1416 0 : m_bListenForDocEvents = sal_False;
1417 : }
1418 :
1419 0 : if (
1420 0 : (xCFG.is() ) &&
1421 : (m_bListenForConfigChanges)
1422 : )
1423 : {
1424 0 : xCFG->removeChangesListener(m_xRecoveryCFGListener);
1425 0 : m_bListenForConfigChanges = sal_False;
1426 0 : }
1427 0 : }
1428 :
1429 : //-----------------------------------------------
1430 0 : void AutoRecovery::implts_startModifyListeningOnDoc(AutoRecovery::TDocumentInfo& rInfo)
1431 : {
1432 0 : if (rInfo.ListenForModify)
1433 0 : return;
1434 :
1435 0 : css::uno::Reference< css::util::XModifyBroadcaster > xBroadcaster(rInfo.Document, css::uno::UNO_QUERY);
1436 0 : if (xBroadcaster.is())
1437 : {
1438 0 : css::uno::Reference< css::util::XModifyListener > xThis(static_cast< css::frame::XDispatch* >(this), css::uno::UNO_QUERY);
1439 0 : xBroadcaster->addModifyListener(xThis);
1440 0 : rInfo.ListenForModify = sal_True;
1441 0 : }
1442 : }
1443 :
1444 : //-----------------------------------------------
1445 0 : void AutoRecovery::implts_stopModifyListeningOnDoc(AutoRecovery::TDocumentInfo& rInfo)
1446 : {
1447 0 : if (! rInfo.ListenForModify)
1448 0 : return;
1449 :
1450 0 : css::uno::Reference< css::util::XModifyBroadcaster > xBroadcaster(rInfo.Document, css::uno::UNO_QUERY);
1451 0 : if (xBroadcaster.is())
1452 : {
1453 0 : css::uno::Reference< css::util::XModifyListener > xThis(static_cast< css::frame::XDispatch* >(this), css::uno::UNO_QUERY);
1454 0 : xBroadcaster->removeModifyListener(xThis);
1455 0 : rInfo.ListenForModify = sal_False;
1456 0 : }
1457 : }
1458 :
1459 : //-----------------------------------------------
1460 0 : void AutoRecovery::implts_updateTimer()
1461 : {
1462 0 : implts_stopTimer();
1463 :
1464 : // SAFE -> ----------------------------------
1465 0 : WriteGuard aWriteLock(m_aLock);
1466 :
1467 0 : if (
1468 : (m_eJob == AutoRecovery::E_NO_JOB ) || // TODO may be superflous - E_DONT_START_TIMER should be used only
1469 : (m_eTimerType == AutoRecovery::E_DONT_START_TIMER)
1470 : )
1471 0 : return;
1472 :
1473 0 : sal_uLong nMilliSeconds = 0;
1474 0 : if (m_eTimerType == AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL)
1475 : {
1476 0 : nMilliSeconds = (m_nAutoSaveTimeIntervall*60000); // [min] => 60.000 ms
1477 : #if OSL_DEBUG_LEVEL > 1
1478 : if (m_dbg_bMakeItFaster)
1479 : nMilliSeconds = m_nAutoSaveTimeIntervall; // [ms]
1480 : #endif
1481 : }
1482 : else
1483 0 : if (m_eTimerType == AutoRecovery::E_POLL_FOR_USER_IDLE)
1484 : {
1485 0 : nMilliSeconds = MIN_TIME_FOR_USER_IDLE;
1486 : #if OSL_DEBUG_LEVEL > 1
1487 : if (m_dbg_bMakeItFaster)
1488 : nMilliSeconds = 300; // let us some time, to finish this method .-)
1489 : #endif
1490 : }
1491 : else
1492 0 : if (m_eTimerType == AutoRecovery::E_POLL_TILL_AUTOSAVE_IS_ALLOWED)
1493 0 : nMilliSeconds = 300; // there is a minimum time frame, where the user can loose some key input data!
1494 :
1495 0 : m_aTimer.SetTimeout(nMilliSeconds);
1496 0 : m_aTimer.Start();
1497 :
1498 0 : aWriteLock.unlock();
1499 : // <- SAFE ----------------------------------
1500 : }
1501 :
1502 : //-----------------------------------------------
1503 0 : void AutoRecovery::implts_stopTimer()
1504 : {
1505 : // SAFE -> ----------------------------------
1506 0 : WriteGuard aWriteLock(m_aLock);
1507 :
1508 0 : if (!m_aTimer.IsActive())
1509 0 : return;
1510 0 : m_aTimer.Stop();
1511 :
1512 : // <- SAFE ----------------------------------
1513 : }
1514 :
1515 : //-----------------------------------------------
1516 0 : IMPL_LINK_NOARG(AutoRecovery, implts_timerExpired)
1517 : {
1518 : try
1519 : {
1520 : // This method is called by using a pointer to us.
1521 : // But we must be aware that we can be destroyed hardly
1522 : // if our uno reference will be gone!
1523 : // => Hold this object alive till this method finish its work.
1524 0 : css::uno::Reference< css::uno::XInterface > xSelfHold(static_cast< css::lang::XTypeProvider* >(this));
1525 :
1526 : // Needed! Otherwise every reschedule request allow a new triggered timer event :-(
1527 0 : implts_stopTimer();
1528 :
1529 : // The timer must be ignored if AutoSave/Recovery was disabled for this
1530 : // office session. That can happen if e.g. the command line arguments "--norestore" or "--headless"
1531 : // was set. But normaly the timer was disabled if recovery was disabled ...
1532 : // But so we are more "safe" .-)
1533 : // SAFE -> ----------------------------------
1534 0 : ReadGuard aReadLock(m_aLock);
1535 0 : if ((m_eJob & AutoRecovery::E_DISABLE_AUTORECOVERY) == AutoRecovery::E_DISABLE_AUTORECOVERY)
1536 0 : return 0;
1537 0 : aReadLock.unlock();
1538 : // <- SAFE ----------------------------------
1539 :
1540 : // check some "states", where its not allowed (better: not a good idea) to
1541 : // start an AutoSave. (e.g. if the user makes drag & drop ...)
1542 : // Then we poll till this "disallowed" state is gone.
1543 0 : sal_Bool bAutoSaveNotAllowed = Application::IsUICaptured();
1544 0 : if (bAutoSaveNotAllowed)
1545 : {
1546 : // SAFE -> ------------------------------
1547 0 : WriteGuard aWriteLock(m_aLock);
1548 0 : m_eTimerType = AutoRecovery::E_POLL_TILL_AUTOSAVE_IS_ALLOWED;
1549 0 : aWriteLock.unlock();
1550 : // <- SAFE ------------------------------
1551 0 : implts_updateTimer();
1552 0 : return 0;
1553 : }
1554 :
1555 : // analyze timer type.
1556 : // If we poll for an user idle period, may be we must
1557 : // do nothing here and start the timer again.
1558 : // SAFE -> ----------------------------------
1559 0 : WriteGuard aWriteLock(m_aLock);
1560 :
1561 0 : if (m_eTimerType == AutoRecovery::E_POLL_FOR_USER_IDLE)
1562 : {
1563 0 : sal_Bool bUserIdle = (Application::GetLastInputInterval()>MIN_TIME_FOR_USER_IDLE);
1564 0 : if (!bUserIdle)
1565 : {
1566 0 : implts_updateTimer();
1567 0 : return 0;
1568 : }
1569 : }
1570 :
1571 0 : aWriteLock.unlock();
1572 : // <- SAFE ----------------------------------
1573 :
1574 : implts_informListener(AutoRecovery::E_AUTO_SAVE,
1575 0 : AutoRecovery::implst_createFeatureStateEvent(AutoRecovery::E_AUTO_SAVE, OPERATION_START, NULL));
1576 :
1577 : // force save of all currently open documents
1578 : // The called method returns an info, if and how this
1579 : // timer must be restarted.
1580 0 : sal_Bool bAllowUserIdleLoop = sal_True;
1581 0 : AutoRecovery::ETimerType eSuggestedTimer = implts_saveDocs(bAllowUserIdleLoop, sal_False);
1582 :
1583 : // If timer isnt used for "short callbacks" (means polling
1584 : // for special states) ... reset the handle state of all
1585 : // cache items. Such handle state indicates, that a document
1586 : // was already saved during the THIS(!) AutoSave session.
1587 : // Of course NEXT AutoSave session must be started without
1588 : // any "handle" state ...
1589 0 : if (
1590 : (eSuggestedTimer == AutoRecovery::E_DONT_START_TIMER ) ||
1591 : (eSuggestedTimer == AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL)
1592 : )
1593 : {
1594 0 : implts_resetHandleStates(sal_False);
1595 : }
1596 :
1597 : implts_informListener(AutoRecovery::E_AUTO_SAVE,
1598 0 : AutoRecovery::implst_createFeatureStateEvent(AutoRecovery::E_AUTO_SAVE, OPERATION_STOP, NULL));
1599 :
1600 : // restart timer - because it was disabled before ...
1601 : // SAFE -> ----------------------------------
1602 0 : aWriteLock.lock();
1603 0 : m_eTimerType = eSuggestedTimer;
1604 0 : aWriteLock.unlock();
1605 : // <- SAFE ----------------------------------
1606 :
1607 0 : implts_updateTimer();
1608 : }
1609 0 : catch(const css::uno::Exception&)
1610 : {
1611 : }
1612 :
1613 0 : return 0;
1614 : }
1615 :
1616 : //-----------------------------------------------
1617 0 : IMPL_LINK_NOARG(AutoRecovery, implts_asyncDispatch)
1618 : {
1619 : // SAFE ->
1620 0 : WriteGuard aWriteLock(m_aLock);
1621 0 : DispatchParams aParams = m_aDispatchParams;
1622 0 : css::uno::Reference< css::uno::XInterface > xHoldRefForMethodAlive = aParams.m_xHoldRefForAsyncOpAlive;
1623 0 : m_aDispatchParams.forget(); // clears all members ... including the ref-hold object .-)
1624 0 : aWriteLock.unlock();
1625 : // <- SAFE
1626 :
1627 : try
1628 : {
1629 0 : implts_dispatch(aParams);
1630 : }
1631 0 : catch (...)
1632 : {
1633 : }
1634 0 : return 0;
1635 : }
1636 :
1637 : //-----------------------------------------------
1638 0 : void AutoRecovery::implts_registerDocument(const css::uno::Reference< css::frame::XModel >& xDocument)
1639 : {
1640 : // ignore corrupted events, where no document is given ... Runtime Error ?!
1641 0 : if (!xDocument.is())
1642 : return;
1643 :
1644 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
1645 :
1646 : // notification for already existing document !
1647 : // Can happen if events came in asynchronous on recovery time.
1648 : // Then our cache was filled from the configuration ... but now we get some
1649 : // asynchronous events from the global event broadcaster. We must be sure that
1650 : // we dont add the same document more then once.
1651 0 : AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
1652 0 : if (pIt != m_lDocCache.end())
1653 : {
1654 : // Normaly nothing must be done for this "late" notification.
1655 : // But may be the modified state was changed inbetween.
1656 : // Check it ...
1657 0 : implts_updateModifiedState(xDocument);
1658 : return;
1659 : }
1660 :
1661 0 : aCacheLock.unlock();
1662 :
1663 0 : ::comphelper::MediaDescriptor lDescriptor(xDocument->getArgs());
1664 :
1665 : // check if this document must be ignored for recovery !
1666 : // Some use cases dont wish support for AutoSave/Recovery ... as e.g. OLE-Server / ActiveX Control etcpp.
1667 0 : sal_Bool bNoAutoSave = lDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_NOAUTOSAVE(), (sal_Bool)(sal_False));
1668 0 : if (bNoAutoSave)
1669 : return;
1670 :
1671 : // Check if doc is well known on the desktop. Otherwhise ignore it!
1672 : // Other frames mostly are used from external programs - e.g. the bean ...
1673 0 : css::uno::Reference< css::frame::XController > xController = xDocument->getCurrentController();
1674 0 : if (!xController.is())
1675 : return;
1676 :
1677 0 : css::uno::Reference< css::frame::XFrame > xFrame = xController->getFrame();
1678 0 : css::uno::Reference< css::frame::XDesktop > xDesktop (xFrame->getCreator(), css::uno::UNO_QUERY);
1679 0 : if (!xDesktop.is())
1680 : return;
1681 :
1682 : // if the document doesn't support the XDocumentRecovery interface, we're not interested in it.
1683 0 : Reference< XDocumentRecovery > xDocRecovery( xDocument, UNO_QUERY );
1684 0 : if ( !xDocRecovery.is() )
1685 : return;
1686 :
1687 : // get all needed informations of this document
1688 : // We need it to update our cache or to locate already existing elements there!
1689 0 : AutoRecovery::TDocumentInfo aNew;
1690 0 : aNew.Document = xDocument;
1691 :
1692 : // TODO replace getLocation() with getURL() ... its a workaround currently only!
1693 0 : css::uno::Reference< css::frame::XStorable > xDoc(aNew.Document, css::uno::UNO_QUERY_THROW);
1694 0 : aNew.OrgURL = xDoc->getLocation();
1695 :
1696 0 : css::uno::Reference< css::frame::XTitle > xTitle(aNew.Document, css::uno::UNO_QUERY_THROW);
1697 0 : aNew.Title = xTitle->getTitle ();
1698 :
1699 : // SAFE -> ----------------------------------
1700 0 : ReadGuard aReadLock(m_aLock);
1701 0 : css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1702 0 : aReadLock.unlock();
1703 : // <- SAFE ----------------------------------
1704 :
1705 : // classify the used application module, which is used by this document.
1706 0 : implts_specifyAppModuleAndFactory(aNew);
1707 :
1708 : // Hack! Check for "illegal office documents" ... as e.g. the Basic IDE
1709 : // Its not realy a full featured office document. It doesnt provide an URL, any filter, a factory URL etcpp.
1710 : // TODO file bug to Basci IDE developers. They must remove the office document API from its service.
1711 0 : if (
1712 0 : (aNew.OrgURL.isEmpty()) &&
1713 0 : (aNew.FactoryURL.isEmpty())
1714 : )
1715 : {
1716 : OSL_FAIL( "AutoRecovery::implts_registerDocument: this should not happen anymore!" );
1717 : // nowadays, the Basic IDE should already die on the "supports XDocumentRecovery" check. And no other known
1718 : // document type fits in here ...
1719 : return;
1720 : }
1721 :
1722 : // By the way - get some information about the default format for saving!
1723 : // and save an information about the real used filter by this document.
1724 : // We save this document with DefaultFilter ... and load it with the RealFilter.
1725 0 : implts_specifyDefaultFilterAndExtension(aNew);
1726 0 : aNew.RealFilter = lDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_FILTERNAME() , ::rtl::OUString());
1727 :
1728 : // Further we must know, if this document base on a template.
1729 : // Then we must load it in a different way.
1730 0 : css::uno::Reference< css::document::XDocumentPropertiesSupplier > xSupplier(aNew.Document, css::uno::UNO_QUERY);
1731 0 : if (xSupplier.is()) // optional interface!
1732 : {
1733 0 : css::uno::Reference< css::document::XDocumentProperties > xDocProps(xSupplier->getDocumentProperties(), css::uno::UNO_QUERY_THROW);
1734 0 : aNew.TemplateURL = xDocProps->getTemplateURL();
1735 : }
1736 :
1737 0 : css::uno::Reference< css::util::XModifiable > xModifyCheck(xDocument, css::uno::UNO_QUERY_THROW);
1738 0 : if (xModifyCheck->isModified())
1739 : {
1740 0 : aNew.DocumentState |= AutoRecovery::E_MODIFIED;
1741 : }
1742 :
1743 0 : aCacheLock.lock(LOCK_FOR_CACHE_ADD_REMOVE);
1744 :
1745 : // SAFE -> ----------------------------------
1746 0 : WriteGuard aWriteLock(m_aLock);
1747 :
1748 : // create a new cache entry ... this document isn't known.
1749 0 : ++m_nIdPool;
1750 0 : aNew.ID = m_nIdPool;
1751 : LOG_ASSERT(m_nIdPool>=0, "AutoRecovery::implts_registerDocument()\nOverflow of ID pool detected.")
1752 0 : m_lDocCache.push_back(aNew);
1753 :
1754 0 : AutoRecovery::TDocumentList::iterator pIt1 = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
1755 0 : AutoRecovery::TDocumentInfo& rInfo = *pIt1;
1756 :
1757 0 : aWriteLock.unlock();
1758 : // <- SAFE ----------------------------------
1759 :
1760 0 : implts_flushConfigItem(rInfo);
1761 0 : implts_startModifyListeningOnDoc(rInfo);
1762 :
1763 0 : aCacheLock.unlock();
1764 : }
1765 :
1766 : //-----------------------------------------------
1767 0 : void AutoRecovery::implts_deregisterDocument(const css::uno::Reference< css::frame::XModel >& xDocument ,
1768 : sal_Bool bStopListening)
1769 : {
1770 :
1771 : // SAFE -> ----------------------------------
1772 0 : WriteGuard aWriteLock(m_aLock);
1773 :
1774 : // Attention: Dont leave SAFE section, if you work with pIt!
1775 : // Because it points directly into the m_lDocCache list ...
1776 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
1777 :
1778 0 : AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
1779 0 : if (pIt == m_lDocCache.end())
1780 : return; // unknown document => not a runtime error! Because we register only a few documents. see registration ...
1781 :
1782 0 : AutoRecovery::TDocumentInfo aInfo = *pIt;
1783 :
1784 0 : aCacheLock.unlock();
1785 :
1786 : // Sometimes we close documents by ourself.
1787 : // And these documents cant be deregistered.
1788 : // Otherwhise we loos our configuration data ... but need it !
1789 : // see SessionSave !
1790 0 : if (aInfo.IgnoreClosing)
1791 : return;
1792 :
1793 0 : CacheLockGuard aCacheLock2(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_ADD_REMOVE);
1794 0 : pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
1795 0 : if (pIt != m_lDocCache.end())
1796 0 : m_lDocCache.erase(pIt);
1797 0 : pIt = m_lDocCache.end(); // otherwhise its not specified what pIt means!
1798 0 : aCacheLock2.unlock();
1799 :
1800 0 : aWriteLock.unlock();
1801 : // <- SAFE ----------------------------------
1802 :
1803 : /* This method is called within disposing() of the document too. But there it's not a good idea to
1804 : deregister us as listener. Furter it make no sense - because the broadcaster dies.
1805 : So we supress deregistration in such case ...
1806 : */
1807 0 : if (bStopListening)
1808 0 : implts_stopModifyListeningOnDoc(aInfo);
1809 :
1810 0 : AutoRecovery::st_impl_removeFile(aInfo.OldTempURL);
1811 0 : AutoRecovery::st_impl_removeFile(aInfo.NewTempURL);
1812 0 : implts_flushConfigItem(aInfo, sal_True); // sal_True => remove it from config
1813 : }
1814 :
1815 : //-----------------------------------------------
1816 0 : void AutoRecovery::implts_markDocumentModifiedAgainstLastBackup(const css::uno::Reference< css::frame::XModel >& xDocument)
1817 : {
1818 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
1819 :
1820 : // SAFE -> ----------------------------------
1821 0 : WriteGuard aWriteLock(m_aLock);
1822 :
1823 0 : AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
1824 0 : if (pIt != m_lDocCache.end())
1825 : {
1826 0 : AutoRecovery::TDocumentInfo& rInfo = *pIt;
1827 :
1828 : /* Now we know, that this document was modified again and must be saved next time.
1829 : But we dont need this information for every e.g. key input of the user.
1830 : So we stop listening here.
1831 : But if the document was saved as temp. file we start listening for this event again.
1832 : */
1833 0 : implts_stopModifyListeningOnDoc(rInfo);
1834 : }
1835 :
1836 0 : aWriteLock.unlock();
1837 : // <- SAFE ----------------------------------
1838 0 : }
1839 :
1840 : //-----------------------------------------------
1841 0 : void AutoRecovery::implts_updateModifiedState(const css::uno::Reference< css::frame::XModel >& xDocument)
1842 : {
1843 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
1844 :
1845 : // SAFE -> ----------------------------------
1846 0 : WriteGuard aWriteLock(m_aLock);
1847 :
1848 0 : AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
1849 0 : if (pIt != m_lDocCache.end())
1850 : {
1851 0 : AutoRecovery::TDocumentInfo& rInfo = *pIt;
1852 :
1853 : // use sal_True as fallback ... so we recognize every document on EmergencySave/AutoRecovery!
1854 0 : sal_Bool bModified = sal_True;
1855 0 : css::uno::Reference< css::util::XModifiable > xModify(xDocument, css::uno::UNO_QUERY);
1856 0 : if (xModify.is())
1857 0 : bModified = xModify->isModified();
1858 0 : if (bModified)
1859 : {
1860 0 : rInfo.DocumentState |= AutoRecovery::E_MODIFIED;
1861 : }
1862 : else
1863 : {
1864 0 : rInfo.DocumentState &= ~AutoRecovery::E_MODIFIED;
1865 0 : }
1866 : }
1867 :
1868 0 : aWriteLock.unlock();
1869 : // <- SAFE ----------------------------------
1870 0 : }
1871 :
1872 : //-----------------------------------------------
1873 0 : void AutoRecovery::implts_updateDocumentUsedForSavingState(const css::uno::Reference< css::frame::XModel >& xDocument ,
1874 : sal_Bool bSaveInProgress)
1875 : {
1876 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
1877 :
1878 : // SAFE -> ----------------------------------
1879 0 : WriteGuard aWriteLock(m_aLock);
1880 :
1881 0 : AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
1882 0 : if (pIt == m_lDocCache.end())
1883 0 : return;
1884 0 : AutoRecovery::TDocumentInfo& rInfo = *pIt;
1885 0 : rInfo.UsedForSaving = bSaveInProgress;
1886 :
1887 0 : aWriteLock.unlock();
1888 : // <- SAFE ----------------------------------
1889 : }
1890 :
1891 : //-----------------------------------------------
1892 0 : void AutoRecovery::implts_markDocumentAsSaved(const css::uno::Reference< css::frame::XModel >& xDocument)
1893 : {
1894 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
1895 :
1896 : // SAFE -> ----------------------------------
1897 0 : WriteGuard aWriteLock(m_aLock);
1898 :
1899 0 : AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
1900 0 : if (pIt == m_lDocCache.end())
1901 0 : return;
1902 0 : AutoRecovery::TDocumentInfo& rInfo = *pIt;
1903 :
1904 0 : rInfo.DocumentState = AutoRecovery::E_UNKNOWN;
1905 : // TODO replace getLocation() with getURL() ... its a workaround currently only!
1906 0 : css::uno::Reference< css::frame::XStorable > xDoc(rInfo.Document, css::uno::UNO_QUERY);
1907 0 : rInfo.OrgURL = xDoc->getLocation();
1908 :
1909 0 : ::rtl::OUString sRemoveURL1 = rInfo.OldTempURL;
1910 0 : ::rtl::OUString sRemoveURL2 = rInfo.NewTempURL;
1911 0 : rInfo.OldTempURL = ::rtl::OUString();
1912 0 : rInfo.NewTempURL = ::rtl::OUString();
1913 :
1914 0 : ::comphelper::MediaDescriptor lDescriptor(rInfo.Document->getArgs());
1915 0 : rInfo.RealFilter = lDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_FILTERNAME(), ::rtl::OUString());
1916 :
1917 0 : css::uno::Reference< css::frame::XTitle > xDocTitle(xDocument, css::uno::UNO_QUERY);
1918 0 : if (xDocTitle.is ())
1919 0 : rInfo.Title = xDocTitle->getTitle ();
1920 : else
1921 : {
1922 0 : rInfo.Title = lDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_TITLE() , ::rtl::OUString());
1923 0 : if (rInfo.Title.isEmpty())
1924 0 : rInfo.Title = lDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_DOCUMENTTITLE(), ::rtl::OUString());
1925 : }
1926 :
1927 0 : rInfo.UsedForSaving = sal_False;
1928 :
1929 0 : aWriteLock.unlock();
1930 : // <- SAFE ----------------------------------
1931 :
1932 0 : implts_flushConfigItem(rInfo);
1933 :
1934 0 : aCacheLock.unlock();
1935 :
1936 0 : AutoRecovery::st_impl_removeFile(sRemoveURL1);
1937 0 : AutoRecovery::st_impl_removeFile(sRemoveURL2);
1938 : }
1939 :
1940 : //-----------------------------------------------
1941 0 : AutoRecovery::TDocumentList::iterator AutoRecovery::impl_searchDocument( AutoRecovery::TDocumentList& rList ,
1942 : const css::uno::Reference< css::frame::XModel >& xDocument)
1943 : {
1944 0 : AutoRecovery::TDocumentList::iterator pIt;
1945 0 : for ( pIt = rList.begin();
1946 0 : pIt != rList.end() ;
1947 : ++pIt )
1948 : {
1949 0 : const AutoRecovery::TDocumentInfo& rInfo = *pIt;
1950 0 : if (rInfo.Document == xDocument)
1951 0 : break;
1952 : }
1953 0 : return pIt;
1954 : }
1955 :
1956 : //-----------------------------------------------
1957 : namespace
1958 : {
1959 0 : void lcl_changeVisibility( const css::uno::Reference< css::frame::XFramesSupplier >& i_rFrames, sal_Bool i_bVisible )
1960 : {
1961 0 : css::uno::Reference< css::container::XIndexAccess > xFramesContainer( i_rFrames->getFrames(), css::uno::UNO_QUERY );
1962 0 : const sal_Int32 count = xFramesContainer->getCount();
1963 :
1964 0 : Any aElement;
1965 0 : for ( sal_Int32 i=0; i < count; ++i )
1966 : {
1967 0 : aElement = xFramesContainer->getByIndex(i);
1968 : // check for sub frames
1969 0 : css::uno::Reference< css::frame::XFramesSupplier > xFramesSupp( aElement, css::uno::UNO_QUERY );
1970 0 : if ( xFramesSupp.is() )
1971 0 : lcl_changeVisibility( xFramesSupp, i_bVisible );
1972 :
1973 0 : css::uno::Reference< css::frame::XFrame > xFrame( aElement, css::uno::UNO_QUERY );
1974 0 : if ( !xFrame.is() )
1975 0 : continue;
1976 :
1977 0 : css::uno::Reference< css::awt::XWindow > xWindow( xFrame->getContainerWindow(), UNO_SET_THROW );
1978 0 : xWindow->setVisible( i_bVisible );
1979 0 : }
1980 0 : }
1981 : }
1982 :
1983 : //-----------------------------------------------
1984 0 : void AutoRecovery::implts_changeAllDocVisibility(sal_Bool bVisible)
1985 : {
1986 : // SAFE -> ----------------------------------
1987 0 : ReadGuard aReadLock(m_aLock);
1988 0 : css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1989 0 : aReadLock.unlock();
1990 : // <- SAFE ----------------------------------
1991 :
1992 0 : css::uno::Reference< css::frame::XFramesSupplier > xDesktop( css::frame::Desktop::create( comphelper::getComponentContext(xSMGR) ), css::uno::UNO_QUERY);
1993 0 : lcl_changeVisibility( xDesktop, bVisible );
1994 :
1995 0 : aReadLock.unlock();
1996 : // <- SAFE ----------------------------------
1997 0 : }
1998 :
1999 : //-----------------------------------------------
2000 : /* Currently the document is not closed in case of crash,
2001 : so the lock file must be removed explicitly
2002 : */
2003 0 : void lc_removeLockFile(AutoRecovery::TDocumentInfo& rInfo)
2004 : {
2005 0 : if ( rInfo.Document.is() )
2006 : {
2007 : try
2008 : {
2009 0 : css::uno::Reference< css::frame::XStorable > xStore(rInfo.Document, css::uno::UNO_QUERY_THROW);
2010 0 : ::rtl::OUString aURL = xStore->getLocation();
2011 0 : if ( !aURL.isEmpty() )
2012 : {
2013 0 : ::svt::DocumentLockFile aLockFile( aURL );
2014 0 : aLockFile.RemoveFile();
2015 0 : }
2016 : }
2017 0 : catch( const css::uno::Exception& )
2018 : {
2019 : }
2020 : }
2021 0 : }
2022 :
2023 :
2024 : //-----------------------------------------------
2025 0 : void AutoRecovery::implts_prepareSessionShutdown()
2026 : {
2027 : LOG_RECOVERY("AutoRecovery::implts_prepareSessionShutdown() starts ...")
2028 :
2029 : // a) reset modified documents (of course the must be saved before this method is called!)
2030 : // b) close it without showing any UI!
2031 :
2032 : // SAFE ->
2033 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
2034 :
2035 0 : AutoRecovery::TDocumentList::iterator pIt;
2036 0 : for ( pIt = m_lDocCache.begin();
2037 0 : pIt != m_lDocCache.end() ;
2038 : ++pIt )
2039 : {
2040 0 : AutoRecovery::TDocumentInfo& rInfo = *pIt;
2041 :
2042 : // WORKAROUND... Since the documents are not closed the lock file must be removed explicitly
2043 : // it is not done on documents saving since shutdown can be cancelled
2044 0 : lc_removeLockFile( rInfo );
2045 :
2046 : // Prevent us from deregistration of these documents.
2047 : // Because we close these documents by ourself (see XClosable below) ...
2048 : // it's fact, that we reach our deregistration method. There we
2049 : // must not(!) update our configuration ... Otherwhise all
2050 : // session data are lost !!!
2051 0 : rInfo.IgnoreClosing = sal_True;
2052 :
2053 : // reset modified flag of these documents (ignoring the notification about it!)
2054 : // Otherwise a message box is shown on closing these models.
2055 0 : implts_stopModifyListeningOnDoc(rInfo);
2056 :
2057 : // if the session save is still running the documents should not be thrown away,
2058 : // actually that would be a bad sign, that means that the SessionManager tryes
2059 : // to kill the session before the saving is ready
2060 0 : if ((m_eJob & AutoRecovery::E_SESSION_SAVE) != AutoRecovery::E_SESSION_SAVE)
2061 : {
2062 0 : css::uno::Reference< css::util::XModifiable > xModify(rInfo.Document, css::uno::UNO_QUERY);
2063 0 : if (xModify.is())
2064 0 : xModify->setModified(sal_False);
2065 :
2066 : // close the model.
2067 0 : css::uno::Reference< css::util::XCloseable > xClose(rInfo.Document, css::uno::UNO_QUERY);
2068 0 : if (xClose.is())
2069 : {
2070 : try
2071 : {
2072 0 : xClose->close(sal_False);
2073 : }
2074 0 : catch(const css::uno::Exception&)
2075 : {
2076 : // At least it's only a try to close these documents before anybody else it does.
2077 : // So it seams to be possible to ignore any error here .-)
2078 : }
2079 :
2080 0 : rInfo.Document.clear();
2081 0 : }
2082 : }
2083 : }
2084 :
2085 0 : aCacheLock.unlock();
2086 : // <- SAFE
2087 0 : }
2088 :
2089 : //-----------------------------------------------
2090 : /* TODO WORKAROUND:
2091 :
2092 : #i64599#
2093 :
2094 : Normaly the MediaDescriptor argument NoAutoSave indicates,
2095 : that a document must be ignored for AutoSave and Recovery.
2096 : But sometimes XModel->getArgs() does not contained this information
2097 : if implts_registerDocument() was called.
2098 : So we have to check a second time, if this property is set ....
2099 : Best place doing so is to check it immeditaly before saving
2100 : and supressingd saving the document then.
2101 : Of course removing the corresponding cache entry isnt an option.
2102 : Because it would disturb iteration over the cache !
2103 : So we ignore such documents only ...
2104 : Hopefully next time they are not inserted in our cache.
2105 : */
2106 0 : sal_Bool lc_checkIfSaveForbiddenByArguments(AutoRecovery::TDocumentInfo& rInfo)
2107 : {
2108 0 : if (! rInfo.Document.is())
2109 0 : return sal_True;
2110 :
2111 0 : ::comphelper::MediaDescriptor lDescriptor(rInfo.Document->getArgs());
2112 0 : sal_Bool bNoAutoSave = lDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_NOAUTOSAVE(), (sal_Bool)(sal_False));
2113 :
2114 0 : return bNoAutoSave;
2115 : }
2116 :
2117 : //-----------------------------------------------
2118 0 : AutoRecovery::ETimerType AutoRecovery::implts_saveDocs( sal_Bool bAllowUserIdleLoop,
2119 : sal_Bool bRemoveLockFiles,
2120 : const DispatchParams* pParams )
2121 : {
2122 : // SAFE -> ----------------------------------
2123 0 : ReadGuard aReadLock(m_aLock);
2124 0 : css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
2125 0 : aReadLock.unlock();
2126 : // <- SAFE ----------------------------------
2127 :
2128 0 : css::uno::Reference< css::task::XStatusIndicator > xExternalProgress;
2129 0 : if (pParams)
2130 0 : xExternalProgress = pParams->m_xProgress;
2131 :
2132 0 : css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( comphelper::getComponentContext(xSMGR));
2133 0 : ::rtl::OUString sBackupPath(SvtPathOptions().GetBackupPath());
2134 :
2135 0 : css::uno::Reference< css::frame::XController > xActiveController;
2136 0 : css::uno::Reference< css::frame::XModel > xActiveModel ;
2137 0 : css::uno::Reference< css::frame::XFrame > xActiveFrame = xDesktop->getActiveFrame();
2138 0 : if (xActiveFrame.is())
2139 0 : xActiveController = xActiveFrame->getController();
2140 0 : if (xActiveController.is())
2141 0 : xActiveModel = xActiveController->getModel();
2142 :
2143 : // Set the default timer action for our calli.
2144 : // Default = NORMAL_AUTOSAVE
2145 : // We return a suggestion for an active timer only.
2146 : // It will be ignored if the timer was disabled by the user ...
2147 : // Further this state can be set to USER_IDLE only later in this method.
2148 : // Its not allowed to reset such state then. Because we must know, if
2149 : // there exists POSTPONED documents. see below ...
2150 0 : AutoRecovery::ETimerType eTimer = AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL;
2151 :
2152 0 : sal_Int32 eJob = m_eJob;
2153 :
2154 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
2155 :
2156 : // SAFE -> ----------------------------------
2157 0 : WriteGuard aWriteLock(m_aLock);
2158 :
2159 : // This list will be filled with every document
2160 : // which should be saved as last one. E.g. if it was used
2161 : // already for an UI save operation => crashed ... and
2162 : // now we try to save it again ... which can fail again ( of course .-) ).
2163 0 : ::std::vector< AutoRecovery::TDocumentList::iterator > lDangerousDocs;
2164 :
2165 0 : AutoRecovery::TDocumentList::iterator pIt;
2166 0 : for ( pIt = m_lDocCache.begin();
2167 0 : pIt != m_lDocCache.end() ;
2168 : ++pIt )
2169 : {
2170 0 : AutoRecovery::TDocumentInfo aInfo = *pIt;
2171 :
2172 : // WORKAROUND... Since the documents are not closed the lock file must be removed explicitly
2173 0 : if ( bRemoveLockFiles )
2174 0 : lc_removeLockFile( aInfo );
2175 :
2176 : // WORKAROUND ... see comment of this method
2177 0 : if (lc_checkIfSaveForbiddenByArguments(aInfo))
2178 0 : continue;
2179 :
2180 : // already auto saved during this session :-)
2181 : // This state must be reset for all documents
2182 : // if timer is started with normnal AutoSaveTimerIntervall!
2183 0 : if ((aInfo.DocumentState & AutoRecovery::E_HANDLED) == AutoRecovery::E_HANDLED)
2184 0 : continue;
2185 :
2186 : // Not modified documents are not saved.
2187 : // We safe an information about the URL only!
2188 0 : Reference< XDocumentRecovery > xDocRecover( aInfo.Document, UNO_QUERY_THROW );
2189 0 : if ( !xDocRecover->wasModifiedSinceLastSave() )
2190 : {
2191 0 : aInfo.DocumentState |= AutoRecovery::E_HANDLED;
2192 0 : continue;
2193 : }
2194 :
2195 : // check if this document is still used by a concurrent save operation
2196 : // e.g. if the user tried to save via UI.
2197 : // Handle it in the following way:
2198 : // i) For an AutoSave ... ignore this document! It will be saved and next time we will (hopefully)
2199 : // get a notification about the state of this operation.
2200 : // And if a document was saved by the user we can remove our temp. file. But that will be done inside
2201 : // our callback for SaveDone notification.
2202 : // ii) For a CrashSave ... add it to the list of dangerous documents and
2203 : // save it after all other documents was saved successfully. That decrease
2204 : // the chance for a crash inside a crash.
2205 : // On the other side it's not neccessary for documents, which are not modified.
2206 : // They can be handled normaly - means we patch the corresponding configuration entry only.
2207 : // iii) For a SessionSave ... ignore it! There is no time to wait for this save operation.
2208 : // Because the WindowManager will kill the process if it doesnt react immediatly.
2209 : // On the other side we cant risk a concurrent save request ... because we know
2210 : // that it will produce a crash.
2211 :
2212 : // Attention: Because eJob is used as a flag field, you have to check for the worst case first.
2213 : // E.g. a CrashSave can overwrite an AutoSave. So you have to check for a CrashSave before an AutoSave!
2214 0 : if (aInfo.UsedForSaving)
2215 : {
2216 0 : if ((eJob & AutoRecovery::E_EMERGENCY_SAVE) == AutoRecovery::E_EMERGENCY_SAVE)
2217 : {
2218 0 : lDangerousDocs.push_back(pIt);
2219 0 : continue;
2220 : }
2221 : else
2222 0 : if ((eJob & AutoRecovery::E_SESSION_SAVE) == AutoRecovery::E_SESSION_SAVE)
2223 : {
2224 0 : continue;
2225 : }
2226 : else
2227 0 : if ((eJob & AutoRecovery::E_AUTO_SAVE) == AutoRecovery::E_AUTO_SAVE)
2228 : {
2229 0 : eTimer = AutoRecovery::E_POLL_TILL_AUTOSAVE_IS_ALLOWED;
2230 0 : aInfo.DocumentState |= AutoRecovery::E_POSTPONED;
2231 0 : continue;
2232 : }
2233 : }
2234 :
2235 : // a) Document was not postponed - and is active now. => postpone it (restart timer, restart loop)
2236 : // b) Document was not postponed - and is not active now. => save it
2237 : // c) Document was postponed - and is not active now. => save it
2238 : // d) Document was postponed - and is active now. => save it (because user idle was checked already)
2239 0 : sal_Bool bActive = (xActiveModel == aInfo.Document);
2240 0 : sal_Bool bWasPostponed = ((aInfo.DocumentState & AutoRecovery::E_POSTPONED) == AutoRecovery::E_POSTPONED);
2241 :
2242 0 : if (
2243 : ! bWasPostponed &&
2244 : bActive
2245 : )
2246 : {
2247 0 : aInfo.DocumentState |= AutoRecovery::E_POSTPONED;
2248 0 : *pIt = aInfo;
2249 : // postponed documents will be saved if this method is called again!
2250 : // That can be done by an outside started timer => E_POLL_FOR_USER_IDLE (if normal AutoSave is active)
2251 : // or it must be done directly without starting any timer => E_CALL_ME_BACK (if Emergency- or SessionSave is active and must be finished ASAP!)
2252 0 : eTimer = AutoRecovery::E_POLL_FOR_USER_IDLE;
2253 0 : if (!bAllowUserIdleLoop)
2254 0 : eTimer = AutoRecovery::E_CALL_ME_BACK;
2255 0 : continue;
2256 : }
2257 :
2258 : // b, c, d)
2259 : // <- SAFE --------------------------
2260 0 : aWriteLock.unlock();
2261 : // changing of aInfo and flushing it is done inside implts_saveOneDoc!
2262 0 : implts_saveOneDoc(sBackupPath, aInfo, xExternalProgress);
2263 0 : implts_informListener(eJob, AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &aInfo));
2264 0 : aWriteLock.lock();
2265 : // SAFE -> --------------------------
2266 :
2267 0 : *pIt = aInfo;
2268 0 : }
2269 :
2270 : // Did we have some "dangerous candidates" ?
2271 : // Try to save it ... but may be it will fail !
2272 0 : ::std::vector< AutoRecovery::TDocumentList::iterator >::iterator pIt2;
2273 0 : for ( pIt2 = lDangerousDocs.begin();
2274 0 : pIt2 != lDangerousDocs.end() ;
2275 : ++pIt2 )
2276 : {
2277 0 : pIt = *pIt2;
2278 0 : AutoRecovery::TDocumentInfo aInfo = *pIt;
2279 :
2280 : // <- SAFE --------------------------
2281 0 : aWriteLock.unlock();
2282 : // changing of aInfo and flushing it is done inside implts_saveOneDoc!
2283 0 : implts_saveOneDoc(sBackupPath, aInfo, xExternalProgress);
2284 0 : implts_informListener(eJob, AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &aInfo));
2285 0 : aWriteLock.lock();
2286 : // SAFE -> --------------------------
2287 :
2288 0 : *pIt = aInfo;
2289 0 : }
2290 :
2291 0 : return eTimer;
2292 : }
2293 :
2294 : //-----------------------------------------------
2295 0 : void AutoRecovery::implts_saveOneDoc(const ::rtl::OUString& sBackupPath ,
2296 : AutoRecovery::TDocumentInfo& rInfo ,
2297 : const css::uno::Reference< css::task::XStatusIndicator >& xExternalProgress)
2298 : {
2299 : // no document? => can occure if we loaded our configuration with files,
2300 : // which couldnt be recovered successfully. In such case we have all needed informations
2301 : // excepting the real document instance!
2302 :
2303 : // TODO: search right place, where such "dead files" can be removed from the configuration!
2304 0 : if (!rInfo.Document.is())
2305 0 : return;
2306 :
2307 0 : ::comphelper::MediaDescriptor lOldArgs(rInfo.Document->getArgs());
2308 0 : implts_generateNewTempURL(sBackupPath, lOldArgs, rInfo);
2309 :
2310 : // if the document was loaded with a password, it should be
2311 : // stored with password
2312 0 : ::comphelper::MediaDescriptor lNewArgs;
2313 0 : ::rtl::OUString sPassword = lOldArgs.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_PASSWORD(), ::rtl::OUString());
2314 0 : if (!sPassword.isEmpty())
2315 0 : lNewArgs[::comphelper::MediaDescriptor::PROP_PASSWORD()] <<= sPassword;
2316 :
2317 : // Further it must be saved using the default file format of that application.
2318 : // Otherwhise we will some data lost.
2319 0 : if (!rInfo.DefaultFilter.isEmpty())
2320 0 : lNewArgs[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= rInfo.DefaultFilter;
2321 :
2322 : // prepare frame/document/mediadescriptor in a way, that it uses OUR progress .-)
2323 0 : if (xExternalProgress.is())
2324 0 : lNewArgs[::comphelper::MediaDescriptor::PROP_STATUSINDICATOR()] <<= xExternalProgress;
2325 0 : impl_establishProgress(rInfo, lNewArgs, css::uno::Reference< css::frame::XFrame >());
2326 :
2327 : // #i66598# use special handling of property "DocumentBaseURL" (it must be an empty string!)
2328 : // for make hyperlinks working
2329 0 : lNewArgs[::comphelper::MediaDescriptor::PROP_DOCUMENTBASEURL()] <<= ::rtl::OUString();
2330 :
2331 : // try to save this document as a new temp file everytimes.
2332 : // Mark AutoSave state as "INCOMPLETE" if it failed.
2333 : // Because the last temp file is to old and does not include all changes.
2334 0 : Reference< XDocumentRecovery > xDocRecover(rInfo.Document, css::uno::UNO_QUERY_THROW);
2335 :
2336 : // safe the state about "trying to save"
2337 : // ... we need it for recovery if e.g. a crash occures inside next line!
2338 0 : rInfo.DocumentState |= AutoRecovery::E_TRY_SAVE;
2339 0 : implts_flushConfigItem(rInfo);
2340 :
2341 0 : sal_Int32 nRetry = RETRY_STORE_ON_FULL_DISC_FOREVER;
2342 0 : sal_Bool bError = sal_False;
2343 0 : do
2344 : {
2345 : try
2346 : {
2347 0 : xDocRecover->storeToRecoveryFile( rInfo.NewTempURL, lNewArgs.getAsConstPropertyValueList() );
2348 :
2349 : #ifdef TRIGGER_FULL_DISC_CHECK
2350 : throw css::uno::Exception();
2351 : #else // TRIGGER_FULL_DISC_CHECK
2352 :
2353 0 : bError = sal_False;
2354 0 : nRetry = 0;
2355 : #endif // TRIGGER_FULL_DISC_CHECK
2356 : }
2357 0 : catch(const css::uno::Exception&)
2358 : {
2359 0 : bError = sal_True;
2360 :
2361 : // a) FULL DISC seams to be the problem behind => show error and retry it forever (e.g. retry=300)
2362 : // b) unknown problem (may be locking problem) => reset RETRY value to more usefull value(!) (e.g. retry=3)
2363 : // c) unknown problem (may be locking problem) + 1..2 repeating operations => throw the original exception to force generation of a stacktrace !
2364 :
2365 : // SAFE ->
2366 0 : ReadGuard aReadLock2(m_aLock);
2367 0 : sal_Int32 nMinSpaceDocSave = m_nMinSpaceDocSave;
2368 0 : aReadLock2.unlock();
2369 : // <- SAFE
2370 :
2371 0 : if (! impl_enoughDiscSpace(nMinSpaceDocSave))
2372 0 : AutoRecovery::impl_showFullDiscError();
2373 : else
2374 0 : if (nRetry > RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL)
2375 0 : nRetry = RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL;
2376 : else
2377 0 : if (nRetry <= GIVE_UP_RETRY)
2378 0 : throw; // force stacktrace to know if there exist might other reasons, why an AutoSave can fail !!!
2379 :
2380 0 : --nRetry;
2381 : }
2382 : }
2383 : while(nRetry>0);
2384 :
2385 0 : if (! bError)
2386 : {
2387 : // safe the state about success
2388 : // ... you know the reason: to know it on recovery time if next line crash .-)
2389 0 : rInfo.DocumentState &= ~AutoRecovery::E_TRY_SAVE;
2390 0 : rInfo.DocumentState |= AutoRecovery::E_HANDLED;
2391 0 : rInfo.DocumentState |= AutoRecovery::E_SUCCEDED;
2392 : }
2393 : else
2394 : {
2395 : // safe the state about error ...
2396 0 : rInfo.NewTempURL = ::rtl::OUString();
2397 0 : rInfo.DocumentState &= ~AutoRecovery::E_TRY_SAVE;
2398 0 : rInfo.DocumentState |= AutoRecovery::E_HANDLED;
2399 0 : rInfo.DocumentState |= AutoRecovery::E_INCOMPLETE;
2400 : }
2401 :
2402 : // make sure the progress isnt referred any longer
2403 0 : impl_forgetProgress(rInfo, lNewArgs, css::uno::Reference< css::frame::XFrame >());
2404 :
2405 : // try to remove the old temp file.
2406 : // Ignore any error here. We have a new temp file, which is up to date.
2407 : // The only thing is: we fill the disk with temp files, if we cant remove old ones :-)
2408 0 : ::rtl::OUString sRemoveFile = rInfo.OldTempURL;
2409 0 : rInfo.OldTempURL = rInfo.NewTempURL;
2410 0 : rInfo.NewTempURL = ::rtl::OUString();
2411 :
2412 0 : implts_flushConfigItem(rInfo);
2413 :
2414 : // We must know if the user modifies the document again ...
2415 0 : implts_startModifyListeningOnDoc(rInfo);
2416 :
2417 0 : AutoRecovery::st_impl_removeFile(sRemoveFile);
2418 : }
2419 :
2420 : //-----------------------------------------------
2421 0 : AutoRecovery::ETimerType AutoRecovery::implts_openDocs(const DispatchParams& aParams)
2422 : {
2423 0 : AutoRecovery::ETimerType eTimer = AutoRecovery::E_DONT_START_TIMER;
2424 :
2425 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
2426 :
2427 : // SAFE -> ----------------------------------
2428 0 : WriteGuard aWriteLock(m_aLock);
2429 :
2430 0 : sal_Int32 eJob = m_eJob;
2431 0 : AutoRecovery::TDocumentList::iterator pIt;
2432 0 : for ( pIt = m_lDocCache.begin();
2433 0 : pIt != m_lDocCache.end() ;
2434 : ++pIt )
2435 : {
2436 0 : AutoRecovery::TDocumentInfo& rInfo = *pIt;
2437 :
2438 : // Such documents are already loaded by the last loop.
2439 : // Dont check E_SUCCEDED here! Its may be the final state of an AutoSave
2440 : // operation before!!!
2441 0 : if ((rInfo.DocumentState & AutoRecovery::E_HANDLED) == AutoRecovery::E_HANDLED)
2442 0 : continue;
2443 :
2444 : // a1,b1,c1,d2,e2,f2)
2445 0 : if ((rInfo.DocumentState & AutoRecovery::E_DAMAGED) == AutoRecovery::E_DAMAGED)
2446 : {
2447 : // dont forget to inform listener! May be this document was
2448 : // damaged on last saving time ...
2449 : // Then our listener need this notification.
2450 : // If it was damaged during last "try to open" ...
2451 : // it will be notified more then once. SH.. HAPPENS ...
2452 : // <- SAFE --------------------------
2453 0 : aWriteLock.unlock();
2454 : implts_informListener(eJob,
2455 0 : AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &rInfo));
2456 0 : aWriteLock.lock();
2457 : // SAFE -> --------------------------
2458 0 : continue;
2459 : }
2460 :
2461 0 : ::comphelper::MediaDescriptor lDescriptor;
2462 :
2463 : // its an UI feature - so the "USER" itself must be set as referer
2464 0 : lDescriptor[::comphelper::MediaDescriptor::PROP_REFERRER()] <<= ::rtl::OUString(REFERRER_USER);
2465 0 : lDescriptor[::comphelper::MediaDescriptor::PROP_SALVAGEDFILE()] <<= ::rtl::OUString();
2466 :
2467 : // recovered documents are loaded hidden, and shown all at once, later
2468 0 : lDescriptor[::comphelper::MediaDescriptor::PROP_HIDDEN()] <<= true;
2469 :
2470 0 : if (aParams.m_xProgress.is())
2471 0 : lDescriptor[::comphelper::MediaDescriptor::PROP_STATUSINDICATOR()] <<= aParams.m_xProgress;
2472 :
2473 : sal_Bool bBackupWasTried = (
2474 : ((rInfo.DocumentState & AutoRecovery::E_TRY_LOAD_BACKUP ) == AutoRecovery::E_TRY_LOAD_BACKUP) || // temp. state!
2475 : ((rInfo.DocumentState & AutoRecovery::E_INCOMPLETE ) == AutoRecovery::E_INCOMPLETE ) // transport TRY_LOAD_BACKUP from last loop to this new one!
2476 0 : );
2477 0 : sal_Bool bOriginalWasTried = ((rInfo.DocumentState & AutoRecovery::E_TRY_LOAD_ORIGINAL) == AutoRecovery::E_TRY_LOAD_ORIGINAL);
2478 :
2479 0 : if (bBackupWasTried)
2480 : {
2481 0 : if (!bOriginalWasTried)
2482 : {
2483 0 : rInfo.DocumentState |= AutoRecovery::E_INCOMPLETE;
2484 : // try original URL ... ! dont continue with next item here ...
2485 : }
2486 : else
2487 : {
2488 0 : rInfo.DocumentState |= AutoRecovery::E_DAMAGED;
2489 0 : continue;
2490 : }
2491 : }
2492 :
2493 0 : ::rtl::OUString sLoadOriginalURL;
2494 0 : ::rtl::OUString sLoadBackupURL ;
2495 :
2496 0 : if (!bBackupWasTried)
2497 0 : sLoadBackupURL = rInfo.OldTempURL;
2498 :
2499 0 : if (!rInfo.OrgURL.isEmpty())
2500 : {
2501 0 : sLoadOriginalURL = rInfo.OrgURL;
2502 : }
2503 : else
2504 0 : if (!rInfo.TemplateURL.isEmpty())
2505 : {
2506 0 : sLoadOriginalURL = rInfo.TemplateURL;
2507 0 : lDescriptor[::comphelper::MediaDescriptor::PROP_ASTEMPLATE()] <<= sal_True;
2508 0 : lDescriptor[::comphelper::MediaDescriptor::PROP_TEMPLATENAME()] <<= rInfo.TemplateURL;
2509 : }
2510 : else
2511 0 : if (!rInfo.FactoryURL.isEmpty())
2512 : {
2513 0 : sLoadOriginalURL = rInfo.FactoryURL;
2514 0 : lDescriptor[::comphelper::MediaDescriptor::PROP_ASTEMPLATE()] <<= sal_True;
2515 : }
2516 :
2517 : // A "Salvaged" item must exists every time. The core can make something special then for recovery.
2518 : // Of course it should be the real file name of the original file, in case we load the temp. backup here.
2519 0 : ::rtl::OUString sURL;
2520 0 : if (!sLoadBackupURL.isEmpty())
2521 : {
2522 0 : sURL = sLoadBackupURL;
2523 0 : rInfo.DocumentState |= AutoRecovery::E_TRY_LOAD_BACKUP;
2524 0 : lDescriptor[::comphelper::MediaDescriptor::PROP_SALVAGEDFILE()] <<= sLoadOriginalURL;
2525 : }
2526 0 : else if (!sLoadOriginalURL.isEmpty())
2527 : {
2528 0 : sURL = sLoadOriginalURL;
2529 0 : rInfo.DocumentState |= AutoRecovery::E_TRY_LOAD_ORIGINAL;
2530 : }
2531 : else
2532 0 : continue; // TODO ERROR!
2533 :
2534 0 : LoadEnv::initializeUIDefaults( m_xSMGR, lDescriptor, true, NULL );
2535 :
2536 : // <- SAFE ------------------------------
2537 0 : aWriteLock.unlock();
2538 :
2539 0 : implts_flushConfigItem(rInfo);
2540 : implts_informListener(eJob,
2541 0 : AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &rInfo));
2542 :
2543 : try
2544 : {
2545 0 : implts_openOneDoc(sURL, lDescriptor, rInfo);
2546 : }
2547 0 : catch(const css::uno::Exception&)
2548 : {
2549 0 : rInfo.DocumentState &= ~AutoRecovery::E_TRY_LOAD_BACKUP;
2550 0 : rInfo.DocumentState &= ~AutoRecovery::E_TRY_LOAD_ORIGINAL;
2551 0 : if (!sLoadBackupURL.isEmpty())
2552 : {
2553 0 : rInfo.DocumentState |= AutoRecovery::E_INCOMPLETE;
2554 0 : eTimer = AutoRecovery::E_CALL_ME_BACK;
2555 : }
2556 : else
2557 : {
2558 0 : rInfo.DocumentState |= AutoRecovery::E_HANDLED;
2559 0 : rInfo.DocumentState |= AutoRecovery::E_DAMAGED;
2560 : }
2561 :
2562 0 : implts_flushConfigItem(rInfo, sal_True);
2563 : implts_informListener(eJob,
2564 0 : AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &rInfo));
2565 :
2566 : // SAFE -> ------------------------------
2567 : // Needed for next loop!
2568 0 : aWriteLock.lock();
2569 0 : continue;
2570 : }
2571 :
2572 0 : if (!rInfo.RealFilter.isEmpty())
2573 : {
2574 0 : ::comphelper::MediaDescriptor lPatchDescriptor(rInfo.Document->getArgs());
2575 0 : lPatchDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= rInfo.RealFilter;
2576 0 : rInfo.Document->attachResource(rInfo.Document->getURL(), lPatchDescriptor.getAsConstPropertyValueList());
2577 : // do *not* use sURL here. In case this points to the recovery file, it has already been passed
2578 : // to recoverFromFile. Also, passing it here is logically wrong, as attachResource is intended
2579 : // to take the logical file URL.
2580 : }
2581 :
2582 0 : css::uno::Reference< css::util::XModifiable > xModify(rInfo.Document, css::uno::UNO_QUERY);
2583 0 : if ( xModify.is() )
2584 : {
2585 0 : sal_Bool bModified = ((rInfo.DocumentState & AutoRecovery::E_MODIFIED) == AutoRecovery::E_MODIFIED);
2586 0 : xModify->setModified(bModified);
2587 : }
2588 :
2589 0 : rInfo.DocumentState &= ~AutoRecovery::E_TRY_LOAD_BACKUP;
2590 0 : rInfo.DocumentState &= ~AutoRecovery::E_TRY_LOAD_ORIGINAL;
2591 0 : rInfo.DocumentState |= AutoRecovery::E_HANDLED;
2592 0 : rInfo.DocumentState |= AutoRecovery::E_SUCCEDED;
2593 :
2594 0 : implts_flushConfigItem(rInfo);
2595 : implts_informListener(eJob,
2596 0 : AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &rInfo));
2597 :
2598 : /* Normaly we listen as XModifyListener on a document to know if a document was changed
2599 : since our last AutoSave. And we deregister us in case we know this state.
2600 : But directly after one document as recovered ... we must start listening.
2601 : Otherwhise the first "modify" doesnt reach us. Because we ourself called setModified()
2602 : on the document via API. And currently we dont listen for any events (not at the GlobalEventBroadcaster
2603 : nor at any document!).
2604 : */
2605 0 : implts_startModifyListeningOnDoc(rInfo);
2606 :
2607 : // SAFE -> ------------------------------
2608 : // Needed for next loop. Dont unlock it again!
2609 0 : aWriteLock.lock();
2610 0 : }
2611 :
2612 0 : aWriteLock.unlock();
2613 : // <- SAFE ----------------------------------
2614 :
2615 0 : return eTimer;
2616 : }
2617 :
2618 : //-----------------------------------------------
2619 0 : void AutoRecovery::implts_openOneDoc(const ::rtl::OUString& sURL ,
2620 : ::comphelper::MediaDescriptor& lDescriptor,
2621 : AutoRecovery::TDocumentInfo& rInfo )
2622 : {
2623 : // SAFE -> ----------------------------------
2624 0 : ReadGuard aReadLock(m_aLock);
2625 0 : css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
2626 0 : aReadLock.unlock();
2627 : // <- SAFE ----------------------------------
2628 :
2629 0 : css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( comphelper::getComponentContext(xSMGR));
2630 :
2631 0 : ::std::vector< Reference< XComponent > > aCleanup;
2632 : try
2633 : {
2634 : // create a new document of the desired type
2635 0 : Reference< XModel2 > xModel( xSMGR->createInstance( rInfo.FactoryService ), UNO_QUERY_THROW );
2636 0 : aCleanup.push_back( xModel.get() );
2637 :
2638 : // put the filter name into the descriptor - we're not going to involve any type detection, so
2639 : // the document might be lost without the FilterName property
2640 0 : if ( (rInfo.DocumentState & AutoRecovery::E_TRY_LOAD_ORIGINAL) == AutoRecovery::E_TRY_LOAD_ORIGINAL)
2641 0 : lDescriptor[ ::comphelper::MediaDescriptor::PROP_FILTERNAME() ] <<= rInfo.RealFilter;
2642 : else
2643 0 : lDescriptor[ ::comphelper::MediaDescriptor::PROP_FILTERNAME() ] <<= rInfo.DefaultFilter;
2644 :
2645 0 : if ( sURL == rInfo.FactoryURL )
2646 : {
2647 : // if the document was a new, unmodified document, then there's nothing to recover, just to init
2648 0 : ENSURE_OR_THROW( ( rInfo.DocumentState & AutoRecovery::E_MODIFIED ) == 0,
2649 : "unexpected document state" );
2650 0 : Reference< XLoadable > xModelLoad( xModel, UNO_QUERY_THROW );
2651 0 : xModelLoad->initNew();
2652 :
2653 : // TODO: remove load-process specific arguments from the descriptor, e.g. the status indicator
2654 0 : xModel->attachResource( sURL, lDescriptor.getAsConstPropertyValueList() );
2655 : }
2656 : else
2657 : {
2658 : // let it recover itself
2659 0 : Reference< XDocumentRecovery > xDocRecover( xModel, UNO_QUERY_THROW );
2660 0 : xDocRecover->recoverFromFile(
2661 : sURL,
2662 0 : lDescriptor.getUnpackedValueOrDefault( ::comphelper::MediaDescriptor::PROP_SALVAGEDFILE(), ::rtl::OUString() ),
2663 : lDescriptor.getAsConstPropertyValueList()
2664 0 : );
2665 :
2666 : // No attachResource needed here. By definition (of XDocumentRecovery), the implementation is responsible
2667 : // for completely initializing the model, which includes attachResource (or equivalent), if required.
2668 : }
2669 :
2670 : // re-create all the views
2671 0 : ::std::vector< ::rtl::OUString > aViewsToRestore( rInfo.ViewNames.getLength() );
2672 0 : if ( rInfo.ViewNames.getLength() )
2673 0 : ::std::copy( rInfo.ViewNames.getConstArray(), rInfo.ViewNames.getConstArray() + rInfo.ViewNames.getLength(), aViewsToRestore.begin() );
2674 : // if we don't have views for whatever reason, then create a default-view, at least
2675 0 : if ( aViewsToRestore.empty() )
2676 0 : aViewsToRestore.push_back( ::rtl::OUString() );
2677 :
2678 0 : for ( ::std::vector< ::rtl::OUString >::const_iterator viewName = aViewsToRestore.begin();
2679 0 : viewName != aViewsToRestore.end();
2680 : ++viewName
2681 : )
2682 : {
2683 : // create a frame
2684 0 : Reference< XFrame > xTargetFrame = xDesktop->findFrame( SPECIALTARGET_BLANK, 0 );
2685 0 : aCleanup.push_back( xTargetFrame.get() );
2686 :
2687 : // create a view to the document
2688 0 : Reference< XController2 > xController;
2689 0 : if ( viewName->getLength() )
2690 : {
2691 0 : xController.set( xModel->createViewController( *viewName, Sequence< PropertyValue >(), xTargetFrame ), UNO_SET_THROW );
2692 : }
2693 : else
2694 : {
2695 0 : xController.set( xModel->createDefaultViewController( xTargetFrame ), UNO_SET_THROW );
2696 : }
2697 :
2698 : // introduce model/view/controller to each other
2699 0 : xController->attachModel( xModel.get() );
2700 0 : xModel->connectController( xController.get() );
2701 0 : xTargetFrame->setComponent( xController->getComponentWindow(), xController.get() );
2702 0 : xController->attachFrame( xTargetFrame );
2703 0 : xModel->setCurrentController( xController.get() );
2704 0 : }
2705 :
2706 0 : rInfo.Document = xModel.get();
2707 : }
2708 0 : catch(const css::uno::RuntimeException&)
2709 : {
2710 0 : throw;
2711 : }
2712 0 : catch(const css::uno::Exception&)
2713 : {
2714 0 : Any aCaughtException( ::cppu::getCaughtException() );
2715 :
2716 : // clean up
2717 0 : for ( ::std::vector< Reference< XComponent > >::const_iterator component = aCleanup.begin();
2718 0 : component != aCleanup.end();
2719 : ++component
2720 : )
2721 : {
2722 0 : css::uno::Reference< css::util::XCloseable > xClose( *component, css::uno::UNO_QUERY );
2723 0 : if ( xClose.is() )
2724 0 : xClose->close( sal_True );
2725 : else
2726 0 : (*component)->dispose();
2727 0 : }
2728 :
2729 : // re-throw
2730 0 : ::rtl::OUStringBuffer sMsg(256);
2731 0 : sMsg.appendAscii("Recovery of \"");
2732 0 : sMsg.append (sURL );
2733 0 : sMsg.appendAscii("\" failed." );
2734 :
2735 : throw css::lang::WrappedTargetException(
2736 : sMsg.makeStringAndClear(),
2737 : static_cast< css::frame::XDispatch* >(this),
2738 : aCaughtException
2739 0 : );
2740 0 : }
2741 0 : }
2742 :
2743 : //-----------------------------------------------
2744 0 : void AutoRecovery::implts_generateNewTempURL(const ::rtl::OUString& sBackupPath ,
2745 : ::comphelper::MediaDescriptor& /*rMediaDescriptor*/,
2746 : AutoRecovery::TDocumentInfo& rInfo )
2747 : {
2748 : // SAFE -> ----------------------------------
2749 0 : ReadGuard aReadLock(m_aLock);
2750 0 : css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
2751 0 : aReadLock.unlock();
2752 : // <- SAFE ----------------------------------
2753 :
2754 : // specify URL for saving (which points to a temp file inside backup directory)
2755 : // and define an unique name, so we can locate it later.
2756 : // This unique name must solve an optimization problem too!
2757 : // In case we are asked to save unmodified documents too - and one of them
2758 : // is an empty one (because it was new created using e.g. an URL private:factory/...)
2759 : // we should not save it realy. Then we put the information about such "empty document"
2760 : // into the configuration and dont create any recovery file on disk.
2761 : // We use the title of the document to make it unique.
2762 0 : ::rtl::OUStringBuffer sUniqueName;
2763 0 : if (!rInfo.OrgURL.isEmpty())
2764 : {
2765 0 : css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(::comphelper::getComponentContext(m_xSMGR)));
2766 0 : css::util::URL aURL;
2767 0 : aURL.Complete = rInfo.OrgURL;
2768 0 : xParser->parseStrict(aURL);
2769 0 : sUniqueName.append(aURL.Name);
2770 : }
2771 0 : else if (!rInfo.FactoryURL.isEmpty())
2772 0 : sUniqueName.appendAscii("untitled");
2773 0 : sUniqueName.appendAscii("_");
2774 :
2775 : // TODO: Must we strip some illegal signes - if we use the title?
2776 :
2777 0 : rtl::OUString sName(sUniqueName.makeStringAndClear());
2778 0 : String sExtension(rInfo.Extension);
2779 0 : String sPath(sBackupPath);
2780 0 : ::utl::TempFile aTempFile(sName, &sExtension, &sPath);
2781 :
2782 0 : rInfo.NewTempURL = aTempFile.GetURL();
2783 0 : }
2784 :
2785 : //-----------------------------------------------
2786 0 : void AutoRecovery::implts_informListener( sal_Int32 eJob ,
2787 : const css::frame::FeatureStateEvent& aEvent)
2788 : {
2789 : // Helper shares mutex with us -> threadsafe!
2790 0 : ::cppu::OInterfaceContainerHelper* pListenerForURL = 0;
2791 0 : ::rtl::OUString sJob = AutoRecovery::implst_getJobDescription(eJob);
2792 :
2793 : // inform listener, which are registered for any URLs(!)
2794 0 : pListenerForURL = m_lListener.getContainer(sJob);
2795 0 : if(pListenerForURL != 0)
2796 : {
2797 0 : ::cppu::OInterfaceIteratorHelper pIt(*pListenerForURL);
2798 0 : while(pIt.hasMoreElements())
2799 : {
2800 : try
2801 : {
2802 0 : css::uno::Reference< css::frame::XStatusListener > xListener(((css::frame::XStatusListener*)pIt.next()), css::uno::UNO_QUERY);
2803 0 : xListener->statusChanged(aEvent);
2804 : }
2805 0 : catch(const css::uno::RuntimeException&)
2806 : {
2807 0 : pIt.remove();
2808 : }
2809 0 : }
2810 0 : }
2811 0 : }
2812 :
2813 : //-----------------------------------------------
2814 0 : ::rtl::OUString AutoRecovery::implst_getJobDescription(sal_Int32 eJob)
2815 : {
2816 : // describe the current running operation
2817 0 : ::rtl::OUStringBuffer sFeature(256);
2818 0 : sFeature.appendAscii(RTL_CONSTASCII_STRINGPARAM(CMD_PROTOCOL));
2819 :
2820 : // Attention: Because "eJob" is used as a flag field the order of checking these
2821 : // flags is importent. We must preferr job with higher priorities!
2822 : // E.g. EmergencySave has an higher prio then AutoSave ...
2823 : // On the other side there exist a well defined order between two different jobs.
2824 : // e.g. PrepareEmergencySave must be done before EmergencySave is started of course.
2825 :
2826 0 : if ((eJob & AutoRecovery::E_PREPARE_EMERGENCY_SAVE) == AutoRecovery::E_PREPARE_EMERGENCY_SAVE)
2827 0 : sFeature.appendAscii(RTL_CONSTASCII_STRINGPARAM(CMD_DO_PREPARE_EMERGENCY_SAVE));
2828 : else
2829 0 : if ((eJob & AutoRecovery::E_EMERGENCY_SAVE) == AutoRecovery::E_EMERGENCY_SAVE)
2830 0 : sFeature.appendAscii(RTL_CONSTASCII_STRINGPARAM(CMD_DO_EMERGENCY_SAVE));
2831 : else
2832 0 : if ((eJob & AutoRecovery::E_RECOVERY) == AutoRecovery::E_RECOVERY)
2833 0 : sFeature.appendAscii(RTL_CONSTASCII_STRINGPARAM(CMD_DO_RECOVERY));
2834 : else
2835 0 : if ((eJob & AutoRecovery::E_SESSION_SAVE) == AutoRecovery::E_SESSION_SAVE)
2836 0 : sFeature.appendAscii(RTL_CONSTASCII_STRINGPARAM(CMD_DO_SESSION_SAVE));
2837 : else
2838 0 : if ((eJob & AutoRecovery::E_SESSION_QUIET_QUIT) == AutoRecovery::E_SESSION_QUIET_QUIT)
2839 0 : sFeature.appendAscii(RTL_CONSTASCII_STRINGPARAM(CMD_DO_SESSION_QUIET_QUIT));
2840 : else
2841 0 : if ((eJob & AutoRecovery::E_SESSION_RESTORE) == AutoRecovery::E_SESSION_RESTORE)
2842 0 : sFeature.appendAscii(RTL_CONSTASCII_STRINGPARAM(CMD_DO_SESSION_RESTORE));
2843 : else
2844 0 : if ((eJob & AutoRecovery::E_ENTRY_BACKUP) == AutoRecovery::E_ENTRY_BACKUP)
2845 0 : sFeature.appendAscii(RTL_CONSTASCII_STRINGPARAM(CMD_DO_ENTRY_BACKUP));
2846 : else
2847 0 : if ((eJob & AutoRecovery::E_ENTRY_CLEANUP) == AutoRecovery::E_ENTRY_CLEANUP)
2848 0 : sFeature.appendAscii(RTL_CONSTASCII_STRINGPARAM(CMD_DO_ENTRY_CLEANUP));
2849 : else
2850 0 : if ((eJob & AutoRecovery::E_AUTO_SAVE) == AutoRecovery::E_AUTO_SAVE)
2851 0 : sFeature.appendAscii(RTL_CONSTASCII_STRINGPARAM(CMD_DO_AUTO_SAVE));
2852 : #ifdef ENABLE_WARNINGS
2853 : else if ( eJob != AutoRecovery::E_NO_JOB )
2854 : LOG_WARNING("AutoRecovery::implst_getJobDescription()", "Invalid job identifier detected.")
2855 : #endif
2856 :
2857 0 : return sFeature.makeStringAndClear();
2858 : }
2859 :
2860 : //-----------------------------------------------
2861 0 : sal_Int32 AutoRecovery::implst_classifyJob(const css::util::URL& aURL)
2862 : {
2863 0 : if ( aURL.Protocol == CMD_PROTOCOL )
2864 : {
2865 0 : if ( aURL.Path == CMD_DO_PREPARE_EMERGENCY_SAVE )
2866 0 : return AutoRecovery::E_PREPARE_EMERGENCY_SAVE;
2867 0 : else if ( aURL.Path == CMD_DO_EMERGENCY_SAVE )
2868 0 : return AutoRecovery::E_EMERGENCY_SAVE;
2869 0 : else if ( aURL.Path == CMD_DO_RECOVERY )
2870 0 : return AutoRecovery::E_RECOVERY;
2871 0 : else if ( aURL.Path == CMD_DO_ENTRY_BACKUP )
2872 0 : return AutoRecovery::E_ENTRY_BACKUP;
2873 0 : else if ( aURL.Path == CMD_DO_ENTRY_CLEANUP )
2874 0 : return AutoRecovery::E_ENTRY_CLEANUP;
2875 0 : else if ( aURL.Path == CMD_DO_SESSION_SAVE )
2876 0 : return AutoRecovery::E_SESSION_SAVE;
2877 0 : else if ( aURL.Path == CMD_DO_SESSION_QUIET_QUIT )
2878 0 : return AutoRecovery::E_SESSION_QUIET_QUIT;
2879 0 : else if ( aURL.Path == CMD_DO_SESSION_RESTORE )
2880 0 : return AutoRecovery::E_SESSION_RESTORE;
2881 0 : else if ( aURL.Path == CMD_DO_DISABLE_RECOVERY )
2882 0 : return AutoRecovery::E_DISABLE_AUTORECOVERY;
2883 0 : else if ( aURL.Path == CMD_DO_SET_AUTOSAVE_STATE )
2884 0 : return AutoRecovery::E_SET_AUTOSAVE_STATE;
2885 : }
2886 :
2887 : LOG_WARNING("AutoRecovery::implts_classifyJob()", "Invalid URL (protocol).")
2888 0 : return AutoRecovery::E_NO_JOB;
2889 : }
2890 :
2891 : //-----------------------------------------------
2892 0 : css::frame::FeatureStateEvent AutoRecovery::implst_createFeatureStateEvent( sal_Int32 eJob ,
2893 : const ::rtl::OUString& sEventType,
2894 : AutoRecovery::TDocumentInfo* pInfo )
2895 : {
2896 0 : css::frame::FeatureStateEvent aEvent;
2897 0 : aEvent.FeatureURL.Complete = AutoRecovery::implst_getJobDescription(eJob);
2898 0 : aEvent.FeatureDescriptor = sEventType;
2899 :
2900 0 : if (pInfo && sEventType.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(OPERATION_UPDATE)))
2901 : {
2902 : // pack rInfo for transport via UNO
2903 0 : ::comphelper::NamedValueCollection aInfo;
2904 0 : aInfo.put( rtl::OUString(CFG_ENTRY_PROP_ID), pInfo->ID );
2905 0 : aInfo.put( rtl::OUString(CFG_ENTRY_PROP_ORIGINALURL), pInfo->OrgURL );
2906 0 : aInfo.put( rtl::OUString(CFG_ENTRY_PROP_FACTORYURL), pInfo->FactoryURL );
2907 0 : aInfo.put( rtl::OUString(CFG_ENTRY_PROP_TEMPLATEURL), pInfo->TemplateURL );
2908 0 : aInfo.put( rtl::OUString(CFG_ENTRY_PROP_TEMPURL), pInfo->OldTempURL.isEmpty() ? pInfo->NewTempURL : pInfo->OldTempURL );
2909 0 : aInfo.put( rtl::OUString(CFG_ENTRY_PROP_MODULE), pInfo->AppModule) ;
2910 0 : aInfo.put( rtl::OUString(CFG_ENTRY_PROP_TITLE), pInfo->Title);
2911 0 : aInfo.put( rtl::OUString(CFG_ENTRY_PROP_VIEWNAMES), pInfo->ViewNames);
2912 0 : aInfo.put( rtl::OUString(CFG_ENTRY_PROP_DOCUMENTSTATE), pInfo->DocumentState);
2913 :
2914 0 : aEvent.State <<= aInfo.getPropertyValues();
2915 : }
2916 :
2917 0 : return aEvent;
2918 : }
2919 :
2920 : //-----------------------------------------------
2921 0 : void AutoRecovery::implts_resetHandleStates(sal_Bool /*bLoadCache*/)
2922 : {
2923 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
2924 :
2925 : // SAFE -> ------------------------------
2926 0 : WriteGuard aWriteLock(m_aLock);
2927 :
2928 0 : AutoRecovery::TDocumentList::iterator pIt;
2929 0 : for ( pIt = m_lDocCache.begin();
2930 0 : pIt != m_lDocCache.end() ;
2931 : ++pIt )
2932 : {
2933 0 : AutoRecovery::TDocumentInfo& rInfo = *pIt;
2934 0 : rInfo.DocumentState &= ~AutoRecovery::E_HANDLED ;
2935 0 : rInfo.DocumentState &= ~AutoRecovery::E_POSTPONED;
2936 :
2937 : // SAFE -> ------------------------------
2938 0 : aWriteLock.unlock();
2939 0 : implts_flushConfigItem(rInfo);
2940 0 : aWriteLock.lock();
2941 : // <- SAFE ------------------------------
2942 : }
2943 :
2944 0 : aWriteLock.unlock();
2945 : // <- SAFE ----------------------------------
2946 0 : }
2947 :
2948 : //-----------------------------------------------
2949 0 : void AutoRecovery::implts_prepareEmergencySave()
2950 : {
2951 : // Be sure to know all open documents realy .-)
2952 0 : implts_verifyCacheAgainstDesktopDocumentList();
2953 :
2954 : // hide all docs, so the user cant disturb our emergency save .-)
2955 0 : implts_changeAllDocVisibility(sal_False);
2956 0 : }
2957 :
2958 : //-----------------------------------------------
2959 0 : void AutoRecovery::implts_doEmergencySave(const DispatchParams& aParams)
2960 : {
2961 : // Write a hint "we chrashed" into the configuration, so
2962 : // the error report tool is started too in case no recovery
2963 : // documents exists and was saved.
2964 : ::comphelper::ConfigurationHelper::writeDirectKey(
2965 : comphelper::getComponentContext(m_xSMGR),
2966 : rtl::OUString(CFG_PACKAGE_RECOVERY),
2967 : rtl::OUString(CFG_PATH_RECOVERYINFO),
2968 : rtl::OUString(CFG_ENTRY_CRASHED),
2969 : css::uno::makeAny(sal_True),
2970 0 : ::comphelper::ConfigurationHelper::E_STANDARD);
2971 :
2972 : // for all docs, store their current view/names in the configurtion
2973 0 : implts_persistAllActiveViewNames();
2974 :
2975 : // The called method for saving documents runs
2976 : // during normal AutoSave more then once. Because
2977 : // it postpone active documents and save it later.
2978 : // That is normaly done by recalling it from a timer.
2979 : // Here we must do it immediatly!
2980 : // Of course this method returns the right state -
2981 : // because it knows, that we are running in ERMERGENCY SAVE mode .-)
2982 :
2983 0 : sal_Bool bAllowUserIdleLoop = sal_False; // not allowed to change that .-)
2984 0 : AutoRecovery::ETimerType eSuggestedTimer = AutoRecovery::E_DONT_START_TIMER;
2985 0 : do
2986 : {
2987 0 : eSuggestedTimer = implts_saveDocs(bAllowUserIdleLoop, sal_True, &aParams);
2988 : }
2989 : while(eSuggestedTimer == AutoRecovery::E_CALL_ME_BACK);
2990 :
2991 : // reset the handle state of all
2992 : // cache items. Such handle state indicates, that a document
2993 : // was already saved during the THIS(!) EmergencySave session.
2994 : // Of course following recovery session must be started without
2995 : // any "handle" state ...
2996 0 : implts_resetHandleStates(sal_False);
2997 :
2998 : // flush config cached back to disc.
2999 0 : impl_flushALLConfigChanges();
3000 :
3001 : // try to make sure next time office will be started user wont be
3002 : // notified about any other might be running office instance
3003 : // remove ".lock" file from disc !
3004 0 : AutoRecovery::st_impl_removeLockFile();
3005 0 : }
3006 :
3007 : //-----------------------------------------------
3008 0 : void AutoRecovery::implts_doRecovery(const DispatchParams& aParams)
3009 : {
3010 0 : AutoRecovery::ETimerType eSuggestedTimer = AutoRecovery::E_DONT_START_TIMER;
3011 0 : do
3012 : {
3013 0 : eSuggestedTimer = implts_openDocs(aParams);
3014 : }
3015 : while(eSuggestedTimer == AutoRecovery::E_CALL_ME_BACK);
3016 :
3017 : // reset the handle state of all
3018 : // cache items. Such handle state indicates, that a document
3019 : // was already saved during the THIS(!) Recovery session.
3020 : // Of course a may be following EmergencySave session must be started without
3021 : // any "handle" state ...
3022 0 : implts_resetHandleStates(sal_True);
3023 :
3024 : // Reset the configuration hint "we was crashed"!
3025 : ::comphelper::ConfigurationHelper::writeDirectKey(
3026 : comphelper::getComponentContext(m_xSMGR),
3027 : rtl::OUString(CFG_PACKAGE_RECOVERY),
3028 : rtl::OUString(CFG_PATH_RECOVERYINFO),
3029 : rtl::OUString(CFG_ENTRY_CRASHED),
3030 : css::uno::makeAny(sal_False),
3031 0 : ::comphelper::ConfigurationHelper::E_STANDARD);
3032 0 : }
3033 :
3034 : //-----------------------------------------------
3035 0 : void AutoRecovery::implts_doSessionSave(const DispatchParams& aParams)
3036 : {
3037 : LOG_RECOVERY("AutoRecovery::implts_doSessionSave()")
3038 :
3039 : // Be sure to know all open documents realy .-)
3040 0 : implts_verifyCacheAgainstDesktopDocumentList();
3041 :
3042 : // for all docs, store their current view/names in the configurtion
3043 0 : implts_persistAllActiveViewNames();
3044 :
3045 : // The called method for saving documents runs
3046 : // during normal AutoSave more then once. Because
3047 : // it postpone active documents and save it later.
3048 : // That is normaly done by recalling it from a timer.
3049 : // Here we must do it immediatly!
3050 : // Of course this method returns the right state -
3051 : // because it knows, that we are running in SESSION SAVE mode .-)
3052 :
3053 0 : sal_Bool bAllowUserIdleLoop = sal_False; // not allowed to change that .-)
3054 0 : AutoRecovery::ETimerType eSuggestedTimer = AutoRecovery::E_DONT_START_TIMER;
3055 0 : do
3056 : {
3057 : // do not remove lock files of the documents, it will be done on session quit
3058 0 : eSuggestedTimer = implts_saveDocs(bAllowUserIdleLoop, sal_False, &aParams);
3059 : }
3060 : while(eSuggestedTimer == AutoRecovery::E_CALL_ME_BACK);
3061 :
3062 : // reset the handle state of all
3063 : // cache items. Such handle state indicates, that a document
3064 : // was already saved during the THIS(!) save session.
3065 : // Of course following restore session must be started without
3066 : // any "handle" state ...
3067 0 : implts_resetHandleStates(sal_False);
3068 :
3069 : // flush config cached back to disc.
3070 0 : impl_flushALLConfigChanges();
3071 0 : }
3072 :
3073 : //-----------------------------------------------
3074 0 : void AutoRecovery::implts_doSessionQuietQuit(const DispatchParams& /*aParams*/)
3075 : {
3076 : LOG_RECOVERY("AutoRecovery::implts_doSessionQuietQuit()")
3077 :
3078 : // try to make sure next time office will be started user wont be
3079 : // notified about any other might be running office instance
3080 : // remove ".lock" file from disc !
3081 : // it is done as a first action for session save since Gnome sessions
3082 : // do not provide enough time for shutdown, and the dialog looks to be
3083 : // confusing for the user
3084 0 : AutoRecovery::st_impl_removeLockFile();
3085 :
3086 : // reset all modified documents, so the dont show any UI on closing ...
3087 : // and close all documents, so we can shutdown the OS!
3088 0 : implts_prepareSessionShutdown();
3089 :
3090 : // Write a hint for "stored session data" into the configuration, so
3091 : // the on next startup we know what's happen last time
3092 : ::comphelper::ConfigurationHelper::writeDirectKey(
3093 : comphelper::getComponentContext(m_xSMGR),
3094 : rtl::OUString(CFG_PACKAGE_RECOVERY),
3095 : rtl::OUString(CFG_PATH_RECOVERYINFO),
3096 : rtl::OUString(CFG_ENTRY_SESSIONDATA),
3097 : css::uno::makeAny(sal_True),
3098 0 : ::comphelper::ConfigurationHelper::E_STANDARD);
3099 :
3100 : // flush config cached back to disc.
3101 0 : impl_flushALLConfigChanges();
3102 0 : }
3103 :
3104 :
3105 : //-----------------------------------------------
3106 0 : void AutoRecovery::implts_doSessionRestore(const DispatchParams& aParams)
3107 : {
3108 : LOG_RECOVERY("AutoRecovery::implts_doSessionRestore() ...")
3109 :
3110 0 : AutoRecovery::ETimerType eSuggestedTimer = AutoRecovery::E_DONT_START_TIMER;
3111 0 : do
3112 : {
3113 0 : eSuggestedTimer = implts_openDocs(aParams);
3114 : }
3115 : while(eSuggestedTimer == AutoRecovery::E_CALL_ME_BACK);
3116 :
3117 : // reset the handle state of all
3118 : // cache items. Such handle state indicates, that a document
3119 : // was already saved during the THIS(!) Restore session.
3120 : // Of course a may be following save session must be started without
3121 : // any "handle" state ...
3122 0 : implts_resetHandleStates(sal_True);
3123 :
3124 : // make all opened documents visible
3125 0 : implts_changeAllDocVisibility(sal_True);
3126 :
3127 : // Reset the configuration hint for "session save"!
3128 : LOG_RECOVERY("... reset config key 'SessionData'")
3129 : ::comphelper::ConfigurationHelper::writeDirectKey(
3130 : comphelper::getComponentContext(m_xSMGR),
3131 : rtl::OUString(CFG_PACKAGE_RECOVERY),
3132 : rtl::OUString(CFG_PATH_RECOVERYINFO),
3133 : rtl::OUString(CFG_ENTRY_SESSIONDATA),
3134 : css::uno::makeAny(sal_False),
3135 0 : ::comphelper::ConfigurationHelper::E_STANDARD);
3136 :
3137 : LOG_RECOVERY("... AutoRecovery::implts_doSessionRestore()")
3138 0 : }
3139 :
3140 : //-----------------------------------------------
3141 0 : void AutoRecovery::implts_backupWorkingEntry(const DispatchParams& aParams)
3142 : {
3143 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
3144 :
3145 0 : AutoRecovery::TDocumentList::iterator pIt;
3146 0 : for ( pIt = m_lDocCache.begin();
3147 0 : pIt != m_lDocCache.end() ;
3148 : ++pIt )
3149 : {
3150 0 : const AutoRecovery::TDocumentInfo& rInfo = *pIt;
3151 0 : if (rInfo.ID != aParams.m_nWorkingEntryID)
3152 0 : continue;
3153 :
3154 0 : ::rtl::OUString sSourceURL;
3155 : // Prefer temp file. It contains the changes against the original document!
3156 0 : if (!rInfo.OldTempURL.isEmpty())
3157 0 : sSourceURL = rInfo.OldTempURL;
3158 0 : else if (!rInfo.NewTempURL.isEmpty())
3159 0 : sSourceURL = rInfo.NewTempURL;
3160 0 : else if (!rInfo.OrgURL.isEmpty())
3161 0 : sSourceURL = rInfo.OrgURL;
3162 : else
3163 0 : continue; // nothing real to save! An unmodified but new created document.
3164 :
3165 0 : INetURLObject aParser(sSourceURL);
3166 : // AutoRecovery::EFailureSafeResult eResult =
3167 0 : implts_copyFile(sSourceURL, aParams.m_sSavePath, aParser.getName());
3168 :
3169 : // TODO: Check eResult and react for errors (InteractionHandler!?)
3170 : // Currently we ignore it ...
3171 : // DONT UPDATE THE CACHE OR REMOVE ANY TEMP. FILES FROM DISK.
3172 : // That has to be forced from outside explicitly.
3173 : // See implts_cleanUpWorkingEntry() for further details.
3174 0 : }
3175 0 : }
3176 :
3177 : //-----------------------------------------------
3178 0 : void AutoRecovery::implts_cleanUpWorkingEntry(const DispatchParams& aParams)
3179 : {
3180 0 : CacheLockGuard aCacheLock(this, m_aLock, m_nDocCacheLock, LOCK_FOR_CACHE_ADD_REMOVE);
3181 :
3182 0 : AutoRecovery::TDocumentList::iterator pIt;
3183 0 : for ( pIt = m_lDocCache.begin();
3184 0 : pIt != m_lDocCache.end() ;
3185 : ++pIt )
3186 : {
3187 0 : AutoRecovery::TDocumentInfo& rInfo = *pIt;
3188 0 : if (rInfo.ID != aParams.m_nWorkingEntryID)
3189 0 : continue;
3190 :
3191 0 : AutoRecovery::st_impl_removeFile(rInfo.OldTempURL);
3192 0 : AutoRecovery::st_impl_removeFile(rInfo.NewTempURL);
3193 0 : implts_flushConfigItem(rInfo, sal_True); // sal_True => remove it from xml config!
3194 :
3195 0 : m_lDocCache.erase(pIt);
3196 0 : break; /// !!! pIt is not defined any longer ... further this function has finished it's work
3197 0 : }
3198 0 : }
3199 :
3200 : //-----------------------------------------------
3201 0 : AutoRecovery::EFailureSafeResult AutoRecovery::implts_copyFile(const ::rtl::OUString& sSource ,
3202 : const ::rtl::OUString& sTargetPath,
3203 : const ::rtl::OUString& sTargetName)
3204 : {
3205 : // create content for the parent folder and call transfer on that content with the source content
3206 : // and the destination file name as parameters
3207 :
3208 0 : css::uno::Reference< css::ucb::XCommandEnvironment > xEnvironment;
3209 :
3210 0 : ::ucbhelper::Content aSourceContent;
3211 0 : ::ucbhelper::Content aTargetContent;
3212 :
3213 : try
3214 : {
3215 0 : aTargetContent = ::ucbhelper::Content(sTargetPath, xEnvironment, comphelper::getComponentContext(m_xSMGR));
3216 : }
3217 0 : catch(const css::uno::Exception&)
3218 : {
3219 0 : return AutoRecovery::E_WRONG_TARGET_PATH;
3220 : }
3221 :
3222 : sal_Int32 nNameClash;
3223 0 : nNameClash = css::ucb::NameClash::RENAME;
3224 :
3225 : try
3226 : {
3227 0 : ::ucbhelper::Content::create(sSource, xEnvironment, comphelper::getComponentContext(m_xSMGR), aSourceContent);
3228 0 : aTargetContent.transferContent(aSourceContent, ::ucbhelper::InsertOperation_COPY, sTargetName, nNameClash);
3229 : }
3230 0 : catch(const css::uno::Exception&)
3231 : {
3232 0 : return AutoRecovery::E_ORIGINAL_FILE_MISSING;
3233 : }
3234 :
3235 0 : return AutoRecovery::E_COPIED;
3236 : }
3237 :
3238 : //-----------------------------------------------
3239 0 : sal_Bool SAL_CALL AutoRecovery::convertFastPropertyValue( css::uno::Any& /*aConvertedValue*/,
3240 : css::uno::Any& /*aOldValue*/ ,
3241 : sal_Int32 /*nHandle*/ ,
3242 : const css::uno::Any& /*aValue*/ )
3243 : throw(css::lang::IllegalArgumentException)
3244 : {
3245 : // not needed currently
3246 0 : return sal_False;
3247 : }
3248 :
3249 : //-----------------------------------------------
3250 0 : void SAL_CALL AutoRecovery::setFastPropertyValue_NoBroadcast( sal_Int32 /*nHandle*/,
3251 : const css::uno::Any& /*aValue*/ )
3252 : throw(css::uno::Exception)
3253 : {
3254 : // not needed currently
3255 0 : }
3256 :
3257 : //-----------------------------------------------
3258 0 : void SAL_CALL AutoRecovery::getFastPropertyValue(css::uno::Any& aValue ,
3259 : sal_Int32 nHandle) const
3260 : {
3261 0 : switch(nHandle)
3262 : {
3263 : case AUTORECOVERY_PROPHANDLE_EXISTS_RECOVERYDATA :
3264 : {
3265 0 : sal_Bool bSessionData = sal_False;
3266 : ::comphelper::ConfigurationHelper::readDirectKey(
3267 : comphelper::getComponentContext(m_xSMGR),
3268 : rtl::OUString(CFG_PACKAGE_RECOVERY),
3269 : rtl::OUString(CFG_PATH_RECOVERYINFO),
3270 : rtl::OUString(CFG_ENTRY_SESSIONDATA),
3271 0 : ::comphelper::ConfigurationHelper::E_READONLY) >>= bSessionData;
3272 :
3273 0 : sal_Bool bRecoveryData = ((sal_Bool)(m_lDocCache.size()>0));
3274 :
3275 : // exists session data ... => then we cant say, that these
3276 : // data are valid for recovery. So we have to return sal_False then!
3277 0 : if (bSessionData)
3278 0 : bRecoveryData = sal_False;
3279 :
3280 0 : aValue <<= bRecoveryData;
3281 : }
3282 0 : break;
3283 :
3284 : case AUTORECOVERY_PROPHANDLE_CRASHED :
3285 : aValue = ::comphelper::ConfigurationHelper::readDirectKey(
3286 : comphelper::getComponentContext(m_xSMGR),
3287 : rtl::OUString(CFG_PACKAGE_RECOVERY),
3288 : rtl::OUString(CFG_PATH_RECOVERYINFO),
3289 : rtl::OUString(CFG_ENTRY_CRASHED),
3290 0 : ::comphelper::ConfigurationHelper::E_READONLY);
3291 0 : break;
3292 :
3293 : case AUTORECOVERY_PROPHANDLE_EXISTS_SESSIONDATA :
3294 : aValue = ::comphelper::ConfigurationHelper::readDirectKey(
3295 : comphelper::getComponentContext(m_xSMGR),
3296 : rtl::OUString(CFG_PACKAGE_RECOVERY),
3297 : rtl::OUString(CFG_PATH_RECOVERYINFO),
3298 : rtl::OUString(CFG_ENTRY_SESSIONDATA),
3299 0 : ::comphelper::ConfigurationHelper::E_READONLY);
3300 0 : break;
3301 : }
3302 0 : }
3303 :
3304 : //-----------------------------------------------
3305 0 : const css::uno::Sequence< css::beans::Property > impl_getStaticPropertyDescriptor()
3306 : {
3307 : const css::beans::Property pPropertys[] =
3308 : {
3309 0 : css::beans::Property( AUTORECOVERY_PROPNAME_CRASHED , AUTORECOVERY_PROPHANDLE_CRASHED , ::getBooleanCppuType() , css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY ),
3310 0 : css::beans::Property( AUTORECOVERY_PROPNAME_EXISTS_RECOVERYDATA, AUTORECOVERY_PROPHANDLE_EXISTS_RECOVERYDATA, ::getBooleanCppuType() , css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY ),
3311 0 : css::beans::Property( AUTORECOVERY_PROPNAME_EXISTS_SESSIONDATA , AUTORECOVERY_PROPHANDLE_EXISTS_SESSIONDATA , ::getBooleanCppuType() , css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY ),
3312 0 : };
3313 0 : const css::uno::Sequence< css::beans::Property > lPropertyDescriptor(pPropertys, AUTORECOVERY_PROPCOUNT);
3314 0 : return lPropertyDescriptor;
3315 : }
3316 :
3317 : //-----------------------------------------------
3318 0 : ::cppu::IPropertyArrayHelper& SAL_CALL AutoRecovery::getInfoHelper()
3319 : {
3320 : static ::cppu::OPropertyArrayHelper* pInfoHelper = 0;
3321 0 : if(!pInfoHelper)
3322 : {
3323 0 : ::osl::MutexGuard aGuard( LockHelper::getGlobalLock().getShareableOslMutex() );
3324 0 : if(!pInfoHelper)
3325 : {
3326 0 : static ::cppu::OPropertyArrayHelper aInfoHelper(impl_getStaticPropertyDescriptor(), sal_True);
3327 0 : pInfoHelper = &aInfoHelper;
3328 0 : }
3329 : }
3330 :
3331 0 : return (*pInfoHelper);
3332 : }
3333 :
3334 : //-----------------------------------------------
3335 0 : css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL AutoRecovery::getPropertySetInfo()
3336 : throw(css::uno::RuntimeException)
3337 : {
3338 : static css::uno::Reference< css::beans::XPropertySetInfo >* pInfo = 0;
3339 0 : if(!pInfo)
3340 : {
3341 0 : ::osl::MutexGuard aGuard( LockHelper::getGlobalLock().getShareableOslMutex() );
3342 0 : if(!pInfo)
3343 : {
3344 0 : static css::uno::Reference< css::beans::XPropertySetInfo > xInfo(createPropertySetInfo(getInfoHelper()));
3345 0 : pInfo = &xInfo;
3346 0 : }
3347 : }
3348 :
3349 0 : return (*pInfo);
3350 : }
3351 :
3352 : //-----------------------------------------------
3353 0 : void AutoRecovery::implts_verifyCacheAgainstDesktopDocumentList()
3354 : {
3355 : LOG_RECOVERY("AutoRecovery::implts_verifyCacheAgainstDesktopDocumentList() ...")
3356 :
3357 : // SAFE -> ----------------------------------
3358 0 : WriteGuard aWriteLock(m_aLock);
3359 0 : css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
3360 0 : aWriteLock.unlock();
3361 : // <- SAFE ----------------------------------
3362 :
3363 : try
3364 : {
3365 0 : css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( comphelper::getComponentContext(xSMGR));
3366 :
3367 : css::uno::Reference< css::container::XIndexAccess > xContainer(
3368 0 : xDesktop->getFrames(),
3369 0 : css::uno::UNO_QUERY_THROW);
3370 :
3371 0 : sal_Int32 i = 0;
3372 0 : sal_Int32 c = xContainer->getCount();
3373 :
3374 0 : for (i=0; i<c; ++i)
3375 : {
3376 0 : css::uno::Reference< css::frame::XFrame > xFrame;
3377 : try
3378 : {
3379 0 : xContainer->getByIndex(i) >>= xFrame;
3380 0 : if (!xFrame.is())
3381 0 : continue;
3382 : }
3383 : // can happen in multithreaded environments, that frames was removed from the container during this loop runs!
3384 : // Ignore it.
3385 0 : catch(const css::lang::IndexOutOfBoundsException&)
3386 : {
3387 0 : continue;
3388 : }
3389 :
3390 : // We are interested on visible documents only.
3391 : // Note: It's n optional interface .-(
3392 : css::uno::Reference< css::awt::XWindow2 > xVisibleCheck(
3393 0 : xFrame->getContainerWindow(),
3394 0 : css::uno::UNO_QUERY);
3395 0 : if (
3396 0 : (!xVisibleCheck.is() ) ||
3397 0 : (!xVisibleCheck->isVisible())
3398 : )
3399 : {
3400 0 : continue;
3401 : }
3402 :
3403 : // extract the model from the frame.
3404 : // Ignore "view only" frames, which does not have a model.
3405 0 : css::uno::Reference< css::frame::XController > xController;
3406 0 : css::uno::Reference< css::frame::XModel > xModel;
3407 :
3408 0 : xController = xFrame->getController();
3409 0 : if (xController.is())
3410 0 : xModel = xController->getModel();
3411 0 : if (!xModel.is())
3412 0 : continue;
3413 :
3414 : // insert model into cache ...
3415 : // If the model is already well known inside cache
3416 : // it's information set will be updated by asking the
3417 : // model again for it's new states.
3418 0 : implts_registerDocument(xModel);
3419 0 : }
3420 : }
3421 0 : catch(const css::uno::RuntimeException&)
3422 : {
3423 0 : throw;
3424 : }
3425 0 : catch(const css::uno::Exception&)
3426 : {
3427 0 : }
3428 :
3429 : LOG_RECOVERY("... AutoRecovery::implts_verifyCacheAgainstDesktopDocumentList()")
3430 0 : }
3431 :
3432 : //-----------------------------------------------
3433 0 : sal_Bool AutoRecovery::impl_enoughDiscSpace(sal_Int32 nRequiredSpace)
3434 : {
3435 : #ifdef SIMULATE_FULL_DISC
3436 : return sal_False;
3437 : #else // SIMULATE_FULL_DISC
3438 : // In case an error occures and we are not able to retrieve the needed information
3439 : // it's better to "disable" the feature ShowErrorOnFullDisc !
3440 : // Otherwhise we start a confusing process of error handling ...
3441 :
3442 0 : sal_uInt64 nFreeSpace = SAL_MAX_UINT64;
3443 :
3444 0 : ::rtl::OUString sBackupPath(SvtPathOptions().GetBackupPath());
3445 0 : ::osl::VolumeInfo aInfo (osl_VolumeInfo_Mask_FreeSpace);
3446 0 : ::osl::FileBase::RC aRC = ::osl::Directory::getVolumeInfo(sBackupPath, aInfo);
3447 :
3448 0 : if (
3449 0 : (aInfo.isValid(osl_VolumeInfo_Mask_FreeSpace)) &&
3450 : (aRC == ::osl::FileBase::E_None )
3451 : )
3452 : {
3453 0 : nFreeSpace = aInfo.getFreeSpace();
3454 : }
3455 :
3456 0 : sal_uInt64 nFreeMB = (nFreeSpace/1048576);
3457 0 : return (nFreeMB >= (sal_uInt64)nRequiredSpace);
3458 : #endif // SIMULATE_FULL_DISC
3459 : }
3460 :
3461 : //-----------------------------------------------
3462 0 : void AutoRecovery::impl_showFullDiscError()
3463 : {
3464 0 : rtl::OUString sBtn(FWK_RESSTR(STR_FULL_DISC_RETRY_BUTTON));
3465 0 : rtl::OUString sMsg(FWK_RESSTR(STR_FULL_DISC_MSG));
3466 :
3467 0 : rtl::OUString sBackupURL(SvtPathOptions().GetBackupPath());
3468 0 : INetURLObject aConverter(sBackupURL);
3469 : sal_Unicode aDelimiter;
3470 0 : rtl::OUString sBackupPath = aConverter.getFSysPath(INetURLObject::FSYS_DETECT, &aDelimiter);
3471 0 : if (sBackupPath.getLength() < 1)
3472 0 : sBackupPath = sBackupURL;
3473 :
3474 : ErrorBox dlgError(
3475 : 0, WB_OK,
3476 0 : sMsg.replaceAll("%PATH", sBackupPath));
3477 0 : dlgError.SetButtonText(dlgError.GetButtonId(0), sBtn);
3478 0 : dlgError.Execute();
3479 0 : }
3480 :
3481 : //-----------------------------------------------
3482 0 : void AutoRecovery::impl_establishProgress(const AutoRecovery::TDocumentInfo& rInfo ,
3483 : ::comphelper::MediaDescriptor& rArgs ,
3484 : const css::uno::Reference< css::frame::XFrame >& xNewFrame)
3485 : {
3486 : // external well known frame must be preferred (because it was created by ourself
3487 : // for loading documents into this frame)!
3488 : // But if no frame exists ... we can try to locate it using any frame bound to the provided
3489 : // document. Of course we must live without any frame in case the document does not exists at this
3490 : // point. But this state shouldnt occure. In such case xNewFrame should be valid ... hopefully .-)
3491 0 : css::uno::Reference< css::frame::XFrame > xFrame = xNewFrame;
3492 0 : if (
3493 0 : (!xFrame.is() ) &&
3494 0 : (rInfo.Document.is())
3495 : )
3496 : {
3497 0 : css::uno::Reference< css::frame::XController > xController = rInfo.Document->getCurrentController();
3498 0 : if (xController.is())
3499 0 : xFrame = xController->getFrame();
3500 : }
3501 :
3502 : // Any outside progress must be used ...
3503 : // Only if there is no progress, we can create our own one.
3504 0 : css::uno::Reference< css::task::XStatusIndicator > xInternalProgress;
3505 : css::uno::Reference< css::task::XStatusIndicator > xExternalProgress = rArgs.getUnpackedValueOrDefault(
3506 0 : ::comphelper::MediaDescriptor::PROP_STATUSINDICATOR(),
3507 0 : css::uno::Reference< css::task::XStatusIndicator >() );
3508 :
3509 : // Normaly a progress is set from outside (e.g. by the CrashSave/Recovery dialog, which uses our dispatch API).
3510 : // But for a normal auto save we dont have such "external progress"... because this function is triggered by our own timer then.
3511 : // In such case we must create our own progress !
3512 0 : if (
3513 0 : (! xExternalProgress.is()) &&
3514 0 : (xFrame.is() )
3515 : )
3516 : {
3517 0 : css::uno::Reference< css::task::XStatusIndicatorFactory > xProgressFactory(xFrame, css::uno::UNO_QUERY);
3518 0 : if (xProgressFactory.is())
3519 0 : xInternalProgress = xProgressFactory->createStatusIndicator();
3520 : }
3521 :
3522 : // HACK
3523 : // An external provided progress (most given by the CrashSave/Recovery dialog)
3524 : // must be preferred. But we know that some application filters query it's own progress instance
3525 : // at the frame method Frame::createStatusIndicator().
3526 : // So we use a two step mechanism:
3527 : // 1) we set the progress inside the MediaDescriptor, which will be provided to the filter
3528 : // 2) and we set a special Frame property, which overwrites the normal behaviour of Frame::createStatusIndicator .-)
3529 : // But we supress 2) in case we uses an internal progress. Because then it doesnt matter
3530 : // if our applications make it wrong. In such case the internal progress resists at the same frame
3531 : // and there is no need to forward progress activities to e.g. an outside dialog .-)
3532 0 : if (
3533 0 : (xExternalProgress.is()) &&
3534 0 : (xFrame.is() )
3535 : )
3536 : {
3537 0 : css::uno::Reference< css::beans::XPropertySet > xFrameProps(xFrame, css::uno::UNO_QUERY);
3538 0 : if (xFrameProps.is())
3539 0 : xFrameProps->setPropertyValue(FRAME_PROPNAME_INDICATORINTERCEPTION, css::uno::makeAny(xExternalProgress));
3540 : }
3541 :
3542 : // But inside the MediaDescriptor we must set our own create progress ...
3543 : // in case there is not already anothe rprogress set.
3544 0 : rArgs.createItemIfMissing(::comphelper::MediaDescriptor::PROP_STATUSINDICATOR(), xInternalProgress);
3545 0 : }
3546 :
3547 : //-----------------------------------------------
3548 0 : void AutoRecovery::impl_forgetProgress(const AutoRecovery::TDocumentInfo& rInfo ,
3549 : ::comphelper::MediaDescriptor& rArgs ,
3550 : const css::uno::Reference< css::frame::XFrame >& xNewFrame)
3551 : {
3552 : // external well known frame must be preferred (because it was created by ourself
3553 : // for loading documents into this frame)!
3554 : // But if no frame exists ... we can try to locate it using any frame bound to the provided
3555 : // document. Of course we must live without any frame in case the document does not exists at this
3556 : // point. But this state shouldnt occure. In such case xNewFrame should be valid ... hopefully .-)
3557 0 : css::uno::Reference< css::frame::XFrame > xFrame = xNewFrame;
3558 0 : if (
3559 0 : (!xFrame.is() ) &&
3560 0 : (rInfo.Document.is())
3561 : )
3562 : {
3563 0 : css::uno::Reference< css::frame::XController > xController = rInfo.Document->getCurrentController();
3564 0 : if (xController.is())
3565 0 : xFrame = xController->getFrame();
3566 : }
3567 :
3568 : // stop progress interception on corresponding frame.
3569 0 : css::uno::Reference< css::beans::XPropertySet > xFrameProps(xFrame, css::uno::UNO_QUERY);
3570 0 : if (xFrameProps.is())
3571 0 : xFrameProps->setPropertyValue(FRAME_PROPNAME_INDICATORINTERCEPTION, css::uno::makeAny(css::uno::Reference< css::task::XStatusIndicator >()));
3572 :
3573 : // forget progress inside list of arguments.
3574 0 : ::comphelper::MediaDescriptor::iterator pArg = rArgs.find(::comphelper::MediaDescriptor::PROP_STATUSINDICATOR());
3575 0 : if (pArg != rArgs.end())
3576 : {
3577 0 : rArgs.erase(pArg);
3578 0 : pArg = rArgs.end();
3579 0 : }
3580 0 : }
3581 :
3582 : //-----------------------------------------------
3583 0 : void AutoRecovery::impl_flushALLConfigChanges()
3584 : {
3585 : try
3586 : {
3587 : // SAFE ->
3588 0 : ReadGuard aReadLock(m_aLock);
3589 0 : css::uno::Reference< css::uno::XInterface > xRecoveryCfg(m_xRecoveryCFG, css::uno::UNO_QUERY);
3590 0 : aReadLock.unlock();
3591 : // <- SAFE
3592 :
3593 0 : if (xRecoveryCfg.is())
3594 0 : ::comphelper::ConfigurationHelper::flush(xRecoveryCfg);
3595 :
3596 : // SOLAR SAFE ->
3597 0 : SolarMutexGuard aGuard;
3598 0 : ::utl::ConfigManager::storeConfigItems();
3599 : }
3600 0 : catch(const css::uno::Exception&)
3601 : {
3602 : }
3603 0 : }
3604 :
3605 : //-----------------------------------------------
3606 0 : void AutoRecovery::st_impl_removeFile(const ::rtl::OUString& sURL)
3607 : {
3608 0 : if ( sURL.isEmpty())
3609 0 : return;
3610 :
3611 : try
3612 : {
3613 0 : ::ucbhelper::Content aContent = ::ucbhelper::Content(sURL, css::uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getComponentContext(m_xSMGR));
3614 0 : aContent.executeCommand(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("delete")), css::uno::makeAny(sal_True));
3615 : }
3616 0 : catch(const css::uno::Exception&)
3617 : {
3618 : }
3619 : }
3620 :
3621 : //-----------------------------------------------
3622 0 : void AutoRecovery::st_impl_removeLockFile()
3623 : {
3624 : try
3625 : {
3626 0 : ::rtl::OUString sUserURL;
3627 0 : ::utl::Bootstrap::locateUserInstallation( sUserURL );
3628 :
3629 0 : ::rtl::OUStringBuffer sLockURLBuf;
3630 0 : sLockURLBuf.append (sUserURL);
3631 0 : sLockURLBuf.appendAscii("/.lock");
3632 0 : ::rtl::OUString sLockURL = sLockURLBuf.makeStringAndClear();
3633 :
3634 0 : AutoRecovery::st_impl_removeFile(sLockURL);
3635 : }
3636 0 : catch(const css::uno::Exception&)
3637 : {
3638 : }
3639 0 : }
3640 :
3641 : } // namespace framework
3642 :
3643 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|