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