summaryrefslogtreecommitdiff
path: root/framework/inc/services/autorecovery.hxx
blob: 56f0c9018052e71adc220225bfdbf78ad18c786a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef __FRAMEWORK_SERVICES_AUTORECOVERY_HXX_
#define __FRAMEWORK_SERVICES_AUTORECOVERY_HXX_

//_______________________________________________
// own includes

#include <threadhelp/threadhelpbase.hxx>
#include <macros/xinterface.hxx>
#include <macros/xtypeprovider.hxx>
#include <macros/xserviceinfo.hxx>
#include <general.h>
#include <stdtypes.h>

//_______________________________________________
// interface includes
#include <com/sun/star/uno/XInterface.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/frame/XDispatch.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/document/XEventListener.hpp>
#include <com/sun/star/document/XEventBroadcaster.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/util/XChangesListener.hpp>
#include <com/sun/star/task/XStatusIndicator.hpp>
#include <com/sun/star/util/XModifyListener.hpp>

//_______________________________________________
// other includes
#include <comphelper/mediadescriptor.hxx>
#include <vcl/timer.hxx>
#include <vcl/evntpost.hxx>
#include <cppuhelper/interfacecontainer.hxx>
#include <cppuhelper/propshlp.hxx>
#include <cppuhelper/weak.hxx>

//_______________________________________________
// definition

#ifndef css
namespace css = ::com::sun::star;
#endif

namespace framework
{

//---------------------------------------
/** @short  hold all needed informations for an asynchronous dispatch alive.

    @descr  Because some operations are forced to be executed asynchronously
            (e.g. requested by our CreashSave/Recovery dialog) ... we must make sure
            that these informations wont be set as "normal" members of our AtoRecovery
            instance. Otherwise they can disturb our normal AutoSave-timer handling.
            e.g. it can be unclear then, which progress has to be used for storing documents ...
 */
struct DispatchParams
{
    public:
         DispatchParams();
         DispatchParams(const ::comphelper::SequenceAsHashMap&             lArgs ,
                        const css::uno::Reference< css::uno::XInterface >& xOwner);
         DispatchParams(const DispatchParams& rCopy);
        ~DispatchParams();

         DispatchParams& operator=(const DispatchParams& rCopy);
         void forget();

    public:

        //---------------------------------------
        /** @short  can be set from outside and is provided to
                    our internal started operations.

            @descr  Normaly we use the normal status indicator
                    of the document windows to show a progress.
                    But in case we are used by any special UI,
                    it can provide its own status indicator object
                    to us - so we use it instead of the normal one.
         */
        css::uno::Reference< css::task::XStatusIndicator > m_xProgress;

        //---------------------------------------
        /** TODO document me */
        ::rtl::OUString m_sSavePath;

        //---------------------------------------
        /** @short  define the current cache entry, which should be used for current
                    backup or cleanUp operation ... which is may be done asynchronous */
        sal_Int32 m_nWorkingEntryID;

