summaryrefslogtreecommitdiff
path: root/dbaccess/source/ui/inc/brwctrlr.hxx
blob: 381c70a2c0cd7d7f07ce619103adaa18dd8d15c8 (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
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: brwctrlr.hxx,v $
 * $Revision: 1.40.6.3 $
 *
 * 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 _SBA_BWRCTRLR_HXX
#define _SBA_BWRCTRLR_HXX

#include "genericcontroller.hxx"
#include "moduledbu.hxx"
#include "brwview.hxx"
#include "sbagrid.hxx"

/** === begin UNO includes === **/
#include <com/sun/star/form/XLoadable.hpp>
#include <com/sun/star/container/XContainerListener.hpp>
#include <com/sun/star/sdb/XSQLErrorListener.hpp>
#include <com/sun/star/sdbc/XRowSet.hpp>
#include <com/sun/star/form/XResetListener.hpp>
#include <com/sun/star/form/XDatabaseParameterListener.hpp>
#include <com/sun/star/form/XConfirmDeleteListener.hpp>
#include <com/sun/star/form/XFormComponent.hpp>
#include <com/sun/star/awt/XFocusListener.hpp>
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
#include <com/sun/star/beans/XPropertyChangeListener.hpp>
#include <com/sun/star/frame/XModule.hpp>
/** === end UNO includes === **/

#include <vcl/timer.hxx>
#include <svtools/transfer.hxx>
#include <osl/mutex.hxx>
#include <vos/thread.hxx>
#include <svtools/cancel.hxx>
#include <cppuhelper/implbase9.hxx>
#include <svtools/cliplistener.hxx>

class ResMgr;
struct FmFoundRecordInformation;
struct FmSearchContext;

namespace dbtools
{
    class SQLExceptionInfo;
}

namespace dbaui
{

    // =========================================================================

    typedef ::cppu::ImplInheritanceHelper9  <   OGenericUnoController
                                            ,   ::com::sun::star::sdb::XSQLErrorListener
                                            ,   ::com::sun::star::form::XDatabaseParameterListener
                                            ,   ::com::sun::star::form::XConfirmDeleteListener
                                            ,   ::com::sun::star::form::XLoadListener
                                            ,   ::com::sun::star::form::XResetListener
                                            ,   ::com::sun::star::awt::XFocusListener
                                            ,   ::com::sun::star::container::XContainerListener
                                            ,   ::com::sun::star::beans::XPropertyChangeListener
                                            ,   ::com::sun::star::frame::XModule
                                            >   SbaXDataBrowserController_Base;

    class SbaXDataBrowserController :public SbaXDataBrowserController_Base
                                    ,public SbaGridListener
    {
    // ==========
    // attributes
    private:
        // for implementing the XFormController
        class FormControllerImpl;
        friend class FormControllerImpl;
        OModuleClient                                                            m_aModuleClient;

        ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRowSet >             m_xRowSet;      // our rowset
        ::com::sun::star::uno::Reference< ::com::sun::star::sdbcx::XColumnsSupplier >   m_xColumnsSupplier; // queried from the rowset member
        ::com::sun::star::uno::Reference< ::com::sun::star::form::XLoadable >           m_xLoadable;        // queried from the rowset member as well
        ::com::sun::star::uno::Reference< ::com::sun::star::form::XFormComponent >      m_xGridModel;   // the model of our grid
        ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter >    m_xFormatter;   // a number formatter working with the connection's NumberFormatsSupplier
        ::com::sun::star::uno::Reference< ::com::sun::star::uno::XAggregation >         m_xFormControllerImpl;
        mutable ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XSingleSelectQueryComposer >
                                                                                        m_xParser;      // for sorting 'n filtering

        AutoTimer               m_aInvalidateClipboard;             // for testing the state of the CUT/COPY/PASTE-slots

        TransferableDataHelper  m_aSystemClipboard;     // content of the clipboard
        TransferableClipboardListener*
                                m_pClipbordNotifier;    // notifier for changes in the clipboard

        ::osl::Mutex            m_aAsyncLoadSafety;     // for multi-thread access to our members

        OAsyncronousLink        m_aAsyncGetCellFocus;

        String                  m_sStateSaveRecord;
        String                  m_sStateUndoRecord;
        ::rtl::OUString         m_sModuleIdentifier;

        // members for asynchronous load operations
        ::vos::OThread*         m_pLoadThread;          // the thread wherein the form is loaded
        FormControllerImpl*     m_pFormControllerImpl;  // implementing the XFormController

        ULONG                   m_nPendingLoadFinished;         // the event used to tell ourself that the load is finished
        sal_uInt16              m_nFormActionNestingLevel;      // see enter-/leaveFormAction

        sal_Bool                m_bLoadCanceled : 1;            // the load was canceled somehow
        sal_Bool                m_bClosingKillOpen : 1;         // are we killing the load thread because we are to be suspended ?
        sal_Bool                m_bErrorOccured : 1;            // see enter-/leaveFormAction
        bool                    m_bCannotSelectUnfiltered : 1;  // recieved an DATA_CANNOT_SELECT_UNFILTERED error

    protected:
        class FormErrorHelper
        {
            SbaXDataBrowserController*  m_pOwner;
        public:
            FormErrorHelper(SbaXDataBrowserController* pOwner) : m_pOwner(pOwner) { m_pOwner->enterFormAction(); }
            virtual ~FormErrorHelper() { m_pOwner->leaveFormAction(); }
        };
        friend class FormErrorHelper;

    // ================
    // attribute access
    protected:
        ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRowSet >             getRowSet()         const   { return m_xRowSet; }
        ::com::sun::star::uno::Reference< ::com::sun::star::sdbcx::XColumnsSupplier >   getColumnsSupplier()const   { return m_xColumnsSupplier; }
        ::com::sun::star::uno::Reference< ::com::sun::star::form::XLoadable >           getLoadable()       const   { return m_xLoadable; }

        ::com::sun::star::uno::Reference< ::com::sun::star::form::XFormComponent >      getFormComponent()  const   { return m_xGridModel; }
        ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel >        getControlModel()   const   { return ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel > (m_xGridModel, ::com::sun::star::uno::UNO_QUERY); }
        ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter >    getNumberFormatter()const   { return m_xFormatter; }

        sal_Bool    isValid() const         { return m_xRowSet.is() && m_xGridModel.is(); }
        sal_Bool    isValidCursor() const;  // checks the ::com::sun::star::data::XDatabaseCursor-interface of m_xRowSet
        sal_Bool    isLoaded() const;
        sal_Bool    loadingCancelled() const { return m_bLoadCanceled; }
        void        onStartLoading( const ::com::sun::star::uno::Reference< ::com::sun::star::form::XLoadable >& _rxLoadable );
        void        setLoadingCancelled()   { m_bLoadCanceled = sal_True; }

        const TransferableDataHelper&
            getViewClipboard() const { return m_aSystemClipboard; }

    public:
        SbaXDataBrowserController(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rM);

        UnoDataBrowserView* getBrowserView() const { return static_cast< UnoDataBrowserView*>(m_pView); }
        // late construction
        virtual sal_Bool Construct(Window* pParent);

        // UNO
        virtual ::com::sun::star::uno::Any  SAL_CALL queryInterface(const ::com::sun::star::uno::Type& _rType) throw (::com::sun::star::uno::RuntimeException);

        // XTypeProvider
        virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes(  ) throw (::com::sun::star::uno::RuntimeException);
        virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId(  ) throw (::com::sun::star::uno::RuntimeException);

        // ::com::sun::star::lang::XEventListener
        virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& Source) throw( ::com::sun::star::uno::RuntimeException );

        // ::com::sun::star::util::XModifyListener
        virtual void SAL_CALL modified(const ::com::sun::star::lang::EventObject& aEvent) throw( ::com::sun::star::uno::RuntimeException );

        // ::com::sun::star::container::XContainerListener
        virtual void SAL_CALL elementInserted(const ::com::sun::star::container::ContainerEvent& Event) throw( ::com::sun::star::uno::RuntimeException );
        virtual void SAL_CALL elementRemoved(const ::com::sun::star::container::ContainerEvent& Event) throw( ::com::sun::star::uno::RuntimeException );
        virtual void SAL_CALL elementReplaced(const ::com::sun::star::container::ContainerEvent& Event) throw( ::com::sun::star::uno::RuntimeException );

        // XPropertyChangeListener
        virtual void SAL_CALL propertyChange( const ::com::sun::star::beans::PropertyChangeEvent& evt ) throw (::com::sun::star::uno::RuntimeException);

        // XModule
        virtual void SAL_CALL setIdentifier( const ::rtl::OUString& Identifier ) throw (::com::sun::star::uno::RuntimeException);
        virtual ::rtl::OUString SAL_CALL getIdentifier(  ) throw (::com::sun::star::uno::RuntimeException);

        // ::com::sun::star::awt::XFocusListener
        virtual void SAL_CALL focusGained(const ::com::sun::star::awt::FocusEvent& e) throw( ::com::sun::star::uno::RuntimeException );
        virtual void SAL_CALL focusLost(const ::com::sun::star::awt::FocusEvent& e) throw( ::com::sun::star::uno::RuntimeException );

        // ::com::sun::star::frame::XController
        virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) throw( ::com::sun::star::uno::RuntimeException );

        // ::com::sun::star::lang::XComponent
        virtual void        SAL_CALL disposing();

        // ::com::sun::star::frame::XFrameActionListener
        virtual void        SAL_CALL frameAction(const ::com::sun::star::frame::FrameActionEvent& aEvent) throw( ::com::sun::star::uno::RuntimeException );

        // ::com::sun::star::sdb::XSQLErrorListener
        virtual void        SAL_CALL errorOccured(const ::com::sun::star::sdb::SQLErrorEvent& aEvent) throw( ::com::sun::star::uno::RuntimeException );

        // ::com::sun::star::form::XDatabaseParameterListener
        virtual sal_Bool    SAL_CALL approveParameter(const ::com::sun::star::form::DatabaseParameterEvent& aEvent) throw( ::com::sun::star::uno::RuntimeException );

        // ::com::sun::star::form::XConfirmDeleteListener
        virtual sal_Bool    SAL_CALL confirmDelete(const ::com::sun::star::sdb::RowChangeEvent& aEvent) throw( ::com::sun::star::uno::RuntimeException );

        // ::com::sun::star::form::XLoadListener
        virtual void SAL_CALL loaded(const ::com::sun::star::lang::EventObject& aEvent) throw( ::com::sun::star::uno::RuntimeException );
        virtual void SAL_CALL unloading(const ::com::sun::star::lang::EventObject& aEvent) throw( ::com::sun::star::uno::RuntimeException );
        virtual void SAL_CALL unloaded(const ::com::sun::star::lang::EventObject& aEvent) throw( ::com::sun::star::uno::RuntimeException );
        virtual void SAL_CALL reloading(const ::com::sun::star::lang::EventObject& aEvent) throw( ::com::sun::star::uno::RuntimeException );
        virtual void SAL_CALL reloaded(const ::com::sun::star::lang::EventObject& aEvent) throw( ::com::sun::star::uno::RuntimeException );

        // ::com::sun::star::form::XResetListener
        virtual sal_Bool SAL_CALL approveReset(const ::com::sun::star::lang::EventObject& rEvent) throw( ::com::sun::star::uno::RuntimeException );
        virtual void SAL_CALL resetted(const ::com::sun::star::lang::EventObject& rEvent) throw( ::com::sun::star::uno::RuntimeException );

        // SbaGridListener
        virtual void RowChanged();
        virtual void ColumnChanged();
        virtual void SelectionChanged();
        virtual void CellActivated();
        virtual void CellDeactivated();
        virtual void BeforeDrop();
        virtual void AfterDrop();

    protected:
        virtual ~SbaXDataBrowserController();

        // all the features which should be handled by this class
        virtual void            describeSupportedFeatures();
        // state of a feature. 'feature' may be the handle of a ::com::sun::star::util::URL somebody requested a dispatch interface for OR a toolbar slot.
        virtual FeatureState    GetState(sal_uInt16 nId) const;
        // execute a feature
        virtual void            Execute(sal_uInt16 nId, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue>& aArgs);

        virtual void    startFrameListening( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& _rxFrame );
        virtual void    stopFrameListening( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& _rxFrame );

        virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRowSet >  CreateForm();
            // our default implementation simply instantiates a stardiv.one.form.component.Form service
            // (probably this needs not to be overloaded, but you may return anything you want as long as it
            // supports the ::com::sun::star::form::DatabaseForm service. For instance you may want to create an adapter here which
            // is synchronized with a foreign ::com::sun::star::form::DatabaseForm you got elsewhere)
        virtual sal_Bool InitializeForm(const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRowSet > & xForm) = 0;
            // called immediately after a successfull CreateForm
            // do any initialization (data source etc.) here. the form should be fully functional after that.
            // return sal_False if you didn't succeed (don't throw exceptions, they won't be caught)

        virtual sal_Bool InitializeGridModel(const ::com::sun::star::uno::Reference< ::com::sun::star::form::XFormComponent > & xGrid);


        virtual ::com::sun::star::uno::Reference< ::com::sun::star::form::XFormComponent >  CreateGridModel();
            // our default implementation simply instantiates a stardiv.one.form.component.Grid service
            // you most probably don't want to override this behaviuor

        // the default implementation of disposing distributes the events to the following disposingXXX functions
        virtual void disposingGridControl(const ::com::sun::star::lang::EventObject& Source);   // calls removeControlListeners
        virtual void disposingGridModel(const ::com::sun::star::lang::EventObject& Source);     // calls removeModelListeners
        virtual void disposingFormModel(const ::com::sun::star::lang::EventObject& Source);
        virtual void disposingColumnModel(const ::com::sun::star::lang::EventObject& Source);

        // want to be a listener to the grid control ? use this !
        virtual void addControlListeners(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControl > & _xGridControl);
        virtual void removeControlListeners(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControl > & _xGridControl);

        // want to be a listener to the grid model ? use this !
        virtual void addModelListeners(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel > & _xGridControlModel);
        virtual void removeModelListeners(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel > & _xGridControlModel);

        // want to be a listener grid columns ? use this !
        virtual void AddColumnListener(const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > & xCol);
        virtual void RemoveColumnListener(const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > & xCol);


            // call after "major changes" (e.g. the completion of the async load).
            // invalidates all toolbox slots and all supported features.

        virtual sal_Bool LoadForm();
            // load the form
            // the default implementation does an direct load or starts a load thread, depending on the multithread capabilities
            // of the data source.
            // the default implementation also calls LoadFinished after a syncronous load, so be sure to do the same if you override
            // this metod and don't call the base class' method

        virtual void LoadFinished(sal_Bool bWasSynch);
            // called if the loading (the _complete_ loading process) is done (no matter if synchron or asynchron).

        virtual void criticalFail();
            // called whenever a reload operation on the rowset failed
            // (a "operation" is not only a simple reload: If the user sets a filter, an reloading the form
            // after setting this filter fails, the filter is reset and the form is reloaded, again. Only the
            // whole process (_both_ XLoadable::reload calls _together_) form the "reload operation"

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

            // empty the frame where our view resides
        virtual sal_Bool CommitCurrent();
            // commit the current column (i.e. cell)
        virtual sal_Bool SaveModified(sal_Bool bAskFor = sal_True);
            // save the modified record

        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >   getBoundField(sal_uInt16 nViewPos = (sal_uInt16)-1) const;
            // a PropertySet corresponding to the cursor field a column is bound to
            // if nViewPos is (sal_uInt16)-1 (the default) then the field for the current column will be retrieved

        sal_Bool PendingLoad() const { return m_pLoadThread != NULL; }
            // is there an asyncronous load operation in progress ?

        void enterFormAction();
        void leaveFormAction();
        bool errorOccured() const { return m_bErrorOccured; }
            // As many form actions don't throw an exception but call their error handler instead we don't have
            // a chance to recognize errors by exception catching.
            // So for error recognition the above methods may be used.
        // init the formatter if form changes
        void initFormatter();

        /// loads or reloads the form
        virtual sal_Bool reloadForm(const ::com::sun::star::uno::Reference< ::com::sun::star::form::XLoadable >& _rxLoadable);

        virtual sal_Bool preReloadForm(){ return sal_False; }
        virtual void postReloadForm(){}

    private:
        void setCurrentModified( sal_Bool _bSet );

        // execute the filter or sort slot
        void ExecuteFilterSortCrit(sal_Bool bFilter);

        // execute the search slot
        void        ExecuteSearch();

        void        initializeParser() const; // changes the mutable member m_xParser
        void        applyParserFilter(const ::rtl::OUString& _rOldFilter, sal_Bool _bOldFilterApplied,const ::rtl::OUString& _sOldHaving = ::rtl::OUString());
        void        applyParserOrder(const ::rtl::OUString& _rOldOrder);

        sal_Int16   getCurrentColumnPosition();
        void        setCurrentColumnPosition( sal_Int16 _nPos );
        void        addColumnListeners(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel > & _xGridControlModel);

        void        impl_checkForCannotSelectUnfiltered( const ::dbtools::SQLExceptionInfo& _rError );

        // time to check the CUT/COPY/PASTE-slot-states
        DECL_LINK( OnInvalidateClipboard, AutoTimer* );
        DECL_LINK( OnClipboardChanged, void* );

        // search callbacks
        DECL_LINK(OnSearchContextRequest, FmSearchContext*);
        DECL_LINK(OnFoundData, FmFoundRecordInformation*);
        DECL_LINK(OnCanceledNotFound, FmFoundRecordInformation*);

        // callbacks for the completed loading process
        DECL_LINK(OnOpenFinished, void*);
        DECL_LINK(OnOpenFinishedMainThread, void*);
            // OnOpenFinsihed is called in a foreign thread (the one which does the loading) so it simply posts the
            // OnOpenFinishedMainThread-link (which will be called in the main thread, then) as user event.
            // (the alternative would be to lock the SolarMutex in OnOpenFinished to avoid problems with the needed updates,
            // but playing with this mutex seems very hazardous to me ....)
        DECL_LINK(OnAsyncGetCellFocus, void*);
    };

    //==================================================================
    // LoadFormThread - a thread for asynchronously loading a form
    //==================================================================
    class LoadFormThread : public ::vos::OThread
    {
        ::osl::Mutex    m_aAccessSafety;        // for securing the multi-thread access
        ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRowSet >                 m_xRowSet;          // the data source to be loaded

        Link                    m_aTerminationHandler;  // the handler to be called upon termination
        sal_Bool                    m_bCanceled;            // StopIt has been called ?
        String                  m_sStopperCaption;      // the caption for the ThreadStopper

        // a ThreadStopper will be instantiated so that the open can be canceled via the UI
        class ThreadStopper : protected SfxCancellable
        {
            LoadFormThread* m_pOwner;

        public:
            ThreadStopper(LoadFormThread* pOwner, const String& rTitle);
            virtual ~ThreadStopper() { }

            virtual void    Cancel();

            virtual void    OwnerTerminated();
            // Normally the Owner (a LoadFormThread) would delete the stopper when terminated.
            // Unfortunally the application doesn't remove the 'red light' when a SfxCancellable is deleted
            // if it (the app) can't acquire the solar mutex. The deletion is IGNORED then. So we have to make
            // sure that a) the stopper is deleted from inside the main thread (where the solar mutex is locked)
            // and b) that in the time between the termination of the thread and the deletion of the stopper
            // the latter doesn't access the former.
            // The OwnerTerminated cares for both aspects.
            // SO DON'T DELETE THE STOPPER EXPLICITLY !

        protected:
            // HACK HACK HACK HACK HACK : this should be private, but MSVC doesn't accept the LINK-macro then ....
            DECL_LINK(OnDeleteInMainThread, ThreadStopper*);
        };
        friend class LoadFormThread::ThreadStopper;

    public:
        LoadFormThread(const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRowSet > & _xRowSet, const String& _rStopperCaption) : m_xRowSet(_xRowSet), m_sStopperCaption(_rStopperCaption) { }

        virtual void SAL_CALL run();
        virtual void SAL_CALL onTerminated();

        void SetTerminationHdl(const Link& aTermHdl) { m_aTerminationHandler = aTermHdl; }
            // the handler will be called synchronously (the parameter is a pointer to the thread)
            // if no termination handler is set, the thread disposes the data source and deletes
            // itself upon termination

        // cancels the process. to be called from another thread (of course ;)
        void StopIt();

        // ask if the load canceled
        sal_Bool WasCanceled() const { return m_bCanceled; }
    };
}

#endif // _SBA_BWRCTRLR_HXX