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

Generated by: LCOV version 1.10