1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: autorecovery.cxx,v $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_framework.hxx"
34 #include "services/autorecovery.hxx"
36 //_______________________________________________
38 #include <loadenv/loaddispatchlistener.hxx>
39 #include <loadenv/targethelper.hxx>
40 #include <pattern/frame.hxx>
41 #include <threadhelp/readguard.hxx>
42 #include <threadhelp/writeguard.hxx>
44 #include <classes/resource.hrc>
45 #include <classes/fwkresid.hxx>
46 #include <protocols.h>
47 #include <properties.h>
50 //_______________________________________________
52 #include <com/sun/star/ucb/NameClash.hpp>
53 #include <com/sun/star/container/XNameAccess.hpp>
54 #include <com/sun/star/frame/XModuleManager.hpp>
55 #include <com/sun/star/frame/XTitle.hpp>
56 #include <com/sun/star/frame/XFrame.hpp>
57 #include <com/sun/star/frame/XDispatchProvider.hpp>
58 #include <com/sun/star/frame/DispatchResultState.hpp>
59 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
60 #include <com/sun/star/frame/XController.hpp>
61 #include <com/sun/star/frame/XModel.hpp>
62 #include <com/sun/star/frame/XStorable.hpp>
63 #include <com/sun/star/util/XModifiable.hpp>
64 #include <com/sun/star/util/XURLTransformer.hpp>
65 #include <com/sun/star/frame/XDesktop.hpp>
66 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
67 #include <com/sun/star/container/XNameContainer.hpp>
68 #include <com/sun/star/util/XChangesNotifier.hpp>
69 #include <com/sun/star/util/XChangesBatch.hpp>
70 #include <com/sun/star/beans/XPropertySet.hpp>
71 #include <com/sun/star/beans/PropertyAttribute.hpp>
72 #include <com/sun/star/container/XContainerQuery.hpp>
73 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
74 #include <com/sun/star/util/XCloseable.hpp>
75 #include <com/sun/star/awt/XWindow2.hpp>
76 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
78 //_______________________________________________
80 #include <comphelper/configurationhelper.hxx>
81 #include <comphelper/mediadescriptor.hxx>
82 #include <vcl/svapp.hxx>
83 #include <svtools/pathoptions.hxx>
84 #include <tools/link.hxx>
85 #include <tools/string.hxx>
86 #include <unotools/tempfile.hxx>
87 #include <ucbhelper/content.hxx>
90 #include <vcl/msgbox.hxx>
91 #include <osl/file.hxx>
92 #include <unotools/bootstrap.hxx>
93 #include <unotools/configmgr.hxx>
94 #include <svtools/documentlockfile.hxx>
96 #include <tools/urlobj.hxx>
98 //_______________________________________________
102 namespace css
= ::com::sun::star
;
105 namespace fpf
= ::framework::pattern::frame
;
110 //-----------------------------------------------
112 static const ::rtl::OUString CFG_PACKAGE_RECOVERY
= ::rtl::OUString::createFromAscii("org.openoffice.Office.Recovery/");
113 static const ::rtl::OUString CFG_ENTRY_RECOVERYLIST
= ::rtl::OUString::createFromAscii("RecoveryList" );
114 static const ::rtl::OUString CFG_PATH_RECOVERYINFO
= ::rtl::OUString::createFromAscii("RecoveryInfo" );
115 static const ::rtl::OUString CFG_ENTRY_ENABLED
= ::rtl::OUString::createFromAscii("Enabled" );
116 static const ::rtl::OUString CFG_ENTRY_CRASHED
= ::rtl::OUString::createFromAscii("Crashed" );
117 static const ::rtl::OUString CFG_ENTRY_SESSIONDATA
= ::rtl::OUString::createFromAscii("SessionData" );
119 static const ::rtl::OUString CFG_ENTRY_AUTOSAVE_ENABLED
= ::rtl::OUString::createFromAscii("AutoSave/Enabled" );
120 static const ::rtl::OUString CFG_ENTRY_AUTOSAVE_TIMEINTERVALL
= ::rtl::OUString::createFromAscii("AutoSave/TimeIntervall" );
122 static const ::rtl::OUString CFG_PATH_AUTOSAVE
= ::rtl::OUString::createFromAscii("AutoSave" );
123 static const ::rtl::OUString CFG_ENTRY_MINSPACE_DOCSAVE
= ::rtl::OUString::createFromAscii("MinSpaceDocSave" );
124 static const ::rtl::OUString CFG_ENTRY_MINSPACE_CONFIGSAVE
= ::rtl::OUString::createFromAscii("MinSpaceConfigSave" );
126 static const ::rtl::OUString CFG_PACKAGE_MODULES
= ::rtl::OUString::createFromAscii("org.openoffice.Setup/Office/Factories");
127 static const ::rtl::OUString CFG_ENTRY_REALDEFAULTFILTER
= ::rtl::OUString::createFromAscii("ooSetupFactoryActualFilter" );
129 static const ::rtl::OUString CFG_ENTRY_PROP_TEMPURL
= ::rtl::OUString::createFromAscii("TempURL" );
130 static const ::rtl::OUString CFG_ENTRY_PROP_ORIGINALURL
= ::rtl::OUString::createFromAscii("OriginalURL" );
131 static const ::rtl::OUString CFG_ENTRY_PROP_TEMPLATEURL
= ::rtl::OUString::createFromAscii("TemplateURL" );
132 static const ::rtl::OUString CFG_ENTRY_PROP_FACTORYURL
= ::rtl::OUString::createFromAscii("FactoryURL" );
133 static const ::rtl::OUString CFG_ENTRY_PROP_MODULE
= ::rtl::OUString::createFromAscii("Module" );
134 static const ::rtl::OUString CFG_ENTRY_PROP_DOCUMENTSTATE
= ::rtl::OUString::createFromAscii("DocumentState");
135 static const ::rtl::OUString CFG_ENTRY_PROP_FILTER
= ::rtl::OUString::createFromAscii("Filter" );
136 static const ::rtl::OUString CFG_ENTRY_PROP_TITLE
= ::rtl::OUString::createFromAscii("Title" );
137 static const ::rtl::OUString CFG_ENTRY_PROP_ID
= ::rtl::OUString::createFromAscii("ID" );
139 static const ::rtl::OUString FILTER_PROP_TYPE
= ::rtl::OUString::createFromAscii("Type" );
140 static const ::rtl::OUString FILTER_PROP_NAME
= ::rtl::OUString::createFromAscii("Name" );
141 static const ::rtl::OUString TYPE_PROP_EXTENSIONS
= ::rtl::OUString::createFromAscii("Extensions" );
142 static const ::rtl::OUString DOCINFO_PROP_TEMPLATE
= ::rtl::OUString::createFromAscii("TemplateFileName");
145 static const ::rtl::OUString CFG_ENTRY_PROP_EMPTYDOCUMENTURL
= ::rtl::OUString::createFromAscii("ooSetupFactoryEmptyDocumentURL");
146 static const ::rtl::OUString CFG_ENTRY_PROP_DEFAULTFILTER
= ::rtl::OUString::createFromAscii("ooSetupFactoryDefaultFilter" );
148 static const ::rtl::OUString EVENT_ON_NEW
= ::rtl::OUString::createFromAscii("OnNew" );
149 static const ::rtl::OUString EVENT_ON_LOAD
= ::rtl::OUString::createFromAscii("OnLoad" );
150 static const ::rtl::OUString EVENT_ON_UNLOAD
= ::rtl::OUString::createFromAscii("OnUnload" );
151 static const ::rtl::OUString EVENT_ON_MODIFYCHANGED
= ::rtl::OUString::createFromAscii("OnModifyChanged");
152 static const ::rtl::OUString EVENT_ON_SAVE
= ::rtl::OUString::createFromAscii("OnSave" );
153 static const ::rtl::OUString EVENT_ON_SAVEAS
= ::rtl::OUString::createFromAscii("OnSaveAs" );
154 static const ::rtl::OUString EVENT_ON_SAVETO
= ::rtl::OUString::createFromAscii("OnCopyTo" );
155 static const ::rtl::OUString EVENT_ON_SAVEDONE
= ::rtl::OUString::createFromAscii("OnSaveDone" );
156 static const ::rtl::OUString EVENT_ON_SAVEASDONE
= ::rtl::OUString::createFromAscii("OnSaveAsDone" );
157 static const ::rtl::OUString EVENT_ON_SAVETODONE
= ::rtl::OUString::createFromAscii("OnCopyToDone" );
158 static const ::rtl::OUString EVENT_ON_SAVEFAILED
= ::rtl::OUString::createFromAscii("OnSaveFailed" );
159 static const ::rtl::OUString EVENT_ON_SAVEASFAILED
= ::rtl::OUString::createFromAscii("OnSaveAsFailed" );
160 static const ::rtl::OUString EVENT_ON_SAVETOFAILED
= ::rtl::OUString::createFromAscii("OnCopyToFailed" );
162 static const ::rtl::OUString RECOVERY_ITEM_BASE_IDENTIFIER
= ::rtl::OUString::createFromAscii("recovery_item_" );
164 static const ::rtl::OUString CMD_PROTOCOL
= ::rtl::OUString::createFromAscii("vnd.sun.star.autorecovery:");
166 static const ::rtl::OUString CMD_DO_AUTO_SAVE
= ::rtl::OUString::createFromAscii("/doAutoSave" ); // force AutoSave ignoring the AutoSave timer
167 static const ::rtl::OUString CMD_DO_PREPARE_EMERGENCY_SAVE
= ::rtl::OUString::createFromAscii("/doPrepareEmergencySave" ); // prepare the office for the following EmergencySave step (hide windows etcpp.)
168 static const ::rtl::OUString CMD_DO_EMERGENCY_SAVE
= ::rtl::OUString::createFromAscii("/doEmergencySave" ); // do EmergencySave on crash
169 static const ::rtl::OUString CMD_DO_RECOVERY
= ::rtl::OUString::createFromAscii("/doAutoRecovery" ); // recover all crashed documents
170 static const ::rtl::OUString CMD_DO_ENTRY_BACKUP
= ::rtl::OUString::createFromAscii("/doEntryBackup" ); // try to store a temp or original file to a user defined location
171 static const ::rtl::OUString CMD_DO_ENTRY_CLEANUP
= ::rtl::OUString::createFromAscii("/doEntryCleanUp" ); // remove the specified entry from the recovery cache
172 static const ::rtl::OUString CMD_DO_SESSION_SAVE
= ::rtl::OUString::createFromAscii("/doSessionSave" ); // save all open documents if e.g. a window manager closes an user session
173 static const ::rtl::OUString CMD_DO_SESSION_RESTORE
= ::rtl::OUString::createFromAscii("/doSessionRestore" ); // restore a saved user session from disc
174 static const ::rtl::OUString CMD_DO_DISABLE_RECOVERY
= ::rtl::OUString::createFromAscii("/disableRecovery" ); // disable recovery and auto save (!) temp. for this office session
175 static const ::rtl::OUString CMD_DO_SET_AUTOSAVE_STATE
= ::rtl::OUString::createFromAscii("/setAutoSaveState" ); // disable/enable auto save (not crash save) for this office session
177 static const ::rtl::OUString REFERRER_USER
= ::rtl::OUString::createFromAscii("private:user");
179 static const ::rtl::OUString PROP_DISPATCH_ASYNCHRON
= ::rtl::OUString::createFromAscii("DispatchAsynchron");
180 static const ::rtl::OUString PROP_PROGRESS
= ::rtl::OUString::createFromAscii("StatusIndicator" );
181 static const ::rtl::OUString PROP_SAVEPATH
= ::rtl::OUString::createFromAscii("SavePath" );
182 static const ::rtl::OUString PROP_ENTRY_ID
= ::rtl::OUString::createFromAscii("EntryID" );
183 static const ::rtl::OUString PROP_DBG_MAKE_IT_FASTER
= ::rtl::OUString::createFromAscii("DBGMakeItFaster" );
184 static const ::rtl::OUString PROP_AUTOSAVE_STATE
= ::rtl::OUString::createFromAscii("AutoSaveState" );
186 static const ::rtl::OUString OPERATION_START
= ::rtl::OUString::createFromAscii("start" );
187 static const ::rtl::OUString OPERATION_STOP
= ::rtl::OUString::createFromAscii("stop" );
188 static const ::rtl::OUString OPERATION_UPDATE
= ::rtl::OUString::createFromAscii("update");
190 static const sal_Int32 MIN_DISCSPACE_DOCSAVE
= 5; // [MB]
191 static const sal_Int32 MIN_DISCSPACE_CONFIGSAVE
= 1; // [MB]
192 static const sal_Int32 RETRY_STORE_ON_FULL_DISC_FOREVER
= 300; // not forever ... but often enough .-)
193 static const sal_Int32 RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL
= 3; // in case FULL DISC does not seam the real problem
194 static const sal_Int32 GIVE_UP_RETRY
= 1; // in case FULL DISC does not seam the real problem
196 #define SAVE_IN_PROGRESS sal_True
197 #define SAVE_FINISHED sal_False
199 #define LOCK_FOR_CACHE_ADD_REMOVE sal_True
200 #define LOCK_FOR_CACHE_USE sal_False
202 #define MIN_TIME_FOR_USER_IDLE 10000 // 10s user idle
204 // enable the following defines in case you whish to simulate a full disc for debug purposes .-)
206 // this define throws everytime a document is stored or a configuration change
207 // should be flushed an exception ... so the special error handler for this scenario is triggered
208 // #define TRIGGER_FULL_DISC_CHECK
210 // force "return FALSE" for the method impl_enoughDiscSpace().
211 // #define SIMULATE_FULL_DISC
213 //-----------------------------------------------
214 // #define ENABLE_RECOVERY_LOGGING
215 #undef ENABLE_RECOVERY_LOGGING
216 #ifdef ENABLE_RECOVERY_LOGGING
217 #define LOGFILE_RECOVERY "recovery.log"
219 #define LOG_RECOVERY(MSG) \
221 WRITE_LOGFILE(LOGFILE_RECOVERY, MSG) \
222 WRITE_LOGFILE(LOGFILE_RECOVERY, "\n") \
225 #undef LOGFILE_RECOVERY
226 #define LOG_RECOVERY(MSG)
229 //-----------------------------------------------
230 // TODO debug - remove it!
231 class DbgListener
: private ThreadHelpBase
232 , public ::cppu::OWeakObject
233 , public css::frame::XStatusListener
237 FWK_DECLARE_XINTERFACE
241 WRITE_LOGFILE("autorecovery_states.txt", "\n\nDbgListener::ctor()\n\n")
244 virtual ~DbgListener()
246 WRITE_LOGFILE("autorecovery_states.txt", "\n\nDbgListener::dtor()\n\n")
249 void startListening(const css::uno::Reference
< css::frame::XDispatch
>& xBroadcaster
)
251 ::rtl::OUStringBuffer
sMsg1(256);
252 sMsg1
.appendAscii("//**********************************************************************************\n");
253 sMsg1
.appendAscii("start listening\n{\n");
254 WRITE_LOGFILE("autorecovery_states.txt", U2B(sMsg1
.makeStringAndClear()))
259 aURL
.Complete
= ::rtl::OUString();
260 xBroadcaster
->addStatusListener(static_cast< css::frame::XStatusListener
* >(this), aURL
);
264 ::rtl::OUStringBuffer
sMsg2(256);
265 sMsg2
.appendAscii("}\nstart listening\n");
266 sMsg2
.appendAscii("//**********************************************************************************\n");
267 WRITE_LOGFILE("autorecovery_states.txt", U2B(sMsg2
.makeStringAndClear()))
270 virtual void SAL_CALL
disposing(const css::lang::EventObject
&)
271 throw(css::uno::RuntimeException
)
273 WRITE_LOGFILE("autorecovery_states.txt", "\n\nDbgListener::dtor()\n\n")
276 virtual void SAL_CALL
statusChanged(const css::frame::FeatureStateEvent
& aEvent
)
277 throw(css::uno::RuntimeException
)
279 ::rtl::OUStringBuffer
sMsg(256);
281 sMsg
.appendAscii("//**********************************************************************************\n");
283 sMsg
.appendAscii("FeatureURL = \"");
284 sMsg
.append (aEvent
.FeatureURL
.Complete
);
285 sMsg
.appendAscii("\"\n");
287 sMsg
.appendAscii("State = [");
288 sal_Int32 nState
= -1;
289 aEvent
.State
>>= nState
;
292 sMsg
.appendAscii("?-");
293 sMsg
.append (::rtl::OUString::valueOf(nState
));
294 sMsg
.appendAscii("-? ");
297 sMsg
.appendAscii("UNKNOWN ");
299 sMsg
.appendAscii("MODIFIED ");
301 sMsg
.appendAscii("TRYIT ");
303 sMsg
.appendAscii("HANDLED ");
305 sMsg
.appendAscii("POSTPONED ");
306 if ((nState
& 16)==16)
307 sMsg
.appendAscii("INCOMPLETE ");
308 if ((nState
& 32)==32)
309 sMsg
.appendAscii("DAMAGED ");
310 sMsg
.appendAscii("]\n");
312 sMsg.appendAscii("IsEnabled = \"");
313 sMsg.append (::rtl::OUString::valueOf(aEvent.IsEnabled));
314 sMsg.appendAscii("\"\n");
316 sMsg.appendAscii("Requery = \"");
317 sMsg.append (::rtl::OUString::valueOf(aEvent.Requery));
318 sMsg.appendAscii("\"\n");
320 sMsg
.appendAscii("\n");
322 WRITE_LOGFILE("autorecovery_states.txt", U2B(sMsg
.makeStringAndClear()))
326 //-----------------------------------------------
331 // holds the outside calli alive, so it's shared resources
332 // are valid everytimes
333 css::uno::Reference
< css::uno::XInterface
> m_xOwner
;
335 // mutex shared with outside calli !
336 LockHelper
& m_rSharedMutex
;
338 // this variable knows the state of the "cache lock"
339 sal_Int32
& m_rCacheLock
;
341 // to prevent increasing/decreasing of m_rCacheLock more then ones
342 // we must know if THIS guard has an actual lock set there !
343 sal_Bool m_bLockedByThisGuard
;
347 CacheLockGuard(AutoRecovery
* pOwner
,
349 sal_Int32
& rCacheLock
,
350 sal_Bool bLockForAddRemoveVectorItems
);
353 void lock(sal_Bool bLockForAddRemoveVectorItems
);
357 //-----------------------------------------------
358 CacheLockGuard::CacheLockGuard(AutoRecovery
* pOwner
,
360 sal_Int32
& rCacheLock
,
361 sal_Bool bLockForAddRemoveVectorItems
)
362 : m_xOwner (static_cast< css::frame::XDispatch
* >(pOwner
))
363 , m_rSharedMutex (rMutex
)
364 , m_rCacheLock (rCacheLock
)
365 , m_bLockedByThisGuard(sal_False
)
367 lock(bLockForAddRemoveVectorItems
);
370 //-----------------------------------------------
371 CacheLockGuard::~CacheLockGuard()
377 //-----------------------------------------------
378 void CacheLockGuard::lock(sal_Bool bLockForAddRemoveVectorItems
)
380 // SAFE -> ----------------------------------
381 WriteGuard
aWriteLock(m_rSharedMutex
);
383 if (m_bLockedByThisGuard
)
386 // This cache lock is needed only to prevent us from removing/adding
387 // items from/into the recovery cache ... during it's used at another code place
390 // Modifying of item properties is allowed and sometimes needed!
391 // So we should detect only the dangerous state of concurrent add/remove
392 // requests and throw an exception then ... which can of course break the whole
393 // operation. On the other side a crash reasoned by an invalid stl iterator
394 // will have the same effect .-)
397 (m_rCacheLock
> 0 ) &&
398 (bLockForAddRemoveVectorItems
)
401 OSL_ENSURE(sal_False
, "Re-entrance problem detected. Using of an stl structure in combination with iteration, adding, removing of elements etcpp.");
402 throw css::uno::RuntimeException(
403 ::rtl::OUString::createFromAscii("Re-entrance problem detected. Using of an stl structure in combination with iteration, adding, removing of elements etcpp."),
408 m_bLockedByThisGuard
= sal_True
;
411 // <- SAFE ----------------------------------
414 //-----------------------------------------------
415 void CacheLockGuard::unlock()
417 // SAFE -> ----------------------------------
418 WriteGuard
aWriteLock(m_rSharedMutex
);
420 if ( ! m_bLockedByThisGuard
)
424 m_bLockedByThisGuard
= sal_False
;
426 if (m_rCacheLock
< 0)
428 OSL_ENSURE(sal_False
, "Wrong using of member m_nDocCacheLock detected. A ref counted value shouldn't reach values <0 .-)");
429 throw css::uno::RuntimeException(
430 ::rtl::OUString::createFromAscii("Wrong using of member m_nDocCacheLock detected. A ref counted value shouldn't reach values <0 .-)"),
434 // <- SAFE ----------------------------------
437 //-----------------------------------------------
438 DispatchParams::DispatchParams()
439 : m_nWorkingEntryID(-1)
443 //-----------------------------------------------
444 DispatchParams::DispatchParams(const ::comphelper::SequenceAsHashMap
& lArgs
,
445 const css::uno::Reference
< css::uno::XInterface
>& xOwner
)
447 m_nWorkingEntryID
= lArgs
.getUnpackedValueOrDefault(PROP_ENTRY_ID
, (sal_Int32
)-1 );
448 m_xProgress
= lArgs
.getUnpackedValueOrDefault(PROP_PROGRESS
, css::uno::Reference
< css::task::XStatusIndicator
>());
449 m_sSavePath
= lArgs
.getUnpackedValueOrDefault(PROP_SAVEPATH
, ::rtl::OUString() );
450 m_xHoldRefForAsyncOpAlive
= xOwner
;
453 //-----------------------------------------------
454 DispatchParams::DispatchParams(const DispatchParams
& rCopy
)
456 m_xProgress
= rCopy
.m_xProgress
;
457 m_sSavePath
= rCopy
.m_sSavePath
;
458 m_nWorkingEntryID
= rCopy
.m_nWorkingEntryID
;
459 m_xHoldRefForAsyncOpAlive
= rCopy
.m_xHoldRefForAsyncOpAlive
;
462 //-----------------------------------------------
463 DispatchParams::~DispatchParams()
466 //-----------------------------------------------
467 DispatchParams
& DispatchParams::operator=(const DispatchParams
& rCopy
)
469 m_xProgress
= rCopy
.m_xProgress
;
470 m_sSavePath
= rCopy
.m_sSavePath
;
471 m_nWorkingEntryID
= rCopy
.m_nWorkingEntryID
;
472 m_xHoldRefForAsyncOpAlive
= rCopy
.m_xHoldRefForAsyncOpAlive
;
476 //-----------------------------------------------
477 void DispatchParams::forget()
479 m_sSavePath
= ::rtl::OUString();
480 m_nWorkingEntryID
= -1;
482 m_xHoldRefForAsyncOpAlive
.clear();
485 //-----------------------------------------------
486 DEFINE_XINTERFACE_1(DbgListener
,
488 DIRECT_INTERFACE(css::frame::XStatusListener
))
490 //-----------------------------------------------
491 DEFINE_XINTERFACE_10(AutoRecovery
,
493 DIRECT_INTERFACE (css::lang::XTypeProvider
),
494 DIRECT_INTERFACE (css::lang::XServiceInfo
),
495 DIRECT_INTERFACE (css::frame::XDispatch
),
496 DIRECT_INTERFACE (css::beans::XMultiPropertySet
),
497 DIRECT_INTERFACE (css::beans::XFastPropertySet
),
498 DIRECT_INTERFACE (css::beans::XPropertySet
),
499 DIRECT_INTERFACE (css::document::XEventListener
),
500 DIRECT_INTERFACE (css::util::XChangesListener
),
501 DIRECT_INTERFACE (css::util::XModifyListener
),
502 DERIVED_INTERFACE(css::lang::XEventListener
, css::document::XEventListener
))
504 //-----------------------------------------------
505 DEFINE_XTYPEPROVIDER_6(AutoRecovery
,
506 css::lang::XTypeProvider
,
507 css::lang::XServiceInfo
,
508 css::frame::XDispatch
,
509 css::beans::XMultiPropertySet
,
510 css::beans::XFastPropertySet
,
511 css::beans::XPropertySet
)
513 //-----------------------------------------------
514 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE(AutoRecovery
,
515 ::cppu::OWeakObject
,
516 SERVICENAME_AUTORECOVERY
,
517 IMPLEMENTATIONNAME_AUTORECOVERY
)
519 //-----------------------------------------------
524 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
525 to create a new instance of this class by our own supported service factory.
526 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
529 // read configuration to know if autosave/recovery is on/off etcpp...
532 implts_startListening();
534 // establish callback for our internal used timer.
535 // Note: Its only active, if the timer will be started ...
536 m_aTimer
.SetTimeoutHdl(LINK(this, AutoRecovery
, implts_timerExpired
));
538 DbgListener* pListener = new DbgListener();
539 pListener->startListening(this);
544 //-----------------------------------------------
545 AutoRecovery::AutoRecovery(const css::uno::Reference
< css::lang::XMultiServiceFactory
>& xSMGR
)
546 : ThreadHelpBase (&Application::GetSolarMutex() )
547 , ::cppu::OBroadcastHelper ( m_aLock
.getShareableOslMutex() )
548 , ::cppu::OPropertySetHelper( *(static_cast< ::cppu::OBroadcastHelper
* >(this)) )
549 , ::cppu::OWeakObject ( )
551 , m_bListenForDocEvents (sal_False
)
552 , m_bListenForConfigChanges (sal_False
)
553 , m_nAutoSaveTimeIntervall (0 )
554 , m_eJob (AutoRecovery::E_NO_JOB
)
555 , m_aAsyncDispatcher ( LINK( this, AutoRecovery
, implts_asyncDispatch
) )
556 , m_eTimerType (E_DONT_START_TIMER
)
558 , m_lListener (m_aLock
.getShareableOslMutex() )
559 , m_nDocCacheLock (0 )
560 , m_nMinSpaceDocSave (MIN_DISCSPACE_DOCSAVE
)
561 , m_nMinSpaceConfigSave (MIN_DISCSPACE_CONFIGSAVE
)
563 #if OSL_DEBUG_LEVEL > 1
564 , m_dbg_bMakeItFaster (sal_False
)
569 //-----------------------------------------------
570 AutoRecovery::~AutoRecovery()
575 //-----------------------------------------------
576 void SAL_CALL
AutoRecovery::dispatch(const css::util::URL
& aURL
,
577 const css::uno::Sequence
< css::beans::PropertyValue
>& lArguments
)
578 throw(css::uno::RuntimeException
)
580 LOG_RECOVERY("AutoRecovery::dispatch() starts ...")
581 LOG_RECOVERY(U2B(aURL
.Complete
).getStr())
584 sal_Int32 eNewJob
= AutoRecovery::implst_classifyJob(aURL
);
585 if (eNewJob
== AutoRecovery::E_NO_JOB
)
588 // SAFE -> ----------------------------------
589 WriteGuard
aWriteLock(m_aLock
);
591 // still running operation ... ignoring AUTO_SAVE.
592 // All other requests has higher prio!
594 ( m_eJob
!= AutoRecovery::E_NO_JOB
) &&
595 ((m_eJob
& AutoRecovery::E_AUTO_SAVE
) != AutoRecovery::E_AUTO_SAVE
)
598 LOG_WARNING("AutoRecovery::dispatch()", "There is already an asynchronous dispatch() running. New request will be ignored!")
602 ::comphelper::SequenceAsHashMap
lArgs(lArguments
);
604 // check if somewhere wish to disable recovery temp. for this office session
605 // This can be done immediatly ... must not been done asynchronous.
606 if ((eNewJob
& AutoRecovery::E_DISABLE_AUTORECOVERY
) == AutoRecovery::E_DISABLE_AUTORECOVERY
)
608 // it's important to set a flag internaly, so AutoRecovery will be supressed - even if it's requested.
611 implts_stopListening();
615 // disable/enable AutoSave for this office session only
616 // independend from the configuration entry.
617 if ((eNewJob
& AutoRecovery::E_SET_AUTOSAVE_STATE
) == AutoRecovery::E_SET_AUTOSAVE_STATE
)
619 sal_Bool bOn
= lArgs
.getUnpackedValueOrDefault(PROP_AUTOSAVE_STATE
, (sal_Bool
)sal_True
);
622 // dont enable AutoSave hardly !
623 // reload configuration to know the current state.
624 implts_readAutoSaveConfig();
625 implts_actualizeTimer();
626 // can it happen that might be the listener was stopped ? .-)
627 // make sure it runs always ... even if AutoSave itself was disabled temporarly.
628 implts_startListening();
633 m_eJob
&= ~AutoRecovery::E_AUTO_SAVE
;
634 m_eTimerType
= AutoRecovery::E_DONT_START_TIMER
;
641 sal_Bool bAsync
= lArgs
.getUnpackedValueOrDefault(PROP_DISPATCH_ASYNCHRON
, (sal_Bool
)sal_False
);
642 DispatchParams
aParams (lArgs
, static_cast< css::frame::XDispatch
* >(this));
644 // Hold this instance alive till the asynchronous operation will be finished.
646 m_aDispatchParams
= aParams
;
649 // <- SAFE ----------------------------------
652 m_aAsyncDispatcher
.Post(0);
654 implts_dispatch(aParams
);
657 //-----------------------------------------------
658 void AutoRecovery::implts_dispatch(const DispatchParams
& aParams
)
660 // SAFE -> ----------------------------------
661 WriteGuard
aWriteLock(m_aLock
);
662 sal_Int32 eJob
= m_eJob
;
664 // <- SAFE ----------------------------------
666 // in case a new dispatch overwrites a may ba active AutoSave session
667 // we must restore this session later. see below ...
668 sal_Bool bWasAutoSaveActive
= ((eJob
& AutoRecovery::E_AUTO_SAVE
) == AutoRecovery::E_AUTO_SAVE
);
670 // On the other side it make no sense to reactivate the AutoSave operation
671 // if the new dispatch indicates a final decision ...
672 // E.g. an EmergencySave/SessionSave indicates the end of life of the current office session.
673 // It make no sense to reactivate an AutoSave then.
674 // But a Recovery or SessionRestore should reactivate a may be already active AutoSave.
675 sal_Bool bAllowAutoSaveReactivation
= sal_True
;
678 implts_stopListening();
680 implts_informListener(eJob
,
681 AutoRecovery::implst_createFeatureStateEvent(eJob
, OPERATION_START
, NULL
));
685 // if ((eJob & AutoRecovery::E_AUTO_SAVE) == AutoRecovery::E_AUTO_SAVE)
686 // Auto save is called from our internal timer ... not via dispatch() API !
689 ((eJob
& AutoRecovery::E_PREPARE_EMERGENCY_SAVE
) == AutoRecovery::E_PREPARE_EMERGENCY_SAVE
) &&
690 ((eJob
& AutoRecovery::E_DISABLE_AUTORECOVERY
) != AutoRecovery::E_DISABLE_AUTORECOVERY
)
693 LOG_RECOVERY("... prepare emergency save ...")
694 bAllowAutoSaveReactivation
= sal_False
;
695 implts_prepareEmergencySave();
699 ((eJob
& AutoRecovery::E_EMERGENCY_SAVE
) == AutoRecovery::E_EMERGENCY_SAVE
) &&
700 ((eJob
& AutoRecovery::E_DISABLE_AUTORECOVERY
) != AutoRecovery::E_DISABLE_AUTORECOVERY
)
703 LOG_RECOVERY("... do emergency save ...")
704 bAllowAutoSaveReactivation
= sal_False
;
705 implts_doEmergencySave(aParams
);
709 ((eJob
& AutoRecovery::E_RECOVERY
) == AutoRecovery::E_RECOVERY
) &&
710 ((eJob
& AutoRecovery::E_DISABLE_AUTORECOVERY
) != AutoRecovery::E_DISABLE_AUTORECOVERY
)
713 LOG_RECOVERY("... do recovery ...")
714 implts_doRecovery(aParams
);
718 ((eJob
& AutoRecovery::E_SESSION_SAVE
) == AutoRecovery::E_SESSION_SAVE
) &&
719 ((eJob
& AutoRecovery::E_DISABLE_AUTORECOVERY
) != AutoRecovery::E_DISABLE_AUTORECOVERY
)
722 LOG_RECOVERY("... do session save ...")
723 bAllowAutoSaveReactivation
= sal_False
;
724 implts_doSessionSave(aParams
);
728 ((eJob
& AutoRecovery::E_SESSION_RESTORE
) == AutoRecovery::E_SESSION_RESTORE
) &&
729 ((eJob
& AutoRecovery::E_DISABLE_AUTORECOVERY
) != AutoRecovery::E_DISABLE_AUTORECOVERY
)
732 LOG_RECOVERY("... do session restore ...")
733 implts_doSessionRestore(aParams
);
737 ((eJob
& AutoRecovery::E_ENTRY_BACKUP
) == AutoRecovery::E_ENTRY_BACKUP
) &&
738 ((eJob
& AutoRecovery::E_DISABLE_AUTORECOVERY
) != AutoRecovery::E_DISABLE_AUTORECOVERY
)
740 implts_backupWorkingEntry(aParams
);
743 ((eJob
& AutoRecovery::E_ENTRY_CLEANUP
) == AutoRecovery::E_ENTRY_CLEANUP
) &&
744 ((eJob
& AutoRecovery::E_DISABLE_AUTORECOVERY
) != AutoRecovery::E_DISABLE_AUTORECOVERY
)
746 implts_cleanUpWorkingEntry(aParams
);
748 catch(const css::uno::RuntimeException
& exRun
)
750 catch(const css::uno::Exception
&)
751 {} // TODO better error handling
753 implts_informListener(eJob
,
754 AutoRecovery::implst_createFeatureStateEvent(eJob
, OPERATION_STOP
, NULL
));
756 // SAFE -> ----------------------------------
760 (bAllowAutoSaveReactivation
) &&
761 (bWasAutoSaveActive
)
764 m_eJob
|= AutoRecovery::E_AUTO_SAVE
;
768 // <- SAFE ----------------------------------
770 // depends on bAllowAutoSaveReactivation implicitly by looking on m_eJob=E_AUTO_SAVE! see before ...
771 implts_actualizeTimer();
773 if (bAllowAutoSaveReactivation
)
774 implts_startListening();
777 //-----------------------------------------------
778 void SAL_CALL
AutoRecovery::addStatusListener(const css::uno::Reference
< css::frame::XStatusListener
>& xListener
,
779 const css::util::URL
& aURL
)
780 throw(css::uno::RuntimeException
)
783 throw css::uno::RuntimeException(::rtl::OUString::createFromAscii("Invalid listener reference."), static_cast< css::frame::XDispatch
* >(this));
784 // container is threadsafe by using a shared mutex!
785 m_lListener
.addInterface(aURL
.Complete
, xListener
);
787 // REINTRANT !? -> --------------------------------
788 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
790 // THREAD SAFE -> ----------------------------------
791 ReadGuard
aReadLock(m_aLock
);
793 AutoRecovery::TDocumentList::iterator pIt
;
794 for( pIt
= m_lDocCache
.begin();
795 pIt
!= m_lDocCache
.end() ;
798 AutoRecovery::TDocumentInfo
& rInfo
= *pIt
;
799 css::frame::FeatureStateEvent aEvent
= AutoRecovery::implst_createFeatureStateEvent(m_eJob
, OPERATION_UPDATE
, &rInfo
);
801 // <- SAFE ------------------------------
803 xListener
->statusChanged(aEvent
);
805 // SAFE -> ------------------------------
809 // <- SAFE ----------------------------------
812 //-----------------------------------------------
813 void SAL_CALL
AutoRecovery::removeStatusListener(const css::uno::Reference
< css::frame::XStatusListener
>& xListener
,
814 const css::util::URL
& aURL
)
815 throw(css::uno::RuntimeException
)
818 throw css::uno::RuntimeException(::rtl::OUString::createFromAscii("Invalid listener reference."), static_cast< css::frame::XDispatch
* >(this));
819 // container is threadsafe by using a shared mutex!
820 m_lListener
.removeInterface(aURL
.Complete
, xListener
);
823 //-----------------------------------------------
824 void SAL_CALL
AutoRecovery::notifyEvent(const css::document::EventObject
& aEvent
)
825 throw(css::uno::RuntimeException
)
827 css::uno::Reference
< css::frame::XModel
> xDocument(aEvent
.Source
, css::uno::UNO_QUERY
);
829 // new document => put it into the internal list
831 (aEvent
.EventName
.equals(EVENT_ON_NEW
)) ||
832 (aEvent
.EventName
.equals(EVENT_ON_LOAD
))
835 implts_registerDocument(xDocument
);
837 // document modified => set its modify state new (means modified against the original file!)
839 if (aEvent
.EventName
.equals(EVENT_ON_MODIFYCHANGED
))
841 implts_actualizeModifiedState(xDocument
);
843 /* at least one document starts saving process =>
844 Our application code isnt ready for multiple save requests
845 at the same time. So we have to supress our AutoSave feature
846 for the moment, till this other save requests will be finished.
850 (aEvent
.EventName
.equals(EVENT_ON_SAVE
)) ||
851 (aEvent
.EventName
.equals(EVENT_ON_SAVEAS
)) ||
852 (aEvent
.EventName
.equals(EVENT_ON_SAVETO
))
855 implts_updateDocumentUsedForSavingState(xDocument
, SAVE_IN_PROGRESS
);
857 // document saved => remove tmp. files - but hold config entries alive!
860 (aEvent
.EventName
.equals(EVENT_ON_SAVEDONE
)) ||
861 (aEvent
.EventName
.equals(EVENT_ON_SAVEASDONE
))
864 implts_markDocumentAsSaved(xDocument
);
865 implts_updateDocumentUsedForSavingState(xDocument
, SAVE_FINISHED
);
867 /* document saved as copy => mark it as "non used by concurrent save operation".
868 so we can try to create a backup copy if next time AutoSave is started too.
869 Dont remove temp. files or change the modified state of the document!
870 It was not realy saved to the original file ...
873 if (aEvent
.EventName
.equals(EVENT_ON_SAVETODONE
))
875 implts_updateDocumentUsedForSavingState(xDocument
, SAVE_FINISHED
);
877 // If saving of a document failed by an error ... we have to save this document
878 // by ourself next time AutoSave or EmergencySave is triggered.
879 // But we can reset the state "used for other save requests". Otherwhise
880 // these documents will never be saved!
883 (aEvent
.EventName
.equals(EVENT_ON_SAVEFAILED
)) ||
884 (aEvent
.EventName
.equals(EVENT_ON_SAVEASFAILED
)) ||
885 (aEvent
.EventName
.equals(EVENT_ON_SAVETOFAILED
))
888 implts_updateDocumentUsedForSavingState(xDocument
, SAVE_FINISHED
);
890 // document closed => remove temp. files and configuration entries
892 if (aEvent
.EventName
.equals(EVENT_ON_UNLOAD
))
894 implts_deregisterDocument(xDocument
, sal_True
); // TRUE => stop listening for disposing() !
898 //-----------------------------------------------
899 void SAL_CALL
AutoRecovery::changesOccurred(const css::util::ChangesEvent
& aEvent
)
900 throw(css::uno::RuntimeException
)
902 const css::uno::Sequence
< css::util::ElementChange
> lChanges (aEvent
.Changes
);
903 const css::util::ElementChange
* pChanges
= lChanges
.getConstArray();
905 sal_Int32 c
= lChanges
.getLength();
908 // SAFE -> ----------------------------------
909 WriteGuard
aWriteLock(m_aLock
);
911 // Changes of the configuration must be ignored if AutoSave/Recovery was disabled for this
912 // office session. That can happen if e.g. the command line arguments "-norestore" or "-headless"
914 if ((m_eJob
& AutoRecovery::E_DISABLE_AUTORECOVERY
) == AutoRecovery::E_DISABLE_AUTORECOVERY
)
919 ::rtl::OUString sPath
;
920 pChanges
[i
].Accessor
>>= sPath
;
922 if (sPath
.equals(CFG_ENTRY_AUTOSAVE_ENABLED
))
924 sal_Bool bEnabled
= sal_False
;
925 if (pChanges
[i
].Element
>>= bEnabled
)
929 m_eJob
|= AutoRecovery::E_AUTO_SAVE
;
930 m_eTimerType
= AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL
;
934 m_eJob
&= ~AutoRecovery::E_AUTO_SAVE
;
935 m_eTimerType
= AutoRecovery::E_DONT_START_TIMER
;
940 if (sPath
.equals(CFG_ENTRY_AUTOSAVE_TIMEINTERVALL
))
941 pChanges
[i
].Element
>>= m_nAutoSaveTimeIntervall
;
945 // <- SAFE ----------------------------------
947 // Note: This call stops the timer and starts it again.
948 // But it checks the different timer states internaly and
949 // may be supress the restart!
950 implts_actualizeTimer();
953 //-----------------------------------------------
954 void SAL_CALL
AutoRecovery::modified(const css::lang::EventObject
& aEvent
)
955 throw(css::uno::RuntimeException
)
957 css::uno::Reference
< css::frame::XModel
> xDocument(aEvent
.Source
, css::uno::UNO_QUERY
);
958 if (! xDocument
.is())
961 implts_markDocumentModifiedAgainstLastBackup(xDocument
);
964 //-----------------------------------------------
965 void SAL_CALL
AutoRecovery::disposing(const css::lang::EventObject
& aEvent
)
966 throw(css::uno::RuntimeException
)
968 // SAFE -> ----------------------------------
969 WriteGuard
aWriteLock(m_aLock
);
971 if (aEvent
.Source
== m_xNewDocBroadcaster
)
973 m_xNewDocBroadcaster
.clear();
977 if (aEvent
.Source
== m_xRecoveryCFG
)
979 m_xRecoveryCFG
.clear();
983 // dispose from one of our cached documents ?
984 // Normaly they should send a OnUnload message ...
985 // But some stacktraces shows another possible use case .-)
986 css::uno::Reference
< css::frame::XModel
> xDocument(aEvent
.Source
, css::uno::UNO_QUERY
);
989 implts_deregisterDocument(xDocument
, sal_False
); // FALSE => dont call removeEventListener() .. because it's not needed here
993 // <- SAFE ----------------------------------
996 //-----------------------------------------------
997 css::uno::Reference
< css::container::XNameAccess
> AutoRecovery::implts_openConfig()
999 // SAFE -> ----------------------------------
1000 WriteGuard
aWriteLock(m_aLock
);
1002 if (m_xRecoveryCFG
.is())
1003 return m_xRecoveryCFG
;
1004 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
1006 aWriteLock
.unlock();
1007 // <- SAFE ----------------------------------
1009 // throws a RuntimeException if an error occure!
1010 css::uno::Reference
< css::container::XNameAccess
> xCFG(
1011 ::comphelper::ConfigurationHelper::openConfig(xSMGR
, CFG_PACKAGE_RECOVERY
, ::comphelper::ConfigurationHelper::E_STANDARD
),
1012 css::uno::UNO_QUERY
);
1014 sal_Int32 nMinSpaceDocSave
= MIN_DISCSPACE_DOCSAVE
;
1015 sal_Int32 nMinSpaceConfigSave
= MIN_DISCSPACE_CONFIGSAVE
;
1019 ::comphelper::ConfigurationHelper::readDirectKey(xSMGR
,
1020 CFG_PACKAGE_RECOVERY
,
1022 CFG_ENTRY_MINSPACE_DOCSAVE
,
1023 ::comphelper::ConfigurationHelper::E_STANDARD
) >>= nMinSpaceDocSave
;
1025 ::comphelper::ConfigurationHelper::readDirectKey(xSMGR
,
1026 CFG_PACKAGE_RECOVERY
,
1028 CFG_ENTRY_MINSPACE_CONFIGSAVE
,
1029 ::comphelper::ConfigurationHelper::E_STANDARD
) >>= nMinSpaceConfigSave
;
1031 catch(const css::uno::Exception
&)
1033 // These config keys are not sooooo important, that
1034 // we are interested on errors here realy .-)
1035 nMinSpaceDocSave
= MIN_DISCSPACE_DOCSAVE
;
1036 nMinSpaceConfigSave
= MIN_DISCSPACE_CONFIGSAVE
;
1039 // SAFE -> ----------------------------------
1041 m_xRecoveryCFG
= xCFG
;
1042 m_nMinSpaceDocSave
= nMinSpaceDocSave
;
1043 m_nMinSpaceConfigSave
= nMinSpaceConfigSave
;
1044 aWriteLock
.unlock();
1045 // <- SAFE ----------------------------------
1050 //-----------------------------------------------
1051 void AutoRecovery::implts_readAutoSaveConfig()
1053 css::uno::Reference
< css::container::XHierarchicalNameAccess
> xCommonRegistry(implts_openConfig(), css::uno::UNO_QUERY
);
1056 sal_Bool bEnabled
= sal_False
;
1057 xCommonRegistry
->getByHierarchicalName(CFG_ENTRY_AUTOSAVE_ENABLED
) >>= bEnabled
;
1059 // SAFE -> ------------------------------
1060 WriteGuard
aWriteLock(m_aLock
);
1063 m_eJob
|= AutoRecovery::E_AUTO_SAVE
;
1064 m_eTimerType
= AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL
;
1068 m_eJob
&= ~AutoRecovery::E_AUTO_SAVE
;
1069 m_eTimerType
= AutoRecovery::E_DONT_START_TIMER
;
1071 aWriteLock
.unlock();
1072 // <- SAFE ------------------------------
1074 // AutoSaveTimeIntervall [int] in min
1075 sal_Int32 nTimeIntervall
= 15;
1076 xCommonRegistry
->getByHierarchicalName(CFG_ENTRY_AUTOSAVE_TIMEINTERVALL
) >>= nTimeIntervall
;
1078 // SAFE -> ----------------------------------
1080 m_nAutoSaveTimeIntervall
= nTimeIntervall
;
1081 aWriteLock
.unlock();
1082 // <- SAFE ----------------------------------
1085 //-----------------------------------------------
1086 void AutoRecovery::implts_readConfig()
1088 implts_readAutoSaveConfig();
1090 css::uno::Reference
< css::container::XHierarchicalNameAccess
> xCommonRegistry(implts_openConfig(), css::uno::UNO_QUERY
);
1092 // REINTRANT -> --------------------------------
1093 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_ADD_REMOVE
);
1095 // THREADSAFE -> -------------------------------
1096 WriteGuard
aWriteLock(m_aLock
);
1097 // reset current cache load cache
1098 m_lDocCache
.clear();
1100 aWriteLock
.unlock();
1101 // <- THREADSAFE -------------------------------
1103 aCacheLock
.unlock();
1104 // <- REINTRANT --------------------------------
1106 css::uno::Any aValue
;
1108 // RecoveryList [set]
1109 aValue
= xCommonRegistry
->getByHierarchicalName(CFG_ENTRY_RECOVERYLIST
);
1110 css::uno::Reference
< css::container::XNameAccess
> xList
;
1114 const css::uno::Sequence
< ::rtl::OUString
> lItems
= xList
->getElementNames();
1115 const ::rtl::OUString
* pItems
= lItems
.getConstArray();
1116 sal_Int32 c
= lItems
.getLength();
1119 // REINTRANT -> --------------------------
1120 aCacheLock
.lock(LOCK_FOR_CACHE_ADD_REMOVE
);
1124 css::uno::Reference
< css::beans::XPropertySet
> xItem
;
1125 xList
->getByName(pItems
[i
]) >>= xItem
;
1129 AutoRecovery::TDocumentInfo aInfo
;
1130 aInfo
.NewTempURL
= ::rtl::OUString();
1131 aInfo
.Document
= css::uno::Reference
< css::frame::XModel
>();
1132 xItem
->getPropertyValue(CFG_ENTRY_PROP_ORIGINALURL
) >>= aInfo
.OrgURL
;
1133 xItem
->getPropertyValue(CFG_ENTRY_PROP_TEMPURL
) >>= aInfo
.OldTempURL
;
1134 xItem
->getPropertyValue(CFG_ENTRY_PROP_TEMPLATEURL
) >>= aInfo
.TemplateURL
;
1135 xItem
->getPropertyValue(CFG_ENTRY_PROP_FILTER
) >>= aInfo
.RealFilter
;
1136 xItem
->getPropertyValue(CFG_ENTRY_PROP_DOCUMENTSTATE
) >>= aInfo
.DocumentState
;
1137 xItem
->getPropertyValue(CFG_ENTRY_PROP_MODULE
) >>= aInfo
.AppModule
;
1138 xItem
->getPropertyValue(CFG_ENTRY_PROP_TITLE
) >>= aInfo
.Title
;
1139 implts_specifyAppModuleAndFactoryURL(aInfo
);
1140 implts_specifyDefaultFilterAndExtension(aInfo
);
1142 if (pItems
[i
].indexOf(RECOVERY_ITEM_BASE_IDENTIFIER
)==0)
1144 ::rtl::OUString sID
= pItems
[i
].copy(RECOVERY_ITEM_BASE_IDENTIFIER
.getLength());
1145 aInfo
.ID
= sID
.toInt32();
1146 // SAFE -> ----------------------
1148 if (aInfo
.ID
> m_nIdPool
)
1150 m_nIdPool
= aInfo
.ID
+1;
1151 LOG_ASSERT(m_nIdPool
>=0, "AutoRecovery::implts_readConfig()\nOverflow of IDPool detected!")
1153 aWriteLock
.unlock();
1154 // <- SAFE ----------------------
1156 #ifdef ENABLE_WARNINGS
1158 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 .-)")
1161 // THREADSAFE -> --------------------------
1163 m_lDocCache
.push_back(aInfo
);
1164 aWriteLock
.unlock();
1165 // <- THREADSAFE --------------------------
1168 aCacheLock
.unlock();
1169 // <- REINTRANT --------------------------
1172 implts_actualizeTimer();
1175 //-----------------------------------------------
1176 void AutoRecovery::implts_specifyDefaultFilterAndExtension(AutoRecovery::TDocumentInfo
& rInfo
)
1178 if (!rInfo
.AppModule
.getLength())
1180 throw css::uno::RuntimeException(
1181 ::rtl::OUString::createFromAscii("Cant find out the default filter and its extension, if no application module is known!"),
1182 static_cast< css::frame::XDispatch
* >(this));
1185 // SAFE -> ----------------------------------
1186 ReadGuard
aReadLock(m_aLock
);
1187 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
1188 css::uno::Reference
< css::container::XNameAccess
> xCFG
= m_xModuleCFG
;
1190 // <- SAFE ----------------------------------
1196 // open module config on demand and cache the update access
1197 xCFG
= css::uno::Reference
< css::container::XNameAccess
>(
1198 ::comphelper::ConfigurationHelper::openConfig(xSMGR
, CFG_PACKAGE_MODULES
, ::comphelper::ConfigurationHelper::E_STANDARD
),
1199 css::uno::UNO_QUERY_THROW
);
1201 // SAFE -> ----------------------------------
1202 WriteGuard
aWriteLock(m_aLock
);
1203 m_xModuleCFG
= xCFG
;
1204 aWriteLock
.unlock();
1205 // <- SAFE ----------------------------------
1208 css::uno::Reference
< css::container::XNameAccess
> xModuleProps(
1209 xCFG
->getByName(rInfo
.AppModule
),
1210 css::uno::UNO_QUERY_THROW
);
1212 xModuleProps
->getByName(CFG_ENTRY_REALDEFAULTFILTER
) >>= rInfo
.DefaultFilter
;
1214 css::uno::Reference
< css::container::XNameAccess
> xFilterCFG(xSMGR
->createInstance(SERVICENAME_FILTERFACTORY
), css::uno::UNO_QUERY_THROW
);
1215 css::uno::Reference
< css::container::XNameAccess
> xTypeCFG (xSMGR
->createInstance(SERVICENAME_TYPEDETECTION
), css::uno::UNO_QUERY_THROW
);
1217 ::comphelper::SequenceAsHashMap
lFilterProps (xFilterCFG
->getByName(rInfo
.DefaultFilter
));
1218 ::rtl::OUString sTypeRegistration
= lFilterProps
.getUnpackedValueOrDefault(FILTER_PROP_TYPE
, ::rtl::OUString());
1219 ::comphelper::SequenceAsHashMap
lTypeProps (xTypeCFG
->getByName(sTypeRegistration
));
1220 css::uno::Sequence
< ::rtl::OUString
> lExtensions
= lTypeProps
.getUnpackedValueOrDefault(TYPE_PROP_EXTENSIONS
, css::uno::Sequence
< ::rtl::OUString
>());
1221 if (lExtensions
.getLength())
1223 rInfo
.Extension
= ::rtl::OUString::createFromAscii(".");
1224 rInfo
.Extension
+= lExtensions
[0];
1227 rInfo
.Extension
= ::rtl::OUString::createFromAscii(".unknown");
1229 catch(const css::uno::Exception
&)
1231 rInfo
.DefaultFilter
= ::rtl::OUString();
1232 rInfo
.Extension
= ::rtl::OUString();
1236 //-----------------------------------------------
1237 void AutoRecovery::implts_specifyAppModuleAndFactoryURL(AutoRecovery::TDocumentInfo
& rInfo
)
1240 (!rInfo
.AppModule
.getLength()) &&
1241 (!rInfo
.Document
.is() )
1244 throw css::uno::RuntimeException(
1245 ::rtl::OUString::createFromAscii("Cant find out the application module nor its factory URL, if no application module (or a suitable) document is known!"),
1246 static_cast< css::frame::XDispatch
* >(this));
1249 // SAFE -> ----------------------------------
1250 ReadGuard
aReadLock(m_aLock
);
1251 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
1253 // <- SAFE ----------------------------------
1255 css::uno::Reference
< css::frame::XModuleManager
> xManager (xSMGR
->createInstance(SERVICENAME_MODULEMANAGER
), css::uno::UNO_QUERY_THROW
);
1256 css::uno::Reference
< css::container::XNameAccess
> xModuleConfig(xManager
, css::uno::UNO_QUERY_THROW
);
1258 if (!rInfo
.AppModule
.getLength())
1259 rInfo
.AppModule
= xManager
->identify(rInfo
.Document
);
1261 ::comphelper::SequenceAsHashMap
lModuleDescription(xModuleConfig
->getByName(rInfo
.AppModule
));
1262 lModuleDescription
[CFG_ENTRY_PROP_EMPTYDOCUMENTURL
] >>= rInfo
.FactoryURL
;
1265 //-----------------------------------------------
1266 void AutoRecovery::implts_flushConfigItem(const AutoRecovery::TDocumentInfo
& rInfo
, sal_Bool bRemoveIt
)
1268 css::uno::Reference
< css::container::XHierarchicalNameAccess
> xCFG
;
1272 xCFG
= css::uno::Reference
< css::container::XHierarchicalNameAccess
>(implts_openConfig(), css::uno::UNO_QUERY_THROW
);
1274 css::uno::Reference
< css::container::XNameAccess
> xCheck
;
1275 xCFG
->getByHierarchicalName(CFG_ENTRY_RECOVERYLIST
) >>= xCheck
;
1277 css::uno::Reference
< css::container::XNameContainer
> xModify(xCheck
, css::uno::UNO_QUERY_THROW
);
1278 css::uno::Reference
< css::lang::XSingleServiceFactory
> xCreate(xCheck
, css::uno::UNO_QUERY_THROW
);
1280 ::rtl::OUStringBuffer sIDBuf
;
1281 sIDBuf
.append(RECOVERY_ITEM_BASE_IDENTIFIER
);
1282 sIDBuf
.append((sal_Int32
)rInfo
.ID
);
1283 ::rtl::OUString sID
= sIDBuf
.makeStringAndClear();
1288 // Catch NoSuchElementException.
1289 // Its not a good idea inside multithreaded environments to call hasElement - removeElement.
1293 xModify
->removeByName(sID
);
1295 catch(const css::container::NoSuchElementException
&)
1301 css::uno::Reference
< css::beans::XPropertySet
> xSet
;
1302 sal_Bool bNew
= (!xCheck
->hasByName(sID
));
1304 xSet
= css::uno::Reference
< css::beans::XPropertySet
>(xCreate
->createInstance(), css::uno::UNO_QUERY_THROW
);
1306 xCheck
->getByName(sID
) >>= xSet
;
1308 xSet
->setPropertyValue(CFG_ENTRY_PROP_ORIGINALURL
, css::uno::makeAny(rInfo
.OrgURL
));
1309 xSet
->setPropertyValue(CFG_ENTRY_PROP_TEMPURL
, css::uno::makeAny(rInfo
.OldTempURL
));
1310 xSet
->setPropertyValue(CFG_ENTRY_PROP_TEMPLATEURL
, css::uno::makeAny(rInfo
.TemplateURL
));
1311 xSet
->setPropertyValue(CFG_ENTRY_PROP_FILTER
, css::uno::makeAny(rInfo
.RealFilter
));
1312 xSet
->setPropertyValue(CFG_ENTRY_PROP_DOCUMENTSTATE
, css::uno::makeAny(rInfo
.DocumentState
));
1313 xSet
->setPropertyValue(CFG_ENTRY_PROP_MODULE
, css::uno::makeAny(rInfo
.AppModule
));
1314 xSet
->setPropertyValue(CFG_ENTRY_PROP_TITLE
, css::uno::makeAny(rInfo
.Title
));
1317 xModify
->insertByName(sID
, css::uno::makeAny(xSet
));
1320 catch(const css::uno::RuntimeException
& exRun
)
1322 catch(const css::uno::Exception
&)
1323 {} // ??? can it happen that a full disc let these set of operations fail too ???
1325 sal_Int32 nRetry
= RETRY_STORE_ON_FULL_DISC_FOREVER
;
1330 css::uno::Reference
< css::util::XChangesBatch
> xFlush(xCFG
, css::uno::UNO_QUERY_THROW
);
1331 xFlush
->commitChanges();
1333 #ifdef TRIGGER_FULL_DISC_CHECK
1334 throw css::uno::Exception();
1339 catch(const css::uno::Exception
& ex
)
1341 // a) FULL DISC seams to be the problem behind => show error and retry it forever (e.g. retry=300)
1342 // b) unknown problem (may be locking problem) => reset RETRY value to more usefull value(!) (e.g. retry=3)
1343 // c) unknown problem (may be locking problem) + 1..2 repeating operations => throw the original exception to force generation of a stacktrace !
1346 ReadGuard
aReadLock(m_aLock
);
1347 sal_Int32 nMinSpaceConfigSave
= m_nMinSpaceConfigSave
;
1351 if (! impl_enoughDiscSpace(nMinSpaceConfigSave
))
1352 AutoRecovery::impl_showFullDiscError();
1354 if (nRetry
> RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL
)
1355 nRetry
= RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL
;
1357 if (nRetry
<= GIVE_UP_RETRY
)
1358 throw ex
; // force stacktrace to know if there exist might other reasons, why an AutoSave can fail !!!
1366 //-----------------------------------------------
1367 void AutoRecovery::implts_startListening()
1369 // SAFE -> ----------------------------------
1370 ReadGuard
aReadLock(m_aLock
);
1371 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
1372 css::uno::Reference
< css::util::XChangesNotifier
> xCFG (m_xRecoveryCFG
, css::uno::UNO_QUERY
);
1373 css::uno::Reference
< css::document::XEventBroadcaster
> xBroadcaster
= m_xNewDocBroadcaster
;
1374 sal_Bool bListenForDocEvents
= m_bListenForDocEvents
;
1376 // <- SAFE ----------------------------------
1380 (! m_bListenForConfigChanges
)
1383 xCFG
->addChangesListener(static_cast< css::util::XChangesListener
* >(this));
1384 m_bListenForConfigChanges
= sal_True
;
1387 if (!xBroadcaster
.is())
1389 xBroadcaster
= css::uno::Reference
< css::document::XEventBroadcaster
>(xSMGR
->createInstance(SERVICENAME_GLOBALEVENTBROADCASTER
), css::uno::UNO_QUERY_THROW
);
1390 // SAFE -> ----------------------------------
1391 WriteGuard
aWriteLock(m_aLock
);
1392 m_xNewDocBroadcaster
= xBroadcaster
;
1393 aWriteLock
.unlock();
1394 // <- SAFE ----------------------------------
1398 ( xBroadcaster
.is() ) &&
1399 (! bListenForDocEvents
)
1402 xBroadcaster
->addEventListener(static_cast< css::document::XEventListener
* >(this));
1404 WriteGuard
aWriteLock(m_aLock
);
1405 m_bListenForDocEvents
= sal_True
;
1406 aWriteLock
.unlock();
1411 //-----------------------------------------------
1412 void AutoRecovery::implts_stopListening()
1414 // SAFE -> ----------------------------------
1415 ReadGuard
aReadLock(m_aLock
);
1416 // Attention: Dont reset our internal members here too.
1417 // May be we must work with our configuration, but dont wish to be informed
1418 // about changes any longer. Needed e.g. during EMERGENCY_SAVE!
1419 css::uno::Reference
< css::util::XChangesNotifier
> xCFG (m_xRecoveryCFG
, css::uno::UNO_QUERY
);
1420 css::uno::Reference
< css::document::XEventBroadcaster
> xGlobalEventBroadcaster(m_xNewDocBroadcaster
, css::uno::UNO_QUERY
);
1422 // <- SAFE ----------------------------------
1425 (xGlobalEventBroadcaster
.is()) &&
1426 (m_bListenForDocEvents
)
1429 xGlobalEventBroadcaster
->removeEventListener(static_cast< css::document::XEventListener
* >(this));
1430 m_bListenForDocEvents
= sal_False
;
1435 (m_bListenForConfigChanges
)
1438 xCFG
->removeChangesListener(static_cast< css::util::XChangesListener
* >(this));
1439 m_bListenForConfigChanges
= sal_False
;
1443 //-----------------------------------------------
1444 void AutoRecovery::implts_startModifyListeningOnDoc(AutoRecovery::TDocumentInfo
& rInfo
)
1446 if (rInfo
.ListenForModify
)
1449 css::uno::Reference
< css::util::XModifyBroadcaster
> xBroadcaster(rInfo
.Document
, css::uno::UNO_QUERY
);
1450 if (xBroadcaster
.is())
1452 css::uno::Reference
< css::util::XModifyListener
> xThis(static_cast< css::frame::XDispatch
* >(this), css::uno::UNO_QUERY
);
1453 xBroadcaster
->addModifyListener(xThis
);
1454 rInfo
.ListenForModify
= sal_True
;
1458 //-----------------------------------------------
1459 void AutoRecovery::implts_stopModifyListeningOnDoc(AutoRecovery::TDocumentInfo
& rInfo
)
1461 if (! rInfo
.ListenForModify
)
1464 css::uno::Reference
< css::util::XModifyBroadcaster
> xBroadcaster(rInfo
.Document
, css::uno::UNO_QUERY
);
1465 if (xBroadcaster
.is())
1467 css::uno::Reference
< css::util::XModifyListener
> xThis(static_cast< css::frame::XDispatch
* >(this), css::uno::UNO_QUERY
);
1468 xBroadcaster
->removeModifyListener(xThis
);
1469 rInfo
.ListenForModify
= sal_False
;
1473 //-----------------------------------------------
1474 void AutoRecovery::implts_actualizeTimer()
1478 // SAFE -> ----------------------------------
1479 WriteGuard
aWriteLock(m_aLock
);
1482 (m_eJob
== AutoRecovery::E_NO_JOB
) || // TODO may be superflous - E_DONT_START_TIMER should be used only
1483 (m_eTimerType
== AutoRecovery::E_DONT_START_TIMER
)
1487 ULONG nMilliSeconds
= 0;
1488 if (m_eTimerType
== AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL
)
1490 nMilliSeconds
= (m_nAutoSaveTimeIntervall
*60000); // [min] => 60.000 ms
1491 #if OSL_DEBUG_LEVEL > 1
1492 if (m_dbg_bMakeItFaster
)
1493 nMilliSeconds
= m_nAutoSaveTimeIntervall
; // [ms]
1497 if (m_eTimerType
== AutoRecovery::E_POLL_FOR_USER_IDLE
)
1499 nMilliSeconds
= MIN_TIME_FOR_USER_IDLE
;
1500 #if OSL_DEBUG_LEVEL > 1
1501 if (m_dbg_bMakeItFaster
)
1502 nMilliSeconds
= 300; // let us some time, to finish this method .-)
1506 if (m_eTimerType
== AutoRecovery::E_POLL_TILL_AUTOSAVE_IS_ALLOWED
)
1507 nMilliSeconds
= 300; // there is a minimum time frame, where the user can loose some key input data!
1509 m_aTimer
.SetTimeout(nMilliSeconds
);
1512 aWriteLock
.unlock();
1513 // <- SAFE ----------------------------------
1516 //-----------------------------------------------
1517 void AutoRecovery::implts_stopTimer()
1519 // SAFE -> ----------------------------------
1520 WriteGuard
aWriteLock(m_aLock
);
1522 if (!m_aTimer
.IsActive())
1526 // <- SAFE ----------------------------------
1529 //-----------------------------------------------
1530 IMPL_LINK(AutoRecovery
, implts_timerExpired
, void*, EMPTYARG
)
1534 // This method is called by using a pointer to us.
1535 // But we must be aware that we can be destroyed hardly
1536 // if our uno reference will be gone!
1537 // => Hold this object alive till this method finish its work.
1538 css::uno::Reference
< css::uno::XInterface
> xSelfHold(static_cast< css::lang::XTypeProvider
* >(this));
1540 // Needed! Otherwise every reschedule request allow a new triggered timer event :-(
1543 // The timer must be ignored if AutoSave/Recovery was disabled for this
1544 // office session. That can happen if e.g. the command line arguments "-norestore" or "-headless"
1545 // was set. But normaly the timer was disabled if recovery was disabled ...
1546 // But so we are more "safe" .-)
1547 // SAFE -> ----------------------------------
1548 ReadGuard
aReadLock(m_aLock
);
1549 if ((m_eJob
& AutoRecovery::E_DISABLE_AUTORECOVERY
) == AutoRecovery::E_DISABLE_AUTORECOVERY
)
1552 // <- SAFE ----------------------------------
1554 // check some "states", where its not allowed (better: not a good idea) to
1555 // start an AutoSave. (e.g. if the user makes drag & drop ...)
1556 // Then we poll till this "disallowed" state is gone.
1557 sal_Bool bAutoSaveNotAllowed
= Application::IsUICaptured();
1558 if (bAutoSaveNotAllowed
)
1560 // SAFE -> ------------------------------
1561 WriteGuard
aWriteLock(m_aLock
);
1562 m_eTimerType
= AutoRecovery::E_POLL_TILL_AUTOSAVE_IS_ALLOWED
;
1563 aWriteLock
.unlock();
1564 // <- SAFE ------------------------------
1565 implts_actualizeTimer();
1569 // analyze timer type.
1570 // If we poll for an user idle period, may be we must
1571 // do nothing here and start the timer again.
1572 // SAFE -> ----------------------------------
1573 WriteGuard
aWriteLock(m_aLock
);
1575 if (m_eTimerType
== AutoRecovery::E_POLL_FOR_USER_IDLE
)
1577 sal_Bool bUserIdle
= (Application::GetLastInputInterval()>MIN_TIME_FOR_USER_IDLE
);
1580 implts_actualizeTimer();
1585 aWriteLock
.unlock();
1586 // <- SAFE ----------------------------------
1588 implts_informListener(AutoRecovery::E_AUTO_SAVE
,
1589 AutoRecovery::implst_createFeatureStateEvent(AutoRecovery::E_AUTO_SAVE
, OPERATION_START
, NULL
));
1591 // force save of all currently open documents
1592 // The called method returns an info, if and how this
1593 // timer must be restarted.
1594 sal_Bool bAllowUserIdleLoop
= sal_True
;
1595 AutoRecovery::ETimerType eSuggestedTimer
= implts_saveDocs(bAllowUserIdleLoop
, sal_False
);
1597 // If timer isnt used for "short callbacks" (means polling
1598 // for special states) ... reset the handle state of all
1599 // cache items. Such handle state indicates, that a document
1600 // was already saved during the THIS(!) AutoSave session.
1601 // Of course NEXT AutoSave session must be started without
1602 // any "handle" state ...
1604 (eSuggestedTimer
== AutoRecovery::E_DONT_START_TIMER
) ||
1605 (eSuggestedTimer
== AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL
)
1608 implts_resetHandleStates(sal_False
);
1611 implts_informListener(AutoRecovery::E_AUTO_SAVE
,
1612 AutoRecovery::implst_createFeatureStateEvent(AutoRecovery::E_AUTO_SAVE
, OPERATION_STOP
, NULL
));
1614 // restart timer - because it was disabled before ...
1615 // SAFE -> ----------------------------------
1617 m_eTimerType
= eSuggestedTimer
;
1618 aWriteLock
.unlock();
1619 // <- SAFE ----------------------------------
1621 implts_actualizeTimer();
1623 catch(const css::uno::Exception
&)
1625 LOG_ASSERT(sal_False
, "May be you found the reason for bug #125528#. Please report a test scenario to the right developer. THX.");
1631 //-----------------------------------------------
1632 IMPL_LINK(AutoRecovery
, implts_asyncDispatch
, void*, EMPTYARG
)
1635 WriteGuard
aWriteLock(m_aLock
);
1636 DispatchParams aParams
= m_aDispatchParams
;
1637 css::uno::Reference
< css::uno::XInterface
> xHoldRefForMethodAlive
= aParams
.m_xHoldRefForAsyncOpAlive
;
1638 m_aDispatchParams
.forget(); // clears all members ... including the ref-hold object .-)
1639 aWriteLock
.unlock();
1642 implts_dispatch(aParams
);
1646 //-----------------------------------------------
1647 void AutoRecovery::implts_registerDocument(const css::uno::Reference
< css::frame::XModel
>& xDocument
)
1649 // ignore corrupted events, where no document is given ... Runtime Error ?!
1650 if (!xDocument
.is())
1653 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
1655 // notification for already existing document !
1656 // Can happen if events came in asynchronous on recovery time.
1657 // Then our cache was filled from the configuration ... but now we get some
1658 // asynchronous events from the global event broadcaster. We must be shure that
1659 // we dont add the same document more then once.
1660 AutoRecovery::TDocumentList::iterator pIt
= AutoRecovery::impl_searchDocument(m_lDocCache
, xDocument
);
1661 if (pIt
!= m_lDocCache
.end())
1663 // Normaly nothing must be done for this "late" notification.
1664 // But may be the modified state was changed inbetween.
1666 implts_actualizeModifiedState(xDocument
);
1670 aCacheLock
.unlock();
1672 ::comphelper::MediaDescriptor
lDescriptor(xDocument
->getArgs());
1674 // check if this document must be ignored for recovery !
1675 // Some use cases dont wish support for AutoSave/Recovery ... as e.g. OLE-Server / ActiveX Control etcpp.
1676 sal_Bool bNoAutoSave
= lDescriptor
.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_NOAUTOSAVE(), (sal_Bool
)(sal_False
));
1680 // Check if doc is well known on the desktop. Otherwhise ignore it!
1681 // Other frames mostly are used from external programs - e.g. the bean ...
1682 css::uno::Reference
< css::frame::XController
> xController
= xDocument
->getCurrentController();
1683 if (!xController
.is())
1686 css::uno::Reference
< css::frame::XFrame
> xFrame
= xController
->getFrame();
1687 css::uno::Reference
< css::frame::XDesktop
> xDesktop (xFrame
->getCreator(), css::uno::UNO_QUERY
);
1691 // get all needed informations of this document
1692 // We need it to update our cache or to locate already existing elements there!
1693 AutoRecovery::TDocumentInfo aNew
;
1694 aNew
.Document
= xDocument
;
1696 // TODO replace getLocation() with getURL() ... its a workaround currently only!
1697 css::uno::Reference
< css::frame::XStorable
> xDoc(aNew
.Document
, css::uno::UNO_QUERY_THROW
);
1698 aNew
.OrgURL
= xDoc
->getLocation();
1700 css::uno::Reference
< css::frame::XTitle
> xTitle(aNew
.Document
, css::uno::UNO_QUERY_THROW
);
1701 aNew
.Title
= xTitle
->getTitle ();
1703 // SAFE -> ----------------------------------
1704 ReadGuard
aReadLock(m_aLock
);
1705 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
1707 // <- SAFE ----------------------------------
1709 // classify the used application module, which is used by this document.
1710 implts_specifyAppModuleAndFactoryURL(aNew
);
1712 // Hack! Check for "illegal office documents" ... as e.g. the Basic IDE
1713 // Its not realy a full featured office document. It doesnt provide an URL, any filter, a factory URL etcpp.
1714 // TODO file bug to Basci IDE developers. They must remove the office document API from its service.
1716 (!aNew
.OrgURL
.getLength() ) &&
1717 (!aNew
.FactoryURL
.getLength())
1721 // By the way - get some information about the default format for saving!
1722 // and save an information about the real used filter by this document.
1723 // We save this document with DefaultFilter ... and load it with the RealFilter.
1724 implts_specifyDefaultFilterAndExtension(aNew
);
1725 aNew
.RealFilter
= lDescriptor
.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_FILTERNAME() , ::rtl::OUString());
1727 // Further we must know, if this document base on a template.
1728 // Then we must load it in a different way.
1729 css::uno::Reference
< css::document::XDocumentPropertiesSupplier
> xSupplier(aNew
.Document
, css::uno::UNO_QUERY
);
1730 if (xSupplier
.is()) // optional interface!
1732 css::uno::Reference
< css::document::XDocumentProperties
> xDocProps(xSupplier
->getDocumentProperties(), css::uno::UNO_QUERY_THROW
);
1733 aNew
.TemplateURL
= xDocProps
->getTemplateURL();
1736 css::uno::Reference
< css::util::XModifiable
> xModifyCheck(xDocument
, css::uno::UNO_QUERY_THROW
);
1737 if (xModifyCheck
->isModified())
1739 aNew
.DocumentState
|= AutoRecovery::E_MODIFIED
;
1740 aNew
.DocumentState
|= AutoRecovery::E_MODIFIED_SINCE_LAST_AUTOSAVE
;
1743 aCacheLock
.lock(LOCK_FOR_CACHE_ADD_REMOVE
);
1745 // SAFE -> ----------------------------------
1746 WriteGuard
aWriteLock(m_aLock
);
1748 // create a new cache entry ... this document isnt well known.
1750 aNew
.ID
= m_nIdPool
;
1751 LOG_ASSERT(m_nIdPool
>=0, "AutoRecovery::implts_registerDocument()\nOverflow of ID pool detected.")
1752 m_lDocCache
.push_back(aNew
);
1754 AutoRecovery::TDocumentList::iterator pIt1
= AutoRecovery::impl_searchDocument(m_lDocCache
, xDocument
);
1755 AutoRecovery::TDocumentInfo
& rInfo
= *pIt1
;
1757 aWriteLock
.unlock();
1758 // <- SAFE ----------------------------------
1760 implts_flushConfigItem(rInfo
);
1761 implts_startModifyListeningOnDoc(rInfo
);
1763 aCacheLock
.unlock();
1766 //-----------------------------------------------
1767 void AutoRecovery::implts_deregisterDocument(const css::uno::Reference
< css::frame::XModel
>& xDocument
,
1768 sal_Bool bStopListening
)
1771 // SAFE -> ----------------------------------
1772 WriteGuard
aWriteLock(m_aLock
);
1774 // Attention: Dont leave SAFE section, if you work with pIt!
1775 // Because it points directly into the m_lDocCache list ...
1776 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
1778 AutoRecovery::TDocumentList::iterator pIt
= AutoRecovery::impl_searchDocument(m_lDocCache
, xDocument
);
1779 if (pIt
== m_lDocCache
.end())
1780 return; // unknown document => not a runtime error! Because we register only a few documents. see registration ...
1782 AutoRecovery::TDocumentInfo aInfo
= *pIt
;
1784 aCacheLock
.unlock();
1786 // Sometimes we close documents by ourself.
1787 // And these documents cant be deregistered.
1788 // Otherwhise we loos our configuration data ... but need it !
1789 // see SessionSave !
1790 if (aInfo
.IgnoreClosing
)
1793 CacheLockGuard
aCacheLock2(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_ADD_REMOVE
);
1794 pIt
= AutoRecovery::impl_searchDocument(m_lDocCache
, xDocument
);
1795 if (pIt
!= m_lDocCache
.end())
1796 m_lDocCache
.erase(pIt
);
1797 pIt
= m_lDocCache
.end(); // otherwhise its not specified what pIt means!
1798 aCacheLock2
.unlock();
1800 aWriteLock
.unlock();
1801 // <- SAFE ----------------------------------
1803 /* This method is called within disposing() of the document too. But there it's not a good idea to
1804 deregister us as listener. Furter it make no sense - because the broadcaster dies.
1805 So we supress deregistration in such case ...
1808 implts_stopModifyListeningOnDoc(aInfo
);
1810 AutoRecovery::st_impl_removeFile(aInfo
.OldTempURL
);
1811 AutoRecovery::st_impl_removeFile(aInfo
.NewTempURL
);
1812 implts_flushConfigItem(aInfo
, sal_True
); // TRUE => remove it from config
1815 //-----------------------------------------------
1816 void AutoRecovery::implts_markDocumentModifiedAgainstLastBackup(const css::uno::Reference
< css::frame::XModel
>& xDocument
)
1818 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
1820 // SAFE -> ----------------------------------
1821 WriteGuard
aWriteLock(m_aLock
);
1823 AutoRecovery::TDocumentList::iterator pIt
= AutoRecovery::impl_searchDocument(m_lDocCache
, xDocument
);
1824 if (pIt
!= m_lDocCache
.end())
1826 AutoRecovery::TDocumentInfo
& rInfo
= *pIt
;
1827 rInfo
.DocumentState
|= AutoRecovery::E_MODIFIED_SINCE_LAST_AUTOSAVE
;
1829 /* Now we know, that this document was modified again and must be saved next time.
1830 But we dont need this information for every e.g. key input of the user.
1831 So we stop listening here.
1832 But if the document was saved as temp. file we start listening for this event again.
1834 implts_stopModifyListeningOnDoc(rInfo
);
1837 aWriteLock
.unlock();
1838 // <- SAFE ----------------------------------
1841 //-----------------------------------------------
1842 void AutoRecovery::implts_actualizeModifiedState(const css::uno::Reference
< css::frame::XModel
>& xDocument
)
1844 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
1846 // SAFE -> ----------------------------------
1847 WriteGuard
aWriteLock(m_aLock
);
1849 AutoRecovery::TDocumentList::iterator pIt
= AutoRecovery::impl_searchDocument(m_lDocCache
, xDocument
);
1850 if (pIt
!= m_lDocCache
.end())
1852 AutoRecovery::TDocumentInfo
& rInfo
= *pIt
;
1854 // use TRUE as fallback ... so we recognize every document on EmergencySave/AutoRecovery!
1855 sal_Bool bModified
= sal_True
;
1856 css::uno::Reference
< css::util::XModifiable
> xModify(xDocument
, css::uno::UNO_QUERY
);
1858 bModified
= xModify
->isModified();
1861 rInfo
.DocumentState
|= AutoRecovery::E_MODIFIED
;
1862 rInfo
.DocumentState
|= AutoRecovery::E_MODIFIED_SINCE_LAST_AUTOSAVE
;
1866 rInfo
.DocumentState
&= ~AutoRecovery::E_MODIFIED
;
1867 rInfo
.DocumentState
&= ~AutoRecovery::E_MODIFIED_SINCE_LAST_AUTOSAVE
;
1871 aWriteLock
.unlock();
1872 // <- SAFE ----------------------------------
1875 //-----------------------------------------------
1876 void AutoRecovery::implts_updateDocumentUsedForSavingState(const css::uno::Reference
< css::frame::XModel
>& xDocument
,
1877 sal_Bool bSaveInProgress
)
1879 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
1881 // SAFE -> ----------------------------------
1882 WriteGuard
aWriteLock(m_aLock
);
1884 AutoRecovery::TDocumentList::iterator pIt
= AutoRecovery::impl_searchDocument(m_lDocCache
, xDocument
);
1885 if (pIt
== m_lDocCache
.end())
1887 AutoRecovery::TDocumentInfo
& rInfo
= *pIt
;
1888 rInfo
.UsedForSaving
= bSaveInProgress
;
1890 aWriteLock
.unlock();
1891 // <- SAFE ----------------------------------
1894 //-----------------------------------------------
1895 void AutoRecovery::implts_markDocumentAsSaved(const css::uno::Reference
< css::frame::XModel
>& xDocument
)
1897 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
1899 // SAFE -> ----------------------------------
1900 WriteGuard
aWriteLock(m_aLock
);
1902 AutoRecovery::TDocumentList::iterator pIt
= AutoRecovery::impl_searchDocument(m_lDocCache
, xDocument
);
1903 if (pIt
== m_lDocCache
.end())
1905 AutoRecovery::TDocumentInfo
& rInfo
= *pIt
;
1907 rInfo
.DocumentState
= AutoRecovery::E_UNKNOWN
;
1908 // TODO replace getLocation() with getURL() ... its a workaround currently only!
1909 css::uno::Reference
< css::frame::XStorable
> xDoc(rInfo
.Document
, css::uno::UNO_QUERY
);
1910 rInfo
.OrgURL
= xDoc
->getLocation();
1912 ::rtl::OUString sRemoveURL1
= rInfo
.OldTempURL
;
1913 ::rtl::OUString sRemoveURL2
= rInfo
.NewTempURL
;
1914 rInfo
.OldTempURL
= ::rtl::OUString();
1915 rInfo
.NewTempURL
= ::rtl::OUString();
1917 ::comphelper::MediaDescriptor
lDescriptor(rInfo
.Document
->getArgs());
1918 rInfo
.RealFilter
= lDescriptor
.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_FILTERNAME(), ::rtl::OUString());
1920 css::uno::Reference
< css::frame::XTitle
> xDocTitle(xDocument
, css::uno::UNO_QUERY
);
1921 if (xDocTitle
.is ())
1922 rInfo
.Title
= xDocTitle
->getTitle ();
1925 rInfo
.Title
= lDescriptor
.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_TITLE() , ::rtl::OUString());
1926 if (!rInfo
.Title
.getLength())
1927 rInfo
.Title
= lDescriptor
.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_DOCUMENTTITLE(), ::rtl::OUString());
1930 rInfo
.UsedForSaving
= sal_False
;
1932 aWriteLock
.unlock();
1933 // <- SAFE ----------------------------------
1935 implts_flushConfigItem(rInfo
);
1937 aCacheLock
.unlock();
1939 AutoRecovery::st_impl_removeFile(sRemoveURL1
);
1940 AutoRecovery::st_impl_removeFile(sRemoveURL2
);
1943 //-----------------------------------------------
1944 AutoRecovery::TDocumentList::iterator
AutoRecovery::impl_searchDocument( AutoRecovery::TDocumentList
& rList
,
1945 const css::uno::Reference
< css::frame::XModel
>& xDocument
)
1947 AutoRecovery::TDocumentList::iterator pIt
;
1948 for ( pIt
= rList
.begin();
1949 pIt
!= rList
.end() ;
1952 const AutoRecovery::TDocumentInfo
& rInfo
= *pIt
;
1953 if (rInfo
.Document
== xDocument
)
1959 //-----------------------------------------------
1960 void AutoRecovery::implts_changeAllDocVisibility(sal_Bool bVisible
)
1962 // SAFE -> ----------------------------------
1963 ReadGuard
aReadLock(m_aLock
);
1964 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
1966 // <- SAFE ----------------------------------
1968 css::uno::Reference
< css::frame::XFramesSupplier
> xDesktop (xSMGR
->createInstance(SERVICENAME_DESKTOP
), css::uno::UNO_QUERY
);
1969 css::uno::Reference
< css::container::XIndexAccess
> xContainer(xDesktop
->getFrames() , css::uno::UNO_QUERY
);
1970 sal_Int32 c
= xContainer
->getCount();
1975 css::uno::Reference
< css::frame::XFrame
> xTask
;
1977 xContainer
->getByIndex(i
) >>= xTask
;
1981 css::uno::Reference
< css::awt::XWindow
> xWindow
= xTask
->getContainerWindow();
1982 xWindow
->setVisible(bVisible
);
1986 // <- SAFE ----------------------------------
1989 //-----------------------------------------------
1990 void AutoRecovery::implts_prepareSessionShutdown()
1992 LOG_RECOVERY("AutoRecovery::implts_prepareSessionShutdown() starts ...")
1994 // a) reset modified documents (of course the must be saved before this method is called!)
1995 // b) close it without showing any UI!
1998 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
2000 AutoRecovery::TDocumentList::iterator pIt
;
2001 for ( pIt
= m_lDocCache
.begin();
2002 pIt
!= m_lDocCache
.end() ;
2005 AutoRecovery::TDocumentInfo
& rInfo
= *pIt
;
2007 // Prevent us from deregistration of these documents.
2008 // Because we close these documents by ourself (see XClosable below) ...
2009 // it's fact, that we reach our deregistration method. There we
2010 // must not(!) update our configuration ... Otherwhise all
2011 // session data are lost !!!
2012 rInfo
.IgnoreClosing
= sal_True
;
2014 // reset modified flag of these documents (ignoring the notification about it!)
2015 // Otherwise a message box is shown on closing these models.
2016 implts_stopModifyListeningOnDoc(rInfo
);
2017 css::uno::Reference
< css::util::XModifiable
> xModify(rInfo
.Document
, css::uno::UNO_QUERY
);
2019 xModify
->setModified(sal_False
);
2022 css::uno::Reference
< css::util::XCloseable
> xClose(rInfo
.Document
, css::uno::UNO_QUERY
);
2027 xClose
->close(sal_False
);
2030 catch(const css::lang::DisposedException&)
2032 // closed ... disposed ... always the same .-)
2035 catch(const css::uno::Exception
&)
2037 // At least it's only a try to close these documents before anybody else it does.
2038 // So it seams to be possible to ignore any error here .-)
2041 rInfo
.Document
.clear();
2045 aCacheLock
.unlock();
2049 //-----------------------------------------------
2050 /* Currently the document is not closed in case of crash,
2051 so the lock file must be removed explicitly
2053 void lc_removeLockFile(AutoRecovery::TDocumentInfo
& rInfo
)
2055 if ( rInfo
.Document
.is() )
2059 css::uno::Reference
< css::frame::XStorable
> xStore(rInfo
.Document
, css::uno::UNO_QUERY_THROW
);
2060 ::rtl::OUString aURL
= xStore
->getLocation();
2061 if ( aURL
.getLength() )
2063 ::svt::DocumentLockFile
aLockFile( aURL
);
2064 aLockFile
.RemoveFile();
2067 catch( const css::uno::Exception
& )
2073 //-----------------------------------------------
2078 Normaly the MediaDescriptor argument NoAutoSave indicates,
2079 that a document must be ignored for AutoSave and Recovery.
2080 But sometimes XModel->getArgs() does not contained this information
2081 if implts_registerDocument() was called.
2082 So we have to check a second time, if this property is set ....
2083 Best place doing so is to check it immeditaly before saving
2084 and supressingd saving the document then.
2085 Of course removing the corresponding cache entry isnt an option.
2086 Because it would disturb iteration over the cache !
2087 So we ignore such documents only ...
2088 Hopefully next time they are not inserted in our cache.
2090 sal_Bool
lc_checkIfSaveForbiddenByArguments(AutoRecovery::TDocumentInfo
& rInfo
)
2092 if (! rInfo
.Document
.is())
2095 ::comphelper::MediaDescriptor
lDescriptor(rInfo
.Document
->getArgs());
2096 sal_Bool bNoAutoSave
= lDescriptor
.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_NOAUTOSAVE(), (sal_Bool
)(sal_False
));
2101 //-----------------------------------------------
2102 AutoRecovery::ETimerType
AutoRecovery::implts_saveDocs( sal_Bool bAllowUserIdleLoop
,
2103 sal_Bool bRemoveLockFiles
,
2104 const DispatchParams
* pParams
)
2106 // SAFE -> ----------------------------------
2107 ReadGuard
aReadLock(m_aLock
);
2108 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
2110 // <- SAFE ----------------------------------
2112 css::uno::Reference
< css::task::XStatusIndicator
> xExternalProgress
;
2114 xExternalProgress
= pParams
->m_xProgress
;
2116 css::uno::Reference
< css::frame::XFramesSupplier
> xDesktop (xSMGR
->createInstance(SERVICENAME_DESKTOP
), css::uno::UNO_QUERY
);
2117 ::rtl::OUString
sBackupPath (SvtPathOptions().GetBackupPath());
2119 css::uno::Reference
< css::frame::XController
> xActiveController
;
2120 css::uno::Reference
< css::frame::XModel
> xActiveModel
;
2121 css::uno::Reference
< css::frame::XFrame
> xActiveFrame
= xDesktop
->getActiveFrame();
2122 if (xActiveFrame
.is())
2123 xActiveController
= xActiveFrame
->getController();
2124 if (xActiveController
.is())
2125 xActiveModel
= xActiveController
->getModel();
2127 // Set the default timer action for our calli.
2128 // Default = NORMAL_AUTOSAVE
2129 // We return a suggestion for an active timer only.
2130 // It will be ignored if the timer was disabled by the user ...
2131 // Further this state can be set to USER_IDLE only later in this method.
2132 // Its not allowed to reset such state then. Because we must know, if
2133 // there exists POSTPONED documents. see below ...
2134 AutoRecovery::ETimerType eTimer
= AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL
;
2136 sal_Int32 eJob
= m_eJob
;
2138 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
2140 // SAFE -> ----------------------------------
2141 WriteGuard
aWriteLock(m_aLock
);
2143 // This list will be filled with every document
2144 // which should be saved as last one. E.g. if it was used
2145 // already for an UI save operation => crashed ... and
2146 // now we try to save it again ... which can fail again ( of course .-) ).
2147 ::std::vector
< AutoRecovery::TDocumentList::iterator
> lDangerousDocs
;
2149 AutoRecovery::TDocumentList::iterator pIt
;
2150 for ( pIt
= m_lDocCache
.begin();
2151 pIt
!= m_lDocCache
.end() ;
2154 AutoRecovery::TDocumentInfo aInfo
= *pIt
;
2156 // WORKAROUND... Since the documents are not closed the lock file must be removed explicitly
2157 if ( bRemoveLockFiles
)
2158 lc_removeLockFile( aInfo
);
2160 // WORKAROUND ... see comment of this method
2161 if (lc_checkIfSaveForbiddenByArguments(aInfo
))
2164 // already auto saved during this session :-)
2165 // This state must be reseted for all documents
2166 // if timer is started with normnal AutoSaveTimerIntervall!
2167 if ((aInfo
.DocumentState
& AutoRecovery::E_HANDLED
) == AutoRecovery::E_HANDLED
)
2170 // Not modified documents are not saved.
2171 // We safe an information about the URL only!
2172 sal_Bool bModified
= ((aInfo
.DocumentState
& AutoRecovery::E_MODIFIED_SINCE_LAST_AUTOSAVE
) == AutoRecovery::E_MODIFIED_SINCE_LAST_AUTOSAVE
);
2175 aInfo
.DocumentState
|= AutoRecovery::E_HANDLED
;
2179 // check if this document is still used by a concurrent save operation
2180 // e.g. if the user tried to save via UI.
2181 // Handle it in the following way:
2182 // i) For an AutoSave ... ignore this document! It will be saved and next time we will (hopefully)
2183 // get a notification about the state of this operation.
2184 // And if a document was saved by the user we can remove our temp. file. But that will be done inside
2185 // our callback for SaveDone notification.
2186 // ii) For a CrashSave ... add it to the list of dangerous documents and
2187 // save it after all other documents was saved successfully. That decrease
2188 // the chance for a crash inside a crash.
2189 // On the other side it's not neccessary for documents, which are not modified.
2190 // They can be handled normaly - means we patch the corresponding configuration entry only.
2191 // iii) For a SessionSave ... ignore it! There is no time to wait for this save operation.
2192 // Because the WindowManager will kill the process if it doesnt react immediatly.
2193 // On the other side we cant risk a concurrent save request ... because we know
2194 // that it will produce a crash.
2196 // Attention: Because eJob is used as a flag field, you have to check for the worst case first.
2197 // E.g. a CrashSave can overwrite an AutoSave. So you have to check for a CrashSave before an AutoSave!
2198 if (aInfo
.UsedForSaving
)
2200 if ((eJob
& AutoRecovery::E_EMERGENCY_SAVE
) == AutoRecovery::E_EMERGENCY_SAVE
)
2202 lDangerousDocs
.push_back(pIt
);
2206 if ((eJob
& AutoRecovery::E_SESSION_SAVE
) == AutoRecovery::E_SESSION_SAVE
)
2211 if ((eJob
& AutoRecovery::E_AUTO_SAVE
) == AutoRecovery::E_AUTO_SAVE
)
2213 eTimer
= AutoRecovery::E_POLL_TILL_AUTOSAVE_IS_ALLOWED
;
2214 aInfo
.DocumentState
|= AutoRecovery::E_POSTPONED
;
2219 // a) Document was not postponed - and is active now. => postpone it (restart timer, restart loop)
2220 // b) Document was not postponed - and is not active now. => save it
2221 // c) Document was postponed - and is not active now. => save it
2222 // d) Document was postponed - and is active now. => save it (because user idle was checked already)
2223 sal_Bool bActive
= (xActiveModel
== aInfo
.Document
);
2224 sal_Bool bWasPostponed
= ((aInfo
.DocumentState
& AutoRecovery::E_POSTPONED
) == AutoRecovery::E_POSTPONED
);
2231 aInfo
.DocumentState
|= AutoRecovery::E_POSTPONED
;
2233 // postponed documents will be saved if this method is called again!
2234 // That can be done by an outside started timer => E_POLL_FOR_USER_IDLE (if normal AutoSave is active)
2235 // 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!)
2236 eTimer
= AutoRecovery::E_POLL_FOR_USER_IDLE
;
2237 if (!bAllowUserIdleLoop
)
2238 eTimer
= AutoRecovery::E_CALL_ME_BACK
;
2243 // <- SAFE --------------------------
2244 aWriteLock
.unlock();
2245 // changing of aInfo and flushing it is done inside implts_saveOneDoc!
2246 implts_saveOneDoc(sBackupPath
, aInfo
, xExternalProgress
);
2247 implts_informListener(eJob
, AutoRecovery::implst_createFeatureStateEvent(eJob
, OPERATION_UPDATE
, &aInfo
));
2249 // SAFE -> --------------------------
2254 // Did we have some "dangerous candidates" ?
2255 // Try to save it ... but may be it will fail !
2256 ::std::vector
< AutoRecovery::TDocumentList::iterator
>::iterator pIt2
;
2257 for ( pIt2
= lDangerousDocs
.begin();
2258 pIt2
!= lDangerousDocs
.end() ;
2262 AutoRecovery::TDocumentInfo aInfo
= *pIt
;
2264 // <- SAFE --------------------------
2265 aWriteLock
.unlock();
2266 // changing of aInfo and flushing it is done inside implts_saveOneDoc!
2267 implts_saveOneDoc(sBackupPath
, aInfo
, xExternalProgress
);
2268 implts_informListener(eJob
, AutoRecovery::implst_createFeatureStateEvent(eJob
, OPERATION_UPDATE
, &aInfo
));
2270 // SAFE -> --------------------------
2278 //-----------------------------------------------
2279 void AutoRecovery::implts_saveOneDoc(const ::rtl::OUString
& sBackupPath
,
2280 AutoRecovery::TDocumentInfo
& rInfo
,
2281 const css::uno::Reference
< css::task::XStatusIndicator
>& xExternalProgress
)
2283 // no document? => can occure if we loaded our configuration with files,
2284 // which couldnt be recovered successfully. In such case we have all needed informations
2285 // excepting the real document instance!
2287 // TODO: search right place, where such "dead files" can be removed from the configuration!
2288 if (!rInfo
.Document
.is())
2291 ::comphelper::MediaDescriptor
lOldArgs(rInfo
.Document
->getArgs());
2292 implts_generateNewTempURL(sBackupPath
, lOldArgs
, rInfo
);
2294 // if the document was loaded with a password, it should be
2295 // stored with password
2296 ::comphelper::MediaDescriptor lNewArgs
;
2297 ::rtl::OUString sPassword
= lOldArgs
.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_PASSWORD(), ::rtl::OUString());
2298 if (sPassword
.getLength())
2299 lNewArgs
[::comphelper::MediaDescriptor::PROP_PASSWORD()] <<= sPassword
;
2301 // Further it must be saved using the default file format of that application.
2302 // Otherwhise we will some data lost.
2303 if (rInfo
.DefaultFilter
.getLength())
2304 lNewArgs
[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= rInfo
.DefaultFilter
;
2306 // prepare frame/document/mediadescriptor in a way, that it uses OUR progress .-)
2307 if (xExternalProgress
.is())
2308 lNewArgs
[::comphelper::MediaDescriptor::PROP_STATUSINDICATOR()] <<= xExternalProgress
;
2309 impl_establishProgress(rInfo
, lNewArgs
, css::uno::Reference
< css::frame::XFrame
>());
2311 // #i66598# use special handling of property "DocumentBaseURL" (it must be an empty string!)
2312 // for make hyperlinks working
2313 lNewArgs
[::comphelper::MediaDescriptor::PROP_DOCUMENTBASEURL()] <<= ::rtl::OUString();
2315 // try to save this document as a new temp file everytimes.
2316 // Mark AutoSave state as "INCOMPLETE" if it failed.
2317 // Because the last temp file is to old and does not include all changes.
2318 css::uno::Reference
< css::frame::XStorable
> xStore(rInfo
.Document
, css::uno::UNO_QUERY_THROW
);
2320 // safe the state about "trying to save"
2321 // ... we need it for recovery if e.g. a crash occures inside next line!
2322 rInfo
.DocumentState
|= AutoRecovery::E_TRY_SAVE
;
2323 implts_flushConfigItem(rInfo
);
2325 sal_Int32 nRetry
= RETRY_STORE_ON_FULL_DISC_FOREVER
;
2326 sal_Bool bError
= sal_False
;
2331 xStore
->storeToURL(rInfo
.NewTempURL
, lNewArgs
.getAsConstPropertyValueList());
2333 #ifdef TRIGGER_FULL_DISC_CHECK
2334 throw css::uno::Exception();
2340 catch(const css::uno::Exception
& ex
)
2344 // a) FULL DISC seams to be the problem behind => show error and retry it forever (e.g. retry=300)
2345 // b) unknown problem (may be locking problem) => reset RETRY value to more usefull value(!) (e.g. retry=3)
2346 // c) unknown problem (may be locking problem) + 1..2 repeating operations => throw the original exception to force generation of a stacktrace !
2349 ReadGuard
aReadLock2(m_aLock
);
2350 sal_Int32 nMinSpaceDocSave
= m_nMinSpaceDocSave
;
2351 aReadLock2
.unlock();
2354 if (! impl_enoughDiscSpace(nMinSpaceDocSave
))
2355 AutoRecovery::impl_showFullDiscError();
2357 if (nRetry
> RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL
)
2358 nRetry
= RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL
;
2360 if (nRetry
<= GIVE_UP_RETRY
)
2361 throw ex
; // force stacktrace to know if there exist might other reasons, why an AutoSave can fail !!!
2370 // safe the state about success
2371 // ... you know the reason: to know it on recovery time if next line crash .-)
2372 rInfo
.DocumentState
&= ~AutoRecovery::E_TRY_SAVE
;
2373 rInfo
.DocumentState
|= AutoRecovery::E_HANDLED
;
2374 rInfo
.DocumentState
|= AutoRecovery::E_SUCCEDED
;
2375 rInfo
.DocumentState
&= ~AutoRecovery::E_MODIFIED_SINCE_LAST_AUTOSAVE
;
2379 // safe the state about error ...
2380 rInfo
.NewTempURL
= ::rtl::OUString();
2381 rInfo
.DocumentState
&= ~AutoRecovery::E_TRY_SAVE
;
2382 rInfo
.DocumentState
|= AutoRecovery::E_HANDLED
;
2383 rInfo
.DocumentState
|= AutoRecovery::E_INCOMPLETE
;
2386 // make sure the progress isnt referred any longer
2387 impl_forgetProgress(rInfo
, lNewArgs
, css::uno::Reference
< css::frame::XFrame
>());
2389 // try to remove the old temp file.
2390 // Ignore any error here. We have a new temp file, which is up to date.
2391 // The only thing is: we fill the disk with temp files, if we cant remove old ones :-)
2392 ::rtl::OUString sRemoveFile
= rInfo
.OldTempURL
;
2393 rInfo
.OldTempURL
= rInfo
.NewTempURL
;
2394 rInfo
.NewTempURL
= ::rtl::OUString();
2396 implts_flushConfigItem(rInfo
);
2398 // We must know if the user modifies the document again ...
2399 implts_startModifyListeningOnDoc(rInfo
);
2401 AutoRecovery::st_impl_removeFile(sRemoveFile
);
2404 //-----------------------------------------------
2405 AutoRecovery::ETimerType
AutoRecovery::implts_openDocs(const DispatchParams
& aParams
)
2407 AutoRecovery::ETimerType eTimer
= AutoRecovery::E_DONT_START_TIMER
;
2409 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
2411 // SAFE -> ----------------------------------
2412 WriteGuard
aWriteLock(m_aLock
);
2414 sal_Int32 eJob
= m_eJob
;
2415 AutoRecovery::TDocumentList::iterator pIt
;
2416 for ( pIt
= m_lDocCache
.begin();
2417 pIt
!= m_lDocCache
.end() ;
2420 AutoRecovery::TDocumentInfo
& rInfo
= *pIt
;
2422 // Such documents are already loaded by the last loop.
2423 // Dont check E_SUCCEDED here! Its may be the final state of an AutoSave
2424 // operation before!!!
2425 if ((rInfo
.DocumentState
& AutoRecovery::E_HANDLED
) == AutoRecovery::E_HANDLED
)
2428 // a1,b1,c1,d2,e2,f2)
2429 if ((rInfo
.DocumentState
& AutoRecovery::E_DAMAGED
) == AutoRecovery::E_DAMAGED
)
2431 // dont forget to inform listener! May be this document was
2432 // damaged on last saving time ...
2433 // Then our listener need this notification.
2434 // If it was damaged during last "try to open" ...
2435 // it will be notified more then once. SH.. HAPPENS ...
2436 // <- SAFE --------------------------
2437 aWriteLock
.unlock();
2438 implts_informListener(eJob
,
2439 AutoRecovery::implst_createFeatureStateEvent(eJob
, OPERATION_UPDATE
, &rInfo
));
2441 // SAFE -> --------------------------
2445 ::comphelper::MediaDescriptor lDescriptor
;
2447 // its an UI feature - so the "USER" itself must be set as referer
2448 lDescriptor
[::comphelper::MediaDescriptor::PROP_REFERRER()] <<= REFERRER_USER
;
2449 lDescriptor
[::comphelper::MediaDescriptor::PROP_SALVAGEDFILE()] <<= ::rtl::OUString();
2451 if (aParams
.m_xProgress
.is())
2452 lDescriptor
[::comphelper::MediaDescriptor::PROP_STATUSINDICATOR()] <<= aParams
.m_xProgress
;
2454 sal_Bool bBackupWasTried
= (
2455 ((rInfo
.DocumentState
& AutoRecovery::E_TRY_LOAD_BACKUP
) == AutoRecovery::E_TRY_LOAD_BACKUP
) || // temp. state!
2456 ((rInfo
.DocumentState
& AutoRecovery::E_INCOMPLETE
) == AutoRecovery::E_INCOMPLETE
) // transport TRY_LOAD_BACKUP from last loop to this new one!
2458 sal_Bool bOriginalWasTried
= ((rInfo
.DocumentState
& AutoRecovery::E_TRY_LOAD_ORIGINAL
) == AutoRecovery::E_TRY_LOAD_ORIGINAL
);
2460 if (bBackupWasTried
)
2462 if (!bOriginalWasTried
)
2464 rInfo
.DocumentState
|= AutoRecovery::E_INCOMPLETE
;
2465 // try original URL ... ! dont continue with next item here ...
2469 rInfo
.DocumentState
|= AutoRecovery::E_DAMAGED
;
2474 ::rtl::OUString sLoadOriginalURL
;
2475 ::rtl::OUString sLoadBackupURL
;
2477 if (!bBackupWasTried
)
2478 sLoadBackupURL
= rInfo
.OldTempURL
;
2480 if (rInfo
.OrgURL
.getLength())
2482 sLoadOriginalURL
= rInfo
.OrgURL
;
2485 if (rInfo
.TemplateURL
.getLength())
2487 sLoadOriginalURL
= rInfo
.TemplateURL
;
2488 lDescriptor
[::comphelper::MediaDescriptor::PROP_ASTEMPLATE()] <<= sal_True
;
2489 lDescriptor
[::comphelper::MediaDescriptor::PROP_TEMPLATENAME()] <<= rInfo
.TemplateURL
;
2492 if (rInfo
.FactoryURL
.getLength())
2494 sLoadOriginalURL
= rInfo
.FactoryURL
;
2495 lDescriptor
[::comphelper::MediaDescriptor::PROP_ASTEMPLATE()] <<= sal_True
;
2498 // A "Salvaged" item must exists every time. The core can make something special then for recovery.
2499 // Of course it should be the real file name of the original file, in case we load the temp. backup here.
2500 ::rtl::OUString sURL
;
2501 if (sLoadBackupURL
.getLength())
2503 sURL
= sLoadBackupURL
;
2504 rInfo
.DocumentState
|= AutoRecovery::E_TRY_LOAD_BACKUP
;
2505 lDescriptor
[::comphelper::MediaDescriptor::PROP_SALVAGEDFILE()] <<= sLoadOriginalURL
;
2508 if (sLoadOriginalURL
.getLength())
2510 sURL
= sLoadOriginalURL
;
2511 rInfo
.DocumentState
|= AutoRecovery::E_TRY_LOAD_ORIGINAL
;
2514 continue; // TODO ERROR!
2516 // <- SAFE ------------------------------
2517 aWriteLock
.unlock();
2519 implts_flushConfigItem(rInfo
);
2520 implts_informListener(eJob
,
2521 AutoRecovery::implst_createFeatureStateEvent(eJob
, OPERATION_UPDATE
, &rInfo
));
2525 implts_openOneDoc(sURL
, lDescriptor
, rInfo
);
2527 catch(const css::uno::Exception
&)
2529 rInfo
.DocumentState
&= ~AutoRecovery::E_TRY_LOAD_BACKUP
;
2530 rInfo
.DocumentState
&= ~AutoRecovery::E_TRY_LOAD_ORIGINAL
;
2531 if (sLoadBackupURL
.getLength())
2533 rInfo
.DocumentState
|= AutoRecovery::E_INCOMPLETE
;
2534 eTimer
= AutoRecovery::E_CALL_ME_BACK
;
2538 rInfo
.DocumentState
|= AutoRecovery::E_HANDLED
;
2539 rInfo
.DocumentState
|= AutoRecovery::E_DAMAGED
;
2542 implts_flushConfigItem(rInfo
, sal_True
);
2543 implts_informListener(eJob
,
2544 AutoRecovery::implst_createFeatureStateEvent(eJob
, OPERATION_UPDATE
, &rInfo
));
2546 // SAFE -> ------------------------------
2547 // Needed for next loop!
2552 if (rInfo
.RealFilter
.getLength())
2554 ::comphelper::MediaDescriptor
lPatchDescriptor(rInfo
.Document
->getArgs());
2555 lPatchDescriptor
[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= rInfo
.RealFilter
;
2556 rInfo
.Document
->attachResource(sURL
, lPatchDescriptor
.getAsConstPropertyValueList());
2559 css::uno::Reference
< css::util::XModifiable
> xModify(rInfo
.Document
, css::uno::UNO_QUERY
);
2560 sal_Bool bModified
= ((rInfo
.DocumentState
& AutoRecovery::E_MODIFIED
) == AutoRecovery::E_MODIFIED
);
2561 xModify
->setModified(bModified
);
2563 rInfo
.DocumentState
&= ~AutoRecovery::E_TRY_LOAD_BACKUP
;
2564 rInfo
.DocumentState
&= ~AutoRecovery::E_TRY_LOAD_ORIGINAL
;
2565 rInfo
.DocumentState
|= AutoRecovery::E_HANDLED
;
2566 rInfo
.DocumentState
|= AutoRecovery::E_SUCCEDED
;
2568 implts_flushConfigItem(rInfo
);
2569 implts_informListener(eJob
,
2570 AutoRecovery::implst_createFeatureStateEvent(eJob
, OPERATION_UPDATE
, &rInfo
));
2572 /* Normaly we listen as XModifyListener on a document to know if a document was changed
2573 since our last AutoSave. And we deregister us in case we know this state.
2574 But directly after one documentw as recovered ... we must start listening.
2575 Otherwhise the first "modify" dont reach us. Because weself called setModified()
2576 on the document via API. And currently we dont listen for any events (not at the GlobalEventBroadcaster
2577 nor at any document!).
2579 implts_startModifyListeningOnDoc(rInfo
);
2581 // SAFE -> ------------------------------
2582 // Needed for next loop. Dont unlock it again!
2586 aWriteLock
.unlock();
2587 // <- SAFE ----------------------------------
2592 //-----------------------------------------------
2593 void AutoRecovery::implts_openOneDoc(const ::rtl::OUString
& sURL
,
2594 ::comphelper::MediaDescriptor
& lDescriptor
,
2595 AutoRecovery::TDocumentInfo
& rInfo
)
2597 // SAFE -> ----------------------------------
2598 ReadGuard
aReadLock(m_aLock
);
2599 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
2601 // <- SAFE ----------------------------------
2603 css::uno::Reference
< css::util::XURLTransformer
> xParser(xSMGR
->createInstance(SERVICENAME_URLTRANSFORMER
), css::uno::UNO_QUERY_THROW
);
2604 css::util::URL aURL
;
2605 aURL
.Complete
= sURL
;
2606 xParser
->parseStrict(aURL
);
2608 LoadDispatchListener
* pLoadListener
= new LoadDispatchListener();
2609 css::uno::Reference
< css::frame::XDispatchResultListener
> xLoadListener (static_cast< css::frame::XDispatchResultListener
* >(pLoadListener
), css::uno::UNO_QUERY_THROW
);
2611 css::uno::Reference
< css::frame::XFrame
> xDesktop (xSMGR
->createInstance(SERVICENAME_DESKTOP
), css::uno::UNO_QUERY_THROW
);
2612 css::uno::Reference
< css::frame::XFrame
> xNewTarget
= xDesktop
->findFrame(SPECIALTARGET_BLANK
, 0);
2613 css::uno::Reference
< css::frame::XDispatchProvider
> xProvider (xNewTarget
, css::uno::UNO_QUERY_THROW
);
2614 css::uno::Reference
< css::frame::XNotifyingDispatch
> xDispatcher(
2615 xProvider
->queryDispatch(aURL
, SPECIALTARGET_SELF
, 0),
2616 css::uno::UNO_QUERY_THROW
);
2618 // load the document and listen for the state of this operation.
2619 pLoadListener
->setURL(aURL
.Complete
);
2621 // make sure the right progress is used always.
2622 impl_establishProgress(rInfo
, lDescriptor
, xNewTarget
);
2626 xDispatcher
->dispatchWithNotification(
2628 lDescriptor
.getAsConstPropertyValueList(),
2631 pLoadListener
->wait(0); // wait for ever!
2633 css::frame::DispatchResultEvent aResult
= pLoadListener
->getResult();
2634 if (aResult
.State
!= css::frame::DispatchResultState::SUCCESS
)
2636 ::rtl::OUStringBuffer
sMsg(256);
2637 sMsg
.appendAscii("Recovery of \"");
2638 sMsg
.append (aURL
.Complete
);
2639 sMsg
.appendAscii("\" failed." );
2640 throw css::uno::Exception(sMsg
.makeStringAndClear(), static_cast< css::frame::XDispatch
* >(this));
2643 rInfo
.Document
= fpf::extractFrameModel(xNewTarget
);
2645 catch(const css::uno::RuntimeException
&)
2647 catch(const css::uno::Exception
&)
2649 css::uno::Reference
< css::util::XCloseable
> xClose(xNewTarget
, css::uno::UNO_QUERY
);
2650 xClose
->close(sal_True
);
2655 // of course we must forget all references to this temp(!) progress
2656 impl_forgetProgress(rInfo
, lDescriptor
, xNewTarget
);
2659 //-----------------------------------------------
2660 void AutoRecovery::implts_generateNewTempURL(const ::rtl::OUString
& sBackupPath
,
2661 ::comphelper::MediaDescriptor
& /*rMediaDescriptor*/,
2662 AutoRecovery::TDocumentInfo
& rInfo
)
2664 // SAFE -> ----------------------------------
2665 ReadGuard
aReadLock(m_aLock
);
2666 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
2668 // <- SAFE ----------------------------------
2670 // specify URL for saving (which points to a temp file inside backup directory)
2671 // and define an unique name, so we can locate it later.
2672 // This unique name must solve an optimization problem too!
2673 // In case we are asked to save unmodified documents too - and one of them
2674 // is an empty one (because it was new created using e.g. an URL private:factory/...)
2675 // we should not save it realy. Then we put the information about such "empty document"
2676 // into the configuration and dont create any recovery file on disk.
2677 // We use the title of the document to make it unique.
2678 ::rtl::OUStringBuffer sUniqueName
;
2679 if (rInfo
.OrgURL
.getLength())
2681 css::uno::Reference
< css::util::XURLTransformer
> xParser(xSMGR
->createInstance(SERVICENAME_URLTRANSFORMER
), css::uno::UNO_QUERY
);
2682 css::util::URL aURL
;
2683 aURL
.Complete
= rInfo
.OrgURL
;
2684 xParser
->parseStrict(aURL
);
2685 sUniqueName
.append(aURL
.Name
);
2688 if (rInfo
.FactoryURL
.getLength())
2689 sUniqueName
.appendAscii("untitled");
2690 sUniqueName
.appendAscii("_");
2692 // TODO: Must we strip some illegal signes - if we use the title?
2694 String
sName (sUniqueName
.makeStringAndClear());
2695 String
sExtension(rInfo
.Extension
);
2696 String
sPath (sBackupPath
);
2697 ::utl::TempFile
aTempFile(sName
, &sExtension
, &sPath
);
2699 rInfo
.NewTempURL
= aTempFile
.GetURL();
2702 //-----------------------------------------------
2703 void AutoRecovery::implts_informListener( sal_Int32 eJob
,
2704 const css::frame::FeatureStateEvent
& aEvent
)
2706 // Helper shares mutex with us -> threadsafe!
2707 ::cppu::OInterfaceContainerHelper
* pListenerForURL
= 0;
2708 ::rtl::OUString sJob
= AutoRecovery::implst_getJobDescription(eJob
);
2710 // inform listener, which are registered for any URLs(!)
2711 pListenerForURL
= m_lListener
.getContainer(sJob
);
2712 if(pListenerForURL
!= 0)
2714 ::cppu::OInterfaceIteratorHelper
pIt(*pListenerForURL
);
2715 while(pIt
.hasMoreElements())
2719 css::uno::Reference
< css::frame::XStatusListener
> xListener(((css::frame::XStatusListener
*)pIt
.next()), css::uno::UNO_QUERY
);
2720 xListener
->statusChanged(aEvent
);
2722 catch(const css::uno::RuntimeException
&)
2728 //-----------------------------------------------
2729 ::rtl::OUString
AutoRecovery::implst_getJobDescription(sal_Int32 eJob
)
2731 // describe the current running operation
2732 ::rtl::OUStringBuffer
sFeature(256);
2733 sFeature
.append(CMD_PROTOCOL
);
2735 // Attention: Because "eJob" is used as a flag field the order of checking these
2736 // flags is importent. We must preferr job with higher priorities!
2737 // E.g. EmergencySave has an higher prio then AutoSave ...
2738 // On the other side there exist a well defined order between two different jobs.
2739 // e.g. PrepareEmergencySave must be done before EmergencySave is started of course.
2741 if ((eJob
& AutoRecovery::E_PREPARE_EMERGENCY_SAVE
) == AutoRecovery::E_PREPARE_EMERGENCY_SAVE
)
2742 sFeature
.append(CMD_DO_PREPARE_EMERGENCY_SAVE
);
2744 if ((eJob
& AutoRecovery::E_EMERGENCY_SAVE
) == AutoRecovery::E_EMERGENCY_SAVE
)
2745 sFeature
.append(CMD_DO_EMERGENCY_SAVE
);
2747 if ((eJob
& AutoRecovery::E_RECOVERY
) == AutoRecovery::E_RECOVERY
)
2748 sFeature
.append(CMD_DO_RECOVERY
);
2750 if ((eJob
& AutoRecovery::E_SESSION_SAVE
) == AutoRecovery::E_SESSION_SAVE
)
2751 sFeature
.append(CMD_DO_SESSION_SAVE
);
2753 if ((eJob
& AutoRecovery::E_SESSION_RESTORE
) == AutoRecovery::E_SESSION_RESTORE
)
2754 sFeature
.append(CMD_DO_SESSION_RESTORE
);
2756 if ((eJob
& AutoRecovery::E_ENTRY_BACKUP
) == AutoRecovery::E_ENTRY_BACKUP
)
2757 sFeature
.append(CMD_DO_ENTRY_BACKUP
);
2759 if ((eJob
& AutoRecovery::E_ENTRY_CLEANUP
) == AutoRecovery::E_ENTRY_CLEANUP
)
2760 sFeature
.append(CMD_DO_ENTRY_CLEANUP
);
2762 if ((eJob
& AutoRecovery::E_AUTO_SAVE
) == AutoRecovery::E_AUTO_SAVE
)
2763 sFeature
.append(CMD_DO_AUTO_SAVE
);
2764 #ifdef ENABLE_WARNINGS
2766 LOG_WARNING("AutoRecovery::implst_getJobDescription()", "Invalid job identifier detected.")
2769 return sFeature
.makeStringAndClear();
2772 //-----------------------------------------------
2773 sal_Int32
AutoRecovery::implst_classifyJob(const css::util::URL
& aURL
)
2775 if (aURL
.Protocol
.equals(CMD_PROTOCOL
))
2777 if (aURL
.Path
.equals(CMD_DO_PREPARE_EMERGENCY_SAVE
))
2778 return AutoRecovery::E_PREPARE_EMERGENCY_SAVE
;
2780 if (aURL
.Path
.equals(CMD_DO_EMERGENCY_SAVE
))
2781 return AutoRecovery::E_EMERGENCY_SAVE
;
2783 if (aURL
.Path
.equals(CMD_DO_RECOVERY
))
2784 return AutoRecovery::E_RECOVERY
;
2786 if (aURL
.Path
.equals(CMD_DO_ENTRY_BACKUP
))
2787 return AutoRecovery::E_ENTRY_BACKUP
;
2789 if (aURL
.Path
.equals(CMD_DO_ENTRY_CLEANUP
))
2790 return AutoRecovery::E_ENTRY_CLEANUP
;
2792 if (aURL
.Path
.equals(CMD_DO_SESSION_SAVE
))
2793 return AutoRecovery::E_SESSION_SAVE
;
2795 if (aURL
.Path
.equals(CMD_DO_SESSION_RESTORE
))
2796 return AutoRecovery::E_SESSION_RESTORE
;
2798 if (aURL
.Path
.equals(CMD_DO_DISABLE_RECOVERY
))
2799 return AutoRecovery::E_DISABLE_AUTORECOVERY
;
2801 if (aURL
.Path
.equals(CMD_DO_SET_AUTOSAVE_STATE
))
2802 return AutoRecovery::E_SET_AUTOSAVE_STATE
;
2805 LOG_WARNING("AutoRecovery::implts_classifyJob()", "Invalid URL (protocol).")
2806 return AutoRecovery::E_NO_JOB
;
2809 //-----------------------------------------------
2810 css::frame::FeatureStateEvent
AutoRecovery::implst_createFeatureStateEvent( sal_Int32 eJob
,
2811 const ::rtl::OUString
& sEventType
,
2812 AutoRecovery::TDocumentInfo
* pInfo
)
2814 css::frame::FeatureStateEvent aEvent
;
2815 aEvent
.FeatureURL
.Complete
= AutoRecovery::implst_getJobDescription(eJob
);
2816 aEvent
.FeatureDescriptor
= sEventType
;
2818 if (sEventType
.equals(OPERATION_UPDATE
) && pInfo
)
2820 // pack rInfo for transport via UNO
2821 css::uno::Sequence
< css::beans::NamedValue
> lInfo(8);
2822 lInfo
[0].Name
= CFG_ENTRY_PROP_ID
;
2823 lInfo
[0].Value
<<= pInfo
->ID
;
2825 lInfo
[1].Name
= CFG_ENTRY_PROP_ORIGINALURL
;
2826 lInfo
[1].Value
<<= pInfo
->OrgURL
;
2828 lInfo
[2].Name
= CFG_ENTRY_PROP_FACTORYURL
;
2829 lInfo
[2].Value
<<= pInfo
->FactoryURL
;
2831 lInfo
[3].Name
= CFG_ENTRY_PROP_TEMPLATEURL
;
2832 lInfo
[3].Value
<<= pInfo
->TemplateURL
;
2834 lInfo
[4].Name
= CFG_ENTRY_PROP_TEMPURL
;
2835 if (pInfo
->OldTempURL
.getLength())
2836 lInfo
[4].Value
<<= pInfo
->OldTempURL
;
2838 lInfo
[4].Value
<<= pInfo
->NewTempURL
;
2840 lInfo
[5].Name
= CFG_ENTRY_PROP_MODULE
;
2841 lInfo
[5].Value
<<= pInfo
->AppModule
;
2843 lInfo
[6].Name
= CFG_ENTRY_PROP_TITLE
;
2844 lInfo
[6].Value
<<= pInfo
->Title
;
2846 lInfo
[7].Name
= CFG_ENTRY_PROP_DOCUMENTSTATE
;
2847 lInfo
[7].Value
<<= pInfo
->DocumentState
;
2849 aEvent
.State
<<= lInfo
;
2855 //-----------------------------------------------
2856 void AutoRecovery::implts_resetHandleStates(sal_Bool
/*bLoadCache*/)
2858 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
2860 // SAFE -> ------------------------------
2861 WriteGuard
aWriteLock(m_aLock
);
2863 AutoRecovery::TDocumentList::iterator pIt
;
2864 for ( pIt
= m_lDocCache
.begin();
2865 pIt
!= m_lDocCache
.end() ;
2868 AutoRecovery::TDocumentInfo
& rInfo
= *pIt
;
2869 rInfo
.DocumentState
&= ~AutoRecovery::E_HANDLED
;
2870 rInfo
.DocumentState
&= ~AutoRecovery::E_POSTPONED
;
2872 // SAFE -> ------------------------------
2873 aWriteLock
.unlock();
2874 implts_flushConfigItem(rInfo
);
2876 // <- SAFE ------------------------------
2879 aWriteLock
.unlock();
2880 // <- SAFE ----------------------------------
2883 //-----------------------------------------------
2884 void AutoRecovery::implts_prepareEmergencySave()
2886 // Be sure to know all open documents realy .-)
2887 implts_verifyCacheAgainstDesktopDocumentList();
2889 // hide all docs, so the user cant disturb our emergency save .-)
2890 implts_changeAllDocVisibility(sal_False
);
2893 //-----------------------------------------------
2894 void AutoRecovery::implts_doEmergencySave(const DispatchParams
& aParams
)
2896 // Write a hint "we chrashed" into the configuration, so
2897 // the error report tool is started too in case no recovery
2898 // documents exists and was saved.
2899 ::comphelper::ConfigurationHelper::writeDirectKey(
2901 CFG_PACKAGE_RECOVERY
,
2902 CFG_PATH_RECOVERYINFO
,
2904 css::uno::makeAny(sal_True
),
2905 ::comphelper::ConfigurationHelper::E_STANDARD
);
2907 // The called method for saving documents runs
2908 // during normal AutoSave more then once. Because
2909 // it postpone active documents and save it later.
2910 // That is normaly done by recalling it from a timer.
2911 // Here we must do it immediatly!
2912 // Of course this method returns the right state -
2913 // because it knows, that we are running in ERMERGENCY SAVE mode .-)
2915 sal_Bool bAllowUserIdleLoop
= sal_False
; // not allowed to change that .-)
2916 AutoRecovery::ETimerType eSuggestedTimer
= AutoRecovery::E_DONT_START_TIMER
;
2919 eSuggestedTimer
= implts_saveDocs(bAllowUserIdleLoop
, sal_True
, &aParams
);
2921 while(eSuggestedTimer
== AutoRecovery::E_CALL_ME_BACK
);
2923 // reset the handle state of all
2924 // cache items. Such handle state indicates, that a document
2925 // was already saved during the THIS(!) EmergencySave session.
2926 // Of course following recovery session must be started without
2927 // any "handle" state ...
2928 implts_resetHandleStates(sal_False
);
2930 // flush config cached back to disc.
2931 impl_flushALLConfigChanges();
2933 // try to make sure next time office will be started user wont be
2934 // notified about any other might be running office instance
2935 // remove ".lock" file from disc !
2936 AutoRecovery::st_impl_removeLockFile();
2939 //-----------------------------------------------
2940 void AutoRecovery::implts_doRecovery(const DispatchParams
& aParams
)
2942 AutoRecovery::ETimerType eSuggestedTimer
= AutoRecovery::E_DONT_START_TIMER
;
2945 eSuggestedTimer
= implts_openDocs(aParams
);
2947 while(eSuggestedTimer
== AutoRecovery::E_CALL_ME_BACK
);
2949 // reset the handle state of all
2950 // cache items. Such handle state indicates, that a document
2951 // was already saved during the THIS(!) Recovery session.
2952 // Of course a may be following EmergencySave session must be started without
2953 // any "handle" state ...
2954 implts_resetHandleStates(sal_True
);
2956 // Reset the configuration hint "we was crashed"!
2957 ::comphelper::ConfigurationHelper::writeDirectKey(
2959 CFG_PACKAGE_RECOVERY
,
2960 CFG_PATH_RECOVERYINFO
,
2962 css::uno::makeAny(sal_False
),
2963 ::comphelper::ConfigurationHelper::E_STANDARD
);
2966 //-----------------------------------------------
2967 void AutoRecovery::implts_doSessionSave(const DispatchParams
& aParams
)
2969 LOG_RECOVERY("AutoRecovery::implts_doSessionSave()")
2971 // try to make sure next time office will be started user wont be
2972 // notified about any other might be running office instance
2973 // remove ".lock" file from disc !
2974 // it is done as a first action for session save since Gnome sessions
2975 // do not provide enough time for shutdown, and the dialog looks to be
2976 // confusing for the user
2977 AutoRecovery::st_impl_removeLockFile();
2979 // Be sure to know all open documents realy .-)
2980 implts_verifyCacheAgainstDesktopDocumentList();
2982 // The called method for saving documents runs
2983 // during normal AutoSave more then once. Because
2984 // it postpone active documents and save it later.
2985 // That is normaly done by recalling it from a timer.
2986 // Here we must do it immediatly!
2987 // Of course this method returns the right state -
2988 // because it knows, that we are running in SESSION SAVE mode .-)
2990 sal_Bool bAllowUserIdleLoop
= sal_False
; // not allowed to change that .-)
2991 AutoRecovery::ETimerType eSuggestedTimer
= AutoRecovery::E_DONT_START_TIMER
;
2994 eSuggestedTimer
= implts_saveDocs(bAllowUserIdleLoop
, sal_True
, &aParams
);
2996 while(eSuggestedTimer
== AutoRecovery::E_CALL_ME_BACK
);
2998 // reset the handle state of all
2999 // cache items. Such handle state indicates, that a document
3000 // was already saved during the THIS(!) save session.
3001 // Of course following restore session must be started without
3002 // any "handle" state ...
3003 implts_resetHandleStates(sal_False
);
3005 // reset all modified documents, so the dont show any UI on closing ...
3006 // and close all documents, so we can shutdown the OS!
3007 implts_prepareSessionShutdown();
3009 // Write a hint for "stored session data" into the configuration, so
3010 // the on next startup we know what's happen last time
3011 ::comphelper::ConfigurationHelper::writeDirectKey(
3013 CFG_PACKAGE_RECOVERY
,
3014 CFG_PATH_RECOVERYINFO
,
3015 CFG_ENTRY_SESSIONDATA
,
3016 css::uno::makeAny(sal_True
),
3017 ::comphelper::ConfigurationHelper::E_STANDARD
);
3019 // flush config cached back to disc.
3020 impl_flushALLConfigChanges();
3023 //-----------------------------------------------
3024 void AutoRecovery::implts_doSessionRestore(const DispatchParams
& aParams
)
3026 LOG_RECOVERY("AutoRecovery::implts_doSessionRestore() ...")
3028 AutoRecovery::ETimerType eSuggestedTimer
= AutoRecovery::E_DONT_START_TIMER
;
3031 eSuggestedTimer
= implts_openDocs(aParams
);
3033 while(eSuggestedTimer
== AutoRecovery::E_CALL_ME_BACK
);
3035 // reset the handle state of all
3036 // cache items. Such handle state indicates, that a document
3037 // was already saved during the THIS(!) Restore session.
3038 // Of course a may be following save session must be started without
3039 // any "handle" state ...
3040 implts_resetHandleStates(sal_True
);
3042 // make all opened documents visible
3043 implts_changeAllDocVisibility(sal_True
);
3045 // Reset the configuration hint for "session save"!
3046 LOG_RECOVERY("... reset config key 'SessionData'")
3047 ::comphelper::ConfigurationHelper::writeDirectKey(
3049 CFG_PACKAGE_RECOVERY
,
3050 CFG_PATH_RECOVERYINFO
,
3051 CFG_ENTRY_SESSIONDATA
,
3052 css::uno::makeAny(sal_False
),
3053 ::comphelper::ConfigurationHelper::E_STANDARD
);
3055 LOG_RECOVERY("... AutoRecovery::implts_doSessionRestore()")
3058 //-----------------------------------------------
3059 void AutoRecovery::implts_backupWorkingEntry(const DispatchParams
& aParams
)
3061 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_USE
);
3063 AutoRecovery::TDocumentList::iterator pIt
;
3064 for ( pIt
= m_lDocCache
.begin();
3065 pIt
!= m_lDocCache
.end() ;
3068 const AutoRecovery::TDocumentInfo
& rInfo
= *pIt
;
3069 if (rInfo
.ID
!= aParams
.m_nWorkingEntryID
)
3072 ::rtl::OUString sSourceURL
;
3073 // Prefer temp file. It contains the changes against the original document!
3074 if (rInfo
.OldTempURL
.getLength())
3075 sSourceURL
= rInfo
.OldTempURL
;
3077 if (rInfo
.NewTempURL
.getLength())
3078 sSourceURL
= rInfo
.NewTempURL
;
3080 if (rInfo
.OrgURL
.getLength())
3081 sSourceURL
= rInfo
.OrgURL
;
3083 continue; // nothing real to save! An unmodified but new created document.
3085 INetURLObject
aParser(sSourceURL
);
3086 // AutoRecovery::EFailureSafeResult eResult =
3087 implts_copyFile(sSourceURL
, aParams
.m_sSavePath
, aParser
.getName());
3089 // TODO: Check eResult and react for errors (InteractionHandler!?)
3090 // Currently we ignore it ...
3091 // DONT UPDATE THE CACHE OR REMOVE ANY TEMP. FILES FROM DISK.
3092 // That has to be forced from outside explicitly.
3093 // See implts_cleanUpWorkingEntry() for further details.
3097 //-----------------------------------------------
3098 void AutoRecovery::implts_cleanUpWorkingEntry(const DispatchParams
& aParams
)
3100 CacheLockGuard
aCacheLock(this, m_aLock
, m_nDocCacheLock
, LOCK_FOR_CACHE_ADD_REMOVE
);
3102 AutoRecovery::TDocumentList::iterator pIt
;
3103 for ( pIt
= m_lDocCache
.begin();
3104 pIt
!= m_lDocCache
.end() ;
3107 AutoRecovery::TDocumentInfo
& rInfo
= *pIt
;
3108 if (rInfo
.ID
!= aParams
.m_nWorkingEntryID
)
3111 AutoRecovery::st_impl_removeFile(rInfo
.OldTempURL
);
3112 AutoRecovery::st_impl_removeFile(rInfo
.NewTempURL
);
3113 implts_flushConfigItem(rInfo
, sal_True
); // TRUE => remove it from xml config!
3115 m_lDocCache
.erase(pIt
);
3116 break; /// !!! pIt is not defined any longer ... further this function has finished it's work
3120 //-----------------------------------------------
3121 AutoRecovery::EFailureSafeResult
AutoRecovery::implts_copyFile(const ::rtl::OUString
& sSource
,
3122 const ::rtl::OUString
& sTargetPath
,
3123 const ::rtl::OUString
& sTargetName
)
3125 // create content for the parent folder and call transfer on that content with the source content
3126 // and the destination file name as parameters
3128 css::uno::Reference
< css::ucb::XCommandEnvironment
> xEnvironment
;
3130 ::ucbhelper::Content aSourceContent
;
3131 ::ucbhelper::Content aTargetContent
;
3135 aTargetContent
= ::ucbhelper::Content(sTargetPath
, xEnvironment
);
3137 catch(const css::uno::Exception
&)
3138 { return AutoRecovery::E_WRONG_TARGET_PATH
; }
3140 sal_Int32 nNameClash
;
3141 // nNameClash = css::ucb::NameClash::ERROR;
3142 nNameClash
= css::ucb::NameClash::RENAME
;
3143 // nNameClash = css::ucb::NameClash::OVERWRITE;
3147 ::ucbhelper::Content::create(sSource
, xEnvironment
, aSourceContent
);
3148 aTargetContent
.transferContent(aSourceContent
, ::ucbhelper::InsertOperation_COPY
, sTargetName
, nNameClash
);
3150 catch(const css::uno::Exception
&)
3151 { return AutoRecovery::E_ORIGINAL_FILE_MISSING
; }
3153 return AutoRecovery::E_COPIED
;
3156 //-----------------------------------------------
3157 sal_Bool SAL_CALL
AutoRecovery::convertFastPropertyValue( css::uno::Any
& /*aConvertedValue*/,
3158 css::uno::Any
& /*aOldValue*/ ,
3159 sal_Int32
/*nHandle*/ ,
3160 const css::uno::Any
& /*aValue*/ )
3161 throw(css::lang::IllegalArgumentException
)
3163 // not needed currently
3167 //-----------------------------------------------
3168 void SAL_CALL
AutoRecovery::setFastPropertyValue_NoBroadcast( sal_Int32
/*nHandle*/,
3169 const css::uno::Any
& /*aValue*/ )
3170 throw(css::uno::Exception
)
3172 // not needed currently
3175 //-----------------------------------------------
3176 void SAL_CALL
AutoRecovery::getFastPropertyValue(css::uno::Any
& aValue
,
3177 sal_Int32 nHandle
) const
3181 case AUTORECOVERY_PROPHANDLE_EXISTS_RECOVERYDATA
:
3183 sal_Bool bSessionData
= sal_False
;
3184 ::comphelper::ConfigurationHelper::readDirectKey(
3186 CFG_PACKAGE_RECOVERY
,
3187 CFG_PATH_RECOVERYINFO
,
3188 CFG_ENTRY_SESSIONDATA
,
3189 ::comphelper::ConfigurationHelper::E_READONLY
) >>= bSessionData
;
3191 sal_Bool bRecoveryData
= ((sal_Bool
)(m_lDocCache
.size()>0));
3193 // exists session data ... => then we cant say, that these
3194 // data are valid for recovery. So we have to return FALSE then!
3196 bRecoveryData
= sal_False
;
3198 aValue
<<= bRecoveryData
;
3202 case AUTORECOVERY_PROPHANDLE_CRASHED
:
3203 aValue
= ::comphelper::ConfigurationHelper::readDirectKey(
3205 CFG_PACKAGE_RECOVERY
,
3206 CFG_PATH_RECOVERYINFO
,
3208 ::comphelper::ConfigurationHelper::E_READONLY
);
3211 case AUTORECOVERY_PROPHANDLE_EXISTS_SESSIONDATA
:
3212 aValue
= ::comphelper::ConfigurationHelper::readDirectKey(
3214 CFG_PACKAGE_RECOVERY
,
3215 CFG_PATH_RECOVERYINFO
,
3216 CFG_ENTRY_SESSIONDATA
,
3217 ::comphelper::ConfigurationHelper::E_READONLY
);
3222 //-----------------------------------------------
3223 const css::uno::Sequence
< css::beans::Property
> impl_getStaticPropertyDescriptor()
3225 static const css::beans::Property pPropertys
[] =
3227 css::beans::Property( AUTORECOVERY_PROPNAME_CRASHED
, AUTORECOVERY_PROPHANDLE_CRASHED
, ::getBooleanCppuType() , css::beans::PropertyAttribute::TRANSIENT
| css::beans::PropertyAttribute::READONLY
),
3228 css::beans::Property( AUTORECOVERY_PROPNAME_EXISTS_RECOVERYDATA
, AUTORECOVERY_PROPHANDLE_EXISTS_RECOVERYDATA
, ::getBooleanCppuType() , css::beans::PropertyAttribute::TRANSIENT
| css::beans::PropertyAttribute::READONLY
),
3229 css::beans::Property( AUTORECOVERY_PROPNAME_EXISTS_SESSIONDATA
, AUTORECOVERY_PROPHANDLE_EXISTS_SESSIONDATA
, ::getBooleanCppuType() , css::beans::PropertyAttribute::TRANSIENT
| css::beans::PropertyAttribute::READONLY
),
3231 static const css::uno::Sequence
< css::beans::Property
> lPropertyDescriptor(pPropertys
, AUTORECOVERY_PROPCOUNT
);
3232 return lPropertyDescriptor
;
3235 //-----------------------------------------------
3236 ::cppu::IPropertyArrayHelper
& SAL_CALL
AutoRecovery::getInfoHelper()
3238 static ::cppu::OPropertyArrayHelper
* pInfoHelper
= 0;
3241 ::osl::MutexGuard
aGuard( LockHelper::getGlobalLock().getShareableOslMutex() );
3244 static ::cppu::OPropertyArrayHelper
aInfoHelper(impl_getStaticPropertyDescriptor(), sal_True
);
3245 pInfoHelper
= &aInfoHelper
;
3249 return (*pInfoHelper
);
3252 //-----------------------------------------------
3253 css::uno::Reference
< css::beans::XPropertySetInfo
> SAL_CALL
AutoRecovery::getPropertySetInfo()
3254 throw(css::uno::RuntimeException
)
3256 static css::uno::Reference
< css::beans::XPropertySetInfo
>* pInfo
= 0;
3259 ::osl::MutexGuard
aGuard( LockHelper::getGlobalLock().getShareableOslMutex() );
3262 static css::uno::Reference
< css::beans::XPropertySetInfo
> xInfo(createPropertySetInfo(getInfoHelper()));
3270 //-----------------------------------------------
3271 void AutoRecovery::implts_verifyCacheAgainstDesktopDocumentList()
3273 LOG_RECOVERY("AutoRecovery::implts_verifyCacheAgainstDesktopDocumentList() ...")
3275 // SAFE -> ----------------------------------
3276 WriteGuard
aWriteLock(m_aLock
);
3277 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
3278 aWriteLock
.unlock();
3279 // <- SAFE ----------------------------------
3283 css::uno::Reference
< css::frame::XFramesSupplier
> xDesktop(
3284 xSMGR
->createInstance(SERVICENAME_DESKTOP
),
3285 css::uno::UNO_QUERY_THROW
);
3287 css::uno::Reference
< css::container::XIndexAccess
> xContainer(
3288 xDesktop
->getFrames(),
3289 css::uno::UNO_QUERY_THROW
);
3292 sal_Int32 c
= xContainer
->getCount();
3296 css::uno::Reference
< css::frame::XFrame
> xFrame
;
3299 xContainer
->getByIndex(i
) >>= xFrame
;
3303 // can happen in multithreaded environments, that frames was removed from the container during this loop runs!
3305 catch(const css::lang::IndexOutOfBoundsException
&)
3308 // We are interested on visible documents only.
3309 // Note: It's n optional interface .-(
3310 css::uno::Reference
< css::awt::XWindow2
> xVisibleCheck(
3311 xFrame
->getContainerWindow(),
3312 css::uno::UNO_QUERY
);
3314 (!xVisibleCheck
.is() ) ||
3315 (!xVisibleCheck
->isVisible())
3321 // extract the model from the frame.
3322 // Ignore "view only" frames, which does not have a model.
3323 css::uno::Reference
< css::frame::XController
> xController
;
3324 css::uno::Reference
< css::frame::XModel
> xModel
;
3326 xController
= xFrame
->getController();
3327 if (xController
.is())
3328 xModel
= xController
->getModel();
3332 // insert model into cache ...
3333 // If the model is already well known inside cache
3334 // it's information set will be updated by asking the
3335 // model again for it's new states.
3336 implts_registerDocument(xModel
);
3339 catch(const css::uno::RuntimeException
& exRun
)
3341 catch(const css::uno::Exception
&)
3344 LOG_RECOVERY("... AutoRecovery::implts_verifyCacheAgainstDesktopDocumentList()")
3347 //-----------------------------------------------
3348 sal_Bool
AutoRecovery::impl_enoughDiscSpace(sal_Int32 nRequiredSpace
)
3350 #ifdef SIMULATE_FULL_DISC
3354 // In case an error occures and we are not able to retrieve the needed information
3355 // it's better to "disable" the feature ShowErrorOnFullDisc !
3356 // Otherwhise we start a confusing process of error handling ...
3358 sal_uInt64 nFreeSpace
= SAL_MAX_UINT64
;
3360 ::rtl::OUString
sBackupPath(SvtPathOptions().GetBackupPath());
3361 ::osl::VolumeInfo
aInfo (VolumeInfoMask_FreeSpace
);
3362 ::osl::FileBase::RC aRC
= ::osl::Directory::getVolumeInfo(sBackupPath
, aInfo
);
3365 (aInfo
.isValid(VolumeInfoMask_FreeSpace
)) &&
3366 (aRC
== ::osl::FileBase::E_None
)
3369 nFreeSpace
= aInfo
.getFreeSpace();
3372 sal_uInt64 nFreeMB
= (nFreeSpace
/1048576);
3373 return (nFreeMB
>= (sal_uInt64
)nRequiredSpace
);
3376 //-----------------------------------------------
3377 void AutoRecovery::impl_showFullDiscError()
3379 static String PLACEHOLDER_PATH
= String::CreateFromAscii("%PATH");
3381 String
sBtn(FwkResId(STR_FULL_DISC_RETRY_BUTTON
));
3382 String
sMsg(FwkResId(STR_FULL_DISC_MSG
));
3384 String
sBackupURL(SvtPathOptions().GetBackupPath());
3385 INetURLObject
aConverter(sBackupURL
);
3386 sal_Unicode aDelimiter
;
3387 String sBackupPath
= aConverter
.getFSysPath(INetURLObject::FSYS_DETECT
, &aDelimiter
);
3388 if (sBackupPath
.Len()<1)
3389 sBackupPath
= sBackupURL
;
3390 sMsg
.SearchAndReplace(PLACEHOLDER_PATH
, sBackupPath
);
3392 ErrorBox
dlgError(0, WB_OK
, sMsg
);
3393 dlgError
.SetButtonText(dlgError
.GetButtonId(0), sBtn
);
3397 //-----------------------------------------------
3398 void AutoRecovery::impl_establishProgress(const AutoRecovery::TDocumentInfo
& rInfo
,
3399 ::comphelper::MediaDescriptor
& rArgs
,
3400 const css::uno::Reference
< css::frame::XFrame
>& xNewFrame
)
3402 // external well known frame must be preferred (because it was created by ourself
3403 // for loading documents into this frame)!
3404 // But if no frame exists ... we can try to locate it using any frame bound to the provided
3405 // document. Of course we must live without any frame in case the document does not exists at this
3406 // point. But this state shouldnt occure. In such case xNewFrame should be valid ... hopefully .-)
3407 css::uno::Reference
< css::frame::XFrame
> xFrame
= xNewFrame
;
3410 (rInfo
.Document
.is())
3413 css::uno::Reference
< css::frame::XController
> xController
= rInfo
.Document
->getCurrentController();
3414 if (xController
.is())
3415 xFrame
= xController
->getFrame();
3418 // Any outside progress must be used ...
3419 // Only if there is no progress, we can create our own one.
3420 css::uno::Reference
< css::task::XStatusIndicator
> xInternalProgress
;
3421 css::uno::Reference
< css::task::XStatusIndicator
> xExternalProgress
= rArgs
.getUnpackedValueOrDefault(
3422 ::comphelper::MediaDescriptor::PROP_STATUSINDICATOR(),
3423 css::uno::Reference
< css::task::XStatusIndicator
>() );
3425 // Normaly a progress is set from outside (e.g. by the CrashSave/Recovery dialog, which uses our dispatch API).
3426 // But for a normal auto save we dont have such "external progress"... because this function is triggered by our own timer then.
3427 // In such case we must create our own progress !
3429 (! xExternalProgress
.is()) &&
3433 css::uno::Reference
< css::task::XStatusIndicatorFactory
> xProgressFactory(xFrame
, css::uno::UNO_QUERY
);
3434 if (xProgressFactory
.is())
3435 xInternalProgress
= xProgressFactory
->createStatusIndicator();
3439 // An external provided progress (most given by the CrashSave/Recovery dialog)
3440 // must be preferred. But we know that some application filters query it's own progress instance
3441 // at the frame method Frame::createStatusIndicator().
3442 // So we use a two step mechanism:
3443 // 1) we set the progress inside the MediaDescriptor, which will be provided to the filter
3444 // 2) and we set a special Frame property, which overwrites the normal behaviour of Frame::createStatusIndicator .-)
3445 // But we supress 2) in case we uses an internal progress. Because then it doesnt matter
3446 // if our applications make it wrong. In such case the internal progress resists at the same frame
3447 // and there is no need to forward progress activities to e.g. an outside dialog .-)
3449 (xExternalProgress
.is()) &&
3453 css::uno::Reference
< css::beans::XPropertySet
> xFrameProps(xFrame
, css::uno::UNO_QUERY
);
3454 if (xFrameProps
.is())
3455 xFrameProps
->setPropertyValue(FRAME_PROPNAME_INDICATORINTERCEPTION
, css::uno::makeAny(xExternalProgress
));
3458 // But inside the MediaDescriptor we must set our own create progress ...
3459 // in case there is not already anothe rprogress set.
3460 rArgs
.createItemIfMissing(::comphelper::MediaDescriptor::PROP_STATUSINDICATOR(), xInternalProgress
);
3463 //-----------------------------------------------
3464 void AutoRecovery::impl_forgetProgress(const AutoRecovery::TDocumentInfo
& rInfo
,
3465 ::comphelper::MediaDescriptor
& rArgs
,
3466 const css::uno::Reference
< css::frame::XFrame
>& xNewFrame
)
3468 // external well known frame must be preferred (because it was created by ourself
3469 // for loading documents into this frame)!
3470 // But if no frame exists ... we can try to locate it using any frame bound to the provided
3471 // document. Of course we must live without any frame in case the document does not exists at this
3472 // point. But this state shouldnt occure. In such case xNewFrame should be valid ... hopefully .-)
3473 css::uno::Reference
< css::frame::XFrame
> xFrame
= xNewFrame
;
3476 (rInfo
.Document
.is())
3479 css::uno::Reference
< css::frame::XController
> xController
= rInfo
.Document
->getCurrentController();
3480 if (xController
.is())
3481 xFrame
= xController
->getFrame();
3484 // stop progress interception on corresponding frame.
3485 css::uno::Reference
< css::beans::XPropertySet
> xFrameProps(xFrame
, css::uno::UNO_QUERY
);
3486 if (xFrameProps
.is())
3487 xFrameProps
->setPropertyValue(FRAME_PROPNAME_INDICATORINTERCEPTION
, css::uno::makeAny(css::uno::Reference
< css::task::XStatusIndicator
>()));
3489 // forget progress inside list of arguments.
3490 ::comphelper::MediaDescriptor::iterator pArg
= rArgs
.find(::comphelper::MediaDescriptor::PROP_STATUSINDICATOR());
3491 if (pArg
!= rArgs
.end())
3498 //-----------------------------------------------
3499 void AutoRecovery::impl_flushALLConfigChanges()
3504 ReadGuard
aReadLock(m_aLock
);
3505 css::uno::Reference
< css::uno::XInterface
> xRecoveryCfg(m_xRecoveryCFG
, css::uno::UNO_QUERY
);
3509 if (xRecoveryCfg
.is())
3510 ::comphelper::ConfigurationHelper::flush(xRecoveryCfg
);
3513 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
3514 ::utl::ConfigManager
* pCfgMgr
= ::utl::ConfigManager::GetConfigManager();
3516 pCfgMgr
->StoreConfigItems();
3518 catch(const css::uno::Exception
&)
3522 //-----------------------------------------------
3523 void AutoRecovery::st_impl_removeFile(const ::rtl::OUString
& sURL
)
3525 if ( ! sURL
.getLength())
3530 ::ucbhelper::Content aContent
= ::ucbhelper::Content(sURL
, css::uno::Reference
< css::ucb::XCommandEnvironment
>());
3531 aContent
.executeCommand(::rtl::OUString::createFromAscii("delete"), css::uno::makeAny(sal_True
));
3533 catch(const css::uno::Exception
&)
3537 //-----------------------------------------------
3538 void AutoRecovery::st_impl_removeLockFile()
3542 ::rtl::OUString sUserURL
;
3543 ::utl::Bootstrap::locateUserInstallation( sUserURL
);
3545 ::rtl::OUStringBuffer sLockURLBuf
;
3546 sLockURLBuf
.append (sUserURL
);
3547 sLockURLBuf
.appendAscii("/.lock");
3548 ::rtl::OUString sLockURL
= sLockURLBuf
.makeStringAndClear();
3550 AutoRecovery::st_impl_removeFile(sLockURL
);
3552 catch(const css::uno::Exception
&)
3556 } // namespace framework