        //---------------------------------------
        /** @short  used for asyncoperations, to prevent us from dying.

            @descr  If our dispatch() method was forced to start the
                    internal operation asynchronous ... we send an event
                    to start and return immediatly. But we must be shure that
                    our instance live if the event callback reach us.
                    So we hold an uno reference to ourself.
         */
        css::uno::Reference< css::uno::XInterface > m_xHoldRefForAsyncOpAlive;
};

//_______________________________________________
/**
    implements the functionality of AutoSave and AutoRecovery
    of documents - including features of an EmergencySave in
    case a GPF occures.
 */
class AutoRecovery  : public  css::lang::XTypeProvider
                    , public  css::lang::XServiceInfo
                    , public  css::frame::XDispatch
                    , public  css::document::XEventListener         // => css.lang.XEventListener
                    , public  css::util::XChangesListener           // => css.lang.XEventListener
                    , public  css::util::XModifyListener            // => css.lang.XEventListener
                    // attention! Must be the first base class to guarentee right initialize lock ...
                    , private ThreadHelpBase
                    , public  ::cppu::OBroadcastHelper
                    , public  ::cppu::OPropertySetHelper            // => XPropertySet, XFastPropertySet, XMultiPropertySet
                    , public  ::cppu::OWeakObject
{
    //___________________________________________
    // types

    public:

        /** These values are used as flags and represent the current state of a document.
            Every state of the life time of a document has to be recognized here.
    
            @attention  Do not change (means reorganize) already used numbers.
                        There exists some code inside SVX, which uses the same numbers,
                        to analyze such document states.
                        Not the best design ... but may be it will be changed later .-)
        */
        enum EDocStates
        {
            /* TEMP STATES */

            /// default state, if a document was new created or loaded
            E_UNKNOWN = 0,
            /// modified against the original file
            E_MODIFIED = 1,
            /// an active document can be postponed to be saved later.
            E_POSTPONED = 2,
            /// was already handled during one AutoSave/Recovery session.
            E_HANDLED = 4,
            /** an action was started (saving/loading) ... Can be interesting later if the process may be was interrupted by an exception. */
            E_TRY_SAVE = 8,
            E_TRY_LOAD_BACKUP = 16,
            E_TRY_LOAD_ORIGINAL = 32,
            
            /* FINAL STATES */

            /// the Auto/Emergency saved document isnt useable any longer
            E_DAMAGED = 64,
            /// the Auto/Emergency saved document isnt realy up-to-date (some changes can be missing)
            E_INCOMPLETE = 128,
            /// the Auto/Emergency saved document was processed successfully
            E_SUCCEDED = 512
        };

        /** @short  indicates the results of a FAILURE_SAFE operation

            @descr  We must know, which reason was the real one in case
                    we couldnt copy a "failure document" to a user specified path.
                    We must know, if we can forget our cache entry or not.
         */
        enum EFailureSafeResult
        {
            E_COPIED,
            E_ORIGINAL_FILE_MISSING,
            E_WRONG_TARGET_PATH
        };

        // TODO document me
        enum ETimerType
        {
            /** the timer shouldnt be used next time */
            E_DONT_START_TIMER,
            /** timer (was/must be) started with normal AutoSaveTimeIntervall */
            E_NORMAL_AUTOSAVE_INTERVALL,
            /** timer must be started with special short time intervall,
                to poll for an user idle period */
            E_POLL_FOR_USER_IDLE,
            /** timer mst be started with a very(!) short time intervall,
                to poll for the end of an user action, which does not allow saving documents in general */
            E_POLL_TILL_AUTOSAVE_IS_ALLOWED,
            /** dont start the timer - but calls the same action then before immediatly again! */
            E_CALL_ME_BACK
        };

        // TODO document me ... flag field
        // Emergency_Save and Recovery overwrites Auto_Save!
        enum EJob
        {
            E_NO_JOB                    =   0,
            E_AUTO_SAVE                 =   1,
            E_EMERGENCY_SAVE            =   2,
            E_RECOVERY                  =   4,
            E_ENTRY_BACKUP              =   8,
            E_ENTRY_CLEANUP             =  16,
            E_PREPARE_EMERGENCY_SAVE    =  32,
            E_SESSION_SAVE              =  64,
            E_SESSION_RESTORE           = 128,
            E_DISABLE_AUTORECOVERY      = 256,
            E_SET_AUTOSAVE_STATE        = 512,
            E_SESSION_QUIET_QUIT        = 1024
        };

        //---------------------------------------
        /** @short  combine different informations about one office document. */
        struct TDocumentInfo
        {
            public:

                //-------------------------------
                TDocumentInfo()
                    : DocumentState   (E_UNKNOWN)
                    , UsedForSaving   (sal_False)
                    , ListenForModify (sal_False)
                    , IgnoreClosing   (sal_False)
                    , ID              (-1       )
                {}

                //-------------------------------
                /** @short  points to the document. */
                css::uno::Reference< css::frame::XModel > Document;

                //-------------------------------
                /** @short  knows, if the document is realy modified since the last autosave,
                            or  was postponed, because it was an active one etcpp...

                    @descr  Because we have no CHANGE TRACKING mechanism, based on office document,
                            we implements it by ourself. We listen for MODIFIED events
                            of each document and update this state flag here.

                            Further we postpone saving of active documents, e.g. if the user
                            works currently on it. We wait for an idle period then ...
                 */
                sal_Int32 DocumentState;

                //-------------------------------
                /** Because our applications not ready for concurrent save requests at the same time,
                    we have supress our own AutoSave for the moment, a document will be already saved
                    by others.
                 */
                sal_Bool UsedForSaving;

                //-------------------------------
                /** For every user action, which modifies a document (e.g. key input) we get
                    a notification as XModifyListener. That seams to be a "performance issue" .-)
                    So we decided to listen for such modify events only for the time in which the document
                    was stored as temp. file and was not modified again by the user.
                */
                sal_Bool ListenForModify;

                //-------------------------------
                /** For SessionSave we must close all open documents by ourself.
                    But because we are listen for documents events, we get some ...
                    and deregister these documents from our configuration.
                    That's why we mark these documents as "Closed by ourself" so we can
                    ignore these "OnUnload" or disposing() events .-)
                */
                sal_Bool IgnoreClosing;

                //-------------------------------
                /** TODO: document me */
                ::rtl::OUString OrgURL;
                ::rtl::OUString FactoryURL;
                ::rtl::OUString TemplateURL;

                ::rtl::OUString OldTempURL;
                ::rtl::OUString NewTempURL;

                ::rtl::OUString AppModule;      // e.g. com.sun.star.text.TextDocument - used to identify app module
                ::rtl::OUString FactoryService; // the service to create a document of the module
                ::rtl::OUString RealFilter;     // real filter, which was used at loading time
                ::rtl::OUString DefaultFilter;  // supports saving of the default format without loosing data
                ::rtl::OUString Extension;      // file extension of the default filter
                ::rtl::OUString Title;          // can be used as "DisplayName" on every recovery UI!
                ::com::sun::star::uno::Sequence< ::rtl::OUString >
                                ViewNames;      // names of the view which were active at emergency-save time

                sal_Int32 ID;
        };

        //---------------------------------------
        /** @short  used to know every currently open document. */
        typedef ::std::vector< TDocumentInfo > TDocumentList;

    //___________________________________________
    // member

    private:

        //---------------------------------------
        /** @short  the global uno service manager.
            @descr  Must be used to create own needed services.
         */
        css::uno::Reference< css::lang::XMultiServiceFactory > m_xSMGR;

        //---------------------------------------
        /** @short  points to the underlying recovery configuration.
            @descr  This instance does not cache - it calls directly the
                    configuration API!
          */
        css::uno::Reference< css::container::XNameAccess > m_xRecoveryCFG;

        //---------------------------------------
        /** @short  proxy weak binding to forward Events to ourself without
                    an ownership cycle
          */
        css::uno::Reference< css::util::XChangesListener > m_xRecoveryCFGListener;

        //---------------------------------------
        /** @short  points to the used configuration package or.openoffice.Setup
            @descr  This instance does not cache - it calls directly the
                    configuration API!
          */
        css::uno::Reference< css::container::XNameAccess > m_xModuleCFG;

        //---------------------------------------
        /** @short  holds the global event broadcaster alive,
                    where we listen for new created documents.
          */
        css::uno::Reference< css::document::XEventBroadcaster > m_xNewDocBroadcaster;

        //---------------------------------------
        /** @short  proxy weak binding to forward Events to ourself without
                    an ownership cycle
          */
        css::uno::Reference< css::document::XEventListener > m_xNewDocBroadcasterListener;

        //---------------------------------------
        /** @short  because we stop/restart listening sometimes, it's a good idea to know
                    if we already registered as listener .-)
        */
        sal_Bool m_bListenForDocEvents;
        sal_Bool m_bListenForConfigChanges;

        //---------------------------------------
        /** @short  specify the time intervall between two save actions.
            @descr  Time is measured in [min].
         */
        sal_Int32 m_nAutoSaveTimeIntervall;

        //---------------------------------------
        /** @short  for an asynchronous operation we must know, if there is
                    at least one running job (may be asynchronous!).
         */
        sal_Int32 m_eJob;

        //---------------------------------------
        /** @short  the timer, which is used to be informed about the next
                    saving time ...
         */
        Timer m_aTimer;

        //---------------------------------------
        /** @short  make our dispatch asynchronous ... if required to do so! */
        ::vcl::EventPoster m_aAsyncDispatcher;

        //---------------------------------------
        /** @see    DispatchParams
         */
        DispatchParams m_aDispatchParams;

        //---------------------------------------
        /** @short  indicates, which time period is currently used by the
                    internal timer.
         */
        ETimerType m_eTimerType;

        //---------------------------------------
        /** @short  this cache is used to hold all informations about
                    recovery/emergency save documents alive.
         */
        TDocumentList m_lDocCache;

        //---------------------------------------
        // TODO document me
        sal_Int32 m_nIdPool;

        //---------------------------------------
        /** @short  contains all status listener registered at this instance.
         */
        ListenerHash m_lListener;

        /** @descr  This member is used to prevent us against re-entrance problems.
                    A mutex cant help to prevent us from concurrent using of members
                    inside the same thread. But e.g. our internaly used stl structures
                    are not threadsafe ... and furthermore they cant be used at the same time
                    for iteration and add/remove requests!
                    So we have to detect such states and ... show a warning.
                    May be there will be a better solution next time ... (copying the cache temp.
                    bevor using).

                    And further it's not possible to use a simple boolean value here.
                    Because if more then one operation iterates over the same stl container ...
                    (only to modify it's elements but dont add new or removing existing ones!)
                    it should be possible doing so. But we must guarantee that the last operation reset
                    this lock ... not the first one ! So we use a "ref count" mechanism for that."
         */
        sal_Int32 m_nDocCacheLock;

        /** @descr  These members are used to check the minimum disc space, which must exists
                    to start the corresponding operation.
         */
        sal_Int32 m_nMinSpaceDocSave;
        sal_Int32 m_nMinSpaceConfigSave;

        //---------------------------------------
        /** @short  special debug option to make testing faster.

            @descr  We dont interpret the timer unit as [min] ...
                    we use [ms] instead of that. Further we dont
                    wait 10 s for user idle ...
         */
        #if OSL_DEBUG_LEVEL > 1
        sal_Bool m_dbg_bMakeItFaster;
        #endif

        //---------------------------------------
        // HACK ... TODO
        css::uno::Reference< css::task::XStatusIndicator > m_xExternalProgress;

    //___________________________________________
    // interface

    public:

                 AutoRecovery(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR);
        virtual ~AutoRecovery(                                                                   );

        // XInterface, XTypeProvider, XServiceInfo
        FWK_DECLARE_XINTERFACE
        FWK_DECLARE_XTYPEPROVIDER
        DECLARE_XSERVICEINFO

        //---------------------------------------
        // css.frame.XDispatch
        virtual void SAL_CALL dispatch(const css::util::URL&                                  aURL      ,
                                       const css::uno::Sequence< css::beans::PropertyValue >& lArguments)
            throw(css::uno::RuntimeException);

        virtual void SAL_CALL addStatusListener(const css::uno::Reference< css::frame::XStatusListener >& xListener,
                                                const css::util::URL&                                     aURL     )
            throw(css::uno::RuntimeException);

        virtual void SAL_CALL removeStatusListener(const css::uno::Reference< css::frame::XStatusListener >& xListener,
                                                   const css::util::URL&                                     aURL     )
            throw(css::uno::RuntimeException);

        //---------------------------------------
        // css.document.XEventListener
        /** @short  informs about created/opened documents.

            @descr  Every new opened/created document will be saved internaly
                    so it can be checked if its modified. This modified state
                    is used later to decide, if it must be saved or not.

            @param  aEvent
                    points to the new created/opened document.
         */
        virtual void SAL_CALL notifyEvent(const css::document::EventObject& aEvent)
            throw(css::uno::RuntimeException);

        //---------------------------------------
        // css.util.XChangesListener
        virtual void SAL_CALL changesOccurred(const css::util::ChangesEvent& aEvent)
            throw(css::uno::RuntimeException);
            
        //---------------------------------------
        // css.util.XModifyListener
        virtual void SAL_CALL modified(const css::lang::EventObject& aEvent)
            throw(css::uno::RuntimeException);

        //---------------------------------------
        // css.lang.XEventListener
        using cppu::OPropertySetHelper::disposing;
        virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent)
            throw(css::uno::RuntimeException);

    //___________________________________________
    // helper

    protected:

        //---------------------------------------
        // OPropertySetHelper

        virtual sal_Bool SAL_CALL convertFastPropertyValue(      css::uno::Any& aConvertedValue,
                                                                 css::uno::Any&	aOldValue      ,
                                                                 sal_Int32		nHandle        ,
                                                           const css::uno::Any&	aValue         )
            throw(css::lang::IllegalArgumentException);

        virtual void SAL_CALL setFastPropertyValue_NoBroadcast(      sal_Int32      nHandle,
                                                               const css::uno::Any& aValue )
            throw(css::uno::Exception);
        using cppu::OPropertySetHelper::getFastPropertyValue;
        virtual void SAL_CALL getFastPropertyValue(css::uno::Any& aValue ,
                                                   sal_Int32      nHandle) const;

        virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper();

        virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo()
            throw(css::uno::RuntimeException);
    //___________________________________________
    // helper

    private:

        //---------------------------------------
        /** @short  open the underlying configuration.

            @descr  This method must be called everytimes
                    a configuartion call is needed. Because
                    method works together with the member
                    m_xCFG, open it on demand and cache it
                    afterwards.

            @return [com.sun.star.container.XNameAccess]
                    the configuration object

            @throw  [com.sun.star.uno.RuntimeException]
                    if config could not be opened successfully!

            @threadsafe
          */
        css::uno::Reference< css::container::XNameAccess > implts_openConfig();

