LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/framework/source/services - autorecovery.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 192 1475 13.0 %
Date: 2013-07-09 Functions: 28 101 27.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10