LCOV - code coverage report
Current view: top level - framework/source/services - autorecovery.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 209 1476 14.2 %
Date: 2015-06-13 12:38:46 Functions: 28 104 26.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11