        //---------------------------------------
        /** @short  read the underlying configuration.

            @descr  After that we know the initial state - means:
                    - if AutoSave was enabled by the user
                    - which time intervall has to be used
                    - which recovery entries may already exists

            @throw  [com.sun.star.uno.RuntimeException]
                    if config could not be opened or readed successfully!

            @threadsafe
          */
        void implts_readConfig();

        //---------------------------------------
        /** @short  read the underlying configuration...

            @descr  ... but only keys related to the AutoSave mechanism.
                    Means: State and Timer intervall.
                    E.g. the recovery list isnt adressed here.

            @throw  [com.sun.star.uno.RuntimeException]
                    if config could not be opened or readed successfully!

            @threadsafe
          */
        void implts_readAutoSaveConfig();
        
        //---------------------------------------
        // TODO document me
        void implts_flushConfigItem(const AutoRecovery::TDocumentInfo& rInfo                ,
                                          sal_Bool                     bRemoveIt = sal_False);

        //---------------------------------------
        // TODO document me
        void implts_startListening();
        void implts_startModifyListeningOnDoc(AutoRecovery::TDocumentInfo& rInfo);

        //---------------------------------------
        // TODO document me
        void implts_stopListening();
        void implts_stopModifyListeningOnDoc(AutoRecovery::TDocumentInfo& rInfo);

        //---------------------------------------
        /** @short  stops and may be(!) restarts the timer.

            @descr  A running timer is stopped everytimes here.
                    But starting depends from the different internal
                    timer variables (e.g. AutoSaveEnabled, AutoSaveTimeIntervall,
                    TimerType etcpp.)

            @throw  [com.sun.star.uno.RuntimeException]
                    if timer could not be stopped or started!

            @threadsafe
         */
        void implts_updateTimer();

        //---------------------------------------
        /** @short  stop the timer.

            @descr  Double calls will be ignored - means we do
                    nothing here, if the timer is already disabled.

            @throw  [com.sun.star.uno.RuntimeException]
                    if timer could not be stopped!

            @threadsafe
         */
        void implts_stopTimer();

        //---------------------------------------
        /** @short  callback of our internal timer.
         */
        DECL_LINK(implts_timerExpired, void*);

        //---------------------------------------
        /** @short  makes our dispatch() method asynchronous!
         */
        DECL_LINK(implts_asyncDispatch, void*);

        //---------------------------------------
        /** @short  implements the dispatch real. */
        void implts_dispatch(const DispatchParams& aParams);

        //---------------------------------------
        /** @short  validate new detected document and add it into the internal
                    document list.

            @descr  This method should be called only, if its clear that a new
                    document was opened/created during office runtime.
                    This method checks, if its a top level document (means not an embedded one).
                    Only such top level documents can be recognized by this auto save mechanism.

            @param  xDocument
                    the new document, which should be checked and registered.

            @threadsafe
         */
        void implts_registerDocument(const css::uno::Reference< css::frame::XModel >& xDocument);

        //---------------------------------------
        /** @short  remove the specified document from our internal document list.

            @param  xDocument
                    the new document, which should be deregistered.

            @param  bStopListening
                    FALSE: must be used in case this method is called withion disposing() of the document,
                           where it make no sense to deregister our listener. The container dies ...
                    TRUE : must be used in case this method is used on "dergistration" of this document, where
                           we must deregister our listener .-)

            @threadsafe
         */
        void implts_deregisterDocument(const css::uno::Reference< css::frame::XModel >& xDocument                ,
                                             sal_Bool                                   bStopListening = sal_True);

        //---------------------------------------
        // TODO document me
        void implts_markDocumentModifiedAgainstLastBackup(const css::uno::Reference< css::frame::XModel >& xDocument);
        
        //---------------------------------------
        // TODO document me
        void implts_updateModifiedState(const css::uno::Reference< css::frame::XModel >& xDocument);

        //---------------------------------------
        // TODO document me
        void implts_updateDocumentUsedForSavingState(const css::uno::Reference< css::frame::XModel >& xDocument      ,
                                                           sal_Bool                                   bSaveInProgress);

        //---------------------------------------
        // TODO document me
        void implts_markDocumentAsSaved(const css::uno::Reference< css::frame::XModel >& xDocument);

        //---------------------------------------
        /** @short  search a document inside given list.

            @param  rList
                    reference to a vector, which can contain such
                    document.

            @param  xDocument
                    the document, which should be located inside the
                    given list.

            @return [TDocumentList::iterator]
                    which points to the located document.
                    If document does not exists - its set to
                    rList.end()!
         */
        static TDocumentList::iterator impl_searchDocument(      AutoRecovery::TDocumentList&               rList    ,
                                                           const css::uno::Reference< css::frame::XModel >& xDocument);

        //---------------------------------------
        /** TODO document me */
        void implts_changeAllDocVisibility(sal_Bool bVisible);
        void implts_prepareSessionShutdown();

        //---------------------------------------
        /** @short  save all current opened documents to a specific
                    backup directory.

            @descr  Only realy changed documents will be saved here.

                    Further this method returns a suggestion, if and how it should
                    be called again. May be some documents was not saved yet
                    and must wait for an user idle period ...

            @param  bAllowUserIdleLoop
                    Because this method is used for different uses cases, it must
                    know, which actions are allowed or not.
                    AUTO_SAVE =>
                                 If a document is the most active one, saving it
                                 will be postponed if there exists other unsaved
                                 documents. This feature was implemented, because
                                 we dont wish to disturb the user on it's work.
                                 ... bAllowUserIdleLoop should be set to TRUE
                    EMERGENCY_SAVE / SESSION_SAVE =>
                                 Here we must finish our work ASAP! It's not allowed
                                 to postpone any document.
                                 ... bAllowUserIdleLoop must(!) be set to FALSE

            @param  pParams
                    sometimes this method is required inside an external dispatch request.
                    The it contains some special environment variables, which overwrites
                    our normal environment.
                    AutoSave              => pParams == 0
                    SessionSave/CrashSave => pParams != 0

            @return A suggestion, how the timer (if its not already disabled!)
                    should be restarted to full fill the requirements.

            @threadsafe
         */
        AutoRecovery::ETimerType implts_saveDocs(      sal_Bool        bAllowUserIdleLoop,
                                                       sal_Bool        bRemoveLockFiles,
                                                 const DispatchParams* pParams        = 0);

        //---------------------------------------
        /** @short  save one of the current documents to a specific
                    backup directory.

            @descr  It:
                    - defines a new(!) unique temp file name
                    - save the new temp file
                    - remove the old temp file
                    - patch the given info struct
                    - and return errors.

                    It does not:
                    - patch the configuration.

                    Note further: It paches the info struct
                    more then ones. E.g. the new temp URL is set
                    before the file is saved. And the old URL is removed
                    only if removing oft he old file was successfully.
                    If this method returns without an exception - everything
                    was OK. Otherwhise the info struct can be analyzed to
                    get more information, e.g. when the problem occures.

            @param  sBackupPath
                    the base path for saving such temp files.

            @param  rInfo
                    points to an informations structure, where
                    e.g. the document, its modified state, the count
                    of autosave-retries etcpp. exists.
                    Its used also to return the new temp file name
                    and some other state values!

            @threadsafe
          */
        void implts_saveOneDoc(const ::rtl::OUString&                                    sBackupPath      ,
                                     AutoRecovery::TDocumentInfo&                        rInfo            ,
                               const css::uno::Reference< css::task::XStatusIndicator >& xExternalProgress);

