1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/macros.h>
22 #include <svx/gridctrl.hxx>
23 #include "gridcell.hxx"
24 #include "svx/fmtools.hxx"
25 #include <svtools/stringtransfer.hxx>
26 #include <connectivity/dbtools.hxx>
27 #include <connectivity/dbconversion.hxx>
30 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
31 #include <com/sun/star/accessibility/XAccessible.hpp>
32 #include <com/sun/star/sdb/XResultSetAccess.hpp>
33 #include <com/sun/star/sdb/RowChangeAction.hpp>
34 #include <com/sun/star/sdb/XRowsChangeBroadcaster.hpp>
35 #include <com/sun/star/sdbc/XResultSetUpdate.hpp>
36 #include <com/sun/star/sdbcx/Privilege.hpp>
37 #include <com/sun/star/container/XChild.hpp>
38 #include <com/sun/star/util/NumberFormatter.hpp>
39 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
40 #include <com/sun/star/util/XCloneable.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
43 #include <comphelper/processfactory.hxx>
44 #include <tools/resid.hxx>
45 #include <tools/diagnose_ex.h>
46 #include <tools/fract.hxx>
47 #include <vcl/menu.hxx>
48 #include <vcl/settings.hxx>
50 #include "svx/fmresids.hrc"
52 #include <svx/svxids.hrc>
53 #include <svx/dialmgr.hxx>
54 #include "fmservs.hxx"
55 #include "sdbdatacolumn.hxx"
57 #include <comphelper/property.hxx>
63 using namespace ::dbtools
;
64 using namespace ::dbtools::DBTypeConversion
;
65 using namespace ::svxform
;
66 using namespace ::svt
;
67 using namespace ::com::sun::star::beans
;
68 using namespace ::com::sun::star::lang
;
69 using namespace ::com::sun::star::uno
;
70 using namespace ::com::sun::star::sdbc
;
71 using namespace ::com::sun::star::sdbcx
;
72 using namespace ::com::sun::star::sdb
;
73 using namespace ::com::sun::star::datatransfer
;
74 using namespace ::com::sun::star::container
;
75 using namespace com::sun::star::accessibility
;
77 #define ROWSTATUS(row) (!row.Is() ? "NULL" : row->GetStatus() == GRS_CLEAN ? "CLEAN" : row->GetStatus() == GRS_MODIFIED ? "MODIFIED" : row->GetStatus() == GRS_DELETED ? "DELETED" : "INVALID")
79 #define DEFAULT_BROWSE_MODE \
80 BrowserMode::COLUMNSELECTION \
81 | BrowserMode::MULTISELECTION \
82 | BrowserMode::KEEPHIGHLIGHT \
83 | BrowserMode::TRACKING_TIPS \
84 | BrowserMode::HLINES \
85 | BrowserMode::VLINES \
86 | BrowserMode::HEADERBAR_NEW \
88 class RowSetEventListener : public ::cppu::WeakImplHelper1<XRowsChangeListener>
90 VclPtr
<DbGridControl
> m_pControl
;
92 RowSetEventListener(DbGridControl
* i_pControl
) : m_pControl(i_pControl
)
98 virtual void SAL_CALL
disposing(const ::com::sun::star::lang::EventObject
& /*i_aEvt*/) throw ( RuntimeException
, std::exception
) SAL_OVERRIDE
101 virtual void SAL_CALL
rowsChanged(const ::com::sun::star::sdb::RowsChangeEvent
& i_aEvt
) throw ( RuntimeException
, std::exception
) SAL_OVERRIDE
103 if ( i_aEvt
.Action
== RowChangeAction::UPDATE
)
105 ::DbGridControl::GrantControlAccess aAccess
;
106 CursorWrapper
* pSeek
= m_pControl
->GetSeekCursor(aAccess
);
107 const DbGridRowRef
& rSeekRow
= m_pControl
->GetSeekRow(aAccess
);
108 const Any
* pIter
= i_aEvt
.Bookmarks
.getConstArray();
109 const Any
* pEnd
= pIter
+ i_aEvt
.Bookmarks
.getLength();
110 for(;pIter
!= pEnd
;++pIter
)
112 pSeek
->moveToBookmark(*pIter
);
114 rSeekRow
->SetState(pSeek
, true);
115 sal_Int32 nSeekPos
= pSeek
->getRow() - 1;
116 m_pControl
->SetSeekPos(nSeekPos
,aAccess
);
117 m_pControl
->RowModified(nSeekPos
);
123 class GridFieldValueListener
;
124 typedef std::map
<sal_uInt16
, GridFieldValueListener
*> ColumnFieldValueListeners
;
126 class GridFieldValueListener
: protected ::comphelper::OPropertyChangeListener
129 DbGridControl
& m_rParent
;
130 ::comphelper::OPropertyChangeMultiplexer
* m_pRealListener
;
132 sal_Int16 m_nSuspended
;
133 bool m_bDisposed
: 1;
136 GridFieldValueListener(DbGridControl
& _rParent
, const Reference
< XPropertySet
>& xField
, sal_uInt16 _nId
);
137 virtual ~GridFieldValueListener();
139 virtual void _propertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
) SAL_OVERRIDE
;
141 void suspend() { ++m_nSuspended
; }
142 void resume() { --m_nSuspended
; }
147 GridFieldValueListener::GridFieldValueListener(DbGridControl
& _rParent
, const Reference
< XPropertySet
>& _rField
, sal_uInt16 _nId
)
148 :OPropertyChangeListener(m_aMutex
)
150 ,m_pRealListener(NULL
)
157 m_pRealListener
= new ::comphelper::OPropertyChangeMultiplexer(this, _rField
);
158 m_pRealListener
->addProperty(FM_PROP_VALUE
);
159 m_pRealListener
->acquire();
163 GridFieldValueListener::~GridFieldValueListener()
168 void GridFieldValueListener::_propertyChanged(const PropertyChangeEvent
& _evt
) throw( RuntimeException
)
170 DBG_ASSERT(m_nSuspended
>=0, "GridFieldValueListener::_propertyChanged : resume > suspend !");
171 if (m_nSuspended
<= 0)
172 m_rParent
.FieldValueChanged(m_nId
, _evt
);
175 void GridFieldValueListener::dispose()
179 DBG_ASSERT(m_pRealListener
== NULL
, "GridFieldValueListener::dispose : inconsistent !");
185 m_pRealListener
->dispose();
186 m_pRealListener
->release();
187 m_pRealListener
= NULL
;
191 m_rParent
.FieldListenerDisposing(m_nId
);
194 class DisposeListenerGridBridge
: public FmXDisposeListener
197 DbGridControl
& m_rParent
;
198 FmXDisposeMultiplexer
* m_pRealListener
;
201 DisposeListenerGridBridge( DbGridControl
& _rParent
, const Reference
< XComponent
>& _rxObject
, sal_Int16 _rId
= -1);
202 virtual ~DisposeListenerGridBridge();
204 virtual void disposing(const EventObject
& _rEvent
, sal_Int16 _nId
) throw( RuntimeException
) SAL_OVERRIDE
{ m_rParent
.disposing(_nId
, _rEvent
); }
207 DisposeListenerGridBridge::DisposeListenerGridBridge(DbGridControl
& _rParent
, const Reference
< XComponent
>& _rxObject
, sal_Int16 _rId
)
208 :FmXDisposeListener(m_aMutex
)
210 ,m_pRealListener(NULL
)
215 m_pRealListener
= new FmXDisposeMultiplexer(this, _rxObject
, _rId
);
216 m_pRealListener
->acquire();
220 DisposeListenerGridBridge::~DisposeListenerGridBridge()
224 m_pRealListener
->dispose();
225 m_pRealListener
->release();
226 m_pRealListener
= NULL
;
231 static const sal_uInt16 ControlMap
[] =
233 DbGridControl::NavigationBar::RECORD_TEXT
,
234 DbGridControl::NavigationBar::RECORD_ABSOLUTE
,
235 DbGridControl::NavigationBar::RECORD_OF
,
236 DbGridControl::NavigationBar::RECORD_COUNT
,
237 DbGridControl::NavigationBar::RECORD_FIRST
,
238 DbGridControl::NavigationBar::RECORD_NEXT
,
239 DbGridControl::NavigationBar::RECORD_PREV
,
240 DbGridControl::NavigationBar::RECORD_LAST
,
241 DbGridControl::NavigationBar::RECORD_NEW
,
245 bool CompareBookmark(const Any
& aLeft
, const Any
& aRight
)
247 return ::comphelper::compare(aLeft
, aRight
);
250 class FmXGridSourcePropListener
: public ::comphelper::OPropertyChangeListener
252 VclPtr
<DbGridControl
> m_pParent
;
254 // a DbGridControl has no mutex, so we use our own as the base class expects one
256 sal_Int16 m_nSuspended
;
259 FmXGridSourcePropListener(DbGridControl
* _pParent
);
261 void suspend() { ++m_nSuspended
; }
262 void resume() { --m_nSuspended
; }
264 virtual void _propertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
) SAL_OVERRIDE
;
267 FmXGridSourcePropListener::FmXGridSourcePropListener(DbGridControl
* _pParent
)
268 :OPropertyChangeListener(m_aMutex
)
272 DBG_ASSERT(m_pParent
, "FmXGridSourcePropListener::FmXGridSourcePropListener : invalid parent !");
275 void FmXGridSourcePropListener::_propertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
)
277 DBG_ASSERT(m_nSuspended
>=0, "FmXGridSourcePropListener::_propertyChanged : resume > suspend !");
278 if (m_nSuspended
<= 0)
279 m_pParent
->DataSourcePropertyChanged(evt
);
282 DbGridControl::NavigationBar::AbsolutePos::AbsolutePos(vcl::Window
* pParent
, WinBits nStyle
)
283 :NumericField(pParent
, nStyle
)
290 SetStrictFormat(true);
293 void DbGridControl::NavigationBar::AbsolutePos::KeyInput(const KeyEvent
& rEvt
)
295 if (rEvt
.GetKeyCode() == KEY_RETURN
&& !GetText().isEmpty())
297 sal_Int64 nRecord
= GetValue();
298 if (nRecord
< GetMin() || nRecord
> GetMax())
301 static_cast<NavigationBar
*>(GetParent())->PositionDataSource(static_cast<sal_Int32
>(nRecord
));
303 else if (rEvt
.GetKeyCode() == KEY_TAB
)
304 GetParent()->GetParent()->GrabFocus();
306 NumericField::KeyInput(rEvt
);
309 void DbGridControl::NavigationBar::AbsolutePos::LoseFocus()
311 NumericField::LoseFocus();
312 sal_Int64 nRecord
= GetValue();
313 if (nRecord
< GetMin() || nRecord
> GetMax())
317 static_cast<NavigationBar
*>(GetParent())->PositionDataSource(static_cast<sal_Int32
>(nRecord
));
318 static_cast<NavigationBar
*>(GetParent())->InvalidateState(NavigationBar::RECORD_ABSOLUTE
);
322 void DbGridControl::NavigationBar::PositionDataSource(sal_Int32 nRecord
)
326 // the MoveToPosition may cause a LoseFocus which would lead to a second MoveToPosition,
327 // so protect against this recursion
328 m_bPositioning
= true;
329 static_cast<DbGridControl
*>(GetParent())->MoveToPosition(nRecord
- 1);
330 m_bPositioning
= false;
333 DbGridControl::NavigationBar::NavigationBar(vcl::Window
* pParent
, WinBits nStyle
)
334 :Control(pParent
, nStyle
)
335 ,m_aRecordText(VclPtr
<FixedText
>::Create(this, WB_VCENTER
))
336 ,m_aAbsolute(VclPtr
<DbGridControl::NavigationBar::AbsolutePos
>::Create(this, WB_CENTER
| WB_VCENTER
))
337 ,m_aRecordOf(VclPtr
<FixedText
>::Create(this, WB_VCENTER
))
338 ,m_aRecordCount(VclPtr
<FixedText
>::Create(this, WB_VCENTER
))
339 ,m_aFirstBtn(VclPtr
<ImageButton
>::Create(this, WB_RECTSTYLE
|WB_NOPOINTERFOCUS
))
340 ,m_aPrevBtn(VclPtr
<ImageButton
>::Create(this, WB_REPEAT
|WB_RECTSTYLE
|WB_NOPOINTERFOCUS
))
341 ,m_aNextBtn(VclPtr
<ImageButton
>::Create(this, WB_REPEAT
|WB_RECTSTYLE
|WB_NOPOINTERFOCUS
))
342 ,m_aLastBtn(VclPtr
<ImageButton
>::Create(this, WB_RECTSTYLE
|WB_NOPOINTERFOCUS
))
343 ,m_aNewBtn(VclPtr
<ImageButton
>::Create(this, WB_RECTSTYLE
|WB_NOPOINTERFOCUS
))
346 ,m_bPositioning(false)
348 m_aFirstBtn
->SetSymbol(SymbolType::FIRST
);
349 m_aPrevBtn
->SetSymbol(SymbolType::PREV
);
350 m_aNextBtn
->SetSymbol(SymbolType::NEXT
);
351 m_aLastBtn
->SetSymbol(SymbolType::LAST
);
352 m_aNewBtn
->SetModeImage(static_cast<DbGridControl
*>(pParent
)->GetImage(DbGridControl_Base::NEW
));
354 m_aFirstBtn
->SetHelpId(HID_GRID_TRAVEL_FIRST
);
355 m_aPrevBtn
->SetHelpId(HID_GRID_TRAVEL_PREV
);
356 m_aNextBtn
->SetHelpId(HID_GRID_TRAVEL_NEXT
);
357 m_aLastBtn
->SetHelpId(HID_GRID_TRAVEL_LAST
);
358 m_aNewBtn
->SetHelpId(HID_GRID_TRAVEL_NEW
);
359 m_aAbsolute
->SetHelpId(HID_GRID_TRAVEL_ABSOLUTE
);
360 m_aRecordCount
->SetHelpId(HID_GRID_NUMBEROFRECORDS
);
362 // Handler fuer Buttons einrichten
363 m_aFirstBtn
->SetClickHdl(LINK(this,NavigationBar
,OnClick
));
364 m_aPrevBtn
->SetClickHdl(LINK(this,NavigationBar
,OnClick
));
365 m_aNextBtn
->SetClickHdl(LINK(this,NavigationBar
,OnClick
));
366 m_aLastBtn
->SetClickHdl(LINK(this,NavigationBar
,OnClick
));
367 m_aNewBtn
->SetClickHdl(LINK(this,NavigationBar
,OnClick
));
369 m_aRecordText
->SetText(SVX_RESSTR(RID_STR_REC_TEXT
));
370 m_aRecordOf
->SetText(SVX_RESSTR(RID_STR_REC_FROM_TEXT
));
371 m_aRecordCount
->SetText(OUString('?'));
373 m_nDefaultWidth
= ArrangeControls();
375 m_aFirstBtn
->Disable();
376 m_aPrevBtn
->Disable();
377 m_aNextBtn
->Disable();
378 m_aLastBtn
->Disable();
379 m_aNewBtn
->Disable();
380 m_aRecordText
->Disable();
381 m_aRecordOf
->Disable();
382 m_aRecordCount
->Disable();
383 m_aAbsolute
->Disable();
385 AllSettings aSettings
= m_aNextBtn
->GetSettings();
386 MouseSettings aMouseSettings
= aSettings
.GetMouseSettings();
387 aMouseSettings
.SetButtonRepeat(aMouseSettings
.GetButtonRepeat() / 4);
388 aSettings
.SetMouseSettings(aMouseSettings
);
389 m_aNextBtn
->SetSettings(aSettings
, true);
390 m_aPrevBtn
->SetSettings(aSettings
, true);
397 m_aRecordText
->Show();
399 m_aRecordCount
->Show();
404 DbGridControl::NavigationBar::~NavigationBar()
409 void DbGridControl::NavigationBar::dispose()
411 m_aRecordText
.disposeAndClear();
412 m_aAbsolute
.disposeAndClear();
413 m_aRecordOf
.disposeAndClear();
414 m_aRecordCount
.disposeAndClear();
415 m_aFirstBtn
.disposeAndClear();
416 m_aPrevBtn
.disposeAndClear();
417 m_aNextBtn
.disposeAndClear();
418 m_aLastBtn
.disposeAndClear();
419 m_aNewBtn
.disposeAndClear();
425 void SetPosAndSize(Button
& _rButton
,Point
& _rPos
,const Size
& _rSize
)
427 _rButton
.SetPosPixel( _rPos
);
428 _rButton
.SetSizePixel( _rSize
);
429 _rPos
.X() += (sal_uInt16
)_rSize
.Width();
433 sal_uInt16
DbGridControl::NavigationBar::ArrangeControls()
435 // positioning of the controls
436 // calculate base size
437 Rectangle
aRect(static_cast<DbGridControl
*>(GetParent())->GetControlArea());
438 const long nH
= aRect
.GetSize().Height();
439 Size aBorder
= LogicToPixel(Size(2, 2),MAP_APPFONT
);
440 aBorder
= Size(CalcZoom(aBorder
.Width()), CalcZoom(aBorder
.Height()));
444 // Is the font of this edit larger than the field?
445 if (m_aAbsolute
->GetTextHeight() > nH
)
447 vcl::Font
aApplFont (m_aAbsolute
->GetFont());
448 const Size
pointAbsoluteSize(m_aAbsolute
->PixelToLogic( Size( 0, nH
- 2 ), MapMode(MAP_POINT
) ));
449 aApplFont
.SetSize( pointAbsoluteSize
);
450 m_aAbsolute
->SetControlFont( aApplFont
);
452 aApplFont
.SetTransparent( true );
453 m_aRecordText
->SetControlFont( aApplFont
);
454 m_aRecordOf
->SetControlFont( aApplFont
);
455 m_aRecordCount
->SetControlFont( aApplFont
);
458 // set size and position of the control
459 OUString aText
= m_aRecordText
->GetText();
460 long nTextWidth
= m_aRecordText
->GetTextWidth(aText
);
461 m_aRecordText
->SetPosPixel(Point(nX
,nY
));
462 m_aRecordText
->SetSizePixel(Size(nTextWidth
,nH
));
463 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ nTextWidth
+ aBorder
.Width());
465 // count an extra hairspace (U+200A) left and right
466 const OUString
sevenDigits(m_aAbsolute
->CreateFieldText(6000000));
467 const OUString
hairSpace(static_cast<sal_Unicode
>(0x200A));
468 OUString
textPattern(hairSpace
);
469 textPattern
+= sevenDigits
;
470 textPattern
+= hairSpace
;
471 nTextWidth
= m_aAbsolute
->GetTextWidth( textPattern
);
472 m_aAbsolute
->SetPosPixel(Point(nX
,nY
));
473 m_aAbsolute
->SetSizePixel(Size(nTextWidth
, nH
));
474 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ nTextWidth
+ aBorder
.Width());
476 aText
= m_aRecordOf
->GetText();
477 nTextWidth
= m_aRecordOf
->GetTextWidth(aText
);
478 m_aRecordOf
->SetPosPixel(Point(nX
,nY
));
479 m_aRecordOf
->SetSizePixel(Size(nTextWidth
,nH
));
480 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ nTextWidth
+ aBorder
.Width());
482 textPattern
= sevenDigits
+ " * (" + sevenDigits
+ ")";
483 nTextWidth
= m_aRecordCount
->GetTextWidth( textPattern
);
484 m_aRecordCount
->SetPosPixel(Point(nX
,nY
));
485 m_aRecordCount
->SetSizePixel(Size(nTextWidth
,nH
));
486 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ nTextWidth
+ aBorder
.Width());
488 Point
aButtonPos(nX
,nY
);
489 const Size
aButtonSize(nH
,nH
);
490 SetPosAndSize(*m_aFirstBtn
.get(), aButtonPos
, aButtonSize
);
491 SetPosAndSize(*m_aPrevBtn
.get(), aButtonPos
, aButtonSize
);
492 SetPosAndSize(*m_aNextBtn
.get(), aButtonPos
, aButtonSize
);
493 SetPosAndSize(*m_aLastBtn
.get(), aButtonPos
, aButtonSize
);
494 SetPosAndSize(*m_aNewBtn
.get(), aButtonPos
, aButtonSize
);
496 nX
= sal::static_int_cast
< sal_uInt16
>(aButtonPos
.X() + 1);
501 IMPL_LINK(DbGridControl::NavigationBar
, OnClick
, Button
*, pButton
)
503 DbGridControl
* pParent
= static_cast<DbGridControl
*>(GetParent());
505 if (pParent
->m_aMasterSlotExecutor
.IsSet())
508 if (pButton
== m_aFirstBtn
.get())
509 lResult
= pParent
->m_aMasterSlotExecutor
.Call(reinterpret_cast<void*>(RECORD_FIRST
));
510 else if( pButton
== m_aPrevBtn
.get() )
511 lResult
= pParent
->m_aMasterSlotExecutor
.Call(reinterpret_cast<void*>(RECORD_PREV
));
512 else if( pButton
== m_aNextBtn
.get() )
513 lResult
= pParent
->m_aMasterSlotExecutor
.Call(reinterpret_cast<void*>(RECORD_NEXT
));
514 else if( pButton
== m_aLastBtn
.get() )
515 lResult
= pParent
->m_aMasterSlotExecutor
.Call(reinterpret_cast<void*>(RECORD_LAST
));
516 else if( pButton
== m_aNewBtn
.get() )
517 lResult
= pParent
->m_aMasterSlotExecutor
.Call(reinterpret_cast<void*>(RECORD_NEW
));
520 // the link already handled it
524 if (pButton
== m_aFirstBtn
.get())
525 pParent
->MoveToFirst();
526 else if( pButton
== m_aPrevBtn
.get() )
527 pParent
->MoveToPrev();
528 else if( pButton
== m_aNextBtn
.get() )
529 pParent
->MoveToNext();
530 else if( pButton
== m_aLastBtn
.get() )
531 pParent
->MoveToLast();
532 else if( pButton
== m_aNewBtn
.get() )
533 pParent
->AppendNew();
537 void DbGridControl::NavigationBar::InvalidateAll(sal_Int32 nCurrentPos
, bool bAll
)
539 if (m_nCurrentPos
!= nCurrentPos
|| nCurrentPos
< 0 || bAll
)
541 DbGridControl
* pParent
= static_cast<DbGridControl
*>(GetParent());
543 sal_Int32 nAdjustedRowCount
= pParent
->GetRowCount() - ((pParent
->GetOptions() & DbGridControl::OPT_INSERT
) ? 2 : 1);
545 // check if everything needs to be invalidated
546 bAll
= bAll
|| m_nCurrentPos
<= 0;
547 bAll
= bAll
|| nCurrentPos
<= 0;
548 bAll
= bAll
|| m_nCurrentPos
>= nAdjustedRowCount
;
549 bAll
= bAll
|| nCurrentPos
>= nAdjustedRowCount
;
553 m_nCurrentPos
= nCurrentPos
;
555 while (ControlMap
[i
])
556 SetState(ControlMap
[i
++]);
558 else // is in the center
560 m_nCurrentPos
= nCurrentPos
;
561 SetState(NavigationBar::RECORD_COUNT
);
562 SetState(NavigationBar::RECORD_ABSOLUTE
);
567 bool DbGridControl::NavigationBar::GetState(sal_uInt16 nWhich
) const
569 DbGridControl
* pParent
= static_cast<DbGridControl
*>(GetParent());
571 if (!pParent
->IsOpen() || pParent
->IsDesignMode() || !pParent
->IsEnabled()
572 || pParent
->IsFilterMode() )
576 // check if we have a master state provider
577 if (pParent
->m_aMasterStateProvider
.IsSet())
579 long nState
= pParent
->m_aMasterStateProvider
.Call(reinterpret_cast< void* >( nWhich
) );
584 bool bAvailable
= true;
588 case NavigationBar::RECORD_FIRST
:
589 case NavigationBar::RECORD_PREV
:
590 bAvailable
= m_nCurrentPos
> 0;
592 case NavigationBar::RECORD_NEXT
:
593 if(pParent
->m_bRecordCountFinal
)
595 bAvailable
= m_nCurrentPos
< pParent
->GetRowCount() - 1;
596 if (!bAvailable
&& pParent
->GetOptions() & DbGridControl::OPT_INSERT
)
597 bAvailable
= (m_nCurrentPos
== pParent
->GetRowCount() - 2) && pParent
->IsModified();
600 case NavigationBar::RECORD_LAST
:
601 if(pParent
->m_bRecordCountFinal
)
603 if (pParent
->GetOptions() & DbGridControl::OPT_INSERT
)
604 bAvailable
= pParent
->IsCurrentAppending() ? pParent
->GetRowCount() > 1 :
605 m_nCurrentPos
!= pParent
->GetRowCount() - 2;
607 bAvailable
= m_nCurrentPos
!= pParent
->GetRowCount() - 1;
610 case NavigationBar::RECORD_NEW
:
611 bAvailable
= (pParent
->GetOptions() & DbGridControl::OPT_INSERT
) && pParent
->GetRowCount() && m_nCurrentPos
< pParent
->GetRowCount() - 1;
613 case NavigationBar::RECORD_ABSOLUTE
:
614 bAvailable
= pParent
->GetRowCount() > 0;
621 void DbGridControl::NavigationBar::SetState(sal_uInt16 nWhich
)
623 bool bAvailable
= GetState(nWhich
);
624 DbGridControl
* pParent
= static_cast<DbGridControl
*>(GetParent());
625 vcl::Window
* pWnd
= NULL
;
628 case NavigationBar::RECORD_FIRST
:
629 pWnd
= m_aFirstBtn
.get();
631 case NavigationBar::RECORD_PREV
:
632 pWnd
= m_aPrevBtn
.get();
634 case NavigationBar::RECORD_NEXT
:
635 pWnd
= m_aNextBtn
.get();
637 case NavigationBar::RECORD_LAST
:
638 pWnd
= m_aLastBtn
.get();
640 case NavigationBar::RECORD_NEW
:
641 pWnd
= m_aNewBtn
.get();
643 case NavigationBar::RECORD_ABSOLUTE
:
644 pWnd
= m_aAbsolute
.get();
647 if (pParent
->m_nTotalCount
>= 0)
649 if (pParent
->IsCurrentAppending())
650 m_aAbsolute
->SetMax(pParent
->m_nTotalCount
+ 1);
652 m_aAbsolute
->SetMax(pParent
->m_nTotalCount
);
655 m_aAbsolute
->SetMax(LONG_MAX
);
657 m_aAbsolute
->SetValue(m_nCurrentPos
+ 1);
660 m_aAbsolute
->SetText(OUString());
662 case NavigationBar::RECORD_TEXT
:
663 pWnd
= m_aRecordText
.get();
665 case NavigationBar::RECORD_OF
:
666 pWnd
= m_aRecordOf
.get();
668 case NavigationBar::RECORD_COUNT
:
670 pWnd
= m_aRecordCount
.get();
674 if (pParent
->GetOptions() & DbGridControl::OPT_INSERT
)
676 if (pParent
->IsCurrentAppending() && !pParent
->IsModified())
677 aText
= m_aAbsolute
->CreateFieldText(pParent
->GetRowCount());
679 aText
= m_aAbsolute
->CreateFieldText(pParent
->GetRowCount() - 1);
682 aText
= m_aAbsolute
->CreateFieldText(pParent
->GetRowCount());
683 if(!pParent
->m_bRecordCountFinal
)
689 // add the number of selected rows, if applicable
690 if (pParent
->GetSelectRowCount())
692 OUString
aExtendedInfo(aText
);
693 aExtendedInfo
+= " (";
694 aExtendedInfo
+= m_aAbsolute
->CreateFieldText(pParent
->GetSelectRowCount());
695 aExtendedInfo
+= ")";
696 pWnd
->SetText(aExtendedInfo
);
699 pWnd
->SetText(aText
);
701 pParent
->SetRealRowCount(aText
);
704 DBG_ASSERT(pWnd
, "kein Fenster");
705 if (pWnd
&& (pWnd
->IsEnabled() != bAvailable
))
706 // this "pWnd->IsEnabled() != bAvailable" is a little hack : Window::Enable always generates a user
707 // event (ImplGenerateMouseMove) even if nothing happened. This may lead to some unwanted effects, so we
709 // For further explanation see Bug 69900.
710 pWnd
->Enable(bAvailable
);
713 void DbGridControl::NavigationBar::Resize()
719 void DbGridControl::NavigationBar::Paint(vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
)
721 Control::Paint(rRenderContext
, rRect
);
722 Point aAbsolutePos
= m_aAbsolute
->GetPosPixel();
723 Size aAbsoluteSize
= m_aAbsolute
->GetSizePixel();
725 rRenderContext
.DrawLine(Point(aAbsolutePos
.X() - 1, 0 ),
726 Point(aAbsolutePos
.X() - 1, aAbsolutePos
.Y() + aAbsoluteSize
.Height()));
728 rRenderContext
.DrawLine(Point(aAbsolutePos
.X() + aAbsoluteSize
.Width() + 1, 0 ),
729 Point(aAbsolutePos
.X() + aAbsoluteSize
.Width() + 1, aAbsolutePos
.Y() + aAbsoluteSize
.Height()));
732 void DbGridControl::NavigationBar::StateChanged(StateChangedType nType
)
734 Control::StateChanged(nType
);
736 vcl::Window
* pWindows
[] =
741 m_aRecordCount
.get(),
751 case StateChangedType::Mirroring
:
753 bool bIsRTLEnabled
= IsRTLEnabled();
754 for (size_t i
=0; i
< (sizeof (pWindows
) / sizeof(pWindows
[0])); ++i
)
755 pWindows
[i
]->EnableRTL( bIsRTLEnabled
);
759 case StateChangedType::Zoom
:
761 Fraction aZoom
= GetZoom();
763 // not all of these controls need to know the new zoom, but to be sure ...
764 vcl::Font
aFont(GetSettings().GetStyleSettings().GetFieldFont());
766 aFont
.Merge(GetControlFont());
768 for (size_t i
=0; i
< sizeof(pWindows
)/sizeof(pWindows
[0]); ++i
)
770 pWindows
[i
]->SetZoom(aZoom
);
771 pWindows
[i
]->SetZoomedPointFont(*pWindows
[i
], aFont
);
774 SetZoomedPointFont(*this, aFont
);
776 // rearrange the controls
777 m_nDefaultWidth
= ArrangeControls();
784 DbGridRow::DbGridRow(CursorWrapper
* pCur
, bool bPaintCursor
)
788 if (pCur
&& pCur
->Is())
790 Reference
< XIndexAccess
> xColumns(pCur
->getColumns(), UNO_QUERY
);
791 for (sal_Int32 i
= 0; i
< xColumns
->getCount(); ++i
)
793 Reference
< XPropertySet
> xColSet(
794 xColumns
->getByIndex(i
), css::uno::UNO_QUERY
);
795 DataColumn
* pColumn
= new DataColumn(xColSet
);
796 m_aVariants
.push_back( pColumn
);
799 if (pCur
->rowDeleted())
800 m_eStatus
= GRS_DELETED
;
804 m_eStatus
= (pCur
->isAfterLast() || pCur
->isBeforeFirst()) ? GRS_INVALID
: GRS_CLEAN
;
807 Reference
< XPropertySet
> xSet
= pCur
->getPropertySet();
810 m_bIsNew
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISNEW
));
811 if (!m_bIsNew
&& (pCur
->isAfterLast() || pCur
->isBeforeFirst()))
812 m_eStatus
= GRS_INVALID
;
813 else if (::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISMODIFIED
)))
814 m_eStatus
= GRS_MODIFIED
;
816 m_eStatus
= GRS_CLEAN
;
819 m_eStatus
= GRS_INVALID
;
822 if (!m_bIsNew
&& IsValid())
823 m_aBookmark
= pCur
->getBookmark();
828 m_eStatus
= GRS_INVALID
;
831 DbGridRow::~DbGridRow()
833 for ( size_t i
= 0, n
= m_aVariants
.size(); i
< n
; ++i
)
834 delete m_aVariants
[ i
];
838 void DbGridRow::SetState(CursorWrapper
* pCur
, bool bPaintCursor
)
840 if (pCur
&& pCur
->Is())
842 if (pCur
->rowDeleted())
844 m_eStatus
= GRS_DELETED
;
849 m_eStatus
= GRS_CLEAN
;
852 Reference
< XPropertySet
> xSet
= pCur
->getPropertySet();
853 DBG_ASSERT(xSet
.is(), "DbGridRow::SetState : invalid cursor !");
855 if (::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISMODIFIED
)))
856 m_eStatus
= GRS_MODIFIED
;
857 m_bIsNew
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISNEW
));
865 if (!m_bIsNew
&& IsValid())
866 m_aBookmark
= pCur
->getBookmark();
872 DBG_UNHANDLED_EXCEPTION();
874 m_eStatus
= GRS_INVALID
;
881 m_eStatus
= GRS_INVALID
;
886 DbGridControl::DbGridControl(
887 Reference
< XComponentContext
> _rxContext
,
888 vcl::Window
* pParent
,
890 :DbGridControl_Base(pParent
, EditBrowseBoxFlags::NONE
, nBits
, DEFAULT_BROWSE_MODE
)
891 ,m_xContext(_rxContext
)
892 ,m_aBar(VclPtr
<DbGridControl::NavigationBar
>::Create(this))
893 ,m_nAsynAdjustEvent(0)
894 ,m_pDataSourcePropMultiplexer(NULL
)
895 ,m_pDataSourcePropListener(NULL
)
896 ,m_pFieldListeners(NULL
)
897 ,m_pCursorDisposeListener(NULL
)
898 ,m_pGridListener(NULL
)
903 ,m_aNullDate(::dbtools::DBTypeConversion::getStandardDate())
904 ,m_nMode(DEFAULT_BROWSE_MODE
)
907 ,m_nOptions(OPT_READONLY
)
908 ,m_nOptionMask(OPT_INSERT
| OPT_UPDATE
| OPT_DELETE
)
909 ,m_nLastColId((sal_uInt16
)-1)
911 ,m_bDesignMode(false)
912 ,m_bRecordCountFinal(false)
913 ,m_bMultiSelection(true)
914 ,m_bNavigationBar(true)
915 ,m_bSynchDisplay(true)
916 ,m_bForceROController(false)
918 ,m_bFilterMode(false)
919 ,m_bWantDestruction(false)
920 ,m_bInAdjustDataSource(false)
921 ,m_bPendingAdjustRows(false)
922 ,m_bHideScrollbars( false )
926 OUString
sName(SVX_RESSTR(RID_STR_NAVIGATIONBAR
));
927 m_aBar
->SetAccessibleName(sName
);
929 ImplInitWindow( InitAll
);
932 void DbGridControl::InsertHandleColumn()
934 // BrowseBox has problems when painting without a handleColumn (hide it here)
936 BrowseBox::InsertHandleColumn(GetDefaultColumnWidth(OUString()));
938 BrowseBox::InsertHandleColumn(0);
941 void DbGridControl::Init()
943 BrowserHeader
* pNewHeader
= CreateHeaderBar(this);
944 pHeader
->SetMouseTransparent(false);
946 SetHeaderBar(pNewHeader
);
948 SetCursorColor(Color(0xFF, 0, 0));
950 InsertHandleColumn();
953 DbGridControl::~DbGridControl()
958 void DbGridControl::dispose()
964 m_bWantDestruction
= true;
965 osl::MutexGuard
aGuard(m_aDestructionSafety
);
966 if (m_pFieldListeners
)
967 DisconnectFromFields();
968 if (m_pCursorDisposeListener
)
970 delete m_pCursorDisposeListener
;
971 m_pCursorDisposeListener
= NULL
;
976 Application::RemoveUserEvent(m_nDeleteEvent
);
978 if (m_pDataSourcePropMultiplexer
)
980 m_pDataSourcePropMultiplexer
->dispose();
981 m_pDataSourcePropMultiplexer
->release(); // this should delete the multiplexer
982 delete m_pDataSourcePropListener
;
983 m_pDataSourcePropMultiplexer
= NULL
;
984 m_pDataSourcePropListener
= NULL
;
986 m_xRowSetListener
.clear();
988 delete m_pDataCursor
;
989 m_pDataCursor
= NULL
;
990 delete m_pSeekCursor
;
991 m_pSeekCursor
= NULL
;
993 m_aBar
.disposeAndClear();
995 DbGridControl_Base::dispose();
998 void DbGridControl::StateChanged( StateChangedType nType
)
1000 DbGridControl_Base::StateChanged( nType
);
1004 case StateChangedType::Mirroring
:
1005 ImplInitWindow( InitWritingMode
);
1009 case StateChangedType::Zoom
:
1011 ImplInitWindow( InitFontFacet
);
1013 // and give it a chance to rearrange
1014 Point aPoint
= GetControlArea().TopLeft();
1015 sal_uInt16 nX
= (sal_uInt16
)aPoint
.X();
1016 ArrangeControls(nX
, (sal_uInt16
)aPoint
.Y());
1017 ReserveControlArea((sal_uInt16
)nX
);
1020 case StateChangedType::ControlFont
:
1021 ImplInitWindow( InitFontFacet
);
1024 case StateChangedType::ControlForeground
:
1025 ImplInitWindow( InitForeground
);
1028 case StateChangedType::ControlBackground
:
1029 ImplInitWindow( InitBackground
);
1036 void DbGridControl::DataChanged( const DataChangedEvent
& rDCEvt
)
1038 DbGridControl_Base::DataChanged( rDCEvt
);
1039 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
1040 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
) )
1042 ImplInitWindow( InitAll
);
1047 void DbGridControl::Select()
1049 DbGridControl_Base::Select();
1051 // as the selected rows may have changed, update the according display in our navigation bar
1052 m_aBar
->InvalidateState(NavigationBar::RECORD_COUNT
);
1054 if (m_pGridListener
)
1055 m_pGridListener
->selectionChanged();
1058 void DbGridControl::ImplInitWindow( const InitWindowFacet _eInitWhat
)
1060 for ( size_t i
= 0; i
< m_aColumns
.size(); ++i
)
1062 DbGridColumn
* pCol
= m_aColumns
[ i
];
1064 pCol
->ImplInitWindow( GetDataWindow(), _eInitWhat
);
1067 if ( ( _eInitWhat
& InitWritingMode
) != 0 )
1069 if ( m_bNavigationBar
)
1071 m_aBar
->EnableRTL( IsRTLEnabled() );
1075 if ( ( _eInitWhat
& InitFontFacet
) != 0 )
1077 if ( m_bNavigationBar
)
1079 vcl::Font aFont
= m_aBar
->GetSettings().GetStyleSettings().GetFieldFont();
1080 if ( IsControlFont() )
1081 m_aBar
->SetControlFont( GetControlFont() );
1083 m_aBar
->SetControlFont();
1085 m_aBar
->SetZoom( GetZoom() );
1089 if ( ( _eInitWhat
& InitBackground
) != 0 )
1091 if (IsControlBackground())
1093 GetDataWindow().SetBackground(GetControlBackground());
1094 GetDataWindow().SetControlBackground(GetControlBackground());
1095 GetDataWindow().SetFillColor(GetControlBackground());
1099 GetDataWindow().SetControlBackground();
1100 GetDataWindow().SetFillColor(GetFillColor());
1105 void DbGridControl::RemoveRows(bool bNewCursor
)
1107 // Did the data cursor change?
1110 DELETEZ(m_pSeekCursor
);
1111 m_xPaintRow
= m_xDataRow
= m_xEmptyRow
= m_xCurrentRow
= m_xSeekRow
= NULL
;
1112 m_nCurrentPos
= m_nSeekPos
= -1;
1113 m_nOptions
= OPT_READONLY
;
1115 RowRemoved(0, GetRowCount(), false);
1124 void DbGridControl::RemoveRows()
1126 // we're going to remove all columns and all row, so deactivate the current cell
1130 // de-initialize all columns
1131 // if there are columns, free all controllers
1132 for (size_t i
= 0; i
< m_aColumns
.size(); i
++)
1133 m_aColumns
[ i
]->Clear();
1135 DELETEZ(m_pSeekCursor
);
1136 DELETEZ(m_pDataCursor
);
1138 m_xPaintRow
= m_xDataRow
= m_xEmptyRow
= m_xCurrentRow
= m_xSeekRow
= NULL
;
1139 m_nCurrentPos
= m_nSeekPos
= m_nTotalCount
= -1;
1140 m_nOptions
= OPT_READONLY
;
1142 // reset number of sentences to zero in the browser
1143 DbGridControl_Base::RemoveRows();
1144 m_aBar
->InvalidateAll(m_nCurrentPos
, true);
1147 void DbGridControl::ArrangeControls(sal_uInt16
& nX
, sal_uInt16 nY
)
1149 // positioning of the controls
1150 if (m_bNavigationBar
)
1152 nX
= m_aBar
->GetDefaultWidth();
1153 Rectangle
aRect(GetControlArea());
1154 m_aBar
->SetPosSizePixel(Point(0,nY
+ 1), Size(nX
, aRect
.GetSize().Height() - 1));
1158 void DbGridControl::EnableHandle(bool bEnable
)
1160 if (m_bHandle
== bEnable
)
1163 // HandleColumn is only hidden because there are a lot of problems while painting otherwise
1164 RemoveColumn( HandleColumnId
);
1165 m_bHandle
= bEnable
;
1166 InsertHandleColumn();
1171 bool adjustModeForScrollbars( BrowserMode
& _rMode
, bool _bNavigationBar
, bool _bHideScrollbars
)
1173 BrowserMode nOldMode
= _rMode
;
1175 if ( !_bNavigationBar
)
1177 _rMode
&= ~BrowserMode::AUTO_HSCROLL
;
1180 if ( _bHideScrollbars
)
1182 _rMode
|= ( BrowserMode::NO_HSCROLL
| BrowserMode::NO_VSCROLL
);
1183 _rMode
&= ~BrowserMode( BrowserMode::AUTO_HSCROLL
| BrowserMode::AUTO_VSCROLL
);
1187 _rMode
|= ( BrowserMode::AUTO_HSCROLL
| BrowserMode::AUTO_VSCROLL
);
1188 _rMode
&= ~BrowserMode( BrowserMode::NO_HSCROLL
| BrowserMode::NO_VSCROLL
);
1191 // note: if we have a navigation bar, we always have a AUTO_HSCROLL. In particular,
1192 // _bHideScrollbars is ignored then
1193 if ( _bNavigationBar
)
1195 _rMode
|= BrowserMode::AUTO_HSCROLL
;
1196 _rMode
&= ~BrowserMode::NO_HSCROLL
;
1199 return nOldMode
!= _rMode
;
1203 void DbGridControl::EnableNavigationBar(bool bEnable
)
1205 if (m_bNavigationBar
== bEnable
)
1208 m_bNavigationBar
= bEnable
;
1214 m_aBar
->InvalidateAll(m_nCurrentPos
, true);
1216 if ( adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
) )
1219 // get size of the reserved ControlArea
1220 Point aPoint
= GetControlArea().TopLeft();
1221 sal_uInt16 nX
= (sal_uInt16
)aPoint
.X();
1223 ArrangeControls(nX
, (sal_uInt16
)aPoint
.Y());
1224 ReserveControlArea((sal_uInt16
)nX
);
1231 if ( adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
) )
1234 ReserveControlArea();
1238 sal_uInt16
DbGridControl::SetOptions(sal_uInt16 nOpt
)
1240 DBG_ASSERT(!m_xCurrentRow
|| !m_xCurrentRow
->IsModified(),
1241 "DbGridControl::SetOptions : please do not call when editing a record (things are much easier this way ;) !");
1243 // for the next setDataSource (which is triggered by a refresh, for instance)
1244 m_nOptionMask
= nOpt
;
1246 // normalize the new options
1247 Reference
< XPropertySet
> xDataSourceSet
= m_pDataCursor
->getPropertySet();
1248 if (xDataSourceSet
.is())
1250 // check what kind of options are available
1251 sal_Int32 nPrivileges
= 0;
1252 xDataSourceSet
->getPropertyValue(FM_PROP_PRIVILEGES
) >>= nPrivileges
;
1253 if ((nPrivileges
& Privilege::INSERT
) == 0)
1254 nOpt
&= ~OPT_INSERT
;
1255 if ((nPrivileges
& Privilege::UPDATE
) == 0)
1256 nOpt
&= ~OPT_UPDATE
;
1257 if ((nPrivileges
& Privilege::DELETE
) == 0)
1258 nOpt
&= ~OPT_DELETE
;
1261 nOpt
= OPT_READONLY
;
1263 // need to do something after that ?
1264 if (nOpt
== m_nOptions
)
1267 // the 'update' option only affects our BrowserMode (with or w/o focus rect)
1268 BrowserMode nNewMode
= m_nMode
;
1269 if (!(m_nMode
& BrowserMode::CURSOR_WO_FOCUS
))
1271 if (nOpt
& OPT_UPDATE
)
1272 nNewMode
|= BrowserMode::HIDECURSOR
;
1274 nNewMode
&= ~BrowserMode::HIDECURSOR
;
1277 nNewMode
&= ~BrowserMode::HIDECURSOR
;
1278 // should not be necessary if EnablePermanentCursor is used to change the cursor behaviour, but to be sure ...
1280 if (nNewMode
!= m_nMode
)
1286 // _after_ setting the mode because this results in an ActivateCell
1289 bool bInsertChanged
= (nOpt
& OPT_INSERT
) != (m_nOptions
& OPT_INSERT
);
1291 // we need to set this before the code below because it indirectly uses m_nOptions
1293 // the 'insert' option affects our empty row
1296 if (m_nOptions
& OPT_INSERT
)
1297 { // the insert option is to be set
1298 m_xEmptyRow
= new DbGridRow();
1299 RowInserted(GetRowCount(), 1, true);
1302 { // the insert option is to be reset
1304 if ((GetCurRow() == GetRowCount() - 1) && (GetCurRow() > 0))
1305 GoToRowColumnId(GetCurRow() - 1, GetCurColumnId());
1306 RowRemoved(GetRowCount(), 1, true);
1310 // the 'delete' options has no immediate consequences
1317 void DbGridControl::ForceHideScrollbars( bool _bForce
)
1319 if ( m_bHideScrollbars
== _bForce
)
1322 m_bHideScrollbars
= _bForce
;
1324 if ( adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
) )
1328 void DbGridControl::EnablePermanentCursor(bool bEnable
)
1330 if (IsPermanentCursorEnabled() == bEnable
)
1335 m_nMode
&= ~BrowserMode::HIDECURSOR
; // without this BrowserMode::CURSOR_WO_FOCUS won't have any affect
1336 m_nMode
|= BrowserMode::CURSOR_WO_FOCUS
;
1340 if (m_nOptions
& OPT_UPDATE
)
1341 m_nMode
|= BrowserMode::HIDECURSOR
; // no cursor at all
1343 m_nMode
&= ~BrowserMode::HIDECURSOR
; // at least the "non-permanent" cursor
1345 m_nMode
&= ~BrowserMode::CURSOR_WO_FOCUS
;
1349 bool bWasEditing
= IsEditing();
1355 bool DbGridControl::IsPermanentCursorEnabled() const
1357 return (m_nMode
& BrowserMode::CURSOR_WO_FOCUS
) && !(m_nMode
& BrowserMode::HIDECURSOR
);
1360 void DbGridControl::refreshController(sal_uInt16 _nColId
, GrantControlAccess
/*_aAccess*/)
1362 if ((GetCurColumnId() == _nColId
) && IsEditing())
1363 { // the controller which is currently active needs to be refreshed
1369 void DbGridControl::setDataSource(const Reference
< XRowSet
>& _xCursor
, sal_uInt16 nOpts
)
1371 if (!_xCursor
.is() && !m_pDataCursor
)
1374 if (m_pDataSourcePropMultiplexer
)
1376 m_pDataSourcePropMultiplexer
->dispose();
1377 m_pDataSourcePropMultiplexer
->release(); // this should delete the multiplexer
1378 delete m_pDataSourcePropListener
;
1379 m_pDataSourcePropMultiplexer
= NULL
;
1380 m_pDataSourcePropListener
= NULL
;
1382 m_xRowSetListener
.clear();
1384 // is the new cursor valid ?
1385 // the cursor is only valid if it contains some columns
1386 // if there is no cursor or the cursor is not valid we have to clean up an leave
1387 if (!_xCursor
.is() || !Reference
< XColumnsSupplier
> (_xCursor
, UNO_QUERY
)->getColumns()->hasElements())
1393 // did the data cursor change?
1394 sal_uInt16 nCurPos
= GetColumnPos(GetCurColumnId());
1396 SetUpdateMode(false);
1398 DisconnectFromFields();
1400 DELETEZ(m_pCursorDisposeListener
);
1403 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
1404 if (m_nAsynAdjustEvent
)
1406 // the adjust was thought to work with the old cursor which we don't have anymore
1407 RemoveUserEvent(m_nAsynAdjustEvent
);
1408 m_nAsynAdjustEvent
= 0;
1412 // get a new formatter and data cursor
1413 m_xFormatter
= NULL
;
1414 Reference
< ::com::sun::star::util::XNumberFormatsSupplier
> xSupplier
= getNumberFormats(getConnection(_xCursor
), true);
1417 m_xFormatter
= Reference
< ::com::sun::star::util::XNumberFormatter
>(
1418 ::com::sun::star::util::NumberFormatter::create(m_xContext
),
1420 m_xFormatter
->attachNumberFormatsSupplier(xSupplier
);
1422 // retrieve the datebase of the Numberformatter
1425 xSupplier
->getNumberFormatSettings()->getPropertyValue("NullDate") >>= m_aNullDate
;
1432 m_pDataCursor
= new CursorWrapper(_xCursor
);
1434 // now create a cursor for painting rows
1435 // we need that cursor only if we are not in insert only mode
1436 Reference
< XResultSet
> xClone
;
1437 Reference
< XResultSetAccess
> xAccess( _xCursor
, UNO_QUERY
);
1440 xClone
= xAccess
.is() ? xAccess
->createResultSet() : Reference
< XResultSet
> ();
1446 m_pSeekCursor
= new CursorWrapper(xClone
);
1448 // property listening on the data source
1449 // (Normally one class would be sufficient : the multiplexer which could forward the property change to us.
1450 // But for that we would have been derived from ::comphelper::OPropertyChangeListener, which isn't exported.
1451 // So we introduce a second class, which is a ::comphelper::OPropertyChangeListener (in the implementation file we know this class)
1452 // and forwards the property changes to a our special method "DataSourcePropertyChanged".)
1455 m_pDataSourcePropListener
= new FmXGridSourcePropListener(this);
1456 m_pDataSourcePropMultiplexer
= new ::comphelper::OPropertyChangeMultiplexer(m_pDataSourcePropListener
, m_pDataCursor
->getPropertySet() );
1457 m_pDataSourcePropMultiplexer
->acquire();
1458 m_pDataSourcePropMultiplexer
->addProperty(FM_PROP_ISMODIFIED
);
1459 m_pDataSourcePropMultiplexer
->addProperty(FM_PROP_ISNEW
);
1462 BrowserMode nOldMode
= m_nMode
;
1467 Reference
< XPropertySet
> xSet(_xCursor
, UNO_QUERY
);
1470 // check what kind of options are available
1471 sal_Int32 nConcurrency
= ResultSetConcurrency::READ_ONLY
;
1472 xSet
->getPropertyValue(FM_PROP_RESULTSET_CONCURRENCY
) >>= nConcurrency
;
1474 if ( ResultSetConcurrency::UPDATABLE
== nConcurrency
)
1476 sal_Int32 nPrivileges
= 0;
1477 xSet
->getPropertyValue(FM_PROP_PRIVILEGES
) >>= nPrivileges
;
1479 // Insert Option should be set if insert only otherwise you won't see any rows
1480 // and no insertion is possible
1481 if ((m_nOptionMask
& OPT_INSERT
) && ((nPrivileges
& Privilege::INSERT
) == Privilege::INSERT
) && (nOpts
& OPT_INSERT
))
1482 m_nOptions
|= OPT_INSERT
;
1483 if ((m_nOptionMask
& OPT_UPDATE
) && ((nPrivileges
& Privilege::UPDATE
) == Privilege::UPDATE
) && (nOpts
& OPT_UPDATE
))
1484 m_nOptions
|= OPT_UPDATE
;
1485 if ((m_nOptionMask
& OPT_DELETE
) && ((nPrivileges
& Privilege::DELETE
) == Privilege::DELETE
) && (nOpts
& OPT_DELETE
))
1486 m_nOptions
|= OPT_DELETE
;
1490 catch( const Exception
& )
1492 DBG_UNHANDLED_EXCEPTION();
1495 bool bPermanentCursor
= IsPermanentCursorEnabled();
1496 m_nMode
= DEFAULT_BROWSE_MODE
;
1498 if ( bPermanentCursor
)
1500 m_nMode
|= BrowserMode::CURSOR_WO_FOCUS
;
1501 m_nMode
&= ~BrowserMode::HIDECURSOR
;
1505 // updates are allowed -> no focus rectangle
1506 if ( m_nOptions
& OPT_UPDATE
)
1507 m_nMode
|= BrowserMode::HIDECURSOR
;
1510 if ( m_bMultiSelection
)
1511 m_nMode
|= BrowserMode::MULTISELECTION
;
1513 m_nMode
&= ~BrowserMode::MULTISELECTION
;
1515 adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
);
1517 Reference
< XColumnsSupplier
> xSupplyColumns(_xCursor
, UNO_QUERY
);
1518 if (xSupplyColumns
.is())
1519 InitColumnsByFields(Reference
< XIndexAccess
> (xSupplyColumns
->getColumns(), UNO_QUERY
));
1524 sal_uInt32
nRecordCount(0);
1528 Reference
< XPropertySet
> xSet
= m_pDataCursor
->getPropertySet();
1529 xSet
->getPropertyValue(FM_PROP_ROWCOUNT
) >>= nRecordCount
;
1530 m_bRecordCountFinal
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ROWCOUNTFINAL
));
1532 m_xRowSetListener
= new RowSetEventListener(this);
1533 Reference
< XRowsChangeBroadcaster
> xChangeBroad(xSet
,UNO_QUERY
);
1534 if ( xChangeBroad
.is( ) )
1535 xChangeBroad
->addRowsChangeListener(m_xRowSetListener
);
1538 // insert the currently known rows
1539 // and one row if we are able to insert rows
1540 if (m_nOptions
& OPT_INSERT
)
1542 // insert the empty row for insertion
1543 m_xEmptyRow
= new DbGridRow();
1548 m_xPaintRow
= m_xSeekRow
= new DbGridRow(m_pSeekCursor
, true);
1549 m_xDataRow
= new DbGridRow(m_pDataCursor
, false);
1550 RowInserted(0, nRecordCount
, false);
1552 if (m_xSeekRow
->IsValid())
1555 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
1557 catch( const Exception
& )
1559 DBG_UNHANDLED_EXCEPTION();
1565 // no rows so we don't need a seekcursor
1566 DELETEZ(m_pSeekCursor
);
1570 // go to the old column
1571 if (nCurPos
== BROWSER_INVALIDID
|| nCurPos
>= ColCount())
1574 // Column zero is a valid choice and guaranteed to exist,
1575 // but invisible to the user; if we have at least one
1576 // user-visible column, go to that one.
1577 if (nCurPos
== 0 && ColCount() > 1)
1580 // there are rows so go to the selected current column
1582 GoToRowColumnId(0, GetColumnId(nCurPos
));
1583 // else stop the editing if necessary
1584 else if (IsEditing())
1587 // now reset the mode
1588 if (m_nMode
!= nOldMode
)
1591 // RecalcRows was already called while resizing
1592 if (!IsResizing() && GetRowCount())
1593 RecalcRows(GetTopRow(), GetVisibleRows(), true);
1595 m_aBar
->InvalidateAll(m_nCurrentPos
, true);
1596 SetUpdateMode(true);
1598 // start listening on the seek cursor
1600 m_pCursorDisposeListener
= new DisposeListenerGridBridge(*this, Reference
< XComponent
> (Reference
< XInterface
>(*m_pSeekCursor
), UNO_QUERY
), 0);
1603 void DbGridControl::RemoveColumns()
1608 for (size_t i
= 0, n
= m_aColumns
.size(); i
< n
; i
++)
1609 delete m_aColumns
[ i
];
1612 DbGridControl_Base::RemoveColumns();
1615 DbGridColumn
* DbGridControl::CreateColumn(sal_uInt16 nId
) const
1617 return new DbGridColumn(nId
, *const_cast<DbGridControl
*>(this));
1620 sal_uInt16
DbGridControl::AppendColumn(const OUString
& rName
, sal_uInt16 nWidth
, sal_uInt16 nModelPos
, sal_uInt16 nId
)
1622 DBG_ASSERT(nId
== BROWSER_INVALIDID
, "DbGridControl::AppendColumn : I want to set the ID myself ...");
1623 sal_uInt16 nRealPos
= nModelPos
;
1624 if (nModelPos
!= HEADERBAR_APPEND
)
1626 // calc the view pos. we can't use our converting functions because the new column
1627 // has no VCL-representation, yet.
1628 sal_Int16 nViewPos
= nModelPos
;
1631 if ( m_aColumns
[ nModelPos
]->IsHidden() )
1634 // restore nModelPos, we need it later
1635 nModelPos
= nRealPos
;
1636 // the position the base class gets is the view pos + 1 (because of the handle column)
1637 nRealPos
= nViewPos
+ 1;
1640 // calculate the new id
1641 for (nId
=1; (GetModelColumnPos(nId
) != GRID_COLUMN_NOT_FOUND
) && (nId
<= m_aColumns
.size()); ++nId
)
1643 DBG_ASSERT(GetViewColumnPos(nId
) == GRID_COLUMN_NOT_FOUND
, "DbGridControl::AppendColumn : inconsistent internal state !");
1644 // my column's models say "there is no column with id nId", but the view (the base class) says "there is a column ..."
1646 DbGridControl_Base::AppendColumn(rName
, nWidth
, nRealPos
, nId
);
1647 if (nModelPos
== HEADERBAR_APPEND
)
1648 m_aColumns
.push_back( CreateColumn(nId
) );
1651 DbGridColumns::iterator it
= m_aColumns
.begin();
1652 ::std::advance( it
, nModelPos
);
1653 m_aColumns
.insert( it
, CreateColumn(nId
) );
1659 void DbGridControl::RemoveColumn(sal_uInt16 nId
)
1661 DbGridControl_Base::RemoveColumn(nId
);
1663 const sal_uInt16 nIndex
= GetModelColumnPos(nId
);
1664 if(nIndex
!= GRID_COLUMN_NOT_FOUND
)
1666 delete m_aColumns
[nIndex
];
1667 m_aColumns
.erase( m_aColumns
.begin()+nIndex
);
1671 void DbGridControl::ColumnMoved(sal_uInt16 nId
)
1673 DbGridControl_Base::ColumnMoved(nId
);
1675 // remove the col from the model
1676 sal_uInt16 nOldModelPos
= GetModelColumnPos(nId
);
1678 DbGridColumn
* pCol
= m_aColumns
[ (sal_uInt32
)nOldModelPos
];
1679 DBG_ASSERT(!pCol
->IsHidden(), "DbGridControl::ColumnMoved : moved a hidden col ? how this ?");
1682 // for the new model pos we can't use GetModelColumnPos because we are altering the model at the moment
1683 // so the method won't work (in fact it would return the old model pos)
1685 // the new view pos is calculated easily
1686 sal_uInt16 nNewViewPos
= GetViewColumnPos(nId
);
1688 // from that we can compute the new model pos
1689 sal_uInt16 nNewModelPos
;
1690 for (nNewModelPos
= 0; nNewModelPos
< m_aColumns
.size(); ++nNewModelPos
)
1692 if (!m_aColumns
[ nNewModelPos
]->IsHidden())
1700 DBG_ASSERT( nNewModelPos
< m_aColumns
.size(), "DbGridControl::ColumnMoved : could not find the new model position !");
1702 // this will work. of course the model isn't fully consistent with our view right now, but let's
1703 // look at the situation : a column has been moved with in the VIEW from pos m to n, say m<n (in the
1704 // other case we can use analogue arguments).
1705 // All cols k with m<k<=n have been shifted left on pos, the former col m now has pos n.
1706 // In the model this affects a range of cols x to y, where x<=m and y<=n. And the number of hidden cols
1707 // within this range is constant, so we may calculate the view pos from the model pos in the above way.
1709 // for instance, let's look at a grid with six columns where the third one is hidden. this will
1710 // initially look like this :
1712 // +---+---+---+---+---+---+
1713 // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1714 // +---+---+---+---+---+---+
1715 // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1716 // +---+---+---+---+---+---+
1717 // view pos | 0 | 1 | - | 2 | 3 | 4 |
1718 // +---+---+---+---+---+---+
1720 // if we move the column at (view) pos 1 to (view) pos 3 we have :
1722 // +---+---+---+---+---+---+
1723 // model pos | 0 | 3 |*2*| 4 | 1 | 5 | // not reflecting the changes, yet
1724 // +---+---+---+---+---+---+
1725 // ID | 1 | 4 | 3 | 5 | 2 | 6 | // already reflecting the changes
1726 // +---+---+---+---+---+---+
1727 // view pos | 0 | 1 | - | 2 | 3 | 4 |
1728 // +---+---+---+---+---+---+
1730 // or, sorted by the out-of-date model positions :
1732 // +---+---+---+---+---+---+
1733 // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1734 // +---+---+---+---+---+---+
1735 // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1736 // +---+---+---+---+---+---+
1737 // view pos | 0 | 3 | - | 1 | 2 | 4 |
1738 // +---+---+---+---+---+---+
1740 // We know the new view pos (3) of the moved column because our base class tells us. So we look at our
1741 // model for the 4th (the pos is zero-based) visible column, it is at (model) position 4. And this is
1742 // exactly the pos where we have to re-insert our column's model, so it looks ike this :
1744 // +---+---+---+---+---+---+
1745 // model pos | 0 |*1*| 2 | 3 | 4 | 5 |
1746 // +---+---+---+---+---+---+
1747 // ID | 1 | 3 | 4 | 5 | 2 | 6 |
1748 // +---+---+---+---+---+---+
1749 // view pos | 0 | - | 1 | 2 | 3 | 4 |
1750 // +---+---+---+---+---+---+
1752 // Now, all is consistent again.
1753 // (except of the hidden column : The cycling of the cols occurred on the model, not on the view. maybe
1754 // the user expected the latter but there really is no good argument against our method ;) ...)
1756 // And no, this large explanation isn't just because I wanted to play a board game or something like
1757 // that. It's because it took me a while to see it myself, and the whole theme (hidden cols, model col
1758 // positions, view col positions) is really painful (at least for me) so the above pictures helped me a lot ;)
1760 DbGridColumn
* temp
= m_aColumns
[ nOldModelPos
];
1762 DbGridColumns::iterator it
= m_aColumns
.begin();
1763 ::std::advance( it
, nOldModelPos
);
1764 m_aColumns
.erase( it
);
1766 it
= m_aColumns
.begin();
1767 ::std::advance( it
, nNewModelPos
);
1768 m_aColumns
.insert( it
, temp
);
1771 bool DbGridControl::SeekRow(long nRow
)
1773 // in filter mode or in insert only mode we don't have any cursor!
1774 if ( !SeekCursor( nRow
) )
1777 if ( IsFilterMode() )
1779 DBG_ASSERT( IsFilterRow( nRow
), "DbGridControl::SeekRow(): No filter row, wrong mode" );
1780 m_xPaintRow
= m_xEmptyRow
;
1784 // on the current position we have to take the current row for display as we want
1785 // to have the most recent values for display
1786 if ( ( nRow
== m_nCurrentPos
) && getDisplaySynchron() )
1787 m_xPaintRow
= m_xCurrentRow
;
1788 // seek to the empty insert row
1789 else if ( IsInsertionRow( nRow
) )
1790 m_xPaintRow
= m_xEmptyRow
;
1793 m_xSeekRow
->SetState( m_pSeekCursor
, true );
1794 m_xPaintRow
= m_xSeekRow
;
1798 DbGridControl_Base::SeekRow(nRow
);
1800 return m_nSeekPos
>= 0;
1803 // Is called whenever the visible amount of data changes
1804 void DbGridControl::VisibleRowsChanged( long nNewTopRow
, sal_uInt16 nLinesOnScreen
)
1806 RecalcRows(nNewTopRow
, nLinesOnScreen
, false);
1809 void DbGridControl::RecalcRows(long nNewTopRow
, sal_uInt16 nLinesOnScreen
, bool bUpdateCursor
)
1811 // Wenn kein Cursor -> keine Rows im Browser.
1814 DBG_ASSERT(GetRowCount() == 0,"DbGridControl: ohne Cursor darf es keine Rows geben");
1818 // ignore any implicitly made updates
1819 bool bDisablePaint
= !bUpdateCursor
&& IsPaintEnabled();
1823 // adjust cache to the visible area
1824 Reference
< XPropertySet
> xSet
= m_pSeekCursor
->getPropertySet();
1825 sal_Int32 nCacheSize
= 0;
1826 xSet
->getPropertyValue(FM_PROP_FETCHSIZE
) >>= nCacheSize
;
1827 bool bCacheAligned
= false;
1828 // no further cursor movements after initializing (m_nSeekPos < 0) because it is already
1829 // positioned on the first sentence
1830 long nDelta
= nNewTopRow
- GetTopRow();
1831 // limit for relative positioning
1832 long nLimit
= (nCacheSize
) ? nCacheSize
/ 2 : 0;
1834 // more lines on screen than in cache
1835 if (nLimit
< nLinesOnScreen
)
1838 aCacheSize
<<= sal_Int32(nLinesOnScreen
*2);
1839 xSet
->setPropertyValue(FM_PROP_FETCHSIZE
, aCacheSize
);
1840 // here we need to update the cursor for sure
1841 bUpdateCursor
= true;
1842 bCacheAligned
= true;
1843 nLimit
= nLinesOnScreen
;
1846 // In the following, all positionings are done as it is
1847 // ensured that there are enough lines in the data cache
1849 // window goes downwards with less than two windows difference or
1850 // the cache was updated and no rowcount yet
1851 if (nDelta
< nLimit
&& (nDelta
> 0
1852 || (bCacheAligned
&& m_nTotalCount
< 0)) )
1853 SeekCursor(nNewTopRow
+ nLinesOnScreen
- 1, false);
1854 else if (nDelta
< 0 && std::abs(nDelta
) < nLimit
)
1855 SeekCursor(nNewTopRow
, false);
1856 else if (nDelta
!= 0 || bUpdateCursor
)
1857 SeekCursor(nNewTopRow
, true);
1861 // ignore any updates implicit made
1865 void DbGridControl::RowInserted(long nRow
, long nNumRows
, bool bDoPaint
, bool bKeepSelection
)
1869 if (m_bRecordCountFinal
&& m_nTotalCount
< 0)
1871 // if we have an insert row we have to reduce to count by 1
1872 // as the total count reflects only the existing rows in database
1873 m_nTotalCount
= GetRowCount() + nNumRows
;
1874 if (m_xEmptyRow
.Is())
1877 else if (m_nTotalCount
>= 0)
1878 m_nTotalCount
+= nNumRows
;
1880 DbGridControl_Base::RowInserted(nRow
, nNumRows
, bDoPaint
, bKeepSelection
);
1881 m_aBar
->InvalidateState(NavigationBar::RECORD_COUNT
);
1885 void DbGridControl::RowRemoved(long nRow
, long nNumRows
, bool bDoPaint
)
1889 if (m_bRecordCountFinal
&& m_nTotalCount
< 0)
1891 m_nTotalCount
= GetRowCount() - nNumRows
;
1892 // if we have an insert row reduce by 1
1893 if (m_xEmptyRow
.Is())
1896 else if (m_nTotalCount
>= 0)
1897 m_nTotalCount
-= nNumRows
;
1899 DbGridControl_Base::RowRemoved(nRow
, nNumRows
, bDoPaint
);
1900 m_aBar
->InvalidateState(NavigationBar::RECORD_COUNT
);
1904 void DbGridControl::AdjustRows()
1909 Reference
< XPropertySet
> xSet
= m_pDataCursor
->getPropertySet();
1911 // refresh RecordCount
1912 sal_Int32 nRecordCount
= 0;
1913 xSet
->getPropertyValue(FM_PROP_ROWCOUNT
) >>= nRecordCount
;
1914 if (!m_bRecordCountFinal
)
1915 m_bRecordCountFinal
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ROWCOUNTFINAL
));
1917 // Did the number of rows change?
1918 // Here we need to consider that there might be an additional row for adding new data sets
1920 // add additional AppendRow for insertion
1921 if (m_nOptions
& OPT_INSERT
)
1924 // If there is currently an insertion, so do not consider this added row in RecordCount or Appendrow
1925 if (!IsUpdating() && m_bRecordCountFinal
&& IsModified() && m_xCurrentRow
!= m_xEmptyRow
&&
1926 m_xCurrentRow
->IsNew())
1928 // ensured with !m_bUpdating: otherwise the edited data set (that SaveRow added and why this
1929 // method was called) would be called twice (if m_bUpdating == sal_True): once in RecordCount
1930 // and a second time here (60787 - FS)
1932 if (nRecordCount
!= GetRowCount())
1934 long nDelta
= GetRowCount() - (long)nRecordCount
;
1935 if (nDelta
> 0) // too many
1937 RowRemoved(GetRowCount() - nDelta
, nDelta
, false);
1938 // some rows are gone, thus, repaint starting at the current position
1941 sal_Int32 nNewPos
= AlignSeekCursor();
1942 if (m_bSynchDisplay
)
1943 DbGridControl_Base::GoToRow(nNewPos
);
1945 SetCurrent(nNewPos
);
1946 // there are rows so go to the selected current column
1948 GoToRowColumnId(nNewPos
, GetColumnId(GetCurColumnId()));
1949 if (!IsResizing() && GetRowCount())
1950 RecalcRows(GetTopRow(), GetVisibleRows(), true);
1951 m_aBar
->InvalidateAll(m_nCurrentPos
, true);
1954 RowInserted(GetRowCount(), -nDelta
, true);
1957 if (m_bRecordCountFinal
&& m_nTotalCount
< 0)
1959 if (m_nOptions
& OPT_INSERT
)
1960 m_nTotalCount
= GetRowCount() - 1;
1962 m_nTotalCount
= GetRowCount();
1964 m_aBar
->InvalidateState(NavigationBar::RECORD_COUNT
);
1967 DbGridControl_Base::RowStatus
DbGridControl::GetRowStatus(long nRow
) const
1969 if (IsFilterRow(nRow
))
1970 return DbGridControl_Base::FILTER
;
1971 else if (m_nCurrentPos
>= 0 && nRow
== m_nCurrentPos
)
1974 if (!IsValid(m_xCurrentRow
))
1975 return DbGridControl_Base::DELETED
;
1976 else if (IsModified())
1977 return DbGridControl_Base::MODIFIED
;
1978 else if (m_xCurrentRow
->IsNew())
1979 return DbGridControl_Base::CURRENTNEW
;
1981 return DbGridControl_Base::CURRENT
;
1983 else if (IsInsertionRow(nRow
))
1984 return DbGridControl_Base::NEW
;
1985 else if (!IsValid(m_xSeekRow
))
1986 return DbGridControl_Base::DELETED
;
1988 return DbGridControl_Base::CLEAN
;
1991 void DbGridControl::PaintStatusCell(OutputDevice
& rDev
, const Rectangle
& rRect
) const
1993 DbGridControl_Base::PaintStatusCell(rDev
, rRect
);
1996 void DbGridControl::PaintCell(OutputDevice
& rDev
, const Rectangle
& rRect
, sal_uInt16 nColumnId
) const
1998 if (!IsValid(m_xPaintRow
))
2001 size_t Location
= GetModelColumnPos(nColumnId
);
2002 DbGridColumn
* pColumn
= (Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
2005 Rectangle
aArea(rRect
);
2006 if ((GetMode() & BrowserMode::CURSOR_WO_FOCUS
) == BrowserMode::CURSOR_WO_FOCUS
)
2009 aArea
.Bottom() -= 1;
2011 pColumn
->Paint(rDev
, aArea
, m_xPaintRow
, getNumberFormatter());
2015 bool DbGridControl::CursorMoving(long nNewRow
, sal_uInt16 nNewCol
)
2018 DeactivateCell( false );
2021 && ( m_nCurrentPos
!= nNewRow
)
2022 && !SetCurrent( nNewRow
)
2029 if ( !DbGridControl_Base::CursorMoving( nNewRow
, nNewCol
) )
2035 bool DbGridControl::SetCurrent(long nNewRow
)
2037 // Each movement of the datacursor must start with BeginCursorAction and end with
2038 // EndCursorAction to block all notifications during the movement
2039 BeginCursorAction();
2043 // compare positions
2044 if (SeekCursor(nNewRow
))
2046 if (IsFilterRow(nNewRow
)) // special mode for filtering
2048 m_xCurrentRow
= m_xDataRow
= m_xPaintRow
= m_xEmptyRow
;
2049 m_nCurrentPos
= nNewRow
;
2053 bool bNewRowInserted
= false;
2054 // Should we go to the insertrow ?
2055 if (IsInsertionRow(nNewRow
))
2057 // to we need to move the cursor to the insert row?
2058 // we need to insert the if the current row isn't the insert row or if the
2059 // cursor triggered the move by itselt and we need a reinitialization of the row
2060 Reference
< XPropertySet
> xCursorProps
= m_pDataCursor
->getPropertySet();
2061 if ( !::comphelper::getBOOL(xCursorProps
->getPropertyValue(FM_PROP_ISNEW
)) )
2063 Reference
< XResultSetUpdate
> xUpdateCursor(Reference
< XInterface
>(*m_pDataCursor
), UNO_QUERY
);
2064 xUpdateCursor
->moveToInsertRow();
2066 bNewRowInserted
= true;
2071 if ( !m_pSeekCursor
->isBeforeFirst() && !m_pSeekCursor
->isAfterLast() )
2073 Any aBookmark
= m_pSeekCursor
->getBookmark();
2074 if (!m_xCurrentRow
|| m_xCurrentRow
->IsNew() || !CompareBookmark(aBookmark
, m_pDataCursor
->getBookmark()))
2076 // adjust the cursor to the new desired row
2077 if (!m_pDataCursor
->moveToBookmark(aBookmark
))
2085 m_xDataRow
->SetState(m_pDataCursor
, false);
2086 m_xCurrentRow
= m_xDataRow
;
2088 long nPaintPos
= -1;
2089 // do we have to repaint the last regular row in case of setting defaults or autovalues
2090 if (m_nCurrentPos
>= 0 && m_nCurrentPos
>= (GetRowCount() - 2))
2091 nPaintPos
= m_nCurrentPos
;
2093 m_nCurrentPos
= nNewRow
;
2095 // repaint the new row to display all defaults
2096 if (bNewRowInserted
)
2097 RowModified(m_nCurrentPos
);
2099 RowModified(nPaintPos
);
2104 OSL_FAIL("DbGridControl::SetCurrent : SeekRow failed !");
2109 catch ( const Exception
& )
2111 DBG_UNHANDLED_EXCEPTION();
2120 void DbGridControl::CursorMoved()
2123 // cursor movement due to deletion or insertion of rows
2124 if (m_pDataCursor
&& m_nCurrentPos
!= GetCurRow())
2126 DeactivateCell(true);
2127 SetCurrent(GetCurRow());
2130 DbGridControl_Base::CursorMoved();
2131 m_aBar
->InvalidateAll(m_nCurrentPos
);
2133 // select the new column when they moved
2134 if ( IsDesignMode() && GetSelectedColumnCount() > 0 && GetCurColumnId() )
2136 SelectColumnId( GetCurColumnId() );
2139 if ( m_nLastColId
!= GetCurColumnId() )
2141 m_nLastColId
= GetCurColumnId();
2143 if ( m_nLastRowId
!= GetCurRow() )
2145 m_nLastRowId
= GetCurRow();
2148 void DbGridControl::onRowChange()
2150 // not interested in
2153 void DbGridControl::onColumnChange()
2155 if ( m_pGridListener
)
2156 m_pGridListener
->columnChanged();
2159 void DbGridControl::setDisplaySynchron(bool bSync
)
2161 if (bSync
!= m_bSynchDisplay
)
2163 m_bSynchDisplay
= bSync
;
2164 if (m_bSynchDisplay
)
2165 AdjustDataSource(false);
2169 void DbGridControl::AdjustDataSource(bool bFull
)
2171 SAL_INFO("svx.fmcomp", "DbGridControl::AdjustDataSource");
2172 SolarMutexGuard aGuard
;
2173 // If the current row is recalculated at the moment, do not adjust
2176 m_xCurrentRow
= NULL
;
2177 // if we are on the same row only repaint
2178 // but this is only possible for rows which are not inserted, in that case the comparison result
2179 // may not be correct
2181 if ( m_xCurrentRow
.Is()
2182 && !m_xCurrentRow
->IsNew()
2183 && !m_pDataCursor
->isBeforeFirst()
2184 && !m_pDataCursor
->isAfterLast()
2185 && !m_pDataCursor
->rowDeleted()
2188 bool bEqualBookmarks
= CompareBookmark( m_xCurrentRow
->GetBookmark(), m_pDataCursor
->getBookmark() );
2190 bool bDataCursorIsOnNew
= false;
2191 m_pDataCursor
->getPropertySet()->getPropertyValue( FM_PROP_ISNEW
) >>= bDataCursorIsOnNew
;
2193 if ( bEqualBookmarks
&& !bDataCursorIsOnNew
)
2195 // position of my data cursor is the same as the position our current row points tpo
2196 // sync the status, repaint, done
2197 DBG_ASSERT(m_xDataRow
== m_xCurrentRow
, "Fehler in den Datenzeilen");
2198 SAL_INFO("svx.fmcomp", "same position, new state: " << ROWSTATUS(m_xCurrentRow
));
2199 RowModified(m_nCurrentPos
);
2204 // away from the data cursor's row
2205 if (m_xPaintRow
== m_xCurrentRow
)
2206 m_xPaintRow
= m_xSeekRow
;
2208 // not up-to-date row, thus, adjust completely
2212 sal_Int32 nNewPos
= AlignSeekCursor();
2213 if (nNewPos
< 0)// could not find any position
2216 m_bInAdjustDataSource
= true;
2217 if (nNewPos
!= m_nCurrentPos
)
2219 if (m_bSynchDisplay
)
2220 DbGridControl_Base::GoToRow(nNewPos
);
2222 if (!m_xCurrentRow
.Is())
2223 // Happens e.g. when deleting the n last datasets (n>1) while the cursor was positioned
2224 // on the last one. In this case, AdjustRows deletes two rows from BrowseBox, by what
2225 // CurrentRow is corrected to point two rows down, so that GoToRow will point into
2226 // emptiness (since we are - purportedly - at the correct position)
2227 SetCurrent(nNewPos
);
2231 SetCurrent(nNewPos
);
2232 RowModified(nNewPos
);
2234 m_bInAdjustDataSource
= false;
2236 // if the data cursor was moved from outside, this section is voided
2238 m_aBar
->InvalidateAll(m_nCurrentPos
, m_xCurrentRow
.Is());
2241 sal_Int32
DbGridControl::AlignSeekCursor()
2243 // position SeekCursor onto the data cursor, no data transmission
2248 Reference
< XPropertySet
> xSet
= m_pDataCursor
->getPropertySet();
2250 // now align the seek cursor and the data cursor
2251 if (::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISNEW
)))
2252 m_nSeekPos
= GetRowCount() - 1;
2257 if ( m_pDataCursor
->isBeforeFirst() )
2259 // this is somewhat strange, but can nevertheless happen
2260 DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (before first)!" );
2261 m_pSeekCursor
->first();
2262 m_pSeekCursor
->previous();
2265 else if ( m_pDataCursor
->isAfterLast() )
2267 DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (after last)!" );
2268 m_pSeekCursor
->last();
2269 m_pSeekCursor
->next();
2274 m_pSeekCursor
->moveToBookmark(m_pDataCursor
->getBookmark());
2275 if (!CompareBookmark(m_pDataCursor
->getBookmark(), m_pSeekCursor
->getBookmark()))
2276 // unfortunately, moveToBookmark might lead to a re-positioning of the seek
2277 // cursor (if the complex moveToBookmark with all its events fires an update
2278 // somewhere) -> retry
2279 m_pSeekCursor
->moveToBookmark(m_pDataCursor
->getBookmark());
2280 // Now there is still the chance of a failure but it is less likely.
2281 // The alternative would be an loop until everything is fine - no good solution...
2282 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2292 bool DbGridControl::SeekCursor(long nRow
, bool bAbsolute
)
2294 // position SeekCursor onto the data cursor, no data transmission
2296 // additions for the filtermode
2297 if (IsFilterRow(nRow
))
2306 // is this an insertion?
2307 if (IsValid(m_xCurrentRow
) && m_xCurrentRow
->IsNew() &&
2308 nRow
>= m_nCurrentPos
)
2310 // if so, scrolling down must be prevented as this is already the last data set!
2311 if (nRow
== m_nCurrentPos
)
2313 // no adjustment necessary
2316 else if (IsInsertionRow(nRow
)) // blank row for data insertion
2319 else if (IsInsertionRow(nRow
)) // blank row for data insertion
2321 else if ((-1 == nRow
) && (GetRowCount() == ((m_nOptions
& OPT_INSERT
) ? 1 : 0)) && m_pSeekCursor
->isAfterLast())
2325 bool bSuccess
= false;
2329 if ( m_pSeekCursor
->rowDeleted() )
2331 // somebody deleted the current row of the seek cursor. Move it away from this row.
2332 m_pSeekCursor
->next();
2333 if ( m_pSeekCursor
->isAfterLast() || m_pSeekCursor
->isBeforeFirst() )
2339 DBG_ASSERT( !m_pSeekCursor
->isAfterLast() && !m_pSeekCursor
->isBeforeFirst(),
2340 "DbGridControl::SeekCursor: how did the seek cursor get to this position?!" );
2341 nSteps
= nRow
- (m_pSeekCursor
->getRow() - 1);
2342 bAbsolute
= bAbsolute
|| (std::abs(nSteps
) > 100);
2347 bSuccess
= m_pSeekCursor
->absolute(nRow
+ 1);
2353 if (nSteps
> 0) // position onto the last needed data set
2355 if (m_pSeekCursor
->isAfterLast())
2357 else if (m_pSeekCursor
->isBeforeFirst())
2358 bSuccess
= m_pSeekCursor
->absolute(nSteps
);
2360 bSuccess
= m_pSeekCursor
->relative(nSteps
);
2362 else if (nSteps
< 0)
2364 if (m_pSeekCursor
->isBeforeFirst())
2366 else if (m_pSeekCursor
->isAfterLast())
2367 bSuccess
= m_pSeekCursor
->absolute(nSteps
);
2369 bSuccess
= m_pSeekCursor
->relative(nSteps
);
2380 OSL_FAIL("DbGridControl::SeekCursor : failed ...");
2387 if (bAbsolute
|| nSteps
> 0)
2389 if (m_pSeekCursor
->isLast())
2392 bSuccess
= m_pSeekCursor
->last();
2396 if (m_pSeekCursor
->isFirst())
2399 bSuccess
= m_pSeekCursor
->first();
2404 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2410 OSL_FAIL("DbGridControl::SeekCursor : failed ...");
2411 DBG_UNHANDLED_EXCEPTION();
2412 m_nSeekPos
= -1; // no further data set available
2415 return m_nSeekPos
== nRow
;
2418 void DbGridControl::MoveToFirst()
2420 if (m_pSeekCursor
&& (GetCurRow() != 0))
2424 void DbGridControl::MoveToLast()
2429 if (m_nTotalCount
< 0) // no RecordCount, yet
2433 bool bRes
= m_pSeekCursor
->last();
2437 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2446 // position onto the last data set not on a blank row
2447 if (m_nOptions
& OPT_INSERT
)
2449 if ((GetRowCount() - 1) > 0)
2450 MoveToPosition(GetRowCount() - 2);
2452 else if (GetRowCount())
2453 MoveToPosition(GetRowCount() - 1);
2456 void DbGridControl::MoveToPrev()
2458 long nNewRow
= std::max(GetCurRow() - 1L, 0L);
2459 if (GetCurRow() != nNewRow
)
2460 MoveToPosition(nNewRow
);
2463 void DbGridControl::MoveToNext()
2468 if (m_nTotalCount
> 0)
2470 // move the data cursor to the right position
2471 long nNewRow
= std::min(GetRowCount() - 1, GetCurRow() + 1);
2472 if (GetCurRow() != nNewRow
)
2473 MoveToPosition(nNewRow
);
2480 // try to move to next row
2481 // when not possible our paint cursor is already on the last row
2482 // then we must be sure that the data cursor is on the position
2483 // we call ourself again
2484 bOk
= m_pSeekCursor
->next();
2487 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2488 MoveToPosition(GetCurRow() + 1);
2491 catch(SQLException
&)
2493 DBG_UNHANDLED_EXCEPTION();
2499 if (m_nTotalCount
> 0) // only to avoid infinte recursion
2505 void DbGridControl::MoveToPosition(sal_uInt32 nPos
)
2510 if (m_nTotalCount
< 0 && (long)nPos
>= GetRowCount())
2514 if (!m_pSeekCursor
->absolute(nPos
+ 1))
2521 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2530 DbGridControl_Base::GoToRow(nPos
);
2531 m_aBar
->InvalidateAll(m_nCurrentPos
);
2534 void DbGridControl::AppendNew()
2536 if (!m_pSeekCursor
|| !(m_nOptions
& OPT_INSERT
))
2539 if (m_nTotalCount
< 0) // no RecordCount, yet
2543 bool bRes
= m_pSeekCursor
->last();
2547 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2557 long nNewRow
= m_nTotalCount
+ 1;
2558 if (nNewRow
> 0 && GetCurRow() != nNewRow
)
2559 MoveToPosition(nNewRow
- 1);
2562 void DbGridControl::SetDesignMode(bool bMode
)
2564 if ((bool) IsDesignMode() != bMode
)
2566 // adjust Enable/Disable for design mode so that the headerbar remains configurable
2572 GetDataWindow().Disable();
2577 // disable completely
2578 if (!GetDataWindow().IsEnabled())
2582 m_bDesignMode
= bMode
;
2583 GetDataWindow().SetMouseTransparent(bMode
);
2584 SetMouseTransparent(bMode
);
2586 m_aBar
->InvalidateAll(m_nCurrentPos
, true);
2590 void DbGridControl::SetFilterMode(bool bMode
)
2592 if (IsFilterMode() != bMode
)
2594 m_bFilterMode
= bMode
;
2598 SetUpdateMode(false);
2600 // there is no cursor anymore
2605 m_xEmptyRow
= new DbGridRow();
2607 // setting the new filter controls
2608 for ( size_t i
= 0; i
< m_aColumns
.size(); ++i
)
2610 DbGridColumn
* pCurCol
= m_aColumns
[ i
];
2611 if (!pCurCol
->IsHidden())
2612 pCurCol
->UpdateControl();
2615 // one row for filtering
2616 RowInserted(0, 1, true);
2617 SetUpdateMode(true);
2620 setDataSource(Reference
< XRowSet
> ());
2624 OUString
DbGridControl::GetCellText(long _nRow
, sal_uInt16 _nColId
) const
2626 size_t Location
= GetModelColumnPos( _nColId
);
2627 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
2629 if ( const_cast<DbGridControl
*>(this)->SeekRow(_nRow
) )
2630 sRet
= GetCurrentRowCellText(pColumn
, m_xPaintRow
);
2634 OUString
DbGridControl::GetCurrentRowCellText(DbGridColumn
* pColumn
,const DbGridRowRef
& _rRow
) const
2636 // text output for a single row
2638 if ( pColumn
&& IsValid(_rRow
) )
2639 aText
= pColumn
->GetCellText(_rRow
, m_xFormatter
);
2643 sal_uInt32
DbGridControl::GetTotalCellWidth(long nRow
, sal_uInt16 nColId
)
2647 size_t Location
= GetModelColumnPos( nColId
);
2648 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
2649 return GetDataWindow().GetTextWidth(GetCurrentRowCellText(pColumn
,m_xPaintRow
));
2652 return 30; // FIXME magic number for defaul cell width
2655 void DbGridControl::PreExecuteRowContextMenu(sal_uInt16
/*nRow*/, PopupMenu
& rMenu
)
2657 bool bDelete
= (m_nOptions
& OPT_DELETE
) && GetSelectRowCount() && !IsCurrentAppending();
2658 // if only a blank row is selected than do not delete
2659 bDelete
= bDelete
&& !((m_nOptions
& OPT_INSERT
) && GetSelectRowCount() == 1 && IsRowSelected(GetRowCount() - 1));
2661 rMenu
.EnableItem(SID_FM_DELETEROWS
, bDelete
);
2662 rMenu
.EnableItem(SID_FM_RECORD_SAVE
, IsModified());
2664 // the undo is more difficult
2665 bool bCanUndo
= IsModified();
2667 if (m_aMasterStateProvider
.IsSet())
2668 nState
= m_aMasterStateProvider
.Call(reinterpret_cast<void*>(SID_FM_RECORD_UNDO
));
2669 bCanUndo
&= ( 0 != nState
);
2671 rMenu
.EnableItem(SID_FM_RECORD_UNDO
, bCanUndo
);
2674 void DbGridControl::PostExecuteRowContextMenu(sal_uInt16
/*nRow*/, const PopupMenu
& /*rMenu*/, sal_uInt16 nExecutionResult
)
2676 switch (nExecutionResult
)
2678 case SID_FM_DELETEROWS
:
2679 // delete asynchronously
2681 Application::RemoveUserEvent(m_nDeleteEvent
);
2682 m_nDeleteEvent
= Application::PostUserEvent(LINK(this,DbGridControl
,OnDelete
), NULL
, true);
2684 case SID_FM_RECORD_UNDO
:
2687 case SID_FM_RECORD_SAVE
:
2695 void DbGridControl::DataSourcePropertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
)
2697 SAL_INFO("svx.fmcomp", "DbGridControl::DataSourcePropertyChanged");
2698 SolarMutexGuard aGuard
;
2699 // prop "IsModified" changed ?
2700 // during update don't care about the modified state
2701 if (!IsUpdating() && evt
.PropertyName
== FM_PROP_ISMODIFIED
)
2703 Reference
< XPropertySet
> xSource(evt
.Source
, UNO_QUERY
);
2704 DBG_ASSERT( xSource
.is(), "DbGridControl::DataSourcePropertyChanged: invalid event source!" );
2705 bool bIsNew
= false;
2707 bIsNew
= ::comphelper::getBOOL(xSource
->getPropertyValue(FM_PROP_ISNEW
));
2709 if (bIsNew
&& m_xCurrentRow
.Is())
2711 DBG_ASSERT(::comphelper::getBOOL(xSource
->getPropertyValue(FM_PROP_ROWCOUNTFINAL
)), "DbGridControl::DataSourcePropertyChanged : somebody moved the form to a new record before the row count was final !");
2712 sal_Int32 nRecordCount
= 0;
2713 xSource
->getPropertyValue(FM_PROP_ROWCOUNT
) >>= nRecordCount
;
2714 if (::comphelper::getBOOL(evt
.NewValue
))
2715 { // modified state changed from sal_False to sal_True and we're on a insert row
2716 // -> we've to add a new grid row
2717 if ((nRecordCount
== GetRowCount() - 1) && m_xCurrentRow
->IsNew())
2719 RowInserted(GetRowCount(), 1, true);
2720 InvalidateStatusCell(m_nCurrentPos
);
2721 m_aBar
->InvalidateAll(m_nCurrentPos
);
2725 { // modified state changed from sal_True to sal_False and we're on a insert row
2726 // we have two "new row"s at the moment : the one we're editing currently (where the current
2727 // column is the only dirty element) and a "new new" row which is completely clean. As the first
2728 // one is about to be cleaned, too, the second one is obsolete now.
2729 if (m_xCurrentRow
->IsNew() && nRecordCount
== (GetRowCount() - 2))
2731 RowRemoved(GetRowCount() - 1, 1, true);
2732 InvalidateStatusCell(m_nCurrentPos
);
2733 m_aBar
->InvalidateAll(m_nCurrentPos
);
2737 if (m_xCurrentRow
.Is())
2739 m_xCurrentRow
->SetStatus(::comphelper::getBOOL(evt
.NewValue
) ? GRS_MODIFIED
: GRS_CLEAN
);
2740 m_xCurrentRow
->SetNew( bIsNew
);
2741 InvalidateStatusCell(m_nCurrentPos
);
2742 SAL_INFO("svx.fmcomp", "modified flag changed, new state: " << ROWSTATUS(m_xCurrentRow
));
2747 void DbGridControl::StartDrag( sal_Int8
/*nAction*/, const Point
& rPosPixel
)
2749 if (!m_pSeekCursor
|| IsResizing())
2752 sal_uInt16 nColId
= GetColumnAtXPosPixel(rPosPixel
.X());
2753 long nRow
= GetRowAtYPosPixel(rPosPixel
.Y());
2754 if (nColId
!= HandleColumnId
&& nRow
>= 0)
2756 if (GetDataWindow().IsMouseCaptured())
2757 GetDataWindow().ReleaseMouse();
2759 size_t Location
= GetModelColumnPos( nColId
);
2760 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
2761 OStringTransferable
* pTransferable
= new OStringTransferable(GetCurrentRowCellText(pColumn
,m_xPaintRow
));
2762 Reference
< XTransferable
> xEnsureDelete(pTransferable
);
2763 pTransferable
->StartDrag(this, DND_ACTION_COPY
);
2767 bool DbGridControl::canCopyCellText(sal_Int32 _nRow
, sal_Int16 _nColId
)
2770 && (_nRow
< GetRowCount())
2771 && (_nColId
!= HandleColumnId
)
2772 && (_nColId
<= ColCount());
2775 void DbGridControl::copyCellText(sal_Int32 _nRow
, sal_Int16 _nColId
)
2777 DBG_ASSERT(canCopyCellText(_nRow
, _nColId
), "DbGridControl::copyCellText: invalid call!");
2778 DbGridColumn
* pColumn
= m_aColumns
[ GetModelColumnPos(_nColId
) ];
2780 OStringTransfer::CopyString( GetCurrentRowCellText( pColumn
,m_xPaintRow
), this );
2783 void DbGridControl::executeRowContextMenu( long _nRow
, const Point
& _rPreferredPos
)
2785 PopupMenu
aContextMenu( SVX_RES( RID_SVXMNU_ROWS
) );
2787 PreExecuteRowContextMenu( (sal_uInt16
)_nRow
, aContextMenu
);
2788 aContextMenu
.RemoveDisabledEntries( true, true );
2789 PostExecuteRowContextMenu( (sal_uInt16
)_nRow
, aContextMenu
, aContextMenu
.Execute( this, _rPreferredPos
) );
2791 // TODO: why this weird cast to sal_uInt16? What if we really have more than 65535 lines?
2792 // -> change this to sal_uInt32
2795 void DbGridControl::Command(const CommandEvent
& rEvt
)
2797 switch (rEvt
.GetCommand())
2799 case CommandEventId::ContextMenu
:
2801 if ( !m_pSeekCursor
)
2803 DbGridControl_Base::Command(rEvt
);
2807 if ( !rEvt
.IsMouseEvent() )
2808 { // context menu requested by keyboard
2809 if ( GetSelectRowCount() )
2811 long nRow
= FirstSelectedRow( );
2813 ::Rectangle
aRowRect( GetRowRectPixel( nRow
, true ) );
2814 executeRowContextMenu( nRow
, aRowRect
.LeftCenter() );
2821 sal_uInt16 nColId
= GetColumnAtXPosPixel(rEvt
.GetMousePosPixel().X());
2822 long nRow
= GetRowAtYPosPixel(rEvt
.GetMousePosPixel().Y());
2824 if (nColId
== HandleColumnId
)
2826 executeRowContextMenu( nRow
, rEvt
.GetMousePosPixel() );
2828 else if (canCopyCellText(nRow
, nColId
))
2830 PopupMenu
aContextMenu(SVX_RES(RID_SVXMNU_CELL
));
2831 aContextMenu
.RemoveDisabledEntries(true, true);
2832 switch (aContextMenu
.Execute(this, rEvt
.GetMousePosPixel()))
2835 copyCellText(nRow
, nColId
);
2841 DbGridControl_Base::Command(rEvt
);
2847 DbGridControl_Base::Command(rEvt
);
2851 IMPL_LINK_NOARG(DbGridControl
, OnDelete
)
2854 DeleteSelectedRows();
2858 void DbGridControl::DeleteSelectedRows()
2860 DBG_ASSERT(GetSelection(), "keine selection!!!");
2866 CellController
* DbGridControl::GetController(long /*nRow*/, sal_uInt16 nColumnId
)
2868 if (!IsValid(m_xCurrentRow
) || !IsEnabled())
2871 size_t Location
= GetModelColumnPos(nColumnId
);
2872 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
2876 CellController
* pReturn
= NULL
;
2878 pReturn
= &pColumn
->GetController();
2881 if (::comphelper::hasProperty(FM_PROP_ENABLED
, pColumn
->getModel()))
2883 if (!::comphelper::getBOOL(pColumn
->getModel()->getPropertyValue(FM_PROP_ENABLED
)))
2887 bool bInsert
= (m_xCurrentRow
->IsNew() && (m_nOptions
& OPT_INSERT
));
2888 bool bUpdate
= (!m_xCurrentRow
->IsNew() && (m_nOptions
& OPT_UPDATE
));
2890 if ((bInsert
&& !pColumn
->IsAutoValue()) || bUpdate
|| m_bForceROController
)
2892 pReturn
= &pColumn
->GetController();
2895 // if it is an edit row, it is possible to give it a forced read-only property
2896 if (!pReturn
->ISA(EditCellController
) && !pReturn
->ISA(SpinCellController
))
2897 // controller could not be set to read-only in forceROController
2898 if (!bInsert
&& !bUpdate
)
2899 // better use no controller than one without read-only
2907 void DbGridControl::CellModified()
2909 SAL_INFO("svx.fmcomp", "DbGridControl::CellModified");
2912 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
2913 if (m_nAsynAdjustEvent
)
2915 SAL_INFO("svx.fmcomp", "forcing a synchron call to " << (m_bPendingAdjustRows
? "AdjustRows" : "AdustDataSource"));
2916 RemoveUserEvent(m_nAsynAdjustEvent
);
2917 m_nAsynAdjustEvent
= 0;
2919 // force the call : this should be no problem as we're probably running in the solar thread here
2920 // (cell modified is triggered by user actions)
2921 if (m_bPendingAdjustRows
)
2928 if (!IsFilterMode() && IsValid(m_xCurrentRow
) && !m_xCurrentRow
->IsModified())
2931 // a data set should be inserted
2932 if (m_xCurrentRow
->IsNew())
2934 m_xCurrentRow
->SetStatus(GRS_MODIFIED
);
2935 SAL_INFO("svx.fmcomp", "current row is new, new state: MODIFIED");
2936 // if no row was added yet, do it now
2937 if (m_nCurrentPos
== GetRowCount() - 1)
2939 // increment RowCount
2940 RowInserted(GetRowCount(), 1, true);
2941 InvalidateStatusCell(m_nCurrentPos
);
2942 m_aBar
->InvalidateAll(m_nCurrentPos
);
2945 else if (m_xCurrentRow
->GetStatus() != GRS_MODIFIED
)
2947 m_xCurrentRow
->SetState(m_pDataCursor
, false);
2948 SAL_INFO("svx.fmcomp", "current row is not new, after SetState, new state: " << ROWSTATUS(m_xCurrentRow
));
2949 m_xCurrentRow
->SetStatus(GRS_MODIFIED
);
2950 SAL_INFO("svx.fmcomp", "current row is not new, new state: MODIFIED");
2951 InvalidateStatusCell(m_nCurrentPos
);
2956 void DbGridControl::Dispatch(sal_uInt16 nId
)
2958 if (nId
== BROWSER_CURSORENDOFFILE
)
2960 if (m_nOptions
& OPT_INSERT
)
2966 DbGridControl_Base::Dispatch(nId
);
2969 void DbGridControl::Undo()
2971 if (!IsFilterMode() && IsValid(m_xCurrentRow
) && IsModified())
2973 // check if we have somebody doin' the UNDO for us
2975 if (m_aMasterStateProvider
.IsSet())
2976 nState
= m_aMasterStateProvider
.Call(reinterpret_cast<void*>(SID_FM_RECORD_UNDO
));
2978 { // yes, we have, and the slot is enabled
2979 DBG_ASSERT(m_aMasterSlotExecutor
.IsSet(), "DbGridControl::Undo : a state, but no execute link ?");
2980 long lResult
= m_aMasterSlotExecutor
.Call(reinterpret_cast<void*>(SID_FM_RECORD_UNDO
));
2985 else if (nState
== 0)
2986 // yes, we have, and the slot is disabled
2989 BeginCursorAction();
2991 bool bAppending
= m_xCurrentRow
->IsNew();
2992 bool bDirty
= m_xCurrentRow
->IsModified();
2997 Reference
< XResultSetUpdate
> xUpdateCursor(Reference
< XInterface
>(*m_pDataCursor
), UNO_QUERY
);
2998 // no effects if we're not updating currently
3000 // just refresh the row
3001 xUpdateCursor
->moveToInsertRow();
3003 xUpdateCursor
->cancelRowUpdates();
3008 DBG_UNHANDLED_EXCEPTION();
3013 m_xDataRow
->SetState(m_pDataCursor
, false);
3014 if (&m_xPaintRow
== &m_xCurrentRow
)
3015 m_xPaintRow
= m_xCurrentRow
= m_xDataRow
;
3017 m_xCurrentRow
= m_xDataRow
;
3019 if (bAppending
&& (DbGridControl_Base::IsModified() || bDirty
))
3021 if (m_nCurrentPos
== GetRowCount() - 2)
3022 { // maybe we already removed it (in resetCurrentRow, called if the above moveToInsertRow
3023 // caused our data source form to be reset - which should be the usual case ....)
3024 RowRemoved(GetRowCount() - 1, 1, true);
3025 m_aBar
->InvalidateAll(m_nCurrentPos
);
3028 RowModified(m_nCurrentPos
);
3032 void DbGridControl::resetCurrentRow()
3036 // scenario : we're on the insert row, the row is dirty, and thus there exists a "second" insert row (which
3037 // is clean). Normally in DataSourcePropertyChanged we would remove this second row if the modified state of
3038 // the insert row changes from sal_True to sal_False. But if our current cell is the only modified element (means the
3039 // data source isn't modified) and we're reset this DataSourcePropertyChanged would never be called, so we
3040 // would never delete the obsolete "second insert row". Thus in this special case this method here
3041 // is the only possibility to determine the redundance of the row (resetCurrentRow is called when the
3042 // "first insert row" is about to be cleaned, so of course the "second insert row" is redundant now)
3043 Reference
< XPropertySet
> xDataSource
= getDataSource()->getPropertySet();
3044 if (xDataSource
.is() && !::comphelper::getBOOL(xDataSource
->getPropertyValue(FM_PROP_ISMODIFIED
)))
3046 // are we on a new row currently ?
3047 if (m_xCurrentRow
->IsNew())
3049 if (m_nCurrentPos
== GetRowCount() - 2)
3051 RowRemoved(GetRowCount() - 1, 1, true);
3052 m_aBar
->InvalidateAll(m_nCurrentPos
);
3058 m_xDataRow
->SetState(m_pDataCursor
, false);
3059 if (&m_xPaintRow
== &m_xCurrentRow
)
3060 m_xPaintRow
= m_xCurrentRow
= m_xDataRow
;
3062 m_xCurrentRow
= m_xDataRow
;
3065 RowModified(GetCurRow()); // will update the current controller if affected
3068 void DbGridControl::RowModified( long nRow
, sal_uInt16
/*nColId*/ )
3070 if (nRow
== m_nCurrentPos
&& IsEditing())
3072 CellControllerRef aTmpRef
= Controller();
3073 aTmpRef
->ClearModified();
3074 InitController(aTmpRef
, m_nCurrentPos
, GetCurColumnId());
3076 DbGridControl_Base::RowModified(nRow
);
3079 bool DbGridControl::IsModified() const
3081 return !IsFilterMode() && IsValid(m_xCurrentRow
) && (m_xCurrentRow
->IsModified() || DbGridControl_Base::IsModified());
3084 bool DbGridControl::IsCurrentAppending() const
3086 return m_xCurrentRow
.Is() && m_xCurrentRow
->IsNew();
3089 bool DbGridControl::IsInsertionRow(long nRow
) const
3091 return (m_nOptions
& OPT_INSERT
) && m_nTotalCount
>= 0 && (nRow
== GetRowCount() - 1);
3094 bool DbGridControl::SaveModified()
3096 SAL_INFO("svx.fmcomp", "DbGridControl::SaveModified");
3097 DBG_ASSERT(IsValid(m_xCurrentRow
), "GridControl:: Invalid row");
3098 if (!IsValid(m_xCurrentRow
))
3101 // accept input for this field
3102 // Where there changes at the current input field?
3103 if (!DbGridControl_Base::IsModified())
3106 size_t Location
= GetModelColumnPos( GetCurColumnId() );
3107 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
3108 bool bOK
= pColumn
&& pColumn
->Commit();
3109 DBG_ASSERT( Controller().Is(), "DbGridControl::SaveModified: was modified, by have no controller?!" );
3110 if ( !Controller().Is() )
3111 // this might happen if the callbacks implicitly triggered by Commit
3112 // fiddled with the form or the control ...
3113 // (Note that this here is a workaround, at most. We need a general concept how
3114 // to treat this, you can imagine an arbitrary number of scenarios where a callback
3115 // triggers something which leaves us in an expected state.)
3116 // #i67147# / 2006-07-17 / frank.schoenheit@sun.com
3121 Controller()->ClearModified();
3123 if ( IsValid(m_xCurrentRow
) )
3125 m_xCurrentRow
->SetState(m_pDataCursor
, false);
3126 SAL_INFO("svx.fmcomp", "explicit SetState, new state: " << ROWSTATUS(m_xCurrentRow
));
3127 InvalidateStatusCell( m_nCurrentPos
);
3131 SAL_INFO("svx.fmcomp", "no SetState, new state: " << ROWSTATUS(m_xCurrentRow
));
3136 // reset the modified flag ....
3137 Controller()->SetModified();
3143 bool DbGridControl::SaveRow()
3145 SAL_INFO("svx.fmcomp", "DbGridControl::SaveRow");
3147 if (!IsValid(m_xCurrentRow
) || !IsModified())
3149 // value of the controller was not saved, yet
3150 else if (Controller().Is() && Controller()->IsModified())
3152 if (!SaveModified())
3157 BeginCursorAction();
3158 bool bAppending
= m_xCurrentRow
->IsNew();
3159 bool bSuccess
= false;
3162 Reference
< XResultSetUpdate
> xUpdateCursor(Reference
< XInterface
>(*m_pDataCursor
), UNO_QUERY
);
3164 xUpdateCursor
->insertRow();
3166 xUpdateCursor
->updateRow();
3169 catch(SQLException
&)
3172 m_bUpdating
= false;
3180 // if we are appending we still sit on the insert row
3181 // we don't move just clear the flags not to move on the current row
3182 m_xCurrentRow
->SetState(m_pDataCursor
, false);
3183 SAL_INFO("svx.fmcomp", "explicit SetState after a successful update, new state: " << ROWSTATUS(m_xCurrentRow
));
3184 m_xCurrentRow
->SetNew(false);
3186 // adjust the seekcursor if it is on the same position as the datacursor
3187 if (m_nSeekPos
== m_nCurrentPos
|| bAppending
)
3189 // get the bookmark to refetch the data
3190 // in insert mode we take the new bookmark of the data cursor
3191 Any aBookmark
= bAppending
? m_pDataCursor
->getBookmark() : m_pSeekCursor
->getBookmark();
3192 m_pSeekCursor
->moveToBookmark(aBookmark
);
3194 m_xSeekRow
->SetState(m_pSeekCursor
, true);
3195 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
3198 // and repaint the row
3199 RowModified(m_nCurrentPos
);
3205 m_bUpdating
= false;
3208 // The old code returned (nRecords != 0) here.
3209 // Me thinks this is wrong : If something goes wrong while update the record, an exception will be thrown,
3210 // which results in a "return sal_False" (see above). If no exception is thrown, everything is fine. If nRecords
3211 // is zero, this simply means all fields had their original values.
3212 // FS - 06.12.99 - 70502
3216 bool DbGridControl::PreNotify(NotifyEvent
& rEvt
)
3218 // do not handle events of the Navbar
3219 if (m_aBar
->IsWindowOrChild(rEvt
.GetWindow()))
3220 return BrowseBox::PreNotify(rEvt
);
3222 switch (rEvt
.GetType())
3224 case MouseNotifyEvent::KEYINPUT
:
3226 const KeyEvent
* pKeyEvent
= rEvt
.GetKeyEvent();
3228 sal_uInt16 nCode
= pKeyEvent
->GetKeyCode().GetCode();
3229 bool bShift
= pKeyEvent
->GetKeyCode().IsShift();
3230 bool bCtrl
= pKeyEvent
->GetKeyCode().IsMod1();
3231 bool bAlt
= pKeyEvent
->GetKeyCode().IsMod2();
3232 if ( ( KEY_TAB
== nCode
) && bCtrl
&& !bAlt
)
3234 // Ctrl-Tab is used to step out of the control, without traveling to the
3235 // remaining cells first
3236 // -> build a new key event without the Ctrl-key, and let the very base class handle it
3237 vcl::KeyCode
aNewCode( KEY_TAB
, bShift
, false, false, false );
3238 KeyEvent
aNewEvent( pKeyEvent
->GetCharCode(), aNewCode
);
3240 // call the Control - our direct base class will interpret this in a way we do not want (and do
3241 // a cell traveling)
3242 Control::KeyInput( aNewEvent
);
3246 if ( !bShift
&& !bCtrl
&& ( KEY_ESCAPE
== nCode
) )
3254 else if ( ( KEY_DELETE
== nCode
) && !bShift
&& !bCtrl
) // delete rows
3256 if ((m_nOptions
& OPT_DELETE
) && GetSelectRowCount())
3258 // delete asynchronously
3260 Application::RemoveUserEvent(m_nDeleteEvent
);
3261 m_nDeleteEvent
= Application::PostUserEvent(LINK(this,DbGridControl
,OnDelete
), NULL
, true);
3267 return DbGridControl_Base::PreNotify(rEvt
);
3271 bool DbGridControl::IsTabAllowed(bool bRight
) const
3274 // Tab only if not on the _last_ row
3275 return GetCurRow() < (GetRowCount() - 1) || !m_bRecordCountFinal
||
3276 GetViewColumnPos(GetCurColumnId()) < (GetViewColCount() - 1);
3279 // Tab only if not on the _first_ row
3280 return GetCurRow() > 0 || (GetCurColumnId() && GetViewColumnPos(GetCurColumnId()) > 0);
3284 void DbGridControl::KeyInput( const KeyEvent
& rEvt
)
3286 if (rEvt
.GetKeyCode().GetFunction() == KeyFuncType::COPY
)
3288 long nRow
= GetCurRow();
3289 sal_uInt16 nColId
= GetCurColumnId();
3290 if (nRow
>= 0 && nRow
< GetRowCount() && nColId
< ColCount())
3292 size_t Location
= GetModelColumnPos( nColId
);
3293 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
3294 OStringTransfer::CopyString( GetCurrentRowCellText( pColumn
, m_xCurrentRow
), this );
3298 DbGridControl_Base::KeyInput(rEvt
);
3301 void DbGridControl::HideColumn(sal_uInt16 nId
)
3305 // determine the col for the focus to set to after removal
3306 sal_uInt16 nPos
= GetViewColumnPos(nId
);
3307 sal_uInt16 nNewColId
= nPos
== (ColCount()-1)
3308 ? GetColumnIdFromViewPos(nPos
-1) // last col is to be removed -> take the previous
3309 : GetColumnIdFromViewPos(nPos
+1); // take the next
3311 long lCurrentWidth
= GetColumnWidth(nId
);
3312 DbGridControl_Base::RemoveColumn(nId
);
3313 // don't use my own RemoveColumn, this would remove it from m_aColumns, too
3316 size_t Location
= GetModelColumnPos( nId
);
3317 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
3318 DBG_ASSERT(pColumn
, "DbGridControl::HideColumn : somebody did hide a nonexistent column !");
3321 pColumn
->m_bHidden
= true;
3322 pColumn
->m_nLastVisibleWidth
= CalcReverseZoom(lCurrentWidth
);
3325 // and reset the focus
3326 if ( nId
== GetCurColumnId() )
3327 GoToColumnId( nNewColId
);
3330 void DbGridControl::ShowColumn(sal_uInt16 nId
)
3332 sal_uInt16 nPos
= GetModelColumnPos(nId
);
3333 DBG_ASSERT(nPos
!= GRID_COLUMN_NOT_FOUND
, "DbGridControl::ShowColumn : invalid argument !");
3334 if (nPos
== GRID_COLUMN_NOT_FOUND
)
3337 DbGridColumn
* pColumn
= m_aColumns
[ nPos
];
3338 if (!pColumn
->IsHidden())
3340 DBG_ASSERT(GetViewColumnPos(nId
) != GRID_COLUMN_NOT_FOUND
, "DbGridControl::ShowColumn : inconsistent internal state !");
3341 // if the column isn't marked as hidden, it should be visible, shouldn't it ?
3344 DBG_ASSERT(GetViewColumnPos(nId
) == GRID_COLUMN_NOT_FOUND
, "DbGridControl::ShowColumn : inconsistent internal state !");
3345 // the opposite situation ...
3347 // to determine the new view position we need an adjacent non-hidden column
3348 sal_uInt16 nNextNonHidden
= BROWSER_INVALIDID
;
3349 // first search the cols to the right
3350 for ( size_t i
= nPos
+ 1; i
< m_aColumns
.size(); ++i
)
3352 DbGridColumn
* pCurCol
= m_aColumns
[ i
];
3353 if (!pCurCol
->IsHidden())
3359 if ((nNextNonHidden
== BROWSER_INVALIDID
) && (nPos
> 0))
3362 for ( size_t i
= nPos
; i
> 0; --i
)
3364 DbGridColumn
* pCurCol
= m_aColumns
[ i
-1 ];
3365 if (!pCurCol
->IsHidden())
3367 nNextNonHidden
= i
-1;
3372 sal_uInt16 nNewViewPos
= (nNextNonHidden
== BROWSER_INVALIDID
)
3373 ? 1 // there is no visible column -> insert behinde the handle col
3374 : GetViewColumnPos( m_aColumns
[ nNextNonHidden
]->GetId() ) + 1;
3375 // the first non-handle col has "view pos" 0, but the pos arg for InsertDataColumn expects
3376 // a position 1 for the first non-handle col -> +1
3377 DBG_ASSERT(nNewViewPos
!= GRID_COLUMN_NOT_FOUND
, "DbGridControl::ShowColumn : inconsistent internal state !");
3378 // we found a col marked as visible but got no view pos for it ...
3380 if ((nNextNonHidden
<nPos
) && (nNextNonHidden
!= BROWSER_INVALIDID
))
3381 // nNextNonHidden is a column to the left, so we want to insert the new col _right_ beside it's pos
3387 pColumn
->getModel()->getPropertyValue(FM_PROP_LABEL
) >>= aName
;
3388 InsertDataColumn(nId
, aName
, CalcZoom(pColumn
->m_nLastVisibleWidth
), HeaderBarItemBits::CENTER
| HeaderBarItemBits::VCENTER
| HeaderBarItemBits::CLICKABLE
, nNewViewPos
);
3389 pColumn
->m_bHidden
= false;
3395 sal_uInt16
DbGridControl::GetColumnIdFromModelPos( sal_uInt16 nPos
) const
3397 if (nPos
>= m_aColumns
.size())
3399 OSL_FAIL("DbGridControl::GetColumnIdFromModelPos : invalid argument !");
3400 return GRID_COLUMN_NOT_FOUND
;
3403 DbGridColumn
* pCol
= m_aColumns
[ nPos
];
3404 #if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
3405 // in der Debug-Version rechnen wir die ModelPos in eine ViewPos um und vergleichen das mit dem Wert,
3406 // den wir zurueckliefern werden (nId an der entsprechenden Col in m_aColumns)
3408 if (!pCol
->IsHidden())
3409 { // macht nur Sinn, wenn die Spalte sichtbar ist
3410 sal_uInt16 nViewPos
= nPos
;
3411 for ( size_t i
= 0; i
< m_aColumns
.size() && i
< nPos
; ++i
)
3412 if ( m_aColumns
[ i
]->IsHidden())
3415 DBG_ASSERT(pCol
&& GetColumnIdFromViewPos(nViewPos
) == pCol
->GetId(),
3416 "DbGridControl::GetColumnIdFromModelPos : this isn't consistent .... did I misunderstand something ?");
3419 return pCol
->GetId();
3422 sal_uInt16
DbGridControl::GetModelColumnPos( sal_uInt16 nId
) const
3424 for ( size_t i
= 0; i
< m_aColumns
.size(); ++i
)
3425 if ( m_aColumns
[ i
]->GetId() == nId
)
3428 return GRID_COLUMN_NOT_FOUND
;
3431 void DbGridControl::implAdjustInSolarThread(bool _bRows
)
3433 SAL_INFO("svx.fmcomp", "DbGridControl::implAdjustInSolarThread");
3434 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
3435 if (::osl::Thread::getCurrentIdentifier() != Application::GetMainThreadIdentifier())
3437 m_nAsynAdjustEvent
= PostUserEvent(LINK(this, DbGridControl
, OnAsyncAdjust
), reinterpret_cast< void* >( _bRows
), true);
3438 m_bPendingAdjustRows
= _bRows
;
3440 SAL_INFO("svx.fmcomp", "posting an AdjustRows");
3442 SAL_INFO("svx.fmcomp", "posting an AdjustDataSource");
3447 SAL_INFO("svx.fmcomp", "doing an AdjustRows");
3449 SAL_INFO("svx.fmcomp", "doing an AdjustDataSource");
3450 // always adjust the rows before adjusting the data source
3451 // If this is not necessary (because the row count did not change), nothing is done
3452 // The problem is that we can't rely on the order of which the calls come in: If the cursor was moved
3453 // to a position behind row count know 'til now, the cursorMoved notification may come before the
3454 // RowCountChanged notification
3455 // 94093 - 02.11.2001 - frank.schoenheit@sun.com
3463 IMPL_LINK(DbGridControl
, OnAsyncAdjust
, void*, pAdjustWhat
)
3465 m_nAsynAdjustEvent
= 0;
3468 // see implAdjustInSolarThread for a comment why we do this every time
3476 void DbGridControl::BeginCursorAction()
3478 if (m_pFieldListeners
)
3480 ColumnFieldValueListeners
* pListeners
= static_cast<ColumnFieldValueListeners
*>(m_pFieldListeners
);
3481 ColumnFieldValueListeners::const_iterator aIter
= pListeners
->begin();
3482 while (aIter
!= pListeners
->end())
3484 GridFieldValueListener
* pCurrent
= (*aIter
).second
;
3486 pCurrent
->suspend();
3491 if (m_pDataSourcePropListener
)
3492 m_pDataSourcePropListener
->suspend();
3495 void DbGridControl::EndCursorAction()
3497 if (m_pFieldListeners
)
3499 ColumnFieldValueListeners
* pListeners
= static_cast<ColumnFieldValueListeners
*>(m_pFieldListeners
);
3500 ColumnFieldValueListeners::const_iterator aIter
= pListeners
->begin();
3501 while (aIter
!= pListeners
->end())
3503 GridFieldValueListener
* pCurrent
= (*aIter
).second
;
3510 if (m_pDataSourcePropListener
)
3511 m_pDataSourcePropListener
->resume();
3514 void DbGridControl::ConnectToFields()
3516 ColumnFieldValueListeners
* pListeners
= static_cast<ColumnFieldValueListeners
*>(m_pFieldListeners
);
3517 DBG_ASSERT(!pListeners
|| pListeners
->empty(), "DbGridControl::ConnectToFields : please call DisconnectFromFields first !");
3521 pListeners
= new ColumnFieldValueListeners
;
3522 m_pFieldListeners
= pListeners
;
3525 for ( size_t i
= 0; i
< m_aColumns
.size(); ++i
)
3527 DbGridColumn
* pCurrent
= m_aColumns
[ i
];
3528 sal_uInt16 nViewPos
= pCurrent
? GetViewColumnPos(pCurrent
->GetId()) : GRID_COLUMN_NOT_FOUND
;
3529 if (GRID_COLUMN_NOT_FOUND
== nViewPos
)
3532 Reference
< XPropertySet
> xField
= pCurrent
->GetField();
3536 // column is visible and bound here
3537 GridFieldValueListener
*& rpListener
= (*pListeners
)[pCurrent
->GetId()];
3538 DBG_ASSERT(!rpListener
, "DbGridControl::ConnectToFields : already a listener for this column ?!");
3539 rpListener
= new GridFieldValueListener(*this, xField
, pCurrent
->GetId());
3543 void DbGridControl::DisconnectFromFields()
3545 if (!m_pFieldListeners
)
3548 ColumnFieldValueListeners
* pListeners
= static_cast<ColumnFieldValueListeners
*>(m_pFieldListeners
);
3549 while (!pListeners
->empty())
3552 sal_Int32 nOldSize
= pListeners
->size();
3554 pListeners
->begin()->second
->dispose();
3555 DBG_ASSERT(nOldSize
> (sal_Int32
)pListeners
->size(), "DbGridControl::DisconnectFromFields : dispose on a listener should result in a removal from my list !");
3559 m_pFieldListeners
= NULL
;
3562 void DbGridControl::FieldValueChanged(sal_uInt16 _nId
, const PropertyChangeEvent
& /*_evt*/)
3564 osl::MutexGuard
aPreventDestruction(m_aDestructionSafety
);
3565 // needed as this may run in a thread other than the main one
3566 if (GetRowStatus(GetCurRow()) != DbGridControl_Base::MODIFIED
)
3567 // all other cases are handled elsewhere
3570 size_t Location
= GetModelColumnPos( _nId
);
3571 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
3574 boost::scoped_ptr
<vcl::SolarMutexTryAndBuyGuard
> pGuard
;
3575 while (!m_bWantDestruction
&& (!pGuard
|| !pGuard
->isAcquired()))
3576 pGuard
.reset(new vcl::SolarMutexTryAndBuyGuard
);
3578 if (m_bWantDestruction
)
3579 { // at this moment, within another thread, our destructor tries to destroy the listener which called this method
3580 // => don't do anything
3581 // 73365 - 23.02.00 - FS
3585 // and finally do the update ...
3586 pColumn
->UpdateFromField(m_xCurrentRow
, m_xFormatter
);
3587 RowModified(GetCurRow(), _nId
);
3591 void DbGridControl::FieldListenerDisposing(sal_uInt16 _nId
)
3593 ColumnFieldValueListeners
* pListeners
= static_cast<ColumnFieldValueListeners
*>(m_pFieldListeners
);
3596 OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (have no listener array) !");
3600 ColumnFieldValueListeners::iterator aPos
= pListeners
->find(_nId
);
3601 if (aPos
== pListeners
->end())
3603 OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (did not find the listener) !");
3607 delete aPos
->second
;
3609 pListeners
->erase(aPos
);
3612 void DbGridControl::disposing(sal_uInt16 _nId
, const EventObject
& /*_rEvt*/)
3615 { // the seek cursor is being disposed
3616 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
3617 setDataSource(NULL
,0); // our clone was disposed so we set our datasource to null to avoid later access to it
3618 if (m_nAsynAdjustEvent
)
3620 RemoveUserEvent(m_nAsynAdjustEvent
);
3621 m_nAsynAdjustEvent
= 0;
3626 sal_Int32
DbGridControl::GetAccessibleControlCount() const
3628 return DbGridControl_Base::GetAccessibleControlCount() + 1; // the navigation control
3631 Reference
<XAccessible
> DbGridControl::CreateAccessibleControl( sal_Int32 _nIndex
)
3633 Reference
<XAccessible
> xRet
;
3634 if ( _nIndex
== DbGridControl_Base::GetAccessibleControlCount() )
3636 xRet
= m_aBar
->GetAccessible();
3639 xRet
= DbGridControl_Base::CreateAccessibleControl( _nIndex
);
3643 Reference
< XAccessible
> DbGridControl::CreateAccessibleCell( sal_Int32 _nRow
, sal_uInt16 _nColumnPos
)
3645 sal_uInt16 nColumnId
= GetColumnId( _nColumnPos
);
3646 size_t Location
= GetModelColumnPos(nColumnId
);
3647 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
3650 Reference
< ::com::sun::star::awt::XControl
> xInt(pColumn
->GetCell());
3651 Reference
< ::com::sun::star::awt::XCheckBox
> xBox(xInt
,UNO_QUERY
);
3654 TriState eValue
= TRISTATE_FALSE
;
3655 switch( xBox
->getState() )
3658 eValue
= TRISTATE_FALSE
;
3661 eValue
= TRISTATE_TRUE
;
3664 eValue
= TRISTATE_INDET
;
3667 return DbGridControl_Base::CreateAccessibleCheckBoxCell( _nRow
, _nColumnPos
,eValue
);
3670 return DbGridControl_Base::CreateAccessibleCell( _nRow
, _nColumnPos
);
3673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */