LCOV - code coverage report
Current view: top level - framework/source/services - autorecovery.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 1476 0.0 %
Date: 2014-04-14 Functions: 0 104 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #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/XEventListener.hpp>
      66             : #include <com/sun/star/document/XEventBroadcaster.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  Normaly 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 shure 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::XEventListener,    // => 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 isnt useable any longer
     204             :         E_DAMAGED = 64,
     205             :         /// the Auto/Emergency saved document isnt 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 mst be started with a very(!) short time intervall,
     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 supress 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 loosing 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::XEventListener > 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  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 cant 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 cant 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 then 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           0 :     virtual OUString SAL_CALL getImplementationName()
     457             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     458             :     {
     459           0 :         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           0 :     virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
     469             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     470             :     {
     471           0 :         css::uno::Sequence< OUString > aSeq(1);
     472           0 :         aSeq[0] = OUString("com.sun.star.frame.AutoRecovery");
     473           0 :         return aSeq;
     474             :     }
     475             : 
     476             :     // XInterface
     477           0 :     virtual void SAL_CALL acquire() throw () SAL_OVERRIDE
     478           0 :         { OWeakObject::acquire(); }
     479           0 :     virtual void SAL_CALL release() throw () SAL_OVERRIDE
     480           0 :         { 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.XEventListener
     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 notifyEvent(const css::document::EventObject& 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 isnt adressed 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(implts_timerExpired, 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 then 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 cant 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 uses the Frame everytime 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 supressed 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 cant 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 offical way .-)
    1010             : 
    1011             :         This method has to be handled "optional". So every error inside
    1012             :         has to be ignored ! This method CANT 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 everytime 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 everytimes
    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 then 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           0 : CacheLockGuard::CacheLockGuard(AutoRecovery* pOwner                      ,
    1150             :                                osl::Mutex&   rMutex                      ,
    1151             :                                sal_Int32&    rCacheLock                  ,
    1152             :                                bool      bLockForAddRemoveVectorItems)
    1153           0 :     : m_xOwner            (static_cast< css::frame::XDispatch* >(pOwner))
    1154             :     , m_rSharedMutex      (rMutex                                       )
    1155             :     , m_rCacheLock        (rCacheLock                                   )
    1156           0 :     , m_bLockedByThisGuard(false                                    )
    1157             : {
    1158           0 :     lock(bLockForAddRemoveVectorItems);
    1159           0 : }
    1160             : 
    1161           0 : CacheLockGuard::~CacheLockGuard()
    1162             : {
    1163           0 :     unlock();
    1164           0 :     m_xOwner.clear();
    1165           0 : }
    1166             : 
    1167           0 : void CacheLockGuard::lock(bool bLockForAddRemoveVectorItems)
    1168             : {
    1169             :     /* SAFE */ {
    1170           0 :     osl::MutexGuard g(m_rSharedMutex);
    1171             : 
    1172           0 :     if (m_bLockedByThisGuard)
    1173           0 :         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           0 :     if (
    1186           0 :         (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           0 :     ++m_rCacheLock;
    1197           0 :     m_bLockedByThisGuard = true;
    1198             :     } /* SAFE */
    1199             : }
    1200             : 
    1201           0 : void CacheLockGuard::unlock()
    1202             : {
    1203             :     /* SAFE */ {
    1204           0 :     osl::MutexGuard g(m_rSharedMutex);
    1205             : 
    1206           0 :     if ( ! m_bLockedByThisGuard)
    1207           0 :         return;
    1208             : 
    1209           0 :     --m_rCacheLock;
    1210           0 :     m_bLockedByThisGuard = false;
    1211             : 
    1212           0 :     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           0 :     }
    1219             :     } /* SAFE */
    1220             : }
    1221             : 
    1222           0 : DispatchParams::DispatchParams()
    1223           0 :     : m_nWorkingEntryID(-1)
    1224             : {
    1225           0 : };
    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           0 : DispatchParams::~DispatchParams()
    1237           0 : {};
    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       = "";
    1251           0 :     m_nWorkingEntryID = -1;
    1252           0 :     m_xProgress.clear();
    1253           0 :     m_xHoldRefForAsyncOpAlive.clear();
    1254           0 : };
    1255             : 
    1256           0 : 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           0 :     , m_nMinSpaceConfigSave     (MIN_DISCSPACE_CONFIGSAVE                           )
    1271             : 
    1272             :     #if OSL_DEBUG_LEVEL > 1
    1273             :     , m_dbg_bMakeItFaster       (sal_False                                          )
    1274             :     #endif
    1275             : {
    1276           0 : }
    1277             : 
    1278           0 : void AutoRecovery::initListeners()
    1279             : {
    1280             :     // read configuration to know if autosave/recovery is on/off etcpp...
    1281           0 :     implts_readConfig();
    1282             : 
    1283           0 :     implts_startListening();
    1284             : 
    1285             :     // establish callback for our internal used timer.
    1286             :     // Note: Its only active, if the timer will be started ...
    1287           0 :     m_aTimer.SetTimeoutHdl(LINK(this, AutoRecovery, implts_timerExpired));
    1288           0 : }
    1289             : 
    1290           0 : AutoRecovery::~AutoRecovery()
    1291             : {
    1292           0 :     disposing();
    1293           0 : }
    1294             : 
    1295           0 : void AutoRecovery::disposing()
    1296             : {
    1297           0 :     implts_stopTimer();
    1298           0 : }
    1299             : 
    1300           0 : Any SAL_CALL AutoRecovery::queryInterface( const css::uno::Type& _rType ) throw(css::uno::RuntimeException, std::exception)
    1301             : {
    1302           0 :     Any aRet = AutoRecovery_BASE::queryInterface( _rType );
    1303           0 :     if ( !aRet.hasValue() )
    1304           0 :         aRet = OPropertySetHelper::queryInterface( _rType );
    1305           0 :     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           0 : 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           0 :     sal_Int32 eNewJob = AutoRecovery::implst_classifyJob(aURL);
    1324           0 :     if (eNewJob == AutoRecovery::E_NO_JOB)
    1325           0 :         return;
    1326             : 
    1327             :     bool bAsync;
    1328           0 :     DispatchParams aParams;
    1329             :     /* SAFE */ {
    1330           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    1331             : 
    1332             :     // still running operation ... ignoring AUTO_SAVE.
    1333             :     // All other requests has higher prio!
    1334           0 :     if (
    1335           0 :         ( m_eJob                               != AutoRecovery::E_NO_JOB   ) &&
    1336           0 :         ((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           0 :     ::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           0 :     if ((eNewJob & AutoRecovery::E_DISABLE_AUTORECOVERY) == AutoRecovery::E_DISABLE_AUTORECOVERY)
    1348             :     {
    1349             :         // it's important to set a flag internally, so AutoRecovery will be supressed - even if it's requested.
    1350           0 :         m_eJob |= eNewJob;
    1351           0 :         implts_stopTimer();
    1352           0 :         implts_stopListening();
    1353           0 :         return;
    1354             :     }
    1355             : 
    1356             :     // disable/enable AutoSave for this office session only
    1357             :     // independend 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, sal_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, sal_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::notifyEvent(const css::document::EventObject& 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 isnt ready for multiple save requests
    1612             :        at the same time. So we have to supress 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 supress 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             :     // Normaly 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           0 : css::uno::Reference< css::container::XNameAccess > AutoRecovery::implts_openConfig()
    1755             : {
    1756             :     /* SAFE */ {
    1757           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    1758             : 
    1759           0 :     if (m_xRecoveryCFG.is())
    1760           0 :         return m_xRecoveryCFG;
    1761             : 
    1762             :     } /* SAFE */
    1763             : 
    1764           0 :     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           0 :         css::uno::UNO_QUERY);
    1769             : 
    1770           0 :     sal_Int32 nMinSpaceDocSave    = MIN_DISCSPACE_DOCSAVE;
    1771           0 :     sal_Int32 nMinSpaceConfigSave = MIN_DISCSPACE_CONFIGSAVE;
    1772             : 
    1773             :     try
    1774             :     {
    1775           0 :         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           0 :                                                          ::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           0 :                                                          ::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           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    1798           0 :     m_xRecoveryCFG        = xCFG;
    1799           0 :     m_nMinSpaceDocSave    = nMinSpaceDocSave;
    1800           0 :     m_nMinSpaceConfigSave = nMinSpaceConfigSave;
    1801             :     } /* SAFE */
    1802             : 
    1803           0 :     return xCFG;
    1804             : }
    1805             : 
    1806           0 : void AutoRecovery::implts_readAutoSaveConfig()
    1807             : {
    1808           0 :     css::uno::Reference< css::container::XHierarchicalNameAccess > xCommonRegistry(implts_openConfig(), css::uno::UNO_QUERY);
    1809             : 
    1810             :     // AutoSave [bool]
    1811           0 :     bool bEnabled = false;
    1812           0 :     xCommonRegistry->getByHierarchicalName(OUString(CFG_ENTRY_AUTOSAVE_ENABLED)) >>= bEnabled;
    1813             : 
    1814             :     // UserAutoSave [bool]
    1815           0 :     bool bUserEnabled = false;
    1816           0 :     xCommonRegistry->getByHierarchicalName(OUString(CFG_ENTRY_USERAUTOSAVE_ENABLED)) >>= bUserEnabled;
    1817             : 
    1818             :     /* SAFE */ {
    1819           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    1820           0 :     if (bEnabled)
    1821             :     {
    1822           0 :         m_eJob       |= AutoRecovery::E_AUTO_SAVE;
    1823           0 :         m_eTimerType  = AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL;
    1824             : 
    1825           0 :         if (bUserEnabled)
    1826             :         {
    1827           0 :             m_eJob |= AutoRecovery::E_USER_AUTO_SAVE;
    1828             :         }
    1829             :         else
    1830             :         {
    1831           0 :             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           0 :     }
    1839             :     } /* SAFE */
    1840             : 
    1841             :     // AutoSaveTimeIntervall [int] in min
    1842           0 :     sal_Int32 nTimeIntervall = 15;
    1843           0 :     xCommonRegistry->getByHierarchicalName(OUString(CFG_ENTRY_AUTOSAVE_TIMEINTERVALL)) >>= nTimeIntervall;
    1844             : 
    1845             :     /* SAFE */ {
    1846           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    1847           0 :     m_nAutoSaveTimeIntervall = nTimeIntervall;
    1848           0 :     } /* SAFE */
    1849           0 : }
    1850             : 
    1851           0 : void AutoRecovery::implts_readConfig()
    1852             : {
    1853           0 :     implts_readAutoSaveConfig();
    1854             : 
    1855           0 :     css::uno::Reference< css::container::XHierarchicalNameAccess > xCommonRegistry(implts_openConfig(), css::uno::UNO_QUERY);
    1856             : 
    1857             :     // REENTRANT -> --------------------------------
    1858           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_ADD_REMOVE);
    1859             : 
    1860             :     /* SAFE */ {
    1861           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    1862             :     // reset current cache load cache
    1863           0 :     m_lDocCache.clear();
    1864           0 :     m_nIdPool = 0;
    1865             :     } /* SAFE */
    1866             : 
    1867           0 :     aCacheLock.unlock();
    1868             :     // <- REENTRANT --------------------------------
    1869             : 
    1870           0 :     css::uno::Any aValue;
    1871             : 
    1872             :     // RecoveryList [set]
    1873           0 :     aValue = xCommonRegistry->getByHierarchicalName(OUString(CFG_ENTRY_RECOVERYLIST));
    1874           0 :     css::uno::Reference< css::container::XNameAccess > xList;
    1875           0 :     aValue >>= xList;
    1876           0 :     if (xList.is())
    1877             :     {
    1878           0 :         const OUString sRECOVERY_ITEM_BASE_IDENTIFIER(RECOVERY_ITEM_BASE_IDENTIFIER);
    1879           0 :         const css::uno::Sequence< OUString > lItems = xList->getElementNames();
    1880           0 :         const OUString*                      pItems = lItems.getConstArray();
    1881           0 :               sal_Int32                             c      = lItems.getLength();
    1882           0 :               sal_Int32                             i      = 0;
    1883             : 
    1884             :         // REENTRANT -> --------------------------
    1885           0 :         aCacheLock.lock(LOCK_FOR_CACHE_ADD_REMOVE);
    1886             : 
    1887           0 :         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 = "";
    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           0 :         aCacheLock.unlock();
    1931             :         // <- REENTRANT --------------------------
    1932             :     }
    1933             : 
    1934           0 :     implts_updateTimer();
    1935           0 : }
    1936             : 
    1937           0 : void AutoRecovery::implts_specifyDefaultFilterAndExtension(AutoRecovery::TDocumentInfo& rInfo)
    1938             : {
    1939           0 :     if (rInfo.AppModule.isEmpty())
    1940             :     {
    1941             :         throw css::uno::RuntimeException(
    1942             :                 OUString("Cant 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 = "";
    1995           0 :         rInfo.Extension     = "";
    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             :         "Cant 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           0 : void AutoRecovery::implts_startListening()
    2177             : {
    2178           0 :     css::uno::Reference< css::util::XChangesNotifier > xCFG;
    2179           0 :     css::uno::Reference< css::frame::XGlobalEventBroadcaster > xBroadcaster;
    2180             :     bool bListenForDocEvents;
    2181             :     /* SAFE */ {
    2182           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2183           0 :     xCFG.set              (m_xRecoveryCFG, css::uno::UNO_QUERY);
    2184           0 :     xBroadcaster        = m_xNewDocBroadcaster;
    2185           0 :     bListenForDocEvents = m_bListenForDocEvents;
    2186             :     } /* SAFE */
    2187             : 
    2188           0 :     if (
    2189           0 :         (  xCFG.is()                ) &&
    2190           0 :         (! m_bListenForConfigChanges)
    2191             :        )
    2192             :     {
    2193           0 :         m_xRecoveryCFGListener = new WeakChangesListener(this);
    2194           0 :         xCFG->addChangesListener(m_xRecoveryCFGListener);
    2195           0 :         m_bListenForConfigChanges = true;
    2196             :     }
    2197             : 
    2198           0 :     if (!xBroadcaster.is())
    2199             :     {
    2200           0 :         xBroadcaster = css::frame::theGlobalEventBroadcaster::get(m_xContext);
    2201             :         /* SAFE */ {
    2202           0 :         osl::MutexGuard g2(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2203           0 :         m_xNewDocBroadcaster = xBroadcaster;
    2204             :         } /* SAFE */
    2205             :     }
    2206             : 
    2207           0 :     if (
    2208           0 :         (  xBroadcaster.is()  ) &&
    2209           0 :         (! bListenForDocEvents)
    2210             :        )
    2211             :     {
    2212           0 :         m_xNewDocBroadcasterListener = new WeakDocumentEventListener(this);
    2213           0 :         xBroadcaster->addEventListener(m_xNewDocBroadcasterListener);
    2214             :         /* SAFE */ {
    2215           0 :         osl::MutexGuard g2(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2216           0 :         m_bListenForDocEvents = true;
    2217             :         } /* SAFE */
    2218           0 :     }
    2219           0 : }
    2220             : 
    2221           0 : void AutoRecovery::implts_stopListening()
    2222             : {
    2223           0 :     css::uno::Reference< css::util::XChangesNotifier > xCFG;
    2224           0 :     css::uno::Reference< css::document::XEventBroadcaster > xGlobalEventBroadcaster;
    2225             :     /* SAFE */ {
    2226           0 :     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           0 :     xCFG.set                   (m_xRecoveryCFG      , css::uno::UNO_QUERY);
    2231           0 :     xGlobalEventBroadcaster.set(m_xNewDocBroadcaster, css::uno::UNO_QUERY);
    2232             :     } /* SAFE */
    2233             : 
    2234           0 :     if (
    2235           0 :         (xGlobalEventBroadcaster.is()) &&
    2236             :         (m_bListenForDocEvents       )
    2237             :        )
    2238             :     {
    2239           0 :         xGlobalEventBroadcaster->removeEventListener(m_xNewDocBroadcasterListener);
    2240           0 :         m_bListenForDocEvents = false;
    2241             :     }
    2242             : 
    2243           0 :     if (
    2244           0 :         (xCFG.is()                ) &&
    2245             :         (m_bListenForConfigChanges)
    2246             :        )
    2247             :     {
    2248           0 :         xCFG->removeChangesListener(m_xRecoveryCFGListener);
    2249           0 :         m_bListenForConfigChanges = false;
    2250           0 :     }
    2251           0 : }
    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           0 : void AutoRecovery::implts_updateTimer()
    2282             : {
    2283           0 :     implts_stopTimer();
    2284             : 
    2285             :     /* SAFE */ {
    2286           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2287             : 
    2288           0 :     if (
    2289           0 :         (m_eJob       == AutoRecovery::E_NO_JOB          ) || // TODO may be superflous - E_DONT_START_TIMER should be used only
    2290           0 :         (m_eTimerType == AutoRecovery::E_DONT_START_TIMER)
    2291             :        )
    2292           0 :         return;
    2293             : 
    2294           0 :     sal_Int32 nMilliSeconds = 0;
    2295           0 :     if (m_eTimerType == AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL)
    2296             :     {
    2297           0 :         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 loose some key input data!
    2313             : 
    2314           0 :     m_aTimer.SetTimeout(nMilliSeconds);
    2315           0 :     m_aTimer.Start();
    2316             : 
    2317             :     } /* SAFE */
    2318             : }
    2319             : 
    2320           0 : void AutoRecovery::implts_stopTimer()
    2321             : {
    2322           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2323             : 
    2324           0 :     if (!m_aTimer.IsActive())
    2325           0 :         return;
    2326           0 :     m_aTimer.Stop();
    2327             : }
    2328             : 
    2329           0 : IMPL_LINK_NOARG(AutoRecovery, implts_timerExpired)
    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 normaly 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 0;
    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 0;
    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 0;
    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 isnt 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           0 :     return 0;
    2423             : }
    2424             : 
    2425           0 : IMPL_LINK_NOARG(AutoRecovery, implts_asyncDispatch)
    2426             : {
    2427           0 :     DispatchParams aParams;
    2428             :     /* SAFE */ {
    2429           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2430           0 :     aParams = m_aDispatchParams;
    2431           0 :     css::uno::Reference< css::uno::XInterface > xHoldRefForMethodAlive = aParams.m_xHoldRefForAsyncOpAlive;
    2432           0 :     m_aDispatchParams.forget(); // clears all members ... including the ref-hold object .-)
    2433             :     } /* SAFE */
    2434             : 
    2435             :     try
    2436             :     {
    2437           0 :         implts_dispatch(aParams);
    2438             :     }
    2439           0 :     catch (...)
    2440             :     {
    2441             :     }
    2442           0 :     return 0;
    2443             : }
    2444             : 
    2445           0 : void AutoRecovery::implts_registerDocument(const css::uno::Reference< css::frame::XModel >& xDocument)
    2446             : {
    2447             :     // ignore corrupted events, where no document is given ... Runtime Error ?!
    2448           0 :     if (!xDocument.is())
    2449           0 :         return;
    2450             : 
    2451           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
    2452             : 
    2453             :     // notification for already existing document !
    2454             :     // Can happen if events came in asynchronous on recovery time.
    2455             :     // Then our cache was filled from the configuration ... but now we get some
    2456             :     // asynchronous events from the global event broadcaster. We must be sure that
    2457             :     // we dont add the same document more then once.
    2458           0 :     AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
    2459           0 :     if (pIt != m_lDocCache.end())
    2460             :     {
    2461             :         // Normaly nothing must be done for this "late" notification.
    2462             :         // But may be the modified state was changed inbetween.
    2463             :         // Check it ...
    2464           0 :         implts_updateModifiedState(xDocument);
    2465           0 :         return;
    2466             :     }
    2467             : 
    2468           0 :     aCacheLock.unlock();
    2469             : 
    2470           0 :     utl::MediaDescriptor lDescriptor(xDocument->getArgs());
    2471             : 
    2472             :     // check if this document must be ignored for recovery !
    2473             :     // Some use cases dont wish support for AutoSave/Recovery ... as e.g. OLE-Server / ActiveX Control etcpp.
    2474           0 :     bool bNoAutoSave = lDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_NOAUTOSAVE(), sal_False);
    2475           0 :     if (bNoAutoSave)
    2476           0 :         return;
    2477             : 
    2478             :     // Check if doc is well known on the desktop. Otherwhise ignore it!
    2479             :     // Other frames mostly are used from external programs - e.g. the bean ...
    2480           0 :     css::uno::Reference< css::frame::XController > xController = xDocument->getCurrentController();
    2481           0 :     if (!xController.is())
    2482           0 :         return;
    2483             : 
    2484           0 :     css::uno::Reference< css::frame::XFrame >   xFrame   = xController->getFrame();
    2485           0 :     css::uno::Reference< css::frame::XDesktop > xDesktop (xFrame->getCreator(), css::uno::UNO_QUERY);
    2486           0 :     if (!xDesktop.is())
    2487           0 :         return;
    2488             : 
    2489             :     // if the document doesn't support the XDocumentRecovery interface, we're not interested in it.
    2490           0 :     Reference< XDocumentRecovery > xDocRecovery( xDocument, UNO_QUERY );
    2491           0 :     if ( !xDocRecovery.is() )
    2492           0 :         return;
    2493             : 
    2494             :     // get all needed information of this document
    2495             :     // We need it to update our cache or to locate already existing elements there!
    2496           0 :     AutoRecovery::TDocumentInfo aNew;
    2497           0 :     aNew.Document = xDocument;
    2498             : 
    2499             :     // TODO replace getLocation() with getURL() ... it's a workaround currently only!
    2500           0 :     css::uno::Reference< css::frame::XStorable > xDoc(aNew.Document, css::uno::UNO_QUERY_THROW);
    2501           0 :     aNew.OrgURL = xDoc->getLocation();
    2502             : 
    2503           0 :     css::uno::Reference< css::frame::XTitle > xTitle(aNew.Document, css::uno::UNO_QUERY_THROW);
    2504           0 :     aNew.Title = xTitle->getTitle ();
    2505             : 
    2506             :     // classify the used application module, which is used by this document.
    2507           0 :     implts_specifyAppModuleAndFactory(aNew);
    2508             : 
    2509             :     // Hack! Check for "illegal office documents" ... as e.g. the Basic IDE
    2510             :     // Its not really a full featured office document. It doesn't provide an URL, any filter, a factory URL etcpp.
    2511             :     // TODO file bug to Basci IDE developers. They must remove the office document API from its service.
    2512           0 :     if (
    2513           0 :         (aNew.OrgURL.isEmpty()) &&
    2514           0 :         (aNew.FactoryURL.isEmpty())
    2515             :        )
    2516             :     {
    2517             :         OSL_FAIL( "AutoRecovery::implts_registerDocument: this should not happen anymore!" );
    2518             :         // nowadays, the Basic IDE should already die on the "supports XDocumentRecovery" check. And no other known
    2519             :         // document type fits in here ...
    2520           0 :         return;
    2521             :     }
    2522             : 
    2523             :     // By the way - get some information about the default format for saving!
    2524             :     // and save an information about the real used filter by this document.
    2525             :     // We save this document with DefaultFilter ... and load it with the RealFilter.
    2526           0 :     implts_specifyDefaultFilterAndExtension(aNew);
    2527           0 :     aNew.RealFilter = lDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME()  , OUString());
    2528             : 
    2529             :     // Further we must know, if this document base on a template.
    2530             :     // Then we must load it in a different way.
    2531           0 :     css::uno::Reference< css::document::XDocumentPropertiesSupplier > xSupplier(aNew.Document, css::uno::UNO_QUERY);
    2532           0 :     if (xSupplier.is()) // optional interface!
    2533             :     {
    2534           0 :         css::uno::Reference< css::document::XDocumentProperties > xDocProps(xSupplier->getDocumentProperties(), css::uno::UNO_QUERY_THROW);
    2535           0 :         aNew.TemplateURL = xDocProps->getTemplateURL();
    2536             :     }
    2537             : 
    2538           0 :     css::uno::Reference< css::util::XModifiable > xModifyCheck(xDocument, css::uno::UNO_QUERY_THROW);
    2539           0 :     if (xModifyCheck->isModified())
    2540             :     {
    2541           0 :         aNew.DocumentState |= AutoRecovery::E_MODIFIED;
    2542             :     }
    2543             : 
    2544           0 :     aCacheLock.lock(LOCK_FOR_CACHE_ADD_REMOVE);
    2545             : 
    2546           0 :     AutoRecovery::TDocumentInfo aInfo;
    2547             :     /* SAFE */ {
    2548           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2549             : 
    2550             :     // create a new cache entry ... this document isn't known.
    2551           0 :     ++m_nIdPool;
    2552           0 :     aNew.ID = m_nIdPool;
    2553             :     SAL_WARN_IF(m_nIdPool<0, "fwk", "AutoRecovery::implts_registerDocument(): Overflow of ID pool detected.");
    2554           0 :     m_lDocCache.push_back(aNew);
    2555             : 
    2556           0 :     AutoRecovery::TDocumentList::iterator pIt1  = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
    2557           0 :     aInfo = *pIt1;
    2558             : 
    2559             :     } /* SAFE */
    2560             : 
    2561           0 :     implts_flushConfigItem(aInfo);
    2562           0 :     implts_startModifyListeningOnDoc(aInfo);
    2563             : 
    2564           0 :     aCacheLock.unlock();
    2565             : }
    2566             : 
    2567           0 : void AutoRecovery::implts_deregisterDocument(const css::uno::Reference< css::frame::XModel >& xDocument     ,
    2568             :                                                    bool                                   bStopListening)
    2569             : {
    2570           0 :     AutoRecovery::TDocumentInfo aInfo;
    2571             :     /* SAFE */ {
    2572           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2573             : 
    2574             :     // Attention: Dont leave SAFE section, if you work with pIt!
    2575             :     // Because it points directly into the m_lDocCache list ...
    2576           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
    2577             : 
    2578           0 :     AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
    2579           0 :     if (pIt == m_lDocCache.end())
    2580           0 :         return; // unknown document => not a runtime error! Because we register only a few documents. see registration ...
    2581             : 
    2582           0 :     aInfo = *pIt;
    2583             : 
    2584           0 :     aCacheLock.unlock();
    2585             : 
    2586             :     // Sometimes we close documents by ourself.
    2587             :     // And these documents cant be deregistered.
    2588             :     // Otherwhise we loos our configuration data ... but need it !
    2589             :     // see SessionSave !
    2590           0 :     if (aInfo.IgnoreClosing)
    2591           0 :         return;
    2592             : 
    2593           0 :     CacheLockGuard aCacheLock2(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_ADD_REMOVE);
    2594           0 :     pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
    2595           0 :     if (pIt != m_lDocCache.end())
    2596           0 :         m_lDocCache.erase(pIt);
    2597           0 :     pIt = m_lDocCache.end(); // otherwise its not specified what pIt means!
    2598           0 :     aCacheLock2.unlock();
    2599             : 
    2600             :     } /* SAFE */
    2601             : 
    2602             :     /* This method is called within disposing() of the document too. But there it's not a good idea to
    2603             :        deregister us as listener. Furter it make no sense - because the broadcaster dies.
    2604             :        So we supress deregistration in such case ...
    2605             :     */
    2606           0 :     if (bStopListening)
    2607           0 :         implts_stopModifyListeningOnDoc(aInfo);
    2608             : 
    2609           0 :     AutoRecovery::st_impl_removeFile(aInfo.OldTempURL);
    2610           0 :     AutoRecovery::st_impl_removeFile(aInfo.NewTempURL);
    2611           0 :     implts_flushConfigItem(aInfo, true); // sal_True => remove it from config
    2612             : }
    2613             : 
    2614           0 : void AutoRecovery::implts_markDocumentModifiedAgainstLastBackup(const css::uno::Reference< css::frame::XModel >& xDocument)
    2615             : {
    2616           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
    2617             : 
    2618             :     /* SAFE */ {
    2619           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2620             : 
    2621           0 :     AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
    2622           0 :     if (pIt != m_lDocCache.end())
    2623             :     {
    2624             :         /* Now we know, that this document was modified again and must be saved next time.
    2625             :            But we dont need this information for every e.g. key input of the user.
    2626             :            So we stop listening here.
    2627             :            But if the document was saved as temp. file we start listening for this event again.
    2628             :         */
    2629           0 :         implts_stopModifyListeningOnDoc(*pIt);
    2630           0 :     }
    2631             : 
    2632           0 :     } /* SAFE */
    2633           0 : }
    2634             : 
    2635           0 : void AutoRecovery::implts_updateModifiedState(const css::uno::Reference< css::frame::XModel >& xDocument)
    2636             : {
    2637           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
    2638             : 
    2639             :     /* SAFE */ {
    2640           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2641             : 
    2642           0 :     AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
    2643           0 :     if (pIt != m_lDocCache.end())
    2644             :     {
    2645           0 :         AutoRecovery::TDocumentInfo& rInfo = *pIt;
    2646             : 
    2647             :         // use sal_True as fallback ... so we recognize every document on EmergencySave/AutoRecovery!
    2648           0 :         bool bModified = true;
    2649           0 :         css::uno::Reference< css::util::XModifiable > xModify(xDocument, css::uno::UNO_QUERY);
    2650           0 :         if (xModify.is())
    2651           0 :             bModified = xModify->isModified();
    2652           0 :         if (bModified)
    2653             :         {
    2654           0 :             rInfo.DocumentState |= AutoRecovery::E_MODIFIED;
    2655             :         }
    2656             :         else
    2657             :         {
    2658           0 :             rInfo.DocumentState &= ~AutoRecovery::E_MODIFIED;
    2659           0 :         }
    2660           0 :     }
    2661             : 
    2662           0 :     } /* SAFE */
    2663           0 : }
    2664             : 
    2665           0 : void AutoRecovery::implts_updateDocumentUsedForSavingState(const css::uno::Reference< css::frame::XModel >& xDocument      ,
    2666             :                                                                  bool                                   bSaveInProgress)
    2667             : {
    2668           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
    2669             : 
    2670             :     /* SAFE */ {
    2671           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2672             : 
    2673           0 :     AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
    2674           0 :     if (pIt == m_lDocCache.end())
    2675           0 :         return;
    2676           0 :     AutoRecovery::TDocumentInfo& rInfo = *pIt;
    2677           0 :     rInfo.UsedForSaving = bSaveInProgress;
    2678             : 
    2679           0 :     } /* SAFE */
    2680             : }
    2681             : 
    2682           0 : void AutoRecovery::implts_markDocumentAsSaved(const css::uno::Reference< css::frame::XModel >& xDocument)
    2683             : {
    2684           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
    2685             : 
    2686           0 :     AutoRecovery::TDocumentInfo aInfo;
    2687           0 :     OUString sRemoveURL1;
    2688           0 :     OUString sRemoveURL2;
    2689             :     /* SAFE */ {
    2690           0 :     osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2691             : 
    2692           0 :     AutoRecovery::TDocumentList::iterator pIt = AutoRecovery::impl_searchDocument(m_lDocCache, xDocument);
    2693           0 :     if (pIt == m_lDocCache.end())
    2694           0 :         return;
    2695           0 :     aInfo = *pIt;
    2696             : 
    2697           0 :     aInfo.DocumentState = AutoRecovery::E_UNKNOWN;
    2698             :     // TODO replace getLocation() with getURL() ... it's a workaround currently only!
    2699           0 :     css::uno::Reference< css::frame::XStorable > xDoc(aInfo.Document, css::uno::UNO_QUERY);
    2700           0 :     aInfo.OrgURL = xDoc->getLocation();
    2701             : 
    2702           0 :     sRemoveURL1 = aInfo.OldTempURL;
    2703           0 :     sRemoveURL2 = aInfo.NewTempURL;
    2704           0 :     aInfo.OldTempURL = "";
    2705           0 :     aInfo.NewTempURL = "";
    2706             : 
    2707           0 :     utl::MediaDescriptor lDescriptor(aInfo.Document->getArgs());
    2708           0 :     aInfo.RealFilter = lDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME(), OUString());
    2709             : 
    2710           0 :     css::uno::Reference< css::frame::XTitle > xDocTitle(xDocument, css::uno::UNO_QUERY);
    2711           0 :     if (xDocTitle.is ())
    2712           0 :         aInfo.Title = xDocTitle->getTitle ();
    2713             :     else
    2714             :     {
    2715           0 :         aInfo.Title      = lDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TITLE()     , OUString());
    2716           0 :         if (aInfo.Title.isEmpty())
    2717           0 :             aInfo.Title  = lDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_DOCUMENTTITLE(), OUString());
    2718             :     }
    2719             : 
    2720           0 :     aInfo.UsedForSaving = false;
    2721             : 
    2722             :     } /* SAFE */
    2723             : 
    2724           0 :     implts_flushConfigItem(aInfo);
    2725             : 
    2726           0 :     aCacheLock.unlock();
    2727             : 
    2728           0 :     AutoRecovery::st_impl_removeFile(sRemoveURL1);
    2729           0 :     AutoRecovery::st_impl_removeFile(sRemoveURL2);
    2730             : }
    2731             : 
    2732           0 : AutoRecovery::TDocumentList::iterator AutoRecovery::impl_searchDocument(      AutoRecovery::TDocumentList&               rList    ,
    2733             :                                                                         const css::uno::Reference< css::frame::XModel >& xDocument)
    2734             : {
    2735           0 :     AutoRecovery::TDocumentList::iterator pIt;
    2736           0 :     for (  pIt  = rList.begin();
    2737           0 :            pIt != rList.end();
    2738             :          ++pIt                 )
    2739             :     {
    2740           0 :         const AutoRecovery::TDocumentInfo& rInfo = *pIt;
    2741           0 :         if (rInfo.Document == xDocument)
    2742           0 :             break;
    2743             :     }
    2744           0 :     return pIt;
    2745             : }
    2746             : 
    2747             : namespace
    2748             : {
    2749           0 :     void lcl_changeVisibility( const css::uno::Reference< css::frame::XFramesSupplier >& i_rFrames, bool i_bVisible )
    2750             :     {
    2751           0 :         css::uno::Reference< css::container::XIndexAccess > xFramesContainer( i_rFrames->getFrames(), css::uno::UNO_QUERY );
    2752           0 :         const sal_Int32 count = xFramesContainer->getCount();
    2753             : 
    2754           0 :         Any aElement;
    2755           0 :         for ( sal_Int32 i=0; i < count; ++i )
    2756             :         {
    2757           0 :             aElement = xFramesContainer->getByIndex(i);
    2758             :             // check for sub frames
    2759           0 :             css::uno::Reference< css::frame::XFramesSupplier > xFramesSupp( aElement, css::uno::UNO_QUERY );
    2760           0 :             if ( xFramesSupp.is() )
    2761           0 :                 lcl_changeVisibility( xFramesSupp, i_bVisible );
    2762             : 
    2763           0 :             css::uno::Reference< css::frame::XFrame > xFrame( aElement, css::uno::UNO_QUERY );
    2764           0 :             if ( !xFrame.is() )
    2765           0 :                 continue;
    2766             : 
    2767           0 :             css::uno::Reference< css::awt::XWindow > xWindow( xFrame->getContainerWindow(), UNO_SET_THROW );
    2768           0 :             xWindow->setVisible( i_bVisible );
    2769           0 :         }
    2770           0 :     }
    2771             : }
    2772             : 
    2773           0 : void AutoRecovery::implts_changeAllDocVisibility(bool bVisible)
    2774             : {
    2775           0 :     css::uno::Reference< css::frame::XFramesSupplier > xDesktop( css::frame::Desktop::create(m_xContext), css::uno::UNO_QUERY);
    2776           0 :     lcl_changeVisibility( xDesktop, bVisible );
    2777           0 : }
    2778             : 
    2779             : /* Currently the document is not closed in case of crash,
    2780             :    so the lock file must be removed explicitly
    2781             : */
    2782           0 : void lc_removeLockFile(AutoRecovery::TDocumentInfo& rInfo)
    2783             : {
    2784             : #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT || HAVE_FEATURE_MACOSX_SANDBOX
    2785             :     (void) rInfo;
    2786             : #else
    2787           0 :     if ( rInfo.Document.is() )
    2788             :     {
    2789             :         try
    2790             :         {
    2791           0 :             css::uno::Reference< css::frame::XStorable > xStore(rInfo.Document, css::uno::UNO_QUERY_THROW);
    2792           0 :             OUString aURL = xStore->getLocation();
    2793           0 :             if ( !aURL.isEmpty() )
    2794             :             {
    2795           0 :                 ::svt::DocumentLockFile aLockFile( aURL );
    2796           0 :                 aLockFile.RemoveFile();
    2797           0 :             }
    2798             :         }
    2799           0 :         catch( const css::uno::Exception& )
    2800             :         {
    2801             :         }
    2802             :     }
    2803             : #endif
    2804           0 : }
    2805             : 
    2806           0 : void AutoRecovery::implts_prepareSessionShutdown()
    2807             : {
    2808             :     SAL_INFO("fwk.autorecovery", "AutoRecovery::implts_prepareSessionShutdown() starts ...");
    2809             : 
    2810             :     // a) reset modified documents (of course the must be saved before this method is called!)
    2811             :     // b) close it without showing any UI!
    2812             : 
    2813             :     /* SAFE */ {
    2814           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
    2815             : 
    2816           0 :     AutoRecovery::TDocumentList::iterator pIt;
    2817           0 :     for (  pIt  = m_lDocCache.begin();
    2818           0 :            pIt != m_lDocCache.end();
    2819             :          ++pIt                       )
    2820             :     {
    2821           0 :         AutoRecovery::TDocumentInfo& rInfo = *pIt;
    2822             : 
    2823             :         // WORKAROUND... Since the documents are not closed the lock file must be removed explicitly
    2824             :         // it is not done on documents saving since shutdown can be cancelled
    2825           0 :         lc_removeLockFile( rInfo );
    2826             : 
    2827             :         // Prevent us from deregistration of these documents.
    2828             :         // Because we close these documents by ourself (see XClosable below) ...
    2829             :         // it's fact, that we reach our deregistration method. There we
    2830             :         // must not(!) update our configuration ... Otherwhise all
    2831             :         // session data are lost !!!
    2832           0 :         rInfo.IgnoreClosing = true;
    2833             : 
    2834             :         // reset modified flag of these documents (ignoring the notification about it!)
    2835             :         // Otherwise a message box is shown on closing these models.
    2836           0 :         implts_stopModifyListeningOnDoc(rInfo);
    2837             : 
    2838             :         // if the session save is still running the documents should not be thrown away,
    2839             :         // actually that would be a bad sign, that means that the SessionManager tryes
    2840             :         // to kill the session before the saving is ready
    2841           0 :         if ((m_eJob & AutoRecovery::E_SESSION_SAVE) != AutoRecovery::E_SESSION_SAVE)
    2842             :         {
    2843           0 :             css::uno::Reference< css::util::XModifiable > xModify(rInfo.Document, css::uno::UNO_QUERY);
    2844           0 :             if (xModify.is())
    2845           0 :                 xModify->setModified(sal_False);
    2846             : 
    2847             :             // close the model.
    2848           0 :             css::uno::Reference< css::util::XCloseable > xClose(rInfo.Document, css::uno::UNO_QUERY);
    2849           0 :             if (xClose.is())
    2850             :             {
    2851             :                 try
    2852             :                 {
    2853           0 :                     xClose->close(sal_False);
    2854             :                 }
    2855           0 :                 catch(const css::uno::Exception&)
    2856             :                 {
    2857             :                     // At least it's only a try to close these documents before anybody else it does.
    2858             :                     // So it seems to be possible to ignore any error here .-)
    2859             :                 }
    2860             : 
    2861           0 :                 rInfo.Document.clear();
    2862           0 :             }
    2863             :         }
    2864             :     }
    2865             : 
    2866           0 :     aCacheLock.unlock();
    2867             :     } /* SAFE */
    2868           0 : }
    2869             : 
    2870             : /* TODO WORKAROUND:
    2871             : 
    2872             :         #i64599#
    2873             : 
    2874             :         Normaly the MediaDescriptor argument NoAutoSave indicates,
    2875             :         that a document must be ignored for AutoSave and Recovery.
    2876             :         But sometimes XModel->getArgs() does not contained this information
    2877             :         if implts_registerDocument() was called.
    2878             :         So we have to check a second time, if this property is set ....
    2879             :         Best place doing so is to check it immeditaly before saving
    2880             :         and supressingd saving the document then.
    2881             :         Of course removing the corresponding cache entry isnt an option.
    2882             :         Because it would disturb iteration over the cache !
    2883             :         So we ignore such documents only ...
    2884             :         Hopefully next time they are not inserted in our cache.
    2885             : */
    2886           0 : bool lc_checkIfSaveForbiddenByArguments(AutoRecovery::TDocumentInfo& rInfo)
    2887             : {
    2888           0 :     if (! rInfo.Document.is())
    2889           0 :         return true;
    2890             : 
    2891           0 :     utl::MediaDescriptor lDescriptor(rInfo.Document->getArgs());
    2892           0 :     bool bNoAutoSave = lDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_NOAUTOSAVE(), sal_False);
    2893             : 
    2894           0 :     return bNoAutoSave;
    2895             : }
    2896             : 
    2897           0 : AutoRecovery::ETimerType AutoRecovery::implts_saveDocs(       bool        bAllowUserIdleLoop,
    2898             :                                                               bool        bRemoveLockFiles,
    2899             :                                                         const DispatchParams* pParams           )
    2900             : {
    2901           0 :     css::uno::Reference< css::task::XStatusIndicator > xExternalProgress;
    2902           0 :     if (pParams)
    2903           0 :         xExternalProgress = pParams->m_xProgress;
    2904             : 
    2905           0 :     css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create(m_xContext);
    2906           0 :     OUString                              sBackupPath(SvtPathOptions().GetBackupPath());
    2907             : 
    2908           0 :     css::uno::Reference< css::frame::XController > xActiveController;
    2909           0 :     css::uno::Reference< css::frame::XModel >      xActiveModel;
    2910           0 :     css::uno::Reference< css::frame::XFrame >      xActiveFrame     = xDesktop->getActiveFrame();
    2911           0 :     if (xActiveFrame.is())
    2912           0 :         xActiveController = xActiveFrame->getController();
    2913           0 :     if (xActiveController.is())
    2914           0 :         xActiveModel = xActiveController->getModel();
    2915             : 
    2916             :     // Set the default timer action for our calli.
    2917             :     // Default = NORMAL_AUTOSAVE
    2918             :     // We return a suggestion for an active timer only.
    2919             :     // It will be ignored if the timer was disabled by the user ...
    2920             :     // Further this state can be set to USER_IDLE only later in this method.
    2921             :     // Its not allowed to reset such state then. Because we must know, if
    2922             :     // there exists POSTPONED documents. see below ...
    2923           0 :     AutoRecovery::ETimerType eTimer = AutoRecovery::E_NORMAL_AUTOSAVE_INTERVALL;
    2924             : 
    2925           0 :     sal_Int32 eJob = m_eJob;
    2926             : 
    2927           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
    2928             : 
    2929             :     /* SAFE */ {
    2930           0 :     osl::ResettableMutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    2931             : 
    2932             :     // This list will be filled with every document
    2933             :     // which should be saved as last one. E.g. if it was used
    2934             :     // already for an UI save operation => crashed ... and
    2935             :     // now we try to save it again ... which can fail again ( of course .-) ).
    2936           0 :     ::std::vector< AutoRecovery::TDocumentList::iterator > lDangerousDocs;
    2937             : 
    2938           0 :     AutoRecovery::TDocumentList::iterator pIt;
    2939           0 :     for (  pIt  = m_lDocCache.begin();
    2940           0 :            pIt != m_lDocCache.end();
    2941             :          ++pIt                       )
    2942             :     {
    2943           0 :         AutoRecovery::TDocumentInfo aInfo = *pIt;
    2944             : 
    2945             :         // WORKAROUND... Since the documents are not closed the lock file must be removed explicitly
    2946           0 :         if ( bRemoveLockFiles )
    2947           0 :             lc_removeLockFile( aInfo );
    2948             : 
    2949             :         // WORKAROUND ... see comment of this method
    2950           0 :         if (lc_checkIfSaveForbiddenByArguments(aInfo))
    2951           0 :             continue;
    2952             : 
    2953             :         // already auto saved during this session :-)
    2954             :         // This state must be reset for all documents
    2955             :         // if timer is started with normnal AutoSaveTimerIntervall!
    2956           0 :         if ((aInfo.DocumentState & AutoRecovery::E_HANDLED) == AutoRecovery::E_HANDLED)
    2957           0 :             continue;
    2958             : 
    2959             :         // Not modified documents are not saved.
    2960             :         // We safe an information about the URL only!
    2961           0 :         Reference< XDocumentRecovery > xDocRecover( aInfo.Document, UNO_QUERY_THROW );
    2962           0 :         if ( !xDocRecover->wasModifiedSinceLastSave() )
    2963             :         {
    2964           0 :             aInfo.DocumentState |= AutoRecovery::E_HANDLED;
    2965           0 :             continue;
    2966             :         }
    2967             : 
    2968             :         // check if this document is still used by a concurrent save operation
    2969             :         // e.g. if the user tried to save via UI.
    2970             :         // Handle it in the following way:
    2971             :         // i)   For an AutoSave ... ignore this document! It will be saved and next time we will (hopefully)
    2972             :         //      get a notification about the state of this operation.
    2973             :         //      And if a document was saved by the user we can remove our temp. file. But that will be done inside
    2974             :         //      our callback for SaveDone notification.
    2975             :         // ii)  For a CrashSave ... add it to the list of dangerous documents and
    2976             :         //      save it after all other documents was saved successfully. That decrease
    2977             :         //      the chance for a crash inside a crash.
    2978             :         //      On the other side it's not necessary for documents, which are not modified.
    2979             :         //      They can be handled normaly - means we patch the corresponding configuration entry only.
    2980             :         // iii) For a SessionSave ... ignore it! There is no time to wait for this save operation.
    2981             :         //      Because the WindowManager will kill the process if it doesn't react immediately.
    2982             :         //      On the other side we cant risk a concurrent save request ... because we know
    2983             :         //      that it will produce a crash.
    2984             : 
    2985             :         // Attention: Because eJob is used as a flag field, you have to check for the worst case first.
    2986             :         // E.g. a CrashSave can overwrite an AutoSave. So you have to check for a CrashSave before an AutoSave!
    2987           0 :         if (aInfo.UsedForSaving)
    2988             :         {
    2989           0 :             if ((eJob & AutoRecovery::E_EMERGENCY_SAVE) == AutoRecovery::E_EMERGENCY_SAVE)
    2990             :             {
    2991           0 :                 lDangerousDocs.push_back(pIt);
    2992           0 :                 continue;
    2993             :             }
    2994             :             else
    2995           0 :             if ((eJob & AutoRecovery::E_SESSION_SAVE) == AutoRecovery::E_SESSION_SAVE)
    2996             :             {
    2997           0 :                 continue;
    2998             :             }
    2999             :             else
    3000           0 :             if ((eJob & AutoRecovery::E_AUTO_SAVE) == AutoRecovery::E_AUTO_SAVE)
    3001             :             {
    3002           0 :                 eTimer = AutoRecovery::E_POLL_TILL_AUTOSAVE_IS_ALLOWED;
    3003           0 :                 aInfo.DocumentState |= AutoRecovery::E_POSTPONED;
    3004           0 :                 continue;
    3005             :             }
    3006             :         }
    3007             : 
    3008             :         // a) Document was not postponed - and is     active now. => postpone it (restart timer, restart loop)
    3009             :         // b) Document was not postponed - and is not active now. => save it
    3010             :         // c) Document was     postponed - and is not active now. => save it
    3011             :         // d) Document was     postponed - and is     active now. => save it (because user idle was checked already)
    3012           0 :         bool bActive       = (xActiveModel == aInfo.Document);
    3013           0 :         bool bWasPostponed = ((aInfo.DocumentState & AutoRecovery::E_POSTPONED) == AutoRecovery::E_POSTPONED);
    3014             : 
    3015           0 :         if (
    3016           0 :             ! bWasPostponed &&
    3017             :               bActive
    3018             :            )
    3019             :         {
    3020           0 :             aInfo.DocumentState |= AutoRecovery::E_POSTPONED;
    3021           0 :             *pIt = aInfo;
    3022             :             // postponed documents will be saved if this method is called again!
    3023             :             // That can be done by an outside started timer           => E_POLL_FOR_USER_IDLE (if normal AutoSave is active)
    3024             :             // 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!)
    3025           0 :             eTimer = AutoRecovery::E_POLL_FOR_USER_IDLE;
    3026           0 :             if (!bAllowUserIdleLoop)
    3027           0 :                 eTimer = AutoRecovery::E_CALL_ME_BACK;
    3028           0 :             continue;
    3029             :         }
    3030             : 
    3031             :         // b, c, d)
    3032             :         // } /* SAFE */
    3033           0 :         g.clear();
    3034             :         // changing of aInfo and flushing it is done inside implts_saveOneDoc!
    3035           0 :         implts_saveOneDoc(sBackupPath, aInfo, xExternalProgress);
    3036           0 :         implts_informListener(eJob, AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &aInfo));
    3037           0 :         g.reset();
    3038             :         // /* SAFE */ {
    3039             : 
    3040           0 :         *pIt = aInfo;
    3041           0 :     }
    3042             : 
    3043             :     // Did we have some "dangerous candidates" ?
    3044             :     // Try to save it ... but may be it will fail !
    3045           0 :     ::std::vector< AutoRecovery::TDocumentList::iterator >::iterator pIt2;
    3046           0 :     for (  pIt2  = lDangerousDocs.begin();
    3047           0 :            pIt2 != lDangerousDocs.end();
    3048             :          ++pIt2                          )
    3049             :     {
    3050           0 :         pIt = *pIt2;
    3051           0 :         AutoRecovery::TDocumentInfo aInfo = *pIt;
    3052             : 
    3053             :         // } /* SAFE */
    3054           0 :         g.clear();
    3055             :         // changing of aInfo and flushing it is done inside implts_saveOneDoc!
    3056           0 :         implts_saveOneDoc(sBackupPath, aInfo, xExternalProgress);
    3057           0 :         implts_informListener(eJob, AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &aInfo));
    3058           0 :         g.reset();
    3059             :         // /* SAFE */ {
    3060             : 
    3061           0 :         *pIt = aInfo;
    3062           0 :     }
    3063             : 
    3064             :     } /* SAFE */
    3065             : 
    3066           0 :     return eTimer;
    3067             : }
    3068             : 
    3069           0 : void AutoRecovery::implts_saveOneDoc(const OUString&                                    sBackupPath      ,
    3070             :                                            AutoRecovery::TDocumentInfo&                        rInfo            ,
    3071             :                                      const css::uno::Reference< css::task::XStatusIndicator >& xExternalProgress)
    3072             : {
    3073             :     // no document? => can occur if we loaded our configuration with files,
    3074             :     // which couldnt be recovered successfully. In such case we have all needed information
    3075             :     // excepting the real document instance!
    3076             : 
    3077             :     // TODO: search right place, where such "dead files" can be removed from the configuration!
    3078           0 :     if (!rInfo.Document.is())
    3079           0 :         return;
    3080             : 
    3081           0 :     utl::MediaDescriptor lOldArgs(rInfo.Document->getArgs());
    3082           0 :     implts_generateNewTempURL(sBackupPath, lOldArgs, rInfo);
    3083             : 
    3084             :     // if the document was loaded with a password, it should be
    3085             :     // stored with password
    3086           0 :     utl::MediaDescriptor lNewArgs;
    3087             :     css::uno::Sequence< css::beans::NamedValue > aEncryptionData =
    3088           0 :         lOldArgs.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ENCRYPTIONDATA(),
    3089           0 :                 css::uno::Sequence< css::beans::NamedValue >());
    3090           0 :     if (aEncryptionData.getLength() > 0)
    3091           0 :         lNewArgs[utl::MediaDescriptor::PROP_ENCRYPTIONDATA()] <<= aEncryptionData;
    3092             : 
    3093             :     // Further it must be saved using the default file format of that application.
    3094             :     // Otherwhise we will some data lost.
    3095           0 :     if (!rInfo.DefaultFilter.isEmpty())
    3096           0 :         lNewArgs[utl::MediaDescriptor::PROP_FILTERNAME()] <<= rInfo.DefaultFilter;
    3097             : 
    3098             :     // prepare frame/document/mediadescriptor in a way, that it uses OUR progress .-)
    3099           0 :     if (xExternalProgress.is())
    3100           0 :         lNewArgs[utl::MediaDescriptor::PROP_STATUSINDICATOR()] <<= xExternalProgress;
    3101           0 :     impl_establishProgress(rInfo, lNewArgs, css::uno::Reference< css::frame::XFrame >());
    3102             : 
    3103             :     // #i66598# use special handling of property "DocumentBaseURL" (it must be an empty string!)
    3104             :     // for make hyperlinks working
    3105           0 :     lNewArgs[utl::MediaDescriptor::PROP_DOCUMENTBASEURL()] <<= OUString();
    3106             : 
    3107             :     // try to save this document as a new temp file everytimes.
    3108             :     // Mark AutoSave state as "INCOMPLETE" if it failed.
    3109             :     // Because the last temp file is to old and does not include all changes.
    3110           0 :     Reference< XDocumentRecovery > xDocRecover(rInfo.Document, css::uno::UNO_QUERY_THROW);
    3111             : 
    3112             :     // safe the state about "trying to save"
    3113             :     // ... we need it for recovery if e.g. a crash occurs inside next line!
    3114           0 :     rInfo.DocumentState |= AutoRecovery::E_TRY_SAVE;
    3115           0 :     implts_flushConfigItem(rInfo);
    3116             : 
    3117           0 :     sal_Int32 nRetry = RETRY_STORE_ON_FULL_DISC_FOREVER;
    3118           0 :     bool  bError = false;
    3119           0 :     do
    3120             :     {
    3121             :         try
    3122             :         {
    3123           0 :             xDocRecover->storeToRecoveryFile( rInfo.NewTempURL, lNewArgs.getAsConstPropertyValueList() );
    3124             : 
    3125             :             // if userautosave is enabled, also save to the original file
    3126           0 :             if((m_eJob & AutoRecovery::E_USER_AUTO_SAVE) == AutoRecovery::E_USER_AUTO_SAVE)
    3127             :             {
    3128           0 :                 Reference< XStorable > xDocSave(rInfo.Document, css::uno::UNO_QUERY_THROW);
    3129           0 :                 xDocSave->store();
    3130             :             }
    3131             : 
    3132             : #ifdef TRIGGER_FULL_DISC_CHECK
    3133             :             throw css::uno::Exception();
    3134             : #else  // TRIGGER_FULL_DISC_CHECK
    3135             : 
    3136           0 :             bError = false;
    3137           0 :             nRetry = 0;
    3138             : #endif // TRIGGER_FULL_DISC_CHECK
    3139             :         }
    3140           0 :         catch(const css::uno::Exception&)
    3141             :         {
    3142           0 :             bError = true;
    3143             : 
    3144             :             // a) FULL DISC seems to be the problem behind                              => show error and retry it forever (e.g. retry=300)
    3145             :             // b) unknown problem (may be locking problem)                              => reset RETRY value to more useful value(!) (e.g. retry=3)
    3146             :             // c) unknown problem (may be locking problem) + 1..2 repeating operations  => throw the original exception to force generation of a stacktrace !
    3147             : 
    3148             :             sal_Int32 nMinSpaceDocSave;
    3149             :             /* SAFE */ {
    3150           0 :             osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    3151           0 :             nMinSpaceDocSave = m_nMinSpaceDocSave;
    3152             :             } /* SAFE */
    3153             : 
    3154           0 :             if (! impl_enoughDiscSpace(nMinSpaceDocSave))
    3155           0 :                 AutoRecovery::impl_showFullDiscError();
    3156           0 :             else if (nRetry > RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL)
    3157           0 :                 nRetry = RETRY_STORE_ON_MIGHT_FULL_DISC_USEFULL;
    3158           0 :             else if (nRetry <= GIVE_UP_RETRY)
    3159           0 :                 throw; // force stacktrace to know if there exist might other reasons, why an AutoSave can fail !!!
    3160             : 
    3161           0 :             --nRetry;
    3162             :         }
    3163             :     }
    3164             :     while(nRetry>0);
    3165             : 
    3166           0 :     if (! bError)
    3167             :     {
    3168             :         // safe the state about success
    3169             :         // ... you know the reason: to know it on recovery time if next line crash .-)
    3170           0 :         rInfo.DocumentState &= ~AutoRecovery::E_TRY_SAVE;
    3171           0 :         rInfo.DocumentState |=  AutoRecovery::E_HANDLED;
    3172           0 :         rInfo.DocumentState |=  AutoRecovery::E_SUCCEDED;
    3173             :     }
    3174             :     else
    3175             :     {
    3176             :         // safe the state about error ...
    3177           0 :         rInfo.NewTempURL     = "";
    3178           0 :         rInfo.DocumentState &= ~AutoRecovery::E_TRY_SAVE;
    3179           0 :         rInfo.DocumentState |=  AutoRecovery::E_HANDLED;
    3180           0 :         rInfo.DocumentState |=  AutoRecovery::E_INCOMPLETE;
    3181             :     }
    3182             : 
    3183             :     // make sure the progress isnt referred any longer
    3184           0 :     impl_forgetProgress(rInfo, lNewArgs, css::uno::Reference< css::frame::XFrame >());
    3185             : 
    3186             :     // try to remove the old temp file.
    3187             :     // Ignore any error here. We have a new temp file, which is up to date.
    3188             :     // The only thing is: we fill the disk with temp files, if we cant remove old ones :-)
    3189           0 :     OUString sRemoveFile      = rInfo.OldTempURL;
    3190           0 :     rInfo.OldTempURL = rInfo.NewTempURL;
    3191           0 :     rInfo.NewTempURL = "";
    3192             : 
    3193           0 :     implts_flushConfigItem(rInfo);
    3194             : 
    3195             :     // We must know if the user modifies the document again ...
    3196           0 :     implts_startModifyListeningOnDoc(rInfo);
    3197             : 
    3198           0 :     AutoRecovery::st_impl_removeFile(sRemoveFile);
    3199             : }
    3200             : 
    3201           0 : AutoRecovery::ETimerType AutoRecovery::implts_openDocs(const DispatchParams& aParams)
    3202             : {
    3203           0 :     AutoRecovery::ETimerType eTimer = AutoRecovery::E_DONT_START_TIMER;
    3204             : 
    3205           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
    3206             : 
    3207             :     /* SAFE */ {
    3208           0 :     osl::ResettableMutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    3209             : 
    3210           0 :     sal_Int32                             eJob = m_eJob;
    3211           0 :     AutoRecovery::TDocumentList::iterator pIt;
    3212           0 :     for (  pIt  = m_lDocCache.begin();
    3213           0 :            pIt != m_lDocCache.end();
    3214             :          ++pIt                       )
    3215             :     {
    3216           0 :         AutoRecovery::TDocumentInfo& rInfo = *pIt;
    3217             : 
    3218             :         // Such documents are already loaded by the last loop.
    3219             :         // Dont check E_SUCCEDED here! Its may be the final state of an AutoSave
    3220             :         // operation before!!!
    3221           0 :         if ((rInfo.DocumentState & AutoRecovery::E_HANDLED) == AutoRecovery::E_HANDLED)
    3222           0 :             continue;
    3223             : 
    3224             :         // a1,b1,c1,d2,e2,f2)
    3225           0 :         if ((rInfo.DocumentState & AutoRecovery::E_DAMAGED) == AutoRecovery::E_DAMAGED)
    3226             :         {
    3227             :             // dont forget to inform listener! May be this document was
    3228             :             // damaged on last saving time ...
    3229             :             // Then our listener need this notification.
    3230             :             // If it was damaged during last "try to open" ...
    3231             :             // it will be notified more then once. SH.. HAPPENS ...
    3232             :             // } /* SAFE */
    3233           0 :             g.clear();
    3234             :             implts_informListener(eJob,
    3235           0 :                 AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &rInfo));
    3236           0 :             g.reset();
    3237             :             // /* SAFE */ {
    3238           0 :             continue;
    3239             :         }
    3240             : 
    3241           0 :         utl::MediaDescriptor lDescriptor;
    3242             : 
    3243             :         // its an UI feature - so the "USER" itself must be set as referer
    3244           0 :         lDescriptor[utl::MediaDescriptor::PROP_REFERRER()] <<= OUString(REFERRER_USER);
    3245           0 :         lDescriptor[utl::MediaDescriptor::PROP_SALVAGEDFILE()] <<= OUString();
    3246             : 
    3247             :         // recovered documents are loaded hidden, and shown all at once, later
    3248           0 :         lDescriptor[utl::MediaDescriptor::PROP_HIDDEN()] <<= true;
    3249             : 
    3250           0 :         if (aParams.m_xProgress.is())
    3251           0 :             lDescriptor[utl::MediaDescriptor::PROP_STATUSINDICATOR()] <<= aParams.m_xProgress;
    3252             : 
    3253             :         bool bBackupWasTried   = (
    3254           0 :                                         ((rInfo.DocumentState & AutoRecovery::E_TRY_LOAD_BACKUP  ) == AutoRecovery::E_TRY_LOAD_BACKUP) || // temp. state!
    3255           0 :                                         ((rInfo.DocumentState & AutoRecovery::E_INCOMPLETE       ) == AutoRecovery::E_INCOMPLETE     )    // transport TRY_LOAD_BACKUP from last loop to this new one!
    3256           0 :                                      );
    3257           0 :         bool bOriginalWasTried = ((rInfo.DocumentState & AutoRecovery::E_TRY_LOAD_ORIGINAL) == AutoRecovery::E_TRY_LOAD_ORIGINAL);
    3258             : 
    3259           0 :         if (bBackupWasTried)
    3260             :         {
    3261           0 :             if (!bOriginalWasTried)
    3262             :             {
    3263           0 :                 rInfo.DocumentState |= AutoRecovery::E_INCOMPLETE;
    3264             :                 // try original URL ... ! dont continue with next item here ...
    3265             :             }
    3266             :             else
    3267             :             {
    3268           0 :                 rInfo.DocumentState |= AutoRecovery::E_DAMAGED;
    3269           0 :                 continue;
    3270             :             }
    3271             :         }
    3272             : 
    3273           0 :         OUString sLoadOriginalURL;
    3274           0 :         OUString sLoadBackupURL;
    3275             : 
    3276           0 :         if (!bBackupWasTried)
    3277           0 :             sLoadBackupURL = rInfo.OldTempURL;
    3278             : 
    3279           0 :         if (!rInfo.OrgURL.isEmpty())
    3280             :         {
    3281           0 :             sLoadOriginalURL = rInfo.OrgURL;
    3282             :         }
    3283           0 :         else if (!rInfo.TemplateURL.isEmpty())
    3284             :         {
    3285           0 :             sLoadOriginalURL = rInfo.TemplateURL;
    3286           0 :             lDescriptor[utl::MediaDescriptor::PROP_ASTEMPLATE()]   <<= sal_True;
    3287           0 :             lDescriptor[utl::MediaDescriptor::PROP_TEMPLATENAME()] <<= rInfo.TemplateURL;
    3288             :         }
    3289           0 :         else if (!rInfo.FactoryURL.isEmpty())
    3290             :         {
    3291           0 :             sLoadOriginalURL = rInfo.FactoryURL;
    3292           0 :             lDescriptor[utl::MediaDescriptor::PROP_ASTEMPLATE()] <<= sal_True;
    3293             :         }
    3294             : 
    3295             :         // A "Salvaged" item must exists every time. The core can make something special then for recovery.
    3296             :         // Of course it should be the real file name of the original file, in case we load the temp. backup here.
    3297           0 :         OUString sURL;
    3298           0 :         if (!sLoadBackupURL.isEmpty())
    3299             :         {
    3300           0 :             sURL = sLoadBackupURL;
    3301           0 :             rInfo.DocumentState |= AutoRecovery::E_TRY_LOAD_BACKUP;
    3302           0 :             lDescriptor[utl::MediaDescriptor::PROP_SALVAGEDFILE()] <<= sLoadOriginalURL;
    3303             :         }
    3304           0 :         else if (!sLoadOriginalURL.isEmpty())
    3305             :         {
    3306           0 :             sURL = sLoadOriginalURL;
    3307           0 :             rInfo.DocumentState |= AutoRecovery::E_TRY_LOAD_ORIGINAL;
    3308             :         }
    3309             :         else
    3310           0 :             continue; // TODO ERROR!
    3311             : 
    3312           0 :         LoadEnv::initializeUIDefaults( m_xContext, lDescriptor, true, NULL );
    3313             : 
    3314             :         // } /* SAFE */
    3315           0 :         g.clear();
    3316             : 
    3317           0 :         implts_flushConfigItem(rInfo);
    3318             :         implts_informListener(eJob,
    3319           0 :             AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &rInfo));
    3320             : 
    3321             :         try
    3322             :         {
    3323           0 :             implts_openOneDoc(sURL, lDescriptor, rInfo);
    3324             :         }
    3325           0 :         catch(const css::uno::Exception&)
    3326             :         {
    3327           0 :             rInfo.DocumentState &= ~AutoRecovery::E_TRY_LOAD_BACKUP;
    3328           0 :             rInfo.DocumentState &= ~AutoRecovery::E_TRY_LOAD_ORIGINAL;
    3329           0 :             if (!sLoadBackupURL.isEmpty())
    3330             :             {
    3331           0 :                 rInfo.DocumentState |= AutoRecovery::E_INCOMPLETE;
    3332           0 :                 eTimer               = AutoRecovery::E_CALL_ME_BACK;
    3333             :             }
    3334             :             else
    3335             :             {
    3336           0 :                 rInfo.DocumentState |=  AutoRecovery::E_HANDLED;
    3337           0 :                 rInfo.DocumentState |=  AutoRecovery::E_DAMAGED;
    3338             :             }
    3339             : 
    3340           0 :             implts_flushConfigItem(rInfo, true);
    3341             :             implts_informListener(eJob,
    3342           0 :                 AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &rInfo));
    3343             : 
    3344             :             // /* SAFE */ {
    3345             :             // Needed for next loop!
    3346           0 :             g.reset();
    3347           0 :             continue;
    3348             :         }
    3349             : 
    3350           0 :         if (!rInfo.RealFilter.isEmpty())
    3351             :         {
    3352           0 :             utl::MediaDescriptor lPatchDescriptor(rInfo.Document->getArgs());
    3353           0 :             lPatchDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] <<= rInfo.RealFilter;
    3354           0 :             rInfo.Document->attachResource(rInfo.Document->getURL(), lPatchDescriptor.getAsConstPropertyValueList());
    3355             :                 // do *not* use sURL here. In case this points to the recovery file, it has already been passed
    3356             :                 // to recoverFromFile. Also, passing it here is logically wrong, as attachResource is intended
    3357             :                 // to take the logical file URL.
    3358             :         }
    3359             : 
    3360           0 :         css::uno::Reference< css::util::XModifiable > xModify(rInfo.Document, css::uno::UNO_QUERY);
    3361           0 :         if ( xModify.is() )
    3362             :         {
    3363           0 :             bool bModified = ((rInfo.DocumentState & AutoRecovery::E_MODIFIED) == AutoRecovery::E_MODIFIED);
    3364           0 :             xModify->setModified(bModified);
    3365             :         }
    3366             : 
    3367           0 :         rInfo.DocumentState &= ~AutoRecovery::E_TRY_LOAD_BACKUP;
    3368           0 :         rInfo.DocumentState &= ~AutoRecovery::E_TRY_LOAD_ORIGINAL;
    3369           0 :         rInfo.DocumentState |=  AutoRecovery::E_HANDLED;
    3370           0 :         rInfo.DocumentState |=  AutoRecovery::E_SUCCEDED;
    3371             : 
    3372           0 :         implts_flushConfigItem(rInfo);
    3373             :         implts_informListener(eJob,
    3374           0 :             AutoRecovery::implst_createFeatureStateEvent(eJob, OPERATION_UPDATE, &rInfo));
    3375             : 
    3376             :         /* Normaly we listen as XModifyListener on a document to know if a document was changed
    3377             :            since our last AutoSave. And we deregister us in case we know this state.
    3378             :            But directly after one document as recovered ... we must start listening.
    3379             :            Otherwhise the first "modify" doesn't reach us. Because we ourself called setModified()
    3380             :            on the document via API. And currently we dont listen for any events (not at theGlobalEventBroadcaster
    3381             :            nor at any document!).
    3382             :         */
    3383           0 :         implts_startModifyListeningOnDoc(rInfo);
    3384             : 
    3385             :         // /* SAFE */ {
    3386             :         // Needed for next loop. Dont unlock it again!
    3387           0 :         g.reset();
    3388           0 :     }
    3389             : 
    3390             :     } /* SAFE */
    3391             : 
    3392           0 :     return eTimer;
    3393             : }
    3394             : 
    3395           0 : void AutoRecovery::implts_openOneDoc(const OUString&               sURL       ,
    3396             :                                            utl::MediaDescriptor& lDescriptor,
    3397             :                                            AutoRecovery::TDocumentInfo&   rInfo      )
    3398             : {
    3399           0 :     css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create(m_xContext);
    3400             : 
    3401           0 :     ::std::vector< Reference< XComponent > > aCleanup;
    3402             :     try
    3403             :     {
    3404             :         // create a new document of the desired type
    3405           0 :         Reference< XModel2 > xModel(m_xContext->getServiceManager()->createInstanceWithContext(
    3406           0 :                     rInfo.FactoryService, m_xContext), UNO_QUERY_THROW);
    3407           0 :         aCleanup.push_back( xModel.get() );
    3408             : 
    3409             :         // put the filter name into the descriptor - we're not going to involve any type detection, so
    3410             :         // the document might be lost without the FilterName property
    3411           0 :         if ( (rInfo.DocumentState & AutoRecovery::E_TRY_LOAD_ORIGINAL) == AutoRecovery::E_TRY_LOAD_ORIGINAL)
    3412           0 :             lDescriptor[ utl::MediaDescriptor::PROP_FILTERNAME() ] <<= rInfo.RealFilter;
    3413             :         else
    3414           0 :             lDescriptor[ utl::MediaDescriptor::PROP_FILTERNAME() ] <<= rInfo.DefaultFilter;
    3415             : 
    3416           0 :         if ( sURL == rInfo.FactoryURL )
    3417             :         {
    3418             :             // if the document was a new, unmodified document, then there's nothing to recover, just to init
    3419           0 :             ENSURE_OR_THROW( ( rInfo.DocumentState & AutoRecovery::E_MODIFIED ) == 0,
    3420             :                 "unexpected document state" );
    3421           0 :             Reference< XLoadable > xModelLoad( xModel, UNO_QUERY_THROW );
    3422           0 :             xModelLoad->initNew();
    3423             : 
    3424             :             // TODO: remove load-process specific arguments from the descriptor, e.g. the status indicator
    3425           0 :             xModel->attachResource( sURL, lDescriptor.getAsConstPropertyValueList() );
    3426             :         }
    3427             :         else
    3428             :         {
    3429             :             // let it recover itself
    3430           0 :             Reference< XDocumentRecovery > xDocRecover( xModel, UNO_QUERY_THROW );
    3431           0 :             xDocRecover->recoverFromFile(
    3432             :                 sURL,
    3433           0 :                 lDescriptor.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_SALVAGEDFILE(), OUString() ),
    3434             :                 lDescriptor.getAsConstPropertyValueList()
    3435           0 :             );
    3436             : 
    3437             :             // No attachResource needed here. By definition (of XDocumentRecovery), the implementation is responsible
    3438             :             // for completely initializing the model, which includes attachResource (or equivalent), if required.
    3439             :         }
    3440             : 
    3441             :         // re-create all the views
    3442           0 :         ::std::vector< OUString > aViewsToRestore( rInfo.ViewNames.getLength() );
    3443           0 :         if ( rInfo.ViewNames.getLength() )
    3444           0 :             ::std::copy( rInfo.ViewNames.getConstArray(), rInfo.ViewNames.getConstArray() + rInfo.ViewNames.getLength(), aViewsToRestore.begin() );
    3445             :         // if we don't have views for whatever reason, then create a default-view, at least
    3446           0 :         if ( aViewsToRestore.empty() )
    3447           0 :             aViewsToRestore.push_back( OUString() );
    3448             : 
    3449           0 :         for (   ::std::vector< OUString >::const_iterator viewName = aViewsToRestore.begin();
    3450           0 :                 viewName != aViewsToRestore.end();
    3451             :                 ++viewName
    3452             :             )
    3453             :         {
    3454             :             // create a frame
    3455           0 :             Reference< XFrame > xTargetFrame = xDesktop->findFrame( SPECIALTARGET_BLANK, 0 );
    3456           0 :             aCleanup.push_back( xTargetFrame.get() );
    3457             : 
    3458             :             // create a view to the document
    3459           0 :             Reference< XController2 > xController;
    3460           0 :             if ( viewName->getLength() )
    3461             :             {
    3462           0 :                 xController.set( xModel->createViewController( *viewName, Sequence< css::beans::PropertyValue >(), xTargetFrame ), UNO_SET_THROW );
    3463             :             }
    3464             :             else
    3465             :             {
    3466           0 :                 xController.set( xModel->createDefaultViewController( xTargetFrame ), UNO_SET_THROW );
    3467             :             }
    3468             : 
    3469             :             // introduce model/view/controller to each other
    3470           0 :             xController->attachModel( xModel.get() );
    3471           0 :             xModel->connectController( xController.get() );
    3472           0 :             xTargetFrame->setComponent( xController->getComponentWindow(), xController.get() );
    3473           0 :             xController->attachFrame( xTargetFrame );
    3474           0 :             xModel->setCurrentController( xController.get() );
    3475           0 :         }
    3476             : 
    3477           0 :         rInfo.Document = xModel.get();
    3478             :     }
    3479           0 :     catch(const css::uno::RuntimeException&)
    3480             :     {
    3481           0 :         throw;
    3482             :     }
    3483           0 :     catch(const css::uno::Exception&)
    3484             :     {
    3485           0 :         Any aCaughtException( ::cppu::getCaughtException() );
    3486             : 
    3487             :         // clean up
    3488           0 :         for (   ::std::vector< Reference< XComponent > >::const_iterator component = aCleanup.begin();
    3489           0 :                 component != aCleanup.end();
    3490             :                 ++component
    3491             :             )
    3492             :         {
    3493           0 :             css::uno::Reference< css::util::XCloseable > xClose( *component, css::uno::UNO_QUERY );
    3494           0 :             if ( xClose.is() )
    3495           0 :                 xClose->close( sal_True );
    3496             :             else
    3497           0 :                 (*component)->dispose();
    3498           0 :         }
    3499             : 
    3500             :         // re-throw
    3501           0 :         OUStringBuffer sMsg(256);
    3502           0 :         sMsg.appendAscii("Recovery of \"");
    3503           0 :         sMsg.append     (sURL            );
    3504           0 :         sMsg.appendAscii("\" failed."    );
    3505             : 
    3506             :         throw css::lang::WrappedTargetException(
    3507             :             sMsg.makeStringAndClear(),
    3508             :             static_cast< css::frame::XDispatch* >(this),
    3509             :             aCaughtException
    3510           0 :         );
    3511           0 :     }
    3512           0 : }
    3513             : 
    3514           0 : void AutoRecovery::implts_generateNewTempURL(const OUString&               sBackupPath     ,
    3515             :                                                    utl::MediaDescriptor& /*rMediaDescriptor*/,
    3516             :                                                    AutoRecovery::TDocumentInfo&   rInfo           )
    3517             : {
    3518             :     // specify URL for saving (which points to a temp file inside backup directory)
    3519             :     // and define an unique name, so we can locate it later.
    3520             :     // This unique name must solve an optimization problem too!
    3521             :     // In case we are asked to save unmodified documents too - and one of them
    3522             :     // is an empty one (because it was new created using e.g. an URL private:factory/...)
    3523             :     // we should not save it really. Then we put the information about such "empty document"
    3524             :     // into the configuration and dont create any recovery file on disk.
    3525             :     // We use the title of the document to make it unique.
    3526           0 :     OUStringBuffer sUniqueName;
    3527           0 :     if (!rInfo.OrgURL.isEmpty())
    3528             :     {
    3529           0 :         css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
    3530           0 :         css::util::URL aURL;
    3531           0 :         aURL.Complete = rInfo.OrgURL;
    3532           0 :         xParser->parseStrict(aURL);
    3533           0 :         sUniqueName.append(aURL.Name);
    3534             :     }
    3535           0 :     else if (!rInfo.FactoryURL.isEmpty())
    3536           0 :         sUniqueName.appendAscii("untitled");
    3537           0 :     sUniqueName.appendAscii("_");
    3538             : 
    3539             :     // TODO: Must we strip some illegal signes - if we use the title?
    3540             : 
    3541           0 :     OUString sName(sUniqueName.makeStringAndClear());
    3542           0 :     OUString sExtension(rInfo.Extension);
    3543           0 :     OUString sPath(sBackupPath);
    3544           0 :     ::utl::TempFile aTempFile(sName, &sExtension, &sPath);
    3545             : 
    3546           0 :     rInfo.NewTempURL = aTempFile.GetURL();
    3547           0 : }
    3548             : 
    3549           0 : void AutoRecovery::implts_informListener(      sal_Int32                      eJob  ,
    3550             :                                          const css::frame::FeatureStateEvent& aEvent)
    3551             : {
    3552             :     // Helper shares mutex with us -> threadsafe!
    3553           0 :     ::cppu::OInterfaceContainerHelper* pListenerForURL = 0;
    3554           0 :     OUString                    sJob            = AutoRecovery::implst_getJobDescription(eJob);
    3555             : 
    3556             :     // inform listener, which are registered for any URLs(!)
    3557           0 :     pListenerForURL = m_lListener.getContainer(sJob);
    3558           0 :     if(pListenerForURL != 0)
    3559             :     {
    3560           0 :         ::cppu::OInterfaceIteratorHelper pIt(*pListenerForURL);
    3561           0 :         while(pIt.hasMoreElements())
    3562             :         {
    3563             :             try
    3564             :             {
    3565           0 :                 css::uno::Reference< css::frame::XStatusListener > xListener(((css::frame::XStatusListener*)pIt.next()), css::uno::UNO_QUERY);
    3566           0 :                 xListener->statusChanged(aEvent);
    3567             :             }
    3568           0 :             catch(const css::uno::RuntimeException&)
    3569             :             {
    3570           0 :                 pIt.remove();
    3571             :             }
    3572           0 :         }
    3573           0 :     }
    3574           0 : }
    3575             : 
    3576           0 : OUString AutoRecovery::implst_getJobDescription(sal_Int32 eJob)
    3577             : {
    3578             :     // describe the current running operation
    3579           0 :     OUStringBuffer sFeature(256);
    3580           0 :     sFeature.append(CMD_PROTOCOL);
    3581             : 
    3582             :     // Attention: Because "eJob" is used as a flag field the order of checking these
    3583             :     // flags is important. We must preferr job with higher priorities!
    3584             :     // E.g. EmergencySave has an higher prio then AutoSave ...
    3585             :     // On the other side there exist a well defined order between two different jobs.
    3586             :     // e.g. PrepareEmergencySave must be done before EmergencySave is started of course.
    3587             : 
    3588           0 :     if ((eJob & AutoRecovery::E_PREPARE_EMERGENCY_SAVE) == AutoRecovery::E_PREPARE_EMERGENCY_SAVE)
    3589           0 :         sFeature.append(CMD_DO_PREPARE_EMERGENCY_SAVE);
    3590           0 :     else if ((eJob & AutoRecovery::E_EMERGENCY_SAVE) == AutoRecovery::E_EMERGENCY_SAVE)
    3591           0 :         sFeature.append(CMD_DO_EMERGENCY_SAVE);
    3592           0 :     else if ((eJob & AutoRecovery::E_RECOVERY) == AutoRecovery::E_RECOVERY)
    3593           0 :         sFeature.append(CMD_DO_RECOVERY);
    3594           0 :     else if ((eJob & AutoRecovery::E_SESSION_SAVE) == AutoRecovery::E_SESSION_SAVE)
    3595           0 :         sFeature.append(CMD_DO_SESSION_SAVE);
    3596           0 :     else if ((eJob & AutoRecovery::E_SESSION_QUIET_QUIT) == AutoRecovery::E_SESSION_QUIET_QUIT)
    3597           0 :         sFeature.append(CMD_DO_SESSION_QUIET_QUIT);
    3598           0 :     else if ((eJob & AutoRecovery::E_SESSION_RESTORE) == AutoRecovery::E_SESSION_RESTORE)
    3599           0 :         sFeature.append(CMD_DO_SESSION_RESTORE);
    3600           0 :     else if ((eJob & AutoRecovery::E_ENTRY_BACKUP) == AutoRecovery::E_ENTRY_BACKUP)
    3601           0 :         sFeature.append(CMD_DO_ENTRY_BACKUP);
    3602           0 :     else if ((eJob & AutoRecovery::E_ENTRY_CLEANUP) == AutoRecovery::E_ENTRY_CLEANUP)
    3603           0 :         sFeature.append(CMD_DO_ENTRY_CLEANUP);
    3604           0 :     else if ((eJob & AutoRecovery::E_AUTO_SAVE) == AutoRecovery::E_AUTO_SAVE)
    3605           0 :         sFeature.append(CMD_DO_AUTO_SAVE);
    3606           0 :     else if ( eJob != AutoRecovery::E_NO_JOB )
    3607             :         SAL_INFO("fwk", "AutoRecovery::implst_getJobDescription(): Invalid job identifier detected.");
    3608             : 
    3609           0 :     return sFeature.makeStringAndClear();
    3610             : }
    3611             : 
    3612           0 : sal_Int32 AutoRecovery::implst_classifyJob(const css::util::URL& aURL)
    3613             : {
    3614           0 :     if ( aURL.Protocol == CMD_PROTOCOL )
    3615             :     {
    3616           0 :         if ( aURL.Path == CMD_DO_PREPARE_EMERGENCY_SAVE )
    3617           0 :             return AutoRecovery::E_PREPARE_EMERGENCY_SAVE;
    3618           0 :         else if ( aURL.Path == CMD_DO_EMERGENCY_SAVE )
    3619           0 :             return AutoRecovery::E_EMERGENCY_SAVE;
    3620           0 :         else if ( aURL.Path == CMD_DO_RECOVERY )
    3621           0 :             return AutoRecovery::E_RECOVERY;
    3622           0 :         else if ( aURL.Path == CMD_DO_ENTRY_BACKUP )
    3623           0 :             return AutoRecovery::E_ENTRY_BACKUP;
    3624           0 :         else if ( aURL.Path == CMD_DO_ENTRY_CLEANUP )
    3625           0 :             return AutoRecovery::E_ENTRY_CLEANUP;
    3626           0 :         else if ( aURL.Path == CMD_DO_SESSION_SAVE )
    3627           0 :             return AutoRecovery::E_SESSION_SAVE;
    3628           0 :         else if ( aURL.Path == CMD_DO_SESSION_QUIET_QUIT )
    3629           0 :             return AutoRecovery::E_SESSION_QUIET_QUIT;
    3630           0 :         else if ( aURL.Path == CMD_DO_SESSION_RESTORE )
    3631           0 :             return AutoRecovery::E_SESSION_RESTORE;
    3632           0 :         else if ( aURL.Path == CMD_DO_DISABLE_RECOVERY )
    3633           0 :             return AutoRecovery::E_DISABLE_AUTORECOVERY;
    3634           0 :         else if ( aURL.Path == CMD_DO_SET_AUTOSAVE_STATE )
    3635           0 :             return AutoRecovery::E_SET_AUTOSAVE_STATE;
    3636             :     }
    3637             : 
    3638             :     SAL_INFO("fwk", "AutoRecovery::implts_classifyJob(): Invalid URL (protocol).");
    3639           0 :     return AutoRecovery::E_NO_JOB;
    3640             : }
    3641             : 
    3642           0 : css::frame::FeatureStateEvent AutoRecovery::implst_createFeatureStateEvent(      sal_Int32                    eJob      ,
    3643             :                                                                            const OUString&             sEventType,
    3644             :                                                                                  AutoRecovery::TDocumentInfo* pInfo     )
    3645             : {
    3646           0 :     css::frame::FeatureStateEvent aEvent;
    3647           0 :     aEvent.FeatureURL.Complete   = AutoRecovery::implst_getJobDescription(eJob);
    3648           0 :     aEvent.FeatureDescriptor     = sEventType;
    3649             : 
    3650           0 :     if (pInfo && sEventType == OPERATION_UPDATE)
    3651             :     {
    3652             :         // pack rInfo for transport via UNO
    3653           0 :         ::comphelper::NamedValueCollection aInfo;
    3654           0 :         aInfo.put( OUString(CFG_ENTRY_PROP_ID), pInfo->ID );
    3655           0 :         aInfo.put( OUString(CFG_ENTRY_PROP_ORIGINALURL), pInfo->OrgURL );
    3656           0 :         aInfo.put( OUString(CFG_ENTRY_PROP_FACTORYURL), pInfo->FactoryURL );
    3657           0 :         aInfo.put( OUString(CFG_ENTRY_PROP_TEMPLATEURL), pInfo->TemplateURL );
    3658           0 :         aInfo.put( OUString(CFG_ENTRY_PROP_TEMPURL), pInfo->OldTempURL.isEmpty() ? pInfo->NewTempURL : pInfo->OldTempURL );
    3659           0 :         aInfo.put( OUString(CFG_ENTRY_PROP_MODULE), pInfo->AppModule);
    3660           0 :         aInfo.put( OUString(CFG_ENTRY_PROP_TITLE), pInfo->Title);
    3661           0 :         aInfo.put( OUString(CFG_ENTRY_PROP_VIEWNAMES), pInfo->ViewNames);
    3662           0 :         aInfo.put( OUString(CFG_ENTRY_PROP_DOCUMENTSTATE), pInfo->DocumentState);
    3663             : 
    3664           0 :         aEvent.State <<= aInfo.getPropertyValues();
    3665             :     }
    3666             : 
    3667           0 :     return aEvent;
    3668             : }
    3669             : 
    3670           0 : void AutoRecovery::implts_resetHandleStates(bool /*bLoadCache*/)
    3671             : {
    3672           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
    3673             : 
    3674             :     /* SAFE */ {
    3675           0 :     osl::ResettableMutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    3676             : 
    3677           0 :     AutoRecovery::TDocumentList::iterator pIt;
    3678           0 :     for (  pIt  = m_lDocCache.begin();
    3679           0 :            pIt != m_lDocCache.end();
    3680             :          ++pIt                       )
    3681             :     {
    3682           0 :         AutoRecovery::TDocumentInfo& rInfo = *pIt;
    3683           0 :         rInfo.DocumentState &= ~AutoRecovery::E_HANDLED;
    3684           0 :         rInfo.DocumentState &= ~AutoRecovery::E_POSTPONED;
    3685             : 
    3686             :         // } /* SAFE */
    3687           0 :         g.clear();
    3688           0 :         implts_flushConfigItem(rInfo);
    3689           0 :         g.reset();
    3690             :         // /* SAFE */ {
    3691           0 :     }
    3692           0 :     } /* SAFE */
    3693           0 : }
    3694             : 
    3695           0 : void AutoRecovery::implts_prepareEmergencySave()
    3696             : {
    3697             :     // Be sure to know all open documents really .-)
    3698           0 :     implts_verifyCacheAgainstDesktopDocumentList();
    3699             : 
    3700             :     // hide all docs, so the user cant disturb our emergency save .-)
    3701           0 :     implts_changeAllDocVisibility(false);
    3702           0 : }
    3703             : 
    3704           0 : void AutoRecovery::implts_doEmergencySave(const DispatchParams& aParams)
    3705             : {
    3706             :     // Write a hint "we chrashed" into the configuration, so
    3707             :     // the error report tool is started too in case no recovery
    3708             :     // documents exists and was saved.
    3709             :     ::comphelper::ConfigurationHelper::writeDirectKey(
    3710             :         m_xContext,
    3711             :         OUString(CFG_PACKAGE_RECOVERY),
    3712             :         OUString(CFG_PATH_RECOVERYINFO),
    3713             :         OUString(CFG_ENTRY_CRASHED),
    3714             :         css::uno::makeAny(sal_True),
    3715           0 :         ::comphelper::ConfigurationHelper::E_STANDARD);
    3716             : 
    3717             :     // for all docs, store their current view/names in the configurtion
    3718           0 :     implts_persistAllActiveViewNames();
    3719             : 
    3720             :     // The called method for saving documents runs
    3721             :     // during normal AutoSave more then once. Because
    3722             :     // it postpone active documents and save it later.
    3723             :     // That is normaly done by recalling it from a timer.
    3724             :     // Here we must do it immediately!
    3725             :     // Of course this method returns the right state -
    3726             :     // because it knows, that we are running in ERMERGENCY SAVE mode .-)
    3727             : 
    3728           0 :     bool                 bAllowUserIdleLoop = false; // not allowed to change that .-)
    3729           0 :     AutoRecovery::ETimerType eSuggestedTimer    = AutoRecovery::E_DONT_START_TIMER;
    3730           0 :     do
    3731             :     {
    3732           0 :         eSuggestedTimer = implts_saveDocs(bAllowUserIdleLoop, true, &aParams);
    3733             :     }
    3734             :     while(eSuggestedTimer == AutoRecovery::E_CALL_ME_BACK);
    3735             : 
    3736             :     // reset the handle state of all
    3737             :     // cache items. Such handle state indicates, that a document
    3738             :     // was already saved during the THIS(!) EmergencySave session.
    3739             :     // Of course following recovery session must be started without
    3740             :     // any "handle" state ...
    3741           0 :     implts_resetHandleStates(false);
    3742             : 
    3743             :     // flush config cached back to disc.
    3744           0 :     impl_flushALLConfigChanges();
    3745             : 
    3746             :     // try to make sure next time office will be started user wont be
    3747             :     // notified about any other might be running office instance
    3748             :     // remove ".lock" file from disc !
    3749           0 :     AutoRecovery::st_impl_removeLockFile();
    3750           0 : }
    3751             : 
    3752           0 : void AutoRecovery::implts_doRecovery(const DispatchParams& aParams)
    3753             : {
    3754           0 :     AutoRecovery::ETimerType eSuggestedTimer = AutoRecovery::E_DONT_START_TIMER;
    3755           0 :     do
    3756             :     {
    3757           0 :         eSuggestedTimer = implts_openDocs(aParams);
    3758             :     }
    3759             :     while(eSuggestedTimer == AutoRecovery::E_CALL_ME_BACK);
    3760             : 
    3761             :     // reset the handle state of all
    3762             :     // cache items. Such handle state indicates, that a document
    3763             :     // was already saved during the THIS(!) Recovery session.
    3764             :     // Of course a may be following EmergencySave session must be started without
    3765             :     // any "handle" state ...
    3766           0 :     implts_resetHandleStates(true);
    3767             : 
    3768             :     // Reset the configuration hint "we was crashed"!
    3769             :     ::comphelper::ConfigurationHelper::writeDirectKey(
    3770             :         m_xContext,
    3771             :         OUString(CFG_PACKAGE_RECOVERY),
    3772             :         OUString(CFG_PATH_RECOVERYINFO),
    3773             :         OUString(CFG_ENTRY_CRASHED),
    3774             :         css::uno::makeAny(sal_False),
    3775           0 :         ::comphelper::ConfigurationHelper::E_STANDARD);
    3776           0 : }
    3777             : 
    3778           0 : void AutoRecovery::implts_doSessionSave(const DispatchParams& aParams)
    3779             : {
    3780             :     SAL_INFO("fwk.autorecovery", "AutoRecovery::implts_doSessionSave()");
    3781             : 
    3782             :     // Be sure to know all open documents really .-)
    3783           0 :     implts_verifyCacheAgainstDesktopDocumentList();
    3784             : 
    3785             :     // for all docs, store their current view/names in the configurtion
    3786           0 :     implts_persistAllActiveViewNames();
    3787             : 
    3788             :     // The called method for saving documents runs
    3789             :     // during normal AutoSave more then once. Because
    3790             :     // it postpone active documents and save it later.
    3791             :     // That is normaly done by recalling it from a timer.
    3792             :     // Here we must do it immediately!
    3793             :     // Of course this method returns the right state -
    3794             :     // because it knows, that we are running in SESSION SAVE mode .-)
    3795             : 
    3796           0 :     bool                 bAllowUserIdleLoop = false; // not allowed to change that .-)
    3797           0 :     AutoRecovery::ETimerType eSuggestedTimer    = AutoRecovery::E_DONT_START_TIMER;
    3798           0 :     do
    3799             :     {
    3800             :         // do not remove lock files of the documents, it will be done on session quit
    3801           0 :         eSuggestedTimer = implts_saveDocs(bAllowUserIdleLoop, false, &aParams);
    3802             :     }
    3803             :     while(eSuggestedTimer == AutoRecovery::E_CALL_ME_BACK);
    3804             : 
    3805             :     // reset the handle state of all
    3806             :     // cache items. Such handle state indicates, that a document
    3807             :     // was already saved during the THIS(!) save session.
    3808             :     // Of course following restore session must be started without
    3809             :     // any "handle" state ...
    3810           0 :     implts_resetHandleStates(false);
    3811             : 
    3812             :     // flush config cached back to disc.
    3813           0 :     impl_flushALLConfigChanges();
    3814           0 : }
    3815             : 
    3816           0 : void AutoRecovery::implts_doSessionQuietQuit(const DispatchParams& /*aParams*/)
    3817             : {
    3818             :     SAL_INFO("fwk.autorecovery", "AutoRecovery::implts_doSessionQuietQuit()");
    3819             : 
    3820             :     // try to make sure next time office will be started user wont be
    3821             :     // notified about any other might be running office instance
    3822             :     // remove ".lock" file from disc !
    3823             :     // it is done as a first action for session save since Gnome sessions
    3824             :     // do not provide enough time for shutdown, and the dialog looks to be
    3825             :     // confusing for the user
    3826           0 :     AutoRecovery::st_impl_removeLockFile();
    3827             : 
    3828             :     // reset all modified documents, so the dont show any UI on closing ...
    3829             :     // and close all documents, so we can shutdown the OS!
    3830           0 :     implts_prepareSessionShutdown();
    3831             : 
    3832             :     // Write a hint for "stored session data" into the configuration, so
    3833             :     // the on next startup we know what's happen last time
    3834             :     ::comphelper::ConfigurationHelper::writeDirectKey(
    3835             :         m_xContext,
    3836             :         OUString(CFG_PACKAGE_RECOVERY),
    3837             :         OUString(CFG_PATH_RECOVERYINFO),
    3838             :         OUString(CFG_ENTRY_SESSIONDATA),
    3839             :         css::uno::makeAny(sal_True),
    3840           0 :         ::comphelper::ConfigurationHelper::E_STANDARD);
    3841             : 
    3842             :     // flush config cached back to disc.
    3843           0 :     impl_flushALLConfigChanges();
    3844           0 : }
    3845             : 
    3846           0 : void AutoRecovery::implts_doSessionRestore(const DispatchParams& aParams)
    3847             : {
    3848             :     SAL_INFO("fwk.autorecovery", "AutoRecovery::implts_doSessionRestore() ...");
    3849             : 
    3850           0 :     AutoRecovery::ETimerType eSuggestedTimer = AutoRecovery::E_DONT_START_TIMER;
    3851           0 :     do
    3852             :     {
    3853           0 :         eSuggestedTimer = implts_openDocs(aParams);
    3854             :     }
    3855             :     while(eSuggestedTimer == AutoRecovery::E_CALL_ME_BACK);
    3856             : 
    3857             :     // reset the handle state of all
    3858             :     // cache items. Such handle state indicates, that a document
    3859             :     // was already saved during the THIS(!) Restore session.
    3860             :     // Of course a may be following save session must be started without
    3861             :     // any "handle" state ...
    3862           0 :     implts_resetHandleStates(true);
    3863             : 
    3864             :     // make all opened documents visible
    3865           0 :     implts_changeAllDocVisibility(true);
    3866             : 
    3867             :     // Reset the configuration hint for "session save"!
    3868             :     SAL_INFO("fwk.autorecovery", "... reset config key 'SessionData'");
    3869             :     ::comphelper::ConfigurationHelper::writeDirectKey(
    3870             :         m_xContext,
    3871             :         OUString(CFG_PACKAGE_RECOVERY),
    3872             :         OUString(CFG_PATH_RECOVERYINFO),
    3873             :         OUString(CFG_ENTRY_SESSIONDATA),
    3874             :         css::uno::makeAny(sal_False),
    3875           0 :         ::comphelper::ConfigurationHelper::E_STANDARD);
    3876             : 
    3877             :     SAL_INFO("fwk.autorecovery", "... AutoRecovery::implts_doSessionRestore()");
    3878           0 : }
    3879             : 
    3880           0 : void AutoRecovery::implts_backupWorkingEntry(const DispatchParams& aParams)
    3881             : {
    3882           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_USE);
    3883             : 
    3884           0 :     AutoRecovery::TDocumentList::iterator pIt;
    3885           0 :     for (  pIt  = m_lDocCache.begin();
    3886           0 :            pIt != m_lDocCache.end();
    3887             :          ++pIt                       )
    3888             :     {
    3889           0 :         const AutoRecovery::TDocumentInfo& rInfo = *pIt;
    3890           0 :         if (rInfo.ID != aParams.m_nWorkingEntryID)
    3891           0 :             continue;
    3892             : 
    3893           0 :         OUString sSourceURL;
    3894             :         // Prefer temp file. It contains the changes against the original document!
    3895           0 :         if (!rInfo.OldTempURL.isEmpty())
    3896           0 :             sSourceURL = rInfo.OldTempURL;
    3897           0 :         else if (!rInfo.NewTempURL.isEmpty())
    3898           0 :             sSourceURL = rInfo.NewTempURL;
    3899           0 :         else if (!rInfo.OrgURL.isEmpty())
    3900           0 :             sSourceURL = rInfo.OrgURL;
    3901             :         else
    3902           0 :             continue; // nothing real to save! An unmodified but new created document.
    3903             : 
    3904           0 :         INetURLObject aParser(sSourceURL);
    3905             :         // AutoRecovery::EFailureSafeResult eResult =
    3906           0 :         implts_copyFile(sSourceURL, aParams.m_sSavePath, aParser.getName());
    3907             : 
    3908             :         // TODO: Check eResult and react for errors (InteractionHandler!?)
    3909             :         // Currently we ignore it ...
    3910             :         // DONT UPDATE THE CACHE OR REMOVE ANY TEMP. FILES FROM DISK.
    3911             :         // That has to be forced from outside explicitly.
    3912             :         // See implts_cleanUpWorkingEntry() for further details.
    3913           0 :     }
    3914           0 : }
    3915             : 
    3916           0 : void AutoRecovery::implts_cleanUpWorkingEntry(const DispatchParams& aParams)
    3917             : {
    3918           0 :     CacheLockGuard aCacheLock(this, cppu::WeakComponentImplHelperBase::rBHelper.rMutex, m_nDocCacheLock, LOCK_FOR_CACHE_ADD_REMOVE);
    3919             : 
    3920           0 :     AutoRecovery::TDocumentList::iterator pIt;
    3921           0 :     for (  pIt  = m_lDocCache.begin();
    3922           0 :            pIt != m_lDocCache.end();
    3923             :          ++pIt                       )
    3924             :     {
    3925           0 :         AutoRecovery::TDocumentInfo& rInfo = *pIt;
    3926           0 :         if (rInfo.ID != aParams.m_nWorkingEntryID)
    3927           0 :             continue;
    3928             : 
    3929           0 :         AutoRecovery::st_impl_removeFile(rInfo.OldTempURL);
    3930           0 :         AutoRecovery::st_impl_removeFile(rInfo.NewTempURL);
    3931           0 :         implts_flushConfigItem(rInfo, true); // sal_True => remove it from xml config!
    3932             : 
    3933           0 :         m_lDocCache.erase(pIt);
    3934           0 :         break; /// !!! pIt is not defined any longer ... further this function has finished it's work
    3935           0 :     }
    3936           0 : }
    3937             : 
    3938           0 : AutoRecovery::EFailureSafeResult AutoRecovery::implts_copyFile(const OUString& sSource    ,
    3939             :                                                                const OUString& sTargetPath,
    3940             :                                                                const OUString& sTargetName)
    3941             : {
    3942             :     // create content for the parent folder and call transfer on that content with the source content
    3943             :     // and the destination file name as parameters
    3944             : 
    3945           0 :     css::uno::Reference< css::ucb::XCommandEnvironment > xEnvironment;
    3946             : 
    3947           0 :     ::ucbhelper::Content aSourceContent;
    3948           0 :     ::ucbhelper::Content aTargetContent;
    3949             : 
    3950             :     try
    3951             :     {
    3952           0 :         aTargetContent = ::ucbhelper::Content(sTargetPath, xEnvironment, m_xContext);
    3953             :     }
    3954           0 :     catch(const css::uno::Exception&)
    3955             :     {
    3956           0 :         return AutoRecovery::E_WRONG_TARGET_PATH;
    3957             :     }
    3958             : 
    3959             :     sal_Int32 nNameClash;
    3960           0 :     nNameClash = css::ucb::NameClash::RENAME;
    3961             : 
    3962             :     try
    3963             :     {
    3964           0 :         bool bSuccess = ::ucbhelper::Content::create(sSource, xEnvironment, m_xContext, aSourceContent);
    3965           0 :         if (!bSuccess)
    3966           0 :             return AutoRecovery::E_ORIGINAL_FILE_MISSING;
    3967           0 :         aTargetContent.transferContent(aSourceContent, ::ucbhelper::InsertOperation_COPY, sTargetName, nNameClash);
    3968             :     }
    3969           0 :     catch(const css::uno::Exception&)
    3970             :     {
    3971           0 :         return AutoRecovery::E_ORIGINAL_FILE_MISSING;
    3972             :     }
    3973             : 
    3974           0 :     return AutoRecovery::E_COPIED;
    3975             : }
    3976             : 
    3977           0 : sal_Bool SAL_CALL AutoRecovery::convertFastPropertyValue(      css::uno::Any& /*aConvertedValue*/,
    3978             :                                                                css::uno::Any& /*aOldValue*/      ,
    3979             :                                                                sal_Int32      /*nHandle*/        ,
    3980             :                                                          const css::uno::Any& /*aValue*/         )
    3981             :     throw(css::lang::IllegalArgumentException)
    3982             : {
    3983             :     // not needed currently
    3984           0 :     return sal_False;
    3985             : }
    3986             : 
    3987           0 : void SAL_CALL AutoRecovery::setFastPropertyValue_NoBroadcast(      sal_Int32      /*nHandle*/,
    3988             :                                                              const css::uno::Any& /*aValue*/ )
    3989             :     throw(css::uno::Exception, std::exception)
    3990             : {
    3991             :     // not needed currently
    3992           0 : }
    3993             : 
    3994           0 : void SAL_CALL AutoRecovery::getFastPropertyValue(css::uno::Any& aValue ,
    3995             :                                                  sal_Int32      nHandle) const
    3996             : {
    3997           0 :     switch(nHandle)
    3998             :     {
    3999             :         case AUTORECOVERY_PROPHANDLE_EXISTS_RECOVERYDATA :
    4000             :                 {
    4001           0 :                     bool bSessionData  = false;
    4002             :                     ::comphelper::ConfigurationHelper::readDirectKey(
    4003             :                                                     m_xContext,
    4004             :                                                     OUString(CFG_PACKAGE_RECOVERY),
    4005             :                                                     OUString(CFG_PATH_RECOVERYINFO),
    4006             :                                                     OUString(CFG_ENTRY_SESSIONDATA),
    4007           0 :                                                     ::comphelper::ConfigurationHelper::E_READONLY) >>= bSessionData;
    4008             : 
    4009           0 :                     bool bRecoveryData = m_lDocCache.size() > 0;
    4010             : 
    4011             :                     // exists session data ... => then we cant say, that these
    4012             :                     // data are valid for recovery. So we have to return sal_False then!
    4013           0 :                     if (bSessionData)
    4014           0 :                         bRecoveryData = false;
    4015             : 
    4016           0 :                     aValue <<= bRecoveryData;
    4017             :                 }
    4018           0 :                 break;
    4019             : 
    4020             :         case AUTORECOVERY_PROPHANDLE_CRASHED :
    4021           0 :                 aValue = ::comphelper::ConfigurationHelper::readDirectKey(
    4022             :                             m_xContext,
    4023             :                             OUString(CFG_PACKAGE_RECOVERY),
    4024             :                             OUString(CFG_PATH_RECOVERYINFO),
    4025             :                             OUString(CFG_ENTRY_CRASHED),
    4026           0 :                             ::comphelper::ConfigurationHelper::E_READONLY);
    4027           0 :                 break;
    4028             : 
    4029             :         case AUTORECOVERY_PROPHANDLE_EXISTS_SESSIONDATA :
    4030           0 :                 aValue = ::comphelper::ConfigurationHelper::readDirectKey(
    4031             :                             m_xContext,
    4032             :                             OUString(CFG_PACKAGE_RECOVERY),
    4033             :                             OUString(CFG_PATH_RECOVERYINFO),
    4034             :                             OUString(CFG_ENTRY_SESSIONDATA),
    4035           0 :                             ::comphelper::ConfigurationHelper::E_READONLY);
    4036           0 :                 break;
    4037             :     }
    4038           0 : }
    4039             : 
    4040           0 : const css::uno::Sequence< css::beans::Property > impl_getStaticPropertyDescriptor()
    4041             : {
    4042             :     const css::beans::Property pPropertys[] =
    4043             :     {
    4044           0 :         css::beans::Property( AUTORECOVERY_PROPNAME_CRASHED            , AUTORECOVERY_PROPHANDLE_CRASHED            , ::getBooleanCppuType() , css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY ),
    4045           0 :         css::beans::Property( AUTORECOVERY_PROPNAME_EXISTS_RECOVERYDATA, AUTORECOVERY_PROPHANDLE_EXISTS_RECOVERYDATA, ::getBooleanCppuType() , css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY ),
    4046           0 :         css::beans::Property( AUTORECOVERY_PROPNAME_EXISTS_SESSIONDATA , AUTORECOVERY_PROPHANDLE_EXISTS_SESSIONDATA , ::getBooleanCppuType() , css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY ),
    4047           0 :     };
    4048           0 :     const css::uno::Sequence< css::beans::Property > lPropertyDescriptor(pPropertys, AUTORECOVERY_PROPCOUNT);
    4049           0 :     return lPropertyDescriptor;
    4050             : }
    4051             : 
    4052           0 : ::cppu::IPropertyArrayHelper& SAL_CALL AutoRecovery::getInfoHelper()
    4053             : {
    4054             :     static ::cppu::OPropertyArrayHelper* pInfoHelper = 0;
    4055           0 :     if(!pInfoHelper)
    4056             :     {
    4057           0 :         SolarMutexGuard g;
    4058           0 :         if(!pInfoHelper)
    4059             :         {
    4060           0 :             static ::cppu::OPropertyArrayHelper aInfoHelper(impl_getStaticPropertyDescriptor(), sal_True);
    4061           0 :             pInfoHelper = &aInfoHelper;
    4062           0 :         }
    4063             :     }
    4064             : 
    4065           0 :     return (*pInfoHelper);
    4066             : }
    4067             : 
    4068           0 : css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL AutoRecovery::getPropertySetInfo()
    4069             :     throw(css::uno::RuntimeException, std::exception)
    4070             : {
    4071             :     static css::uno::Reference< css::beans::XPropertySetInfo >* pInfo = 0;
    4072           0 :     if(!pInfo)
    4073             :     {
    4074           0 :         SolarMutexGuard g;
    4075           0 :         if(!pInfo)
    4076             :         {
    4077             :             static css::uno::Reference< css::beans::XPropertySetInfo > xInfo(
    4078           0 :                     ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()));
    4079           0 :             pInfo = &xInfo;
    4080           0 :         }
    4081             :     }
    4082             : 
    4083           0 :     return (*pInfo);
    4084             : }
    4085             : 
    4086           0 : void AutoRecovery::implts_verifyCacheAgainstDesktopDocumentList()
    4087             : {
    4088             :     SAL_INFO("fwk.autorecovery", "AutoRecovery::implts_verifyCacheAgainstDesktopDocumentList() ...");
    4089             :     try
    4090             :     {
    4091           0 :         css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create(m_xContext);
    4092             : 
    4093             :         css::uno::Reference< css::container::XIndexAccess > xContainer(
    4094           0 :             xDesktop->getFrames(),
    4095           0 :             css::uno::UNO_QUERY_THROW);
    4096             : 
    4097           0 :         sal_Int32 i = 0;
    4098           0 :         sal_Int32 c = xContainer->getCount();
    4099             : 
    4100           0 :         for (i=0; i<c; ++i)
    4101             :         {
    4102           0 :             css::uno::Reference< css::frame::XFrame > xFrame;
    4103             :             try
    4104             :             {
    4105           0 :                 xContainer->getByIndex(i) >>= xFrame;
    4106           0 :                 if (!xFrame.is())
    4107           0 :                     continue;
    4108             :             }
    4109             :             // can happen in multithreaded environments, that frames was removed from the container during this loop runs!
    4110             :             // Ignore it.
    4111           0 :             catch(const css::lang::IndexOutOfBoundsException&)
    4112             :             {
    4113           0 :                 continue;
    4114             :             }
    4115             : 
    4116             :             // We are interested on visible documents only.
    4117             :             // Note: It's n optional interface .-(
    4118             :             css::uno::Reference< css::awt::XWindow2 > xVisibleCheck(
    4119           0 :                 xFrame->getContainerWindow(),
    4120           0 :                 css::uno::UNO_QUERY);
    4121           0 :             if (
    4122           0 :                 (!xVisibleCheck.is()        ) ||
    4123           0 :                 (!xVisibleCheck->isVisible())
    4124             :                )
    4125             :             {
    4126           0 :                 continue;
    4127             :             }
    4128             : 
    4129             :             // extract the model from the frame.
    4130             :             // Ignore "view only" frames, which does not have a model.
    4131           0 :             css::uno::Reference< css::frame::XController > xController;
    4132           0 :             css::uno::Reference< css::frame::XModel >      xModel;
    4133             : 
    4134           0 :             xController = xFrame->getController();
    4135           0 :             if (xController.is())
    4136           0 :                 xModel = xController->getModel();
    4137           0 :             if (!xModel.is())
    4138           0 :                 continue;
    4139             : 
    4140             :             // insert model into cache ...
    4141             :             // If the model is already well known inside cache
    4142             :             // it's information set will be updated by asking the
    4143             :             // model again for it's new states.
    4144           0 :             implts_registerDocument(xModel);
    4145           0 :         }
    4146             :     }
    4147           0 :     catch(const css::uno::RuntimeException&)
    4148             :     {
    4149           0 :         throw;
    4150             :     }
    4151           0 :     catch(const css::uno::Exception&)
    4152             :     {
    4153             :     }
    4154             : 
    4155             :     SAL_INFO("fwk.autorecovery", "... AutoRecovery::implts_verifyCacheAgainstDesktopDocumentList()");
    4156           0 : }
    4157             : 
    4158           0 : bool AutoRecovery::impl_enoughDiscSpace(sal_Int32 nRequiredSpace)
    4159             : {
    4160             : #ifdef SIMULATE_FULL_DISC
    4161             :     return sal_False;
    4162             : #else  // SIMULATE_FULL_DISC
    4163             :     // In case an error occurs and we are not able to retrieve the needed information
    4164             :     // it's better to "disable" the feature ShowErrorOnFullDisc !
    4165             :     // Otherwhise we start a confusing process of error handling ...
    4166             : 
    4167           0 :     sal_uInt64 nFreeSpace = SAL_MAX_UINT64;
    4168             : 
    4169           0 :     OUString     sBackupPath(SvtPathOptions().GetBackupPath());
    4170           0 :     ::osl::VolumeInfo   aInfo      (osl_VolumeInfo_Mask_FreeSpace);
    4171           0 :     ::osl::FileBase::RC aRC         = ::osl::Directory::getVolumeInfo(sBackupPath, aInfo);
    4172             : 
    4173           0 :     if (
    4174           0 :         (aInfo.isValid(osl_VolumeInfo_Mask_FreeSpace)) &&
    4175             :         (aRC == ::osl::FileBase::E_None         )
    4176             :        )
    4177             :     {
    4178           0 :         nFreeSpace = aInfo.getFreeSpace();
    4179             :     }
    4180             : 
    4181           0 :     sal_uInt64 nFreeMB = (nFreeSpace/1048576);
    4182           0 :     return (nFreeMB >= (sal_uInt64)nRequiredSpace);
    4183             : #endif // SIMULATE_FULL_DISC
    4184             : }
    4185             : 
    4186           0 : void AutoRecovery::impl_showFullDiscError()
    4187             : {
    4188           0 :     OUString sBtn(FWK_RESSTR(STR_FULL_DISC_RETRY_BUTTON));
    4189           0 :     OUString sMsg(FWK_RESSTR(STR_FULL_DISC_MSG));
    4190             : 
    4191           0 :     OUString sBackupURL(SvtPathOptions().GetBackupPath());
    4192           0 :     INetURLObject aConverter(sBackupURL);
    4193             :     sal_Unicode aDelimiter;
    4194           0 :     OUString sBackupPath = aConverter.getFSysPath(INetURLObject::FSYS_DETECT, &aDelimiter);
    4195           0 :     if (sBackupPath.getLength() < 1)
    4196           0 :         sBackupPath = sBackupURL;
    4197             : 
    4198             :     ErrorBox dlgError(
    4199             :         0, WB_OK,
    4200           0 :         sMsg.replaceAll("%PATH", sBackupPath));
    4201           0 :     dlgError.SetButtonText(dlgError.GetButtonId(0), sBtn);
    4202           0 :     dlgError.Execute();
    4203           0 : }
    4204             : 
    4205           0 : void AutoRecovery::impl_establishProgress(const AutoRecovery::TDocumentInfo&               rInfo    ,
    4206             :                                                 utl::MediaDescriptor&             rArgs    ,
    4207             :                                           const css::uno::Reference< css::frame::XFrame >& xNewFrame)
    4208             : {
    4209             :     // external well known frame must be preferred (because it was created by ourself
    4210             :     // for loading documents into this frame)!
    4211             :     // But if no frame exists ... we can try to locate it using any frame bound to the provided
    4212             :     // document. Of course we must live without any frame in case the document does not exists at this
    4213             :     // point. But this state should not occur. In such case xNewFrame should be valid ... hopefully .-)
    4214           0 :     css::uno::Reference< css::frame::XFrame > xFrame = xNewFrame;
    4215           0 :     if (
    4216           0 :         (!xFrame.is()       ) &&
    4217           0 :         (rInfo.Document.is())
    4218             :        )
    4219             :     {
    4220           0 :         css::uno::Reference< css::frame::XController > xController = rInfo.Document->getCurrentController();
    4221           0 :         if (xController.is())
    4222           0 :             xFrame = xController->getFrame();
    4223             :     }
    4224             : 
    4225             :     // Any outside progress must be used ...
    4226             :     // Only if there is no progress, we can create our own one.
    4227           0 :     css::uno::Reference< css::task::XStatusIndicator > xInternalProgress;
    4228             :     css::uno::Reference< css::task::XStatusIndicator > xExternalProgress = rArgs.getUnpackedValueOrDefault(
    4229           0 :                                                                                 utl::MediaDescriptor::PROP_STATUSINDICATOR(),
    4230           0 :                                                                                 css::uno::Reference< css::task::XStatusIndicator >() );
    4231             : 
    4232             :     // Normaly a progress is set from outside (e.g. by the CrashSave/Recovery dialog, which uses our dispatch API).
    4233             :     // But for a normal auto save we dont have such "external progress"... because this function is triggered by our own timer then.
    4234             :     // In such case we must create our own progress !
    4235           0 :     if (
    4236           0 :         (! xExternalProgress.is()) &&
    4237           0 :         (xFrame.is()             )
    4238             :        )
    4239             :     {
    4240           0 :         css::uno::Reference< css::task::XStatusIndicatorFactory > xProgressFactory(xFrame, css::uno::UNO_QUERY);
    4241           0 :         if (xProgressFactory.is())
    4242           0 :             xInternalProgress = xProgressFactory->createStatusIndicator();
    4243             :     }
    4244             : 
    4245             :     // HACK
    4246             :     // An external provided progress (most given by the CrashSave/Recovery dialog)
    4247             :     // must be preferred. But we know that some application filters query it's own progress instance
    4248             :     // at the frame method Frame::createStatusIndicator().
    4249             :     // So we use a two step mechanism:
    4250             :     // 1) we set the progress inside the MediaDescriptor, which will be provided to the filter
    4251             :     // 2) and we set a special Frame property, which overwrites the normal behaviour of Frame::createStatusIndicator .-)
    4252             :     // But we supress 2) in case we uses an internal progress. Because then it doesn't matter
    4253             :     // if our applications make it wrong. In such case the internal progress resists at the same frame
    4254             :     // and there is no need to forward progress activities to e.g. an outside dialog .-)
    4255           0 :     if (
    4256           0 :         (xExternalProgress.is()) &&
    4257           0 :         (xFrame.is()           )
    4258             :        )
    4259             :     {
    4260           0 :         css::uno::Reference< css::beans::XPropertySet > xFrameProps(xFrame, css::uno::UNO_QUERY);
    4261           0 :         if (xFrameProps.is())
    4262           0 :             xFrameProps->setPropertyValue(FRAME_PROPNAME_INDICATORINTERCEPTION, css::uno::makeAny(xExternalProgress));
    4263             :     }
    4264             : 
    4265             :     // But inside the MediaDescriptor we must set our own create progress ...
    4266             :     // in case there is not already another progress set.
    4267           0 :     rArgs.createItemIfMissing(utl::MediaDescriptor::PROP_STATUSINDICATOR(), xInternalProgress);
    4268           0 : }
    4269             : 
    4270           0 : void AutoRecovery::impl_forgetProgress(const AutoRecovery::TDocumentInfo&               rInfo    ,
    4271             :                                              utl::MediaDescriptor&             rArgs    ,
    4272             :                                        const css::uno::Reference< css::frame::XFrame >& xNewFrame)
    4273             : {
    4274             :     // external well known frame must be preferred (because it was created by ourself
    4275             :     // for loading documents into this frame)!
    4276             :     // But if no frame exists ... we can try to locate it using any frame bound to the provided
    4277             :     // document. Of course we must live without any frame in case the document does not exists at this
    4278             :     // point. But this state should not occur. In such case xNewFrame should be valid ... hopefully .-)
    4279           0 :     css::uno::Reference< css::frame::XFrame > xFrame = xNewFrame;
    4280           0 :     if (
    4281           0 :         (!xFrame.is()       ) &&
    4282           0 :         (rInfo.Document.is())
    4283             :        )
    4284             :     {
    4285           0 :         css::uno::Reference< css::frame::XController > xController = rInfo.Document->getCurrentController();
    4286           0 :         if (xController.is())
    4287           0 :             xFrame = xController->getFrame();
    4288             :     }
    4289             : 
    4290             :     // stop progress interception on corresponding frame.
    4291           0 :     css::uno::Reference< css::beans::XPropertySet > xFrameProps(xFrame, css::uno::UNO_QUERY);
    4292           0 :     if (xFrameProps.is())
    4293           0 :         xFrameProps->setPropertyValue(FRAME_PROPNAME_INDICATORINTERCEPTION, css::uno::makeAny(css::uno::Reference< css::task::XStatusIndicator >()));
    4294             : 
    4295             :     // forget progress inside list of arguments.
    4296           0 :     utl::MediaDescriptor::iterator pArg = rArgs.find(utl::MediaDescriptor::PROP_STATUSINDICATOR());
    4297           0 :     if (pArg != rArgs.end())
    4298             :     {
    4299           0 :         rArgs.erase(pArg);
    4300           0 :         pArg = rArgs.end();
    4301           0 :     }
    4302           0 : }
    4303             : 
    4304           0 : void AutoRecovery::impl_flushALLConfigChanges()
    4305             : {
    4306             :     try
    4307             :     {
    4308           0 :         css::uno::Reference< css::uno::XInterface > xRecoveryCfg;
    4309             :         /* SAFE */ {
    4310           0 :         osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
    4311           0 :         xRecoveryCfg.set(m_xRecoveryCFG, css::uno::UNO_QUERY);
    4312             :         } /* SAFE */
    4313             : 
    4314           0 :         if (xRecoveryCfg.is())
    4315           0 :             ::comphelper::ConfigurationHelper::flush(xRecoveryCfg);
    4316             : 
    4317             :         // SOLAR SAFE ->
    4318           0 :         SolarMutexGuard aGuard;
    4319           0 :         ::utl::ConfigManager::storeConfigItems();
    4320             :     }
    4321           0 :     catch(const css::uno::Exception&)
    4322             :     {
    4323             :     }
    4324           0 : }
    4325             : 
    4326           0 : void AutoRecovery::st_impl_removeFile(const OUString& sURL)
    4327             : {
    4328           0 :     if ( sURL.isEmpty())
    4329           0 :         return;
    4330             : 
    4331             :     try
    4332             :     {
    4333           0 :         ::ucbhelper::Content aContent = ::ucbhelper::Content(sURL, css::uno::Reference< css::ucb::XCommandEnvironment >(), m_xContext);
    4334           0 :         aContent.executeCommand(OUString("delete"), css::uno::makeAny(sal_True));
    4335             :     }
    4336           0 :     catch(const css::uno::Exception&)
    4337             :     {
    4338             :     }
    4339             : }
    4340             : 
    4341           0 : void AutoRecovery::st_impl_removeLockFile()
    4342             : {
    4343             :     try
    4344             :     {
    4345           0 :         OUString sUserURL;
    4346           0 :         ::utl::Bootstrap::locateUserInstallation( sUserURL );
    4347             : 
    4348           0 :         OUStringBuffer sLockURLBuf;
    4349           0 :         sLockURLBuf.append     (sUserURL);
    4350           0 :         sLockURLBuf.appendAscii("/.lock");
    4351           0 :         OUString sLockURL = sLockURLBuf.makeStringAndClear();
    4352             : 
    4353           0 :         AutoRecovery::st_impl_removeFile(sLockURL);
    4354             :     }
    4355           0 :     catch(const css::uno::Exception&)
    4356             :     {
    4357             :     }
    4358           0 : }
    4359             : 
    4360           0 : struct Instance {
    4361           0 :     explicit Instance(
    4362             :         css::uno::Reference<css::uno::XComponentContext> const & context):
    4363             :         instance(
    4364           0 :             static_cast<cppu::OWeakObject *>(new AutoRecovery(context)))
    4365             :     {
    4366             :         // 2nd phase initialization needed
    4367             :         static_cast<AutoRecovery*>(static_cast<cppu::OWeakObject *>
    4368           0 :                 (instance.get()))->initListeners();
    4369           0 :     }
    4370             : 
    4371             :     css::uno::Reference<css::uno::XInterface> instance;
    4372             : };
    4373             : 
    4374             : struct Singleton:
    4375             :     public rtl::StaticWithArg<
    4376             :         Instance, css::uno::Reference<css::uno::XComponentContext>, Singleton>
    4377             : {};
    4378             : 
    4379             : }
    4380             : 
    4381             : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
    4382           0 : com_sun_star_comp_framework_AutoRecovery_get_implementation(
    4383             :     css::uno::XComponentContext *context,
    4384             :     css::uno::Sequence<css::uno::Any> const &)
    4385             : {
    4386             :     return cppu::acquire(static_cast<cppu::OWeakObject *>(
    4387           0 :                 Singleton::get(context).instance.get()));
    4388             : }
    4389             : 
    4390             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10