        //---------------------------------------
        /** @short  recovery all documents, which was saved during
                    a crash before.

            @return A suggestion, how this method must be called back!

            @threadsafe
         */
        AutoRecovery::ETimerType implts_openDocs(const DispatchParams& aParams);

        //---------------------------------------
        // TODO document me
        void implts_openOneDoc(const ::rtl::OUString&               sURL       ,
                                     ::comphelper::MediaDescriptor& lDescriptor,
                                     AutoRecovery::TDocumentInfo&   rInfo      );

        //---------------------------------------
        // TODO document me
        void implts_generateNewTempURL(const ::rtl::OUString&               sBackupPath     ,
                                             ::comphelper::MediaDescriptor& rMediaDescriptor,
                                             AutoRecovery::TDocumentInfo&   rInfo           );

        //---------------------------------------
        /** @short  notifies all interested listener about the current state
                    of the currently running operation.

            @descr  We support different set's of functions. AUTO_SAVE, EMERGENCY_SAVE,
                    AUTO_RECOVERY, FAILURE_SAVE ... etcpp.
                    Listener can register itself for any type of supported
                    functionality ... but not for document URL's in special.

            @param  eJob
                    is used to know, which set of listener we must notify.

            @param  aEvent
                    describe the event more in detail.

            @threadsafe
          */
        void implts_informListener(      sal_Int32                      eJob  ,
                                   const css::frame::FeatureStateEvent& aEvent);

        //---------------------------------------
        /** short   create a feature event struct, which can be send
                    to any interested listener.

            @param  eJob
                    describe the current running operation
                    AUTOSAVE, EMERGENCYSAVE, RECOVERY

            @param  sEventType
                    describe the type of this event
                    START, STOP, UPDATE

            @param  pInfo
                    if sOperation is an update, this parameter must be different from NULL
                    and is used to send informations regarding the current handled document.

            @return [css::frame::FeatureStateEvent]
                    the event structure for sending.
         */
        static css::frame::FeatureStateEvent implst_createFeatureStateEvent(      sal_Int32                    eJob      ,
                                                                            const ::rtl::OUString&             sEventType,
                                                                                  AutoRecovery::TDocumentInfo* pInfo     );

        //---------------------------------------

        // TODO document me
        void implts_resetHandleStates(sal_Bool bLoadCache);

        //---------------------------------------
        // TODO document me
        void implts_specifyDefaultFilterAndExtension(AutoRecovery::TDocumentInfo& rInfo);

        //---------------------------------------
        // TODO document me
        void implts_specifyAppModuleAndFactory(AutoRecovery::TDocumentInfo& rInfo);

        /** retrieves the names of all active views of the given document
            @param rInfo
                the document info, whose <code>Document</code> member must not be <NULL/>.
        */
        void implts_collectActiveViewNames( AutoRecovery::TDocumentInfo& rInfo );

        /** updates the configuration so that for all documents, their current view/names are stored
        */
        void implts_persistAllActiveViewNames();

        //---------------------------------------
        // TODO document me
        void implts_prepareEmergencySave();

        //---------------------------------------
        // TODO document me
        void implts_doEmergencySave(const DispatchParams& aParams);

        //---------------------------------------
        // TODO document me
        void implts_doRecovery(const DispatchParams& aParams);

        //---------------------------------------
        // TODO document me
        void implts_doSessionSave(const DispatchParams& aParams);

        //---------------------------------------
        // TODO document me
        void implts_doSessionQuietQuit(const DispatchParams& aParams);

        //---------------------------------------
        // TODO document me
        void implts_doSessionRestore(const DispatchParams& aParams);

        //---------------------------------------
        // TODO document me
        void implts_backupWorkingEntry(const DispatchParams& aParams);

