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

Generated by: LCOV version 1.10