        //---------------------------------------
        // TODO document me
        void implts_cleanUpWorkingEntry(const DispatchParams& aParams);

        //---------------------------------------
        /** try to make sure that all changed config items (not our used
            config access only) will be flushed back to disc.
            
            E.g. our svtools::ConfigItems() has to be flushed explicitly .-(
            
            Note: This method cant fail. Flushing of config entries is an
                  optional feature. Errors can be ignored.
         */
        void impl_flushALLConfigChanges();
         
        //---------------------------------------
        // TODO document me
        AutoRecovery::EFailureSafeResult implts_copyFile(const ::rtl::OUString& sSource    ,
                                                         const ::rtl::OUString& sTargetPath,
                                                         const ::rtl::OUString& sTargetName);

        //---------------------------------------
        /** @short  converts m_eJob into a job description, which
                    can be used to inform an outside listener
                    about the current running operation

            @param  eJob
                    describe the current running operation
                    AUTOSAVE, EMERGENCYSAVE, RECOVERY

            @return [string]
                    a suitable job description of form:
                        vnd.sun.star.autorecovery:/do...
         */
        static ::rtl::OUString implst_getJobDescription(sal_Int32 eJob);

        //---------------------------------------
        /** @short  mape the given URL to an internal int representation.

            @param  aURL
                    the url, which describe the next starting or may be already running
                    operation.

            @return [long]
                    the internal int representation
                    see enum EJob
         */
        static sal_Int32 implst_classifyJob(const css::util::URL& aURL);

        /// TODO
        void implts_verifyCacheAgainstDesktopDocumentList();

        /// TODO document me
        sal_Bool impl_enoughDiscSpace(sal_Int32 nRequiredSpace);

        /// TODO document me
        static void impl_showFullDiscError();

        //---------------------------------------
        /** @short  try to create/use a progress and set it inside the
                    environment.

            @descr  The problem behind: There exists different use case of this method.
                    a) An external progress is provided by our CrashSave or Recovery dialog.
                    b) We must create our own progress e.g. for an AutoSave
                    c) Sometimes our application filters dont use the progress
                       provided by the MediaDescriptor. They uses the Frame everytime to create
                       it's own progress. So we implemented a HACK for these and now we set
                       an InterceptedProgress there for the time WE use this frame for loading/storing documents .-)

            @param  xNewFrame
                    must be set only in case WE create a new frame (e.g. for loading documents
                    on session restore or recovery). Then search for a frame using rInfo.Document must
                    be supressed and xFrame must be preferred instead .-)

            @param  rInfo
                    used e.g. to find the frame corresponding to a document.
                    This frame must be used to create a new progress e.g. for an AutoSave.

            @param  rArgs
                    is used to set the new created progress as parameter on these set.
         */
        void impl_establishProgress(const AutoRecovery::TDocumentInfo&               rInfo    ,
                                          ::comphelper::MediaDescriptor&             rArgs    ,
                                    const css::uno::Reference< css::frame::XFrame >& xNewFrame);

        void impl_forgetProgress(const AutoRecovery::TDocumentInfo&               rInfo    ,
                                       ::comphelper::MediaDescriptor&             rArgs    ,
                                 const css::uno::Reference< css::frame::XFrame >& xNewFrame);
                                 
        //---------------------------------------
        /** try to remove the specified file from disc.
        
            Every URL supported by our UCB component can be used here.
            Further it doesnt matter if the file realy exists or not.
            Because removing a non exsistent file will have the same
            result at the end ... a non existing file .-)

            On the other side removing of files from disc is an optional
            feature. If we are not able doing so ... its not a real problem.
            Ok - users disc place will be samller then ... but we should produce
            a crash during crash save because we cant delete a temporary file only !
            
            @param  sURL
                    the url of the file, which should be removed.
         */
        static void st_impl_removeFile(const ::rtl::OUString& sURL);
        
        //---------------------------------------
        /** try to remove ".lock" file from disc if office will be terminated
            not using the offical way .-)
            
            This method has to be handled "optional". So every error inside
            has to be ignored ! This method CANT FAIL ... it can forget something only .-)
         */
        static void st_impl_removeLockFile();
};

} // namespace framework

#endif // __FRAMEWORK_SERVICES_AUTORECOVERY_HXX_

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */