1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: gridctrl.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #ifndef _SVX_FMHELP_HRC
37 #include <svx/gridctrl.hxx>
38 #include "gridcell.hxx"
39 #include "svx/dbtoolsclient.hxx"
40 #include "fmtools.hxx"
41 #include <svtools/stringtransfer.hxx>
43 #ifndef _SVX_FMPROP_HRC
46 #include <svtools/stringtransfer.hxx>
47 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
48 #include <com/sun/star/accessibility/XAccessible.hpp>
49 #include <com/sun/star/sdb/XResultSetAccess.hpp>
50 #include <com/sun/star/sdbc/XResultSetUpdate.hpp>
51 #include <com/sun/star/sdbcx/Privilege.hpp>
52 #include <com/sun/star/container/XChild.hpp>
53 #include <com/sun/star/util/XNumberFormatter.hpp>
54 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
55 #include <com/sun/star/util/XCloneable.hpp>
56 #include <com/sun/star/beans/XPropertySet.hpp>
57 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
58 #include <comphelper/extract.hxx>
59 #include <tools/resid.hxx>
60 #include <tools/diagnose_ex.h>
61 #include <vcl/sound.hxx>
62 #include <vcl/menu.hxx>
64 #ifndef _SVX_FMRESIDS_HRC
65 #include "fmresids.hrc"
68 #ifndef _SVX_SVXIDS_HRC
69 #include <svx/svxids.hrc>
71 #include <tools/shl.hxx>
72 #include <svx/dialmgr.hxx>
73 #include "fmservs.hxx"
74 #include "sdbdatacolumn.hxx"
78 #include <comphelper/stl_types.hxx>
79 #include <comphelper/property.hxx>
84 using namespace ::svxform
;
85 using namespace ::svt
;
86 using namespace ::com::sun::star::beans
;
87 using namespace ::com::sun::star::lang
;
88 using namespace ::com::sun::star::uno
;
89 using namespace ::com::sun::star::sdbc
;
90 using namespace ::com::sun::star::sdbcx
;
91 using namespace ::com::sun::star::sdb
;
92 using namespace ::com::sun::star::datatransfer
;
93 using namespace ::com::sun::star::container
;
94 using namespace com::sun::star::accessibility
;
96 #define ROWSTATUS(row) !row.Is() ? "NULL" : row->GetStatus() == GRS_CLEAN ? "CLEAN" : row->GetStatus() == GRS_MODIFIED ? "MODIFIED" : row->GetStatus() == GRS_DELETED ? "DELETED" : "INVALID"
99 #define DEFAULT_BROWSE_MODE \
100 BROWSER_COLUMNSELECTION \
101 | BROWSER_MULTISELECTION \
102 | BROWSER_KEEPSELECTION \
103 | BROWSER_TRACKING_TIPS \
104 | BROWSER_HLINESFULL \
105 | BROWSER_VLINESFULL \
106 | BROWSER_HEADERBAR_NEW \
108 //==============================================================================
110 class GridFieldValueListener
;
111 DECLARE_STL_MAP(sal_uInt16
, GridFieldValueListener
*, ::std::less
<sal_uInt16
>, ColumnFieldValueListeners
);
113 //==============================================================================
115 DBG_NAME(GridFieldValueListener
)
116 class GridFieldValueListener
: protected ::comphelper::OPropertyChangeListener
119 DbGridControl
& m_rParent
;
120 ::comphelper::OPropertyChangeMultiplexer
* m_pRealListener
;
122 sal_Int16 m_nSuspended
;
123 sal_Bool m_bDisposed
: 1;
126 GridFieldValueListener(DbGridControl
& _rParent
, const Reference
< XPropertySet
>& xField
, sal_uInt16 _nId
);
127 virtual ~GridFieldValueListener();
129 virtual void _propertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
);
131 void suspend() { ++m_nSuspended
; }
132 void resume() { --m_nSuspended
; }
136 //------------------------------------------------------------------------------
137 GridFieldValueListener::GridFieldValueListener(DbGridControl
& _rParent
, const Reference
< XPropertySet
>& _rField
, sal_uInt16 _nId
)
138 :OPropertyChangeListener(m_aMutex
)
140 ,m_pRealListener(NULL
)
143 ,m_bDisposed(sal_False
)
145 DBG_CTOR(GridFieldValueListener
, NULL
);
148 m_pRealListener
= new ::comphelper::OPropertyChangeMultiplexer(this, _rField
);
149 m_pRealListener
->addProperty(FM_PROP_VALUE
);
150 m_pRealListener
->acquire();
154 //------------------------------------------------------------------------------
155 GridFieldValueListener::~GridFieldValueListener()
157 DBG_DTOR(GridFieldValueListener
, NULL
);
161 //------------------------------------------------------------------------------
162 void GridFieldValueListener::_propertyChanged(const PropertyChangeEvent
& _evt
) throw( RuntimeException
)
164 DBG_ASSERT(m_nSuspended
>=0, "GridFieldValueListener::_propertyChanged : resume > suspend !");
165 if (m_nSuspended
<= 0)
166 m_rParent
.FieldValueChanged(m_nId
, _evt
);
169 //------------------------------------------------------------------------------
170 void GridFieldValueListener::dispose()
174 DBG_ASSERT(m_pRealListener
== NULL
, "GridFieldValueListener::dispose : inconsistent !");
180 m_pRealListener
->dispose();
181 m_pRealListener
->release();
182 m_pRealListener
= NULL
;
185 m_bDisposed
= sal_True
;
186 m_rParent
.FieldListenerDisposing(m_nId
);
189 //==============================================================================
191 class DisposeListenerGridBridge
: public FmXDisposeListener
194 DbGridControl
& m_rParent
;
195 FmXDisposeMultiplexer
* m_pRealListener
;
198 DisposeListenerGridBridge( DbGridControl
& _rParent
, const Reference
< XComponent
>& _rxObject
, sal_Int16 _rId
= -1);
199 virtual ~DisposeListenerGridBridge();
201 virtual void disposing(const EventObject
& _rEvent
, sal_Int16 _nId
) throw( RuntimeException
) { m_rParent
.disposing(_nId
, _rEvent
); }
204 //==============================================================================
207 DBG_NAME(DisposeListenerGridBridge
)
208 //------------------------------------------------------------------------------
209 DisposeListenerGridBridge::DisposeListenerGridBridge(DbGridControl
& _rParent
, const Reference
< XComponent
>& _rxObject
, sal_Int16 _rId
)
210 :FmXDisposeListener(m_aMutex
)
212 ,m_pRealListener(NULL
)
214 DBG_CTOR(DisposeListenerGridBridge
,NULL
);
218 m_pRealListener
= new FmXDisposeMultiplexer(this, _rxObject
, _rId
);
219 m_pRealListener
->acquire();
223 //------------------------------------------------------------------------------
224 DisposeListenerGridBridge::~DisposeListenerGridBridge()
228 m_pRealListener
->dispose();
229 m_pRealListener
->release();
230 m_pRealListener
= NULL
;
233 DBG_DTOR(DisposeListenerGridBridge
,NULL
);
236 //==============================================================================
238 static sal_uInt16 ControlMap
[] =
240 DbGridControl::NavigationBar::RECORD_TEXT
,
241 DbGridControl::NavigationBar::RECORD_ABSOLUTE
,
242 DbGridControl::NavigationBar::RECORD_OF
,
243 DbGridControl::NavigationBar::RECORD_COUNT
,
244 DbGridControl::NavigationBar::RECORD_FIRST
,
245 DbGridControl::NavigationBar::RECORD_NEXT
,
246 DbGridControl::NavigationBar::RECORD_PREV
,
247 DbGridControl::NavigationBar::RECORD_LAST
,
248 DbGridControl::NavigationBar::RECORD_NEW
,
252 //------------------------------------------------------------------------------
253 sal_Bool
CompareBookmark(const Any
& aLeft
, const Any
& aRight
)
255 return ::comphelper::compare(aLeft
, aRight
);
258 //==============================================================================
259 class FmXGridSourcePropListener
: public ::comphelper::OPropertyChangeListener
261 DbGridControl
* m_pParent
;
263 // a DbGridControl has no mutex, so we use our own as the base class expects one
265 sal_Int16 m_nSuspended
;
268 FmXGridSourcePropListener(DbGridControl
* _pParent
);
270 void suspend() { ++m_nSuspended
; }
271 void resume() { --m_nSuspended
; }
273 virtual void _propertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
);
276 //------------------------------------------------------------------------------
277 FmXGridSourcePropListener::FmXGridSourcePropListener(DbGridControl
* _pParent
)
278 :OPropertyChangeListener(m_aMutex
)
282 DBG_ASSERT(m_pParent
, "FmXGridSourcePropListener::FmXGridSourcePropListener : invalid parent !");
285 //------------------------------------------------------------------------------
286 void FmXGridSourcePropListener::_propertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
)
288 DBG_ASSERT(m_nSuspended
>=0, "FmXGridSourcePropListener::_propertyChanged : resume > suspend !");
289 if (m_nSuspended
<= 0)
290 m_pParent
->DataSourcePropertyChanged(evt
);
293 //==============================================================================
294 //------------------------------------------------------------------------------
295 DbGridControl::NavigationBar::AbsolutePos::AbsolutePos(Window
* pParent
, WinBits nStyle
)
296 :NumericField(pParent
, nStyle
)
303 SetStrictFormat(sal_True
);
306 //------------------------------------------------------------------------------
307 void DbGridControl::NavigationBar::AbsolutePos::KeyInput(const KeyEvent
& rEvt
)
309 if (rEvt
.GetKeyCode() == KEY_RETURN
&& GetText().Len())
311 sal_Int64 nRecord
= GetValue();
312 if (nRecord
< GetMin() || nRecord
> GetMax())
315 ((NavigationBar
*)GetParent())->PositionDataSource(static_cast<sal_Int32
>(nRecord
));
317 else if (rEvt
.GetKeyCode() == KEY_TAB
)
318 GetParent()->GetParent()->GrabFocus();
320 NumericField::KeyInput(rEvt
);
323 //------------------------------------------------------------------------------
324 void DbGridControl::NavigationBar::AbsolutePos::LoseFocus()
326 NumericField::LoseFocus();
327 sal_Int64 nRecord
= GetValue();
328 if (nRecord
< GetMin() || nRecord
> GetMax())
332 ((NavigationBar
*)GetParent())->PositionDataSource(static_cast<sal_Int32
>(nRecord
));
333 ((NavigationBar
*)GetParent())->InvalidateState(NavigationBar::RECORD_ABSOLUTE
);
337 //------------------------------------------------------------------------------
338 void DbGridControl::NavigationBar::PositionDataSource(sal_Int32 nRecord
)
342 // the MoveToPosition may cause a LoseFocus which would lead to a second MoveToPosition, so protect agains this
344 // 68167 - 13.08.99 - FS
345 m_bPositioning
= sal_True
;
346 ((DbGridControl
*)GetParent())->MoveToPosition(nRecord
- 1);
347 m_bPositioning
= sal_False
;
350 //------------------------------------------------------------------------------
351 DbGridControl::NavigationBar::NavigationBar(Window
* pParent
, WinBits nStyle
)
352 :Control(pParent
, nStyle
)
353 ,m_aRecordText(this, WB_VCENTER
)
354 ,m_aAbsolute(this, WB_VCENTER
)
355 ,m_aRecordOf(this, WB_VCENTER
)
356 ,m_aRecordCount(this, WB_CENTER
| WB_VCENTER
)
357 ,m_aFirstBtn(this, WB_RECTSTYLE
|WB_NOPOINTERFOCUS
)
358 ,m_aPrevBtn(this, WB_REPEAT
|WB_RECTSTYLE
|WB_NOPOINTERFOCUS
)
359 ,m_aNextBtn(this, WB_REPEAT
|WB_RECTSTYLE
|WB_NOPOINTERFOCUS
)
360 ,m_aLastBtn(this, WB_RECTSTYLE
|WB_NOPOINTERFOCUS
)
361 ,m_aNewBtn(this, WB_RECTSTYLE
|WB_NOPOINTERFOCUS
)
364 ,m_bPositioning(sal_False
)
366 m_aFirstBtn
.SetSymbol(SYMBOL_FIRST
);
367 m_aPrevBtn
.SetSymbol(SYMBOL_PREV
);
368 m_aNextBtn
.SetSymbol(SYMBOL_NEXT
);
369 m_aLastBtn
.SetSymbol(SYMBOL_LAST
);
370 m_aNewBtn
.SetModeImage(((DbGridControl
*)pParent
)->GetImage(DbGridControl_Base::NEW
));
372 m_aFirstBtn
.SetHelpId(HID_GRID_TRAVEL_FIRST
);
373 m_aPrevBtn
.SetHelpId(HID_GRID_TRAVEL_PREV
);
374 m_aNextBtn
.SetHelpId(HID_GRID_TRAVEL_NEXT
);
375 m_aLastBtn
.SetHelpId(HID_GRID_TRAVEL_LAST
);
376 m_aNewBtn
.SetHelpId(HID_GRID_TRAVEL_NEW
);
377 m_aAbsolute
.SetHelpId(HID_GRID_TRAVEL_ABSOLUTE
);
378 m_aRecordCount
.SetHelpId(HID_GRID_NUMBEROFRECORDS
);
380 // Handler fuer Buttons einrichten
381 m_aFirstBtn
.SetClickHdl(LINK(this,NavigationBar
,OnClick
));
382 m_aPrevBtn
.SetClickHdl(LINK(this,NavigationBar
,OnClick
));
383 m_aNextBtn
.SetClickHdl(LINK(this,NavigationBar
,OnClick
));
384 m_aLastBtn
.SetClickHdl(LINK(this,NavigationBar
,OnClick
));
385 m_aNewBtn
.SetClickHdl(LINK(this,NavigationBar
,OnClick
));
387 m_aRecordText
.SetText(XubString(SVX_RES(RID_STR_REC_TEXT
)));
388 m_aRecordOf
.SetText(XubString(SVX_RES(RID_STR_REC_FROM_TEXT
)));
389 m_aRecordCount
.SetText('?');
391 m_nDefaultWidth
= ArrangeControls();
393 m_aFirstBtn
.Disable();
394 m_aPrevBtn
.Disable();
395 m_aNextBtn
.Disable();
396 m_aLastBtn
.Disable();
398 m_aRecordText
.Disable();
399 m_aRecordOf
.Disable();
400 m_aRecordCount
.Disable();
401 m_aAbsolute
.Disable();
403 AllSettings aSettings
= m_aNextBtn
.GetSettings();
404 MouseSettings aMouseSettings
= aSettings
.GetMouseSettings();
405 aMouseSettings
.SetButtonRepeat(aMouseSettings
.GetButtonRepeat() / 4);
406 aSettings
.SetMouseSettings(aMouseSettings
);
407 m_aNextBtn
.SetSettings(aSettings
, sal_True
);
408 m_aPrevBtn
.SetSettings(aSettings
, sal_True
);
415 m_aRecordText
.Show();
417 m_aRecordCount
.Show();
423 void SetPosAndSize(Button
& _rButton
,Point
& _rPos
,const Size
& _rSize
)
425 _rButton
.SetPosPixel( _rPos
);
426 _rButton
.SetSizePixel( _rSize
);
427 _rPos
.X() += (sal_uInt16
)_rSize
.Width();
430 //------------------------------------------------------------------------------
431 sal_uInt16
DbGridControl::NavigationBar::ArrangeControls()
433 // Positionierung der Controls
434 // Basisgroessen ermitteln
437 Rectangle
aRect(((DbGridControl
*)GetParent())->GetControlArea());
438 const long nH
= aRect
.GetSize().Height();
439 Size aBorder
= LogicToPixel(Size(3, 3),MAP_APPFONT
);
440 aBorder
= Size(CalcZoom(aBorder
.Width()), CalcZoom(aBorder
.Height()));
442 // Controls Groessen und Positionen setzen
444 XubString aText
= m_aRecordText
.GetText();
445 long nTextWidth
= m_aRecordText
.GetTextWidth(aText
);
446 m_aRecordText
.SetPosPixel(Point(nX
,nY
) );
447 m_aRecordText
.SetSizePixel(Size(nTextWidth
,nH
));
448 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ nTextWidth
+ aBorder
.Width());
450 m_aAbsolute
.SetPosPixel( Point(nX
,nY
));
451 m_aAbsolute
.SetSizePixel( Size(3*nH
,aRect
.GetSize().Height()) ); // Heuristik XXXXXXX
452 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ (3*nH
) + aBorder
.Width());
454 aText
= m_aRecordOf
.GetText();
455 nTextWidth
= m_aRecordOf
.GetTextWidth(aText
);
456 m_aRecordOf
.SetPosPixel(Point(nX
,nY
) );
457 m_aRecordOf
.SetSizePixel(Size(nTextWidth
,nH
));
458 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ nTextWidth
+ aBorder
.Width());
460 nTextWidth
= m_aRecordCount
.GetTextWidth( String::CreateFromAscii("0000000 (00000) *") );
461 m_aRecordCount
.SetPosPixel(Point(nX
,nY
) );
462 m_aRecordCount
.SetSizePixel(Size(nTextWidth
,nH
));
463 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ nTextWidth
+ aBorder
.Width());
465 Point
aButtonPos(nX
,nY
);
466 Size
aButtonSize(nH
,nH
);
467 SetPosAndSize(m_aFirstBtn
, aButtonPos
, aButtonSize
);
468 SetPosAndSize(m_aPrevBtn
, aButtonPos
, aButtonSize
);
469 SetPosAndSize(m_aNextBtn
, aButtonPos
, aButtonSize
);
470 SetPosAndSize(m_aLastBtn
, aButtonPos
, aButtonSize
);
471 SetPosAndSize(m_aNewBtn
, aButtonPos
, aButtonSize
);
473 nX
= sal::static_int_cast
< sal_uInt16
>(
474 aButtonPos
.X() + (sal_uInt16
)(nH
+ aBorder
.Width()));
476 // Ist der Font des Edits groesser als das Feld?
477 Font aOutputFont
= m_aAbsolute
.GetFont();
478 if (aOutputFont
.GetSize().Height() > nH
)
480 Font aApplFont
= OutputDevice::GetDefaultFont(
481 DEFAULTFONT_SANS_UNICODE
,
482 Application::GetSettings().GetUILanguage(),
483 DEFAULTFONT_FLAGS_ONLYONE
,
486 aApplFont
.SetSize( Size( 0, nH
- 2 ) );
487 m_aAbsolute
.SetControlFont( aApplFont
);
489 aApplFont
.SetTransparent( sal_True
);
490 m_aRecordText
.SetControlFont( aApplFont
);
491 m_aRecordOf
.SetControlFont( aApplFont
);
492 m_aRecordCount
.SetControlFont( aApplFont
);
497 //------------------------------------------------------------------------------
498 IMPL_LINK(DbGridControl::NavigationBar
, OnClick
, Button
*, pButton
)
500 DbGridControl
* pParent
= (DbGridControl
*)GetParent();
502 if (pParent
->m_aMasterSlotExecutor
.IsSet())
505 if (pButton
== &m_aFirstBtn
)
506 lResult
= pParent
->m_aMasterSlotExecutor
.Call((void*)RECORD_FIRST
);
507 else if( pButton
== &m_aPrevBtn
)
508 lResult
= pParent
->m_aMasterSlotExecutor
.Call((void*)RECORD_PREV
);
509 else if( pButton
== &m_aNextBtn
)
510 lResult
= pParent
->m_aMasterSlotExecutor
.Call((void*)RECORD_NEXT
);
511 else if( pButton
== &m_aLastBtn
)
512 lResult
= pParent
->m_aMasterSlotExecutor
.Call((void*)RECORD_LAST
);
513 else if( pButton
== &m_aNewBtn
)
514 lResult
= pParent
->m_aMasterSlotExecutor
.Call((void*)RECORD_NEW
);
517 // the link already handled it
521 if (pButton
== &m_aFirstBtn
)
522 pParent
->MoveToFirst();
523 else if( pButton
== &m_aPrevBtn
)
524 pParent
->MoveToPrev();
525 else if( pButton
== &m_aNextBtn
)
526 pParent
->MoveToNext();
527 else if( pButton
== &m_aLastBtn
)
528 pParent
->MoveToLast();
529 else if( pButton
== &m_aNewBtn
)
530 pParent
->AppendNew();
534 //------------------------------------------------------------------------------
535 void DbGridControl::NavigationBar::InvalidateAll(sal_Int32 nCurrentPos
, sal_Bool bAll
)
537 if (m_nCurrentPos
!= nCurrentPos
|| nCurrentPos
< 0 || bAll
)
539 DbGridControl
* pParent
= (DbGridControl
*)GetParent();
541 sal_Int32 nAdjustedRowCount
= pParent
->GetRowCount() - ((pParent
->GetOptions() & DbGridControl::OPT_INSERT
) ? 2 : 1);
543 // Wann mu� alles invalidiert werden
544 bAll
= bAll
|| m_nCurrentPos
<= 0;
545 bAll
= bAll
|| nCurrentPos
<= 0;
546 bAll
= bAll
|| m_nCurrentPos
>= nAdjustedRowCount
;
547 bAll
= bAll
|| nCurrentPos
>= nAdjustedRowCount
;
551 m_nCurrentPos
= nCurrentPos
;
553 while (ControlMap
[i
])
554 SetState(ControlMap
[i
++]);
556 else // befindet sich in der Mitte
558 m_nCurrentPos
= nCurrentPos
;
559 SetState(NavigationBar::RECORD_COUNT
);
560 SetState(NavigationBar::RECORD_ABSOLUTE
);
565 //------------------------------------------------------------------------------
566 sal_Bool
DbGridControl::NavigationBar::GetState(sal_uInt16 nWhich
) const
568 DbGridControl
* pParent
= (DbGridControl
*)GetParent();
570 if (!pParent
->IsOpen() || pParent
->IsDesignMode() || !pParent
->IsEnabled()
571 || pParent
->IsFilterMode() )
575 // check if we have a master state provider
576 if (pParent
->m_aMasterStateProvider
.IsSet())
578 long nState
= pParent
->m_aMasterStateProvider
.Call(reinterpret_cast< void* >( nWhich
) );
583 sal_Bool bAvailable
= sal_True
;
587 case NavigationBar::RECORD_FIRST
:
588 case NavigationBar::RECORD_PREV
:
589 bAvailable
= m_nCurrentPos
> 0;
591 case NavigationBar::RECORD_NEXT
:
592 if(pParent
->m_bRecordCountFinal
)
594 bAvailable
= m_nCurrentPos
< pParent
->GetRowCount() - 1;
595 if (!bAvailable
&& pParent
->GetOptions() & DbGridControl::OPT_INSERT
)
596 bAvailable
= (m_nCurrentPos
== pParent
->GetRowCount() - 2) && pParent
->IsModified();
599 case NavigationBar::RECORD_LAST
:
600 if(pParent
->m_bRecordCountFinal
)
602 if (pParent
->GetOptions() & DbGridControl::OPT_INSERT
)
603 bAvailable
= pParent
->IsCurrentAppending() ? pParent
->GetRowCount() > 1 :
604 m_nCurrentPos
!= pParent
->GetRowCount() - 2;
606 bAvailable
= m_nCurrentPos
!= pParent
->GetRowCount() - 1;
609 case NavigationBar::RECORD_NEW
:
610 bAvailable
= (pParent
->GetOptions() & DbGridControl::OPT_INSERT
) && pParent
->GetRowCount() && m_nCurrentPos
< pParent
->GetRowCount() - 1;
612 case NavigationBar::RECORD_ABSOLUTE
:
613 bAvailable
= pParent
->GetRowCount() > 0;
620 //------------------------------------------------------------------------------
621 void DbGridControl::NavigationBar::SetState(sal_uInt16 nWhich
)
623 sal_Bool bAvailable
= GetState(nWhich
);
624 DbGridControl
* pParent
= (DbGridControl
*)GetParent();
628 case NavigationBar::RECORD_FIRST
:
631 case NavigationBar::RECORD_PREV
:
634 case NavigationBar::RECORD_NEXT
:
637 case NavigationBar::RECORD_LAST
:
640 case NavigationBar::RECORD_NEW
:
643 case NavigationBar::RECORD_ABSOLUTE
:
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(String());
662 case NavigationBar::RECORD_TEXT
:
663 pWnd
= &m_aRecordText
;
665 case NavigationBar::RECORD_OF
:
668 case NavigationBar::RECORD_COUNT
:
670 pWnd
= &m_aRecordCount
;
674 if (pParent
->GetOptions() & DbGridControl::OPT_INSERT
)
676 if (pParent
->IsCurrentAppending() && !pParent
->IsModified())
677 aText
= String::CreateFromInt32(pParent
->GetRowCount());
679 aText
= String::CreateFromInt32(pParent
->GetRowCount() - 1);
682 aText
= String::CreateFromInt32(pParent
->GetRowCount());
683 if(!pParent
->m_bRecordCountFinal
)
684 aText
+= String::CreateFromAscii(" *");
689 // add the number of selected rows, if applicable
690 if (pParent
->GetSelectRowCount())
692 String
aExtendedInfo(aText
);
693 aExtendedInfo
.AppendAscii(" (");
694 aExtendedInfo
+= String::CreateFromInt32(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.
711 pWnd
->Enable(bAvailable
);
714 //------------------------------------------------------------------------------
715 void DbGridControl::NavigationBar::Resize()
721 //------------------------------------------------------------------------------
722 void DbGridControl::NavigationBar::Paint(const Rectangle
& rRect
)
724 Control::Paint(rRect
);
725 Point aAbsolutePos
= m_aAbsolute
.GetPosPixel();
726 Size aAbsoluteSize
= m_aAbsolute
.GetSizePixel();
728 DrawLine(Point(aAbsolutePos
.X() - 1, 0 ),
729 Point(aAbsolutePos
.X() - 1, aAbsolutePos
.Y() + aAbsoluteSize
.Height()));
731 DrawLine(Point(aAbsolutePos
.X() + aAbsoluteSize
.Width() + 1, 0 ),
732 Point(aAbsolutePos
.X() + aAbsoluteSize
.Width() + 1, aAbsolutePos
.Y() + aAbsoluteSize
.Height()));
735 //------------------------------------------------------------------------------
736 void DbGridControl::NavigationBar::StateChanged( StateChangedType nType
)
738 Control::StateChanged( nType
);
740 Window
* pWindows
[] = { &m_aRecordText
,
753 case STATE_CHANGE_MIRRORING
:
755 BOOL bIsRTLEnabled
= IsRTLEnabled();
756 for ( size_t i
=0; i
< sizeof( pWindows
) / sizeof( pWindows
[0] ); ++i
)
757 pWindows
[i
]->EnableRTL( bIsRTLEnabled
);
761 case STATE_CHANGE_ZOOM
:
763 Fraction aZoom
= GetZoom();
765 // not all of these controls need to know the new zoom, but to be sure ...
766 Font
aFont( IsControlFont() ? GetControlFont() : GetPointFont());
767 for (size_t i
=0; i
< sizeof(pWindows
)/sizeof(pWindows
[0]); ++i
)
769 pWindows
[i
]->SetZoom(aZoom
);
770 pWindows
[i
]->SetZoomedPointFont(aFont
);
772 // rearrange the controls
773 m_nDefaultWidth
= ArrangeControls();
779 //------------------------------------------------------------------------------
780 DbGridRow::DbGridRow(CursorWrapper
* pCur
, sal_Bool bPaintCursor
)
784 if (pCur
&& pCur
->Is())
786 Reference
< XIndexAccess
> xColumns(pCur
->getColumns(), UNO_QUERY
);
788 for (sal_Int32 i
= 0; i
< xColumns
->getCount(); ++i
)
790 Reference
< XPropertySet
> xColSet
;
791 ::cppu::extractInterface(xColSet
, xColumns
->getByIndex(i
));
792 pColumn
= new DataColumn(xColSet
);
793 m_aVariants
.Insert(pColumn
, LIST_APPEND
);
796 if (pCur
->rowDeleted())
797 m_eStatus
= GRS_DELETED
;
801 m_eStatus
= (pCur
->isAfterLast() || pCur
->isBeforeFirst()) ? GRS_INVALID
: GRS_CLEAN
;
804 Reference
< XPropertySet
> xSet
= pCur
->getPropertySet();
807 m_bIsNew
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISNEW
));
808 if (!m_bIsNew
&& (pCur
->isAfterLast() || pCur
->isBeforeFirst()))
809 m_eStatus
= GRS_INVALID
;
810 else if (::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISMODIFIED
)))
811 m_eStatus
= GRS_MODIFIED
;
813 m_eStatus
= GRS_CLEAN
;
816 m_eStatus
= GRS_INVALID
;
819 if (!m_bIsNew
&& IsValid())
820 m_aBookmark
= pCur
->getBookmark();
825 m_eStatus
= GRS_INVALID
;
828 //------------------------------------------------------------------------------
829 DbGridRow::~DbGridRow()
831 sal_uInt32 nCount
= m_aVariants
.Count();
832 for (sal_uInt32 i
= 0; i
< nCount
; i
++)
833 delete m_aVariants
.GetObject(i
);
836 //------------------------------------------------------------------------------
837 void DbGridRow::SetState(CursorWrapper
* pCur
, sal_Bool bPaintCursor
)
839 if (pCur
&& pCur
->Is())
841 if (pCur
->rowDeleted())
843 m_eStatus
= GRS_DELETED
;
844 m_bIsNew
= sal_False
;
848 m_eStatus
= GRS_CLEAN
;
851 Reference
< XPropertySet
> xSet
= pCur
->getPropertySet();
852 DBG_ASSERT(xSet
.is(), "DbGridRow::SetState : invalid cursor !");
854 if (::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISMODIFIED
)))
855 m_eStatus
= GRS_MODIFIED
;
856 m_bIsNew
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISNEW
));
859 m_bIsNew
= sal_False
;
864 if (!m_bIsNew
&& IsValid())
865 m_aBookmark
= pCur
->getBookmark();
871 OSL_ENSURE(0,"SQLException catched while getting the bookmark");
873 m_eStatus
= GRS_INVALID
;
874 m_bIsNew
= sal_False
;
880 m_eStatus
= GRS_INVALID
;
881 m_bIsNew
= sal_False
;
885 DBG_NAME(DbGridControl
);
886 //------------------------------------------------------------------------------
887 DbGridControl::DbGridControl(
888 Reference
< XMultiServiceFactory
> _rxFactory
,
891 :DbGridControl_Base(pParent
, EBBF_NONE
, nBits
, DEFAULT_BROWSE_MODE
)
892 ,m_xServiceFactory(_rxFactory
)
894 ,m_nAsynAdjustEvent(0)
895 ,m_pDataSourcePropMultiplexer(NULL
)
896 ,m_pDataSourcePropListener(NULL
)
897 ,m_pFieldListeners(NULL
)
898 ,m_pCursorDisposeListener(NULL
)
899 ,m_pGridListener(NULL
)
904 ,m_aNullDate(OTypeConversionClient().getStandardDate())
905 ,m_nMode(DEFAULT_BROWSE_MODE
)
908 ,m_nOptions(OPT_READONLY
)
909 ,m_nOptionMask(OPT_INSERT
| OPT_UPDATE
| OPT_DELETE
)
910 ,m_nLastColId((USHORT
)-1)
912 ,m_bDesignMode(sal_False
)
913 ,m_bRecordCountFinal(sal_False
)
914 ,m_bMultiSelection(sal_True
)
915 ,m_bNavigationBar(sal_True
)
916 ,m_bSynchDisplay(sal_True
)
917 ,m_bForceROController(sal_False
)
919 ,m_bFilterMode(sal_False
)
920 ,m_bWantDestruction(sal_False
)
921 ,m_bInAdjustDataSource(sal_False
)
922 ,m_bPendingAdjustRows(sal_False
)
923 ,m_bHideScrollbars( sal_False
)
924 ,m_bUpdating(sal_False
)
926 DBG_CTOR(DbGridControl
,NULL
);
928 String
sName(SVX_RES(RID_STR_NAVIGATIONBAR
));
929 m_aBar
.SetAccessibleName(sName
);
931 ImplInitWindow( InitAll
);
934 //------------------------------------------------------------------------------
935 void DbGridControl::InsertHandleColumn()
937 // Handle Column einfuegen
938 // Da die BrowseBox ohne handleColums Paintprobleme hat
939 // wird diese versteckt
941 BrowseBox::InsertHandleColumn(GetDefaultColumnWidth(String()));
943 BrowseBox::InsertHandleColumn(0);
946 //------------------------------------------------------------------------------
947 void DbGridControl::Init()
949 BrowserHeader
* pNewHeader
= CreateHeaderBar(this);
950 pHeader
->SetMouseTransparent(sal_False
);
952 SetHeaderBar(pNewHeader
);
954 SetCursorColor(Color(0xFF, 0, 0));
956 InsertHandleColumn();
959 //------------------------------------------------------------------------------
960 DbGridControl::~DbGridControl()
965 m_bWantDestruction
= sal_True
;
966 osl::MutexGuard
aGuard(m_aDestructionSafety
);
967 if (m_pFieldListeners
)
968 DisconnectFromFields();
969 if (m_pCursorDisposeListener
)
971 delete m_pCursorDisposeListener
;
972 m_pCursorDisposeListener
= NULL
;
977 Application::RemoveUserEvent(m_nDeleteEvent
);
979 if (m_pDataSourcePropMultiplexer
)
981 m_pDataSourcePropMultiplexer
->dispose();
982 m_pDataSourcePropMultiplexer
->release(); // this should delete the multiplexer
983 delete m_pDataSourcePropListener
;
984 m_pDataSourcePropMultiplexer
= NULL
;
985 m_pDataSourcePropListener
= NULL
;
988 delete m_pDataCursor
;
989 delete m_pSeekCursor
;
991 DBG_DTOR(DbGridControl
,NULL
);
994 //------------------------------------------------------------------------------
995 void DbGridControl::StateChanged( StateChangedType nType
)
997 DbGridControl_Base::StateChanged( nType
);
1001 case STATE_CHANGE_MIRRORING
:
1002 ImplInitWindow( InitWritingMode
);
1006 case STATE_CHANGE_ZOOM
:
1008 ImplInitWindow( InitFont
);
1010 // and give it a chance to rearrange
1011 Point aPoint
= GetControlArea().TopLeft();
1012 sal_uInt16 nX
= (sal_uInt16
)aPoint
.X();
1013 ArrangeControls(nX
, (sal_uInt16
)aPoint
.Y());
1014 ReserveControlArea((sal_uInt16
)nX
);
1017 case STATE_CHANGE_CONTROLFONT
:
1018 ImplInitWindow( InitFont
);
1021 case STATE_CHANGE_CONTROLFOREGROUND
:
1022 ImplInitWindow( InitForeground
);
1025 case STATE_CHANGE_CONTROLBACKGROUND
:
1026 ImplInitWindow( InitBackground
);
1032 //------------------------------------------------------------------------------
1033 void DbGridControl::DataChanged( const DataChangedEvent
& rDCEvt
)
1035 DbGridControl_Base::DataChanged( rDCEvt
);
1036 if ( (rDCEvt
.GetType() == DATACHANGED_SETTINGS
) &&
1037 (rDCEvt
.GetFlags() & SETTINGS_STYLE
) )
1039 ImplInitWindow( InitAll
);
1044 //------------------------------------------------------------------------------
1045 void DbGridControl::Select()
1047 DbGridControl_Base::Select();
1049 // as the selected rows may have changed, udate the according display in our navigation bar
1050 m_aBar
.InvalidateState(NavigationBar::RECORD_COUNT
);
1052 if (m_pGridListener
)
1053 m_pGridListener
->selectionChanged();
1056 //------------------------------------------------------------------------------
1057 void DbGridControl::ImplInitWindow( const InitWindowFacet _eInitWhat
)
1059 for ( sal_uInt32 i
= 0; i
< m_aColumns
.Count(); ++i
)
1061 DbGridColumn
* pCol
= m_aColumns
.GetObject(i
);
1063 pCol
->ImplInitWindow( GetDataWindow(), _eInitWhat
);
1066 if ( ( _eInitWhat
& InitWritingMode
) != 0 )
1068 if ( m_bNavigationBar
)
1070 m_aBar
.EnableRTL( IsRTLEnabled() );
1074 if ( ( _eInitWhat
& InitFont
) != 0 )
1076 if ( m_bNavigationBar
)
1078 m_aBar
.SetZoom( GetZoom() );
1080 Font aFont
= m_aBar
.GetSettings().GetStyleSettings().GetFieldFont();
1081 if ( IsControlFont() )
1083 m_aBar
.SetControlFont( GetControlFont() );
1084 aFont
.Merge( GetControlFont() );
1087 m_aBar
.SetControlFont();
1089 m_aBar
.SetZoomedPointFont( aFont
);
1093 if ( ( _eInitWhat
& InitBackground
) != 0 )
1095 if (IsControlBackground())
1097 GetDataWindow().SetBackground(GetControlBackground());
1098 GetDataWindow().SetControlBackground(GetControlBackground());
1099 GetDataWindow().SetFillColor(GetControlBackground());
1103 GetDataWindow().SetControlBackground();
1104 GetDataWindow().SetFillColor(GetFillColor());
1109 //------------------------------------------------------------------------------
1110 void DbGridControl::RemoveRows(sal_Bool bNewCursor
)
1112 // Hat sich der DatenCursor verandert ?
1115 DELETEZ(m_pSeekCursor
);
1116 m_xPaintRow
= m_xDataRow
= m_xEmptyRow
= m_xCurrentRow
= m_xSeekRow
= NULL
;
1117 m_nCurrentPos
= m_nSeekPos
= -1;
1118 m_nOptions
= OPT_READONLY
;
1120 RowRemoved(0, GetRowCount(), sal_False
);
1129 //------------------------------------------------------------------------------
1130 void DbGridControl::RemoveRows()
1132 // we're going to remove all columns and all row, so deactivate the current cell
1136 // alle Columns deinitialisieren
1137 // existieren Spalten, dann alle Controller freigeben
1138 for (sal_uInt32 i
= 0; i
< m_aColumns
.Count(); i
++)
1139 m_aColumns
.GetObject(i
)->Clear();
1141 DELETEZ(m_pSeekCursor
);
1142 DELETEZ(m_pDataCursor
);
1144 m_xPaintRow
= m_xDataRow
= m_xEmptyRow
= m_xCurrentRow
= m_xSeekRow
= NULL
;
1145 m_nCurrentPos
= m_nSeekPos
= m_nTotalCount
= -1;
1146 m_nOptions
= OPT_READONLY
;
1148 // Anzahl Saetze im Browser auf 0 zuruecksetzen
1149 DbGridControl_Base::RemoveRows();
1150 m_aBar
.InvalidateAll(m_nCurrentPos
, sal_True
);
1153 //------------------------------------------------------------------------------
1154 void DbGridControl::ArrangeControls(sal_uInt16
& nX
, sal_uInt16 nY
)
1156 // Positionierung der Controls
1157 if (m_bNavigationBar
)
1159 nX
= m_aBar
.GetDefaultWidth();
1160 Rectangle
aRect(GetControlArea());
1161 m_aBar
.SetPosSizePixel(Point(0,nY
+ 1), Size(nX
, aRect
.GetSize().Height() - 1));
1165 //------------------------------------------------------------------------------
1166 void DbGridControl::EnableHandle(sal_Bool bEnable
)
1168 if (m_bHandle
== bEnable
)
1171 // HandleColumn wird nur ausgeblendet,
1172 // da es sonst etliche Probleme mit dem Zeichnen gibt
1174 m_bHandle
= bEnable
;
1175 InsertHandleColumn();
1178 //------------------------------------------------------------------------------
1181 bool adjustModeForScrollbars( BrowserMode
& _rMode
, sal_Bool _bNavigationBar
, sal_Bool _bHideScrollbars
)
1183 BrowserMode nOldMode
= _rMode
;
1185 if ( !_bNavigationBar
)
1187 _rMode
&= ~BROWSER_AUTO_HSCROLL
;
1190 if ( _bHideScrollbars
)
1192 _rMode
|= ( BROWSER_NO_HSCROLL
| BROWSER_NO_VSCROLL
);
1193 _rMode
&= ~( BROWSER_AUTO_HSCROLL
| BROWSER_AUTO_VSCROLL
);
1197 _rMode
|= ( BROWSER_AUTO_HSCROLL
| BROWSER_AUTO_VSCROLL
);
1198 _rMode
&= ~( BROWSER_NO_HSCROLL
| BROWSER_NO_VSCROLL
);
1201 // note: if we have a navigation bar, we always have a AUTO_HSCROLL. In particular,
1202 // _bHideScrollbars is ignored then
1203 if ( _bNavigationBar
)
1205 _rMode
|= BROWSER_AUTO_HSCROLL
;
1206 _rMode
&= ~BROWSER_NO_HSCROLL
;
1209 return nOldMode
!= _rMode
;
1213 //------------------------------------------------------------------------------
1214 void DbGridControl::EnableNavigationBar(sal_Bool bEnable
)
1216 if (m_bNavigationBar
== bEnable
)
1219 m_bNavigationBar
= bEnable
;
1225 m_aBar
.InvalidateAll(m_nCurrentPos
, sal_True
);
1227 if ( adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
) )
1230 // liefert die Groe�e der Reserved ControlArea
1231 Point aPoint
= GetControlArea().TopLeft();
1232 sal_uInt16 nX
= (sal_uInt16
)aPoint
.X();
1234 ArrangeControls(nX
, (sal_uInt16
)aPoint
.Y());
1235 ReserveControlArea((sal_uInt16
)nX
);
1242 if ( adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
) )
1245 ReserveControlArea();
1249 //------------------------------------------------------------------------------
1250 sal_uInt16
DbGridControl::SetOptions(sal_uInt16 nOpt
)
1252 DBG_ASSERT(!m_xCurrentRow
|| !m_xCurrentRow
->IsModified(),
1253 "DbGridControl::SetOptions : please do not call when editing a record (things are much easier this way ;) !");
1255 // for the next setDataSource (which is triggered by a refresh, for instance)
1256 m_nOptionMask
= nOpt
;
1258 // normalize the new options
1259 Reference
< XPropertySet
> xDataSourceSet
= m_pDataCursor
->getPropertySet();
1260 if (xDataSourceSet
.is())
1262 // feststellen welche Updatem�glichkeiten bestehen
1263 sal_Int32 nPrivileges
= 0;
1264 xDataSourceSet
->getPropertyValue(FM_PROP_PRIVILEGES
) >>= nPrivileges
;
1265 if ((nPrivileges
& Privilege::INSERT
) == 0)
1266 nOpt
&= ~OPT_INSERT
;
1267 if ((nPrivileges
& Privilege::UPDATE
) == 0)
1268 nOpt
&= ~OPT_UPDATE
;
1269 if ((nPrivileges
& Privilege::DELETE
) == 0)
1270 nOpt
&= ~OPT_DELETE
;
1273 nOpt
= OPT_READONLY
;
1275 // need to do something after that ?
1276 if (nOpt
== m_nOptions
)
1279 // the 'update' option only affects our BrowserMode (with or w/o focus rect)
1280 BrowserMode nNewMode
= m_nMode
;
1281 if ((m_nMode
& BROWSER_CURSOR_WO_FOCUS
) == 0)
1283 if (nOpt
& OPT_UPDATE
)
1284 nNewMode
|= BROWSER_HIDECURSOR
;
1286 nNewMode
&= ~BROWSER_HIDECURSOR
;
1289 nNewMode
&= ~BROWSER_HIDECURSOR
;
1290 // should not be neccessary if EnablePermanentCursor is used to change the cursor behaviour, but to be sure ...
1292 if (nNewMode
!= m_nMode
)
1298 // _after_ setting the mode because this results in an ActivateCell
1301 sal_Bool bInsertChanged
= (nOpt
& OPT_INSERT
) != (m_nOptions
& OPT_INSERT
);
1303 // we need to set this before the code below because it indirectly uses m_nOptions
1305 // the 'insert' option affects our empty row
1308 if (m_nOptions
& OPT_INSERT
)
1309 { // the insert option is to be set
1310 m_xEmptyRow
= new DbGridRow();
1311 RowInserted(GetRowCount(), 1, sal_True
);
1314 { // the insert option is to be reset
1316 if ((GetCurRow() == GetRowCount() - 1) && (GetCurRow() > 0))
1317 GoToRowColumnId(GetCurRow() - 1, GetCurColumnId());
1318 RowRemoved(GetRowCount(), 1, sal_True
);
1322 // the 'delete' options has no immediate consequences
1329 //------------------------------------------------------------------------------
1330 void DbGridControl::ForceHideScrollbars( sal_Bool _bForce
)
1332 if ( m_bHideScrollbars
== _bForce
)
1335 m_bHideScrollbars
= _bForce
;
1337 if ( adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
) )
1341 //------------------------------------------------------------------------------
1342 sal_Bool
DbGridControl::IsForceHideScrollbars() const
1344 return m_bHideScrollbars
;
1347 //------------------------------------------------------------------------------
1348 void DbGridControl::EnablePermanentCursor(sal_Bool bEnable
)
1350 if (IsPermanentCursorEnabled() == bEnable
)
1355 m_nMode
&= ~BROWSER_HIDECURSOR
; // without this BROWSER_CURSOR_WO_FOCUS won't have any affect
1356 m_nMode
|= BROWSER_CURSOR_WO_FOCUS
;
1360 if (m_nOptions
& OPT_UPDATE
)
1361 m_nMode
|= BROWSER_HIDECURSOR
; // no cursor at all
1363 m_nMode
&= ~BROWSER_HIDECURSOR
; // at least the "non-permanent" cursor
1365 m_nMode
&= ~BROWSER_CURSOR_WO_FOCUS
;
1369 sal_Bool bWasEditing
= IsEditing();
1375 //------------------------------------------------------------------------------
1376 sal_Bool
DbGridControl::IsPermanentCursorEnabled() const
1378 return ((m_nMode
& BROWSER_CURSOR_WO_FOCUS
) != 0) && ((m_nMode
& BROWSER_HIDECURSOR
) == 0);
1381 //------------------------------------------------------------------------------
1382 void DbGridControl::refreshController(sal_uInt16 _nColId
, GrantCellControlAccess
/*_aAccess*/)
1384 if ((GetCurColumnId() == _nColId
) && IsEditing())
1385 { // the controller which is currently active needs to be refreshed
1391 //------------------------------------------------------------------------------
1392 void DbGridControl::SetMultiSelection(sal_Bool bMulti
)
1394 m_bMultiSelection
= bMulti
;
1395 if (m_bMultiSelection
)
1396 m_nMode
|= BROWSER_MULTISELECTION
;
1398 m_nMode
&= ~BROWSER_MULTISELECTION
;
1403 //------------------------------------------------------------------------------
1404 void DbGridControl::setDataSource(const Reference
< XRowSet
>& _xCursor
, sal_uInt16 nOpts
)
1406 if (!_xCursor
.is() && !m_pDataCursor
)
1409 if (m_pDataSourcePropMultiplexer
)
1411 m_pDataSourcePropMultiplexer
->dispose();
1412 m_pDataSourcePropMultiplexer
->release(); // this should delete the multiplexer
1413 delete m_pDataSourcePropListener
;
1414 m_pDataSourcePropMultiplexer
= NULL
;
1415 m_pDataSourcePropListener
= NULL
;
1418 // is the new cursor valid ?
1419 // the cursor is only valid if it contains some columns
1420 // if there is no cursor or the cursor is not valid we have to clean up an leave
1421 if (!_xCursor
.is() || !Reference
< XColumnsSupplier
> (_xCursor
, UNO_QUERY
)->getColumns()->hasElements())
1427 // Hat sich der DatenCursor verandert ?
1428 sal_uInt16 nCurPos
= GetColumnPos(GetCurColumnId());
1430 SetUpdateMode(sal_False
);
1432 DisconnectFromFields();
1434 DELETEZ(m_pCursorDisposeListener
);
1437 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
1438 if (m_nAsynAdjustEvent
)
1440 // the adjust was thought to work with the old cursor which we don't have anymore
1441 RemoveUserEvent(m_nAsynAdjustEvent
);
1442 m_nAsynAdjustEvent
= 0;
1446 // get a new formatter and data cursor
1447 m_xFormatter
= NULL
;
1448 OStaticDataAccessTools aStaticTools
;
1449 Reference
< ::com::sun::star::util::XNumberFormatsSupplier
> xSupplier
= aStaticTools
.getNumberFormats(aStaticTools
.getRowSetConnection(_xCursor
), sal_True
);
1450 if (xSupplier
.is() && m_xServiceFactory
.is())
1452 m_xFormatter
= Reference
< ::com::sun::star::util::XNumberFormatter
>(
1453 m_xServiceFactory
->createInstance(FM_NUMBER_FORMATTER
),
1455 if (m_xFormatter
.is())
1457 m_xFormatter
->attachNumberFormatsSupplier(xSupplier
);
1459 // retrieve the datebase of the Numberformatter
1462 xSupplier
->getNumberFormatSettings()->getPropertyValue(rtl::OUString::createFromAscii("NullDate")) >>= m_aNullDate
;
1470 m_pDataCursor
= new CursorWrapper(_xCursor
);
1472 // now create a cursor for painting rows
1473 // we need that cursor only if we are not in insert only mode
1474 Reference
< XResultSet
> xClone
;
1475 Reference
< XResultSetAccess
> xAccess( _xCursor
, UNO_QUERY
);
1478 xClone
= xAccess
.is() ? xAccess
->createResultSet() : Reference
< XResultSet
> ();
1484 m_pSeekCursor
= new CursorWrapper(xClone
);
1486 // property listening on the data source
1487 // (Normally one class would be sufficient : the multiplexer which could forward the property change to us.
1488 // But for that we would have been derived from ::comphelper::OPropertyChangeListener, which isn't exported.
1489 // So we introduce a second class, which is a ::comphelper::OPropertyChangeListener (in the implementation file we know this class)
1490 // and forwards the property changes to a our special method "DataSourcePropertyChanged".)
1493 m_pDataSourcePropListener
= new FmXGridSourcePropListener(this);
1494 m_pDataSourcePropMultiplexer
= new ::comphelper::OPropertyChangeMultiplexer(m_pDataSourcePropListener
, m_pDataCursor
->getPropertySet() );
1495 m_pDataSourcePropMultiplexer
->acquire();
1496 m_pDataSourcePropMultiplexer
->addProperty(FM_PROP_ISMODIFIED
);
1497 m_pDataSourcePropMultiplexer
->addProperty(FM_PROP_ISNEW
);
1500 BrowserMode nOldMode
= m_nMode
;
1505 Reference
< XPropertySet
> xSet(_xCursor
, UNO_QUERY
);
1508 // feststellen welche Updatem�glichkeiten bestehen
1509 sal_Int32 nConcurrency
= ResultSetConcurrency::READ_ONLY
;
1510 xSet
->getPropertyValue(FM_PROP_RESULTSET_CONCURRENCY
) >>= nConcurrency
;
1512 if ( ResultSetConcurrency::UPDATABLE
== nConcurrency
)
1514 sal_Int32 nPrivileges
= 0;
1515 xSet
->getPropertyValue(FM_PROP_PRIVILEGES
) >>= nPrivileges
;
1517 // Insert Option should be set if insert only otherwise you won't see any rows
1518 // and no insertion is possible
1519 if ((m_nOptionMask
& OPT_INSERT
) && ((nPrivileges
& Privilege::INSERT
) == Privilege::INSERT
) && (nOpts
& OPT_INSERT
))
1520 m_nOptions
|= OPT_INSERT
;
1521 if ((m_nOptionMask
& OPT_UPDATE
) && ((nPrivileges
& Privilege::UPDATE
) == Privilege::UPDATE
) && (nOpts
& OPT_UPDATE
))
1522 m_nOptions
|= OPT_UPDATE
;
1523 if ((m_nOptionMask
& OPT_DELETE
) && ((nPrivileges
& Privilege::DELETE
) == Privilege::DELETE
) && (nOpts
& OPT_DELETE
))
1524 m_nOptions
|= OPT_DELETE
;
1528 catch( const Exception
& )
1530 DBG_UNHANDLED_EXCEPTION();
1533 sal_Bool bPermanentCursor
= IsPermanentCursorEnabled();
1534 m_nMode
= DEFAULT_BROWSE_MODE
;
1536 if ( bPermanentCursor
)
1538 m_nMode
|= BROWSER_CURSOR_WO_FOCUS
;
1539 m_nMode
&= ~BROWSER_HIDECURSOR
;
1543 // Duerfen Updates gemacht werden, kein Focus-RechtEck
1544 if ( m_nOptions
& OPT_UPDATE
)
1545 m_nMode
|= BROWSER_HIDECURSOR
;
1548 if ( m_bMultiSelection
)
1549 m_nMode
|= BROWSER_MULTISELECTION
;
1551 m_nMode
&= ~BROWSER_MULTISELECTION
;
1553 adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
);
1555 Reference
< XColumnsSupplier
> xSupplyColumns(_xCursor
, UNO_QUERY
);
1556 if (xSupplyColumns
.is())
1557 InitColumnsByFields(Reference
< XIndexAccess
> (xSupplyColumns
->getColumns(), UNO_QUERY
));
1562 sal_uInt32
nRecordCount(0);
1566 Reference
< XPropertySet
> xSet
= m_pDataCursor
->getPropertySet();
1567 xSet
->getPropertyValue(FM_PROP_ROWCOUNT
) >>= nRecordCount
;
1568 m_bRecordCountFinal
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ROWCOUNTFINAL
));
1570 // insert the currently known rows
1571 // and one row if we are able to insert rows
1572 if (m_nOptions
& OPT_INSERT
)
1574 // insert the empty row for insertion
1575 m_xEmptyRow
= new DbGridRow();
1580 m_xPaintRow
= m_xSeekRow
= new DbGridRow(m_pSeekCursor
, sal_True
);
1581 m_xDataRow
= new DbGridRow(m_pDataCursor
, sal_False
);
1582 RowInserted(0, nRecordCount
, sal_False
);
1584 if (m_xSeekRow
->IsValid())
1587 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
1589 catch( const Exception
& )
1591 DBG_UNHANDLED_EXCEPTION();
1597 // no rows so we don't need a seekcursor
1598 DELETEZ(m_pSeekCursor
);
1602 // Zur alten Spalte gehen
1603 if (!nCurPos
|| nCurPos
>= ColCount())
1606 // there are rows so go to the selected current column
1608 GoToRowColumnId(0, GetColumnId(nCurPos
));
1609 // else stop the editing if neccessary
1610 else if (IsEditing())
1613 // now reset the mode
1614 if (m_nMode
!= nOldMode
)
1617 // beim Resizen wird RecalcRows gerufen
1618 if (!IsResizing() && GetRowCount())
1619 RecalcRows(GetTopRow(), GetVisibleRows(), sal_True
);
1621 m_aBar
.InvalidateAll(m_nCurrentPos
, sal_True
);
1622 SetUpdateMode(sal_True
);
1624 // start listening on the seek cursor
1626 m_pCursorDisposeListener
= new DisposeListenerGridBridge(*this, Reference
< XComponent
> ((Reference
< XInterface
>)*m_pSeekCursor
, UNO_QUERY
), 0);
1629 //------------------------------------------------------------------------------
1630 void DbGridControl::RemoveColumns()
1635 for (sal_uInt32 i
= 0; i
< m_aColumns
.Count(); i
++)
1636 delete m_aColumns
.GetObject(i
);
1639 DbGridControl_Base::RemoveColumns();
1642 //------------------------------------------------------------------------------
1643 DbGridColumn
* DbGridControl::CreateColumn(sal_uInt16 nId
) const
1645 return new DbGridColumn(nId
, *(DbGridControl
*)this);
1648 //------------------------------------------------------------------------------
1649 sal_uInt16
DbGridControl::AppendColumn(const XubString
& rName
, sal_uInt16 nWidth
, sal_uInt16 nModelPos
, sal_uInt16 nId
)
1651 DBG_ASSERT(nId
== (sal_uInt16
)-1, "DbGridControl::AppendColumn : I want to set the ID myself ...");
1652 sal_uInt16 nRealPos
= nModelPos
;
1653 if (nModelPos
!= HEADERBAR_APPEND
)
1655 // calc the view pos. we can't use our converting functions because the new column
1656 // has no VCL-representation, yet.
1657 sal_Int16 nViewPos
= nModelPos
;
1660 if (m_aColumns
.GetObject(nModelPos
)->IsHidden())
1663 // restore nModelPos, we need it later
1664 nModelPos
= nRealPos
;
1665 // the position the base class gets is the view pos + 1 (because of the handle column)
1666 nRealPos
= nViewPos
+ 1;
1669 // calculate the new id
1670 for (nId
=1; (GetModelColumnPos(nId
) != GRID_COLUMN_NOT_FOUND
) && (nId
<=m_aColumns
.Count()); ++nId
)
1672 DBG_ASSERT(GetViewColumnPos(nId
) == (sal_uInt16
)-1, "DbGridControl::AppendColumn : inconsistent internal state !");
1673 // my column's models say "there is no column with id nId", but the view (the base class) says "there is a column ..."
1675 DbGridControl_Base::AppendColumn(rName
, nWidth
, nRealPos
, nId
);
1676 if (nModelPos
== HEADERBAR_APPEND
)
1677 m_aColumns
.Insert(CreateColumn(nId
), LIST_APPEND
);
1679 m_aColumns
.Insert(CreateColumn(nId
), nModelPos
);
1684 //------------------------------------------------------------------------------
1685 void DbGridControl::RemoveColumn(sal_uInt16 nId
)
1687 sal_Int16 nIndex
= GetModelColumnPos(nId
);
1688 DbGridControl_Base::RemoveColumn(nId
);
1689 delete m_aColumns
.Remove(nIndex
);
1692 //------------------------------------------------------------------------------
1693 void DbGridControl::ColumnMoved(sal_uInt16 nId
)
1695 DbGridControl_Base::ColumnMoved(nId
);
1697 // remove the col from the model
1698 sal_Int16 nOldModelPos
= GetModelColumnPos(nId
);
1700 DbGridColumn
* pCol
= m_aColumns
.GetObject((sal_uInt32
)nOldModelPos
);
1701 DBG_ASSERT(!pCol
->IsHidden(), "DbGridControl::ColumnMoved : moved a hidden col ? how this ?");
1704 // for the new model pos we can't use GetModelColumnPos because we are altering the model at the moment
1705 // so the method won't work (in fact it would return the old model pos)
1707 // the new view pos is calculated easily
1708 sal_uInt16 nNewViewPos
= GetViewColumnPos(nId
);
1710 // from that we can compute the new model pos
1711 sal_uInt16 nNewModelPos
;
1712 for (nNewModelPos
= 0; nNewModelPos
< m_aColumns
.Count(); ++nNewModelPos
)
1714 if (!m_aColumns
.GetObject(nNewModelPos
)->IsHidden())
1722 DBG_ASSERT(nNewModelPos
<m_aColumns
.Count(), "DbGridControl::ColumnMoved : could not find the new model position !");
1724 // this will work. of course the model isn't fully consistent with our view right now, but let's
1725 // look at the situation : a column has been moved with in the VIEW from pos m to n, say m<n (in the
1726 // other case we can use analogue arguments).
1727 // All cols k with m<k<=n have been shifted left on pos, the former col m now has pos n.
1728 // In the model this affects a range of cols x to y, where x<=m and y<=n. And the number of hidden cols
1729 // within this range is constant, so we may calculate the view pos from the model pos in the above way.
1731 // for instance, let's look at a grid with six columns where the third one is hidden. this will
1732 // initially look like this :
1734 // +---+---+---+---+---+---+
1735 // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1736 // +---+---+---+---+---+---+
1737 // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1738 // +---+---+---+---+---+---+
1739 // view pos | 0 | 1 | - | 2 | 3 | 4 |
1740 // +---+---+---+---+---+---+
1742 // if we move the column at (view) pos 1 to (view) pos 3 we have :
1744 // +---+---+---+---+---+---+
1745 // model pos | 0 | 3 |*2*| 4 | 1 | 5 | // not reflecting the changes, yet
1746 // +---+---+---+---+---+---+
1747 // ID | 1 | 4 | 3 | 5 | 2 | 6 | // already reflecting the changes
1748 // +---+---+---+---+---+---+
1749 // view pos | 0 | 1 | - | 2 | 3 | 4 |
1750 // +---+---+---+---+---+---+
1752 // or, sorted by the out-of-date model positions :
1754 // +---+---+---+---+---+---+
1755 // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1756 // +---+---+---+---+---+---+
1757 // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1758 // +---+---+---+---+---+---+
1759 // view pos | 0 | 3 | - | 1 | 2 | 4 |
1760 // +---+---+---+---+---+---+
1762 // We know the new view pos (3) of the moved column because our base class tells us. So we look at our
1763 // model for the 4th (the pos is zero-based) visible column, it is at (model) position 4. And this is
1764 // exactly the pos where we have to re-insert our column's model, so it looks ike this :
1766 // +---+---+---+---+---+---+
1767 // model pos | 0 |*1*| 2 | 3 | 4 | 5 |
1768 // +---+---+---+---+---+---+
1769 // ID | 1 | 3 | 4 | 5 | 2 | 6 |
1770 // +---+---+---+---+---+---+
1771 // view pos | 0 | - | 1 | 2 | 3 | 4 |
1772 // +---+---+---+---+---+---+
1774 // Now, all is consistent again.
1775 // (except of the hidden column : The cycling of the cols occured on the model, not on the view. maybe
1776 // the user expected the latter but there really is no good argument against our method ;) ...)
1778 // And no, this large explanation isn't just because I wanted to play a board game or something like
1779 // that. It's because it took me a while to see it myself, and the whole theme (hidden cols, model col
1780 // positions, view col positions) is really painful (at least for me) so the above pictures helped me a lot ;)
1782 m_aColumns
.Insert(m_aColumns
.Remove((sal_uInt32
)nOldModelPos
), nNewModelPos
);
1785 //------------------------------------------------------------------------------
1786 sal_Bool
DbGridControl::SeekRow(long nRow
)
1788 // in filter mode or in insert only mode we don't have any cursor!
1789 if (SeekCursor(nRow
))
1793 // on the current position we have to take the current row for display as we want
1794 // to have the most recent values for display
1795 if ((nRow
== m_nCurrentPos
) && getDisplaySynchron())
1796 m_xPaintRow
= m_xCurrentRow
;
1797 // seek to the empty insert row
1798 else if (IsInsertionRow(nRow
))
1799 m_xPaintRow
= m_xEmptyRow
;
1802 m_xSeekRow
->SetState(m_pSeekCursor
, sal_True
);
1803 m_xPaintRow
= m_xSeekRow
;
1806 else if (IsFilterMode())
1808 DBG_ASSERT(IsFilterRow(nRow
), "DbGridControl::SeekRow(): No filter row, wrong mode");
1809 m_xPaintRow
= m_xEmptyRow
;
1811 DbGridControl_Base::SeekRow(nRow
);
1813 return m_nSeekPos
>= 0;
1815 //------------------------------------------------------------------------------
1816 // Wird aufgerufen, wenn die dargestellte Datenmenge sich aendert
1817 //------------------------------------------------------------------------------
1818 void DbGridControl::VisibleRowsChanged( long nNewTopRow
, sal_uInt16 nLinesOnScreen
)
1820 RecalcRows(nNewTopRow
, nLinesOnScreen
, sal_False
);
1823 //------------------------------------------------------------------------------
1824 void DbGridControl::RecalcRows(long nNewTopRow
, sal_uInt16 nLinesOnScreen
, sal_Bool bUpdateCursor
)
1826 DBG_CHKTHIS( DbGridControl
, NULL
);
1827 // Wenn kein Cursor -> keine Rows im Browser.
1830 DBG_ASSERT(GetRowCount() == 0,"DbGridControl: ohne Cursor darf es keine Rows geben");
1834 // ignore any updates implicit made
1835 sal_Bool bDisablePaint
= !bUpdateCursor
&& IsPaintEnabled();
1837 EnablePaint(sal_False
);
1839 // Cache an den sichtbaren Bereich anpassen
1840 Reference
< XPropertySet
> xSet
= m_pSeekCursor
->getPropertySet();
1841 sal_Int32 nCacheSize
= 0;
1842 xSet
->getPropertyValue(FM_PROP_FETCHSIZE
) >>= nCacheSize
;
1843 sal_Bool bCacheAligned
= sal_False
;
1844 // Nach der Initialisierung (m_nSeekPos < 0) keine Cursorbewegung, da bereits auf den ersten
1845 // Satz positioniert
1846 long nDelta
= nNewTopRow
- GetTopRow();
1847 // Limit fuer relative Positionierung
1848 long nLimit
= (nCacheSize
) ? nCacheSize
/ 2 : 0;
1850 // mehr Zeilen auf dem Bildschirm als im Cache
1851 if (nLimit
< nLinesOnScreen
)
1854 aCacheSize
<<= sal_Int32(nLinesOnScreen
*2);
1855 xSet
->setPropertyValue(FM_PROP_FETCHSIZE
, aCacheSize
);
1856 // jetzt auf alle Faelle den Cursor anpassen
1857 bUpdateCursor
= sal_True
;
1858 bCacheAligned
= sal_True
;
1859 nLimit
= nLinesOnScreen
;
1862 // Im folgenden werden die Positionierungen so vorgenommen, da� sichergestellt ist
1863 // da� ausreichend Zeilen im DatenCache vorhanden sind
1865 // Fenster geht nach unten, weniger als zwei Fenster Differenz
1866 // oder Cache angepasst und noch kein Rowcount
1867 if (nDelta
< nLimit
&& (nDelta
> 0
1868 || (bCacheAligned
&& m_nTotalCount
< 0)) )
1869 SeekCursor(nNewTopRow
+ nLinesOnScreen
- 1, sal_False
);
1870 else if (nDelta
< 0 && Abs(nDelta
) < nLimit
)
1871 SeekCursor(nNewTopRow
, sal_False
);
1872 else if (nDelta
!= 0 || bUpdateCursor
)
1873 SeekCursor(nNewTopRow
, sal_True
);
1877 // ignore any updates implicit made
1878 EnablePaint(sal_True
);
1881 //------------------------------------------------------------------------------
1882 void DbGridControl::RowInserted(long nRow
, long nNumRows
, sal_Bool bDoPaint
, sal_Bool bKeepSelection
)
1886 if (m_bRecordCountFinal
&& m_nTotalCount
< 0)
1888 // if we have an insert row we have to reduce to count by 1
1889 // as the total count reflects only the existing rows in database
1890 m_nTotalCount
= GetRowCount() + nNumRows
;
1891 if (m_xEmptyRow
.Is())
1894 else if (m_nTotalCount
>= 0)
1895 m_nTotalCount
+= nNumRows
;
1897 DbGridControl_Base::RowInserted(nRow
, nNumRows
, bDoPaint
, bKeepSelection
);
1898 m_aBar
.InvalidateState(NavigationBar::RECORD_COUNT
);
1902 //------------------------------------------------------------------------------
1903 void DbGridControl::RowRemoved(long nRow
, long nNumRows
, sal_Bool bDoPaint
)
1907 if (m_bRecordCountFinal
&& m_nTotalCount
< 0)
1909 m_nTotalCount
= GetRowCount() - nNumRows
;
1910 // if we have an insert row reduce by 1
1911 if (m_xEmptyRow
.Is())
1914 else if (m_nTotalCount
>= 0)
1915 m_nTotalCount
-= nNumRows
;
1917 DbGridControl_Base::RowRemoved(nRow
, nNumRows
, bDoPaint
);
1918 m_aBar
.InvalidateState(NavigationBar::RECORD_COUNT
);
1922 //------------------------------------------------------------------------------
1923 void DbGridControl::AdjustRows()
1928 Reference
< XPropertySet
> xSet
= m_pDataCursor
->getPropertySet();
1930 // Aktualisieren des RecordCounts
1931 sal_Int32 nRecordCount
= 0;
1932 xSet
->getPropertyValue(FM_PROP_ROWCOUNT
) >>= nRecordCount
;
1933 if (!m_bRecordCountFinal
)
1934 m_bRecordCountFinal
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ROWCOUNTFINAL
));
1936 // hat sich die aktuelle Anzahl Rows veraendert
1937 // hierbei muss auch beruecksichtigt werden,
1938 // das eine zusaetzliche Zeile zum einfuegen von Datensaetzen vorhanden sein kann
1940 // zusaetzliche AppendRow fuers einfuegen
1941 if (m_nOptions
& OPT_INSERT
)
1944 // wird gerade eingefuegt, dann gehoert die gerade hinzuzufuegende
1945 // Zeile nicht zum RecordCount und die Appendrow ebenfalls nicht
1946 if (!IsUpdating() && m_bRecordCountFinal
&& IsModified() && m_xCurrentRow
!= m_xEmptyRow
&&
1947 m_xCurrentRow
->IsNew())
1949 // das ist mit !m_bUpdating abgesichert : innerhalb von SaveRow (m_bUpdating == sal_True) wuerde sonst der Datensatz, den ich editiere
1950 // (und den SaveRow gerade angefuegt hat, wodurch diese Methode hier getriggert wurde), doppelt zaehlen : einmal ist er schon
1951 // in dem normalen RecordCount drin, zum zweiten wuerde er hier gezaehlt werden (60787 - FS)
1953 if (nRecordCount
!= GetRowCount())
1955 long nDelta
= GetRowCount() - (long)nRecordCount
;
1956 if (nDelta
> 0) // zuviele
1958 RowRemoved(GetRowCount() - nDelta
, nDelta
, sal_False
);
1959 // es sind Zeilen weggefallen, dann ab der aktuellen Position neu zeichen
1963 RowInserted(GetRowCount(), -nDelta
, sal_True
);
1966 if (m_bRecordCountFinal
&& m_nTotalCount
< 0)
1968 if (m_nOptions
& OPT_INSERT
)
1969 m_nTotalCount
= GetRowCount() - 1;
1971 m_nTotalCount
= GetRowCount();
1973 m_aBar
.InvalidateState(NavigationBar::RECORD_COUNT
);
1976 //------------------------------------------------------------------------------
1977 DbGridControl_Base::RowStatus
DbGridControl::GetRowStatus(long nRow
) const
1979 if (IsFilterRow(nRow
))
1980 return DbGridControl_Base::FILTER
;
1981 else if (m_nCurrentPos
>= 0 && nRow
== m_nCurrentPos
)
1984 if (!IsValid(m_xCurrentRow
))
1985 return DbGridControl_Base::DELETED
;
1986 else if (IsModified())
1987 return DbGridControl_Base::MODIFIED
;
1988 else if (m_xCurrentRow
->IsNew())
1989 return DbGridControl_Base::CURRENTNEW
;
1991 return DbGridControl_Base::CURRENT
;
1993 else if (IsInsertionRow(nRow
))
1994 return DbGridControl_Base::NEW
;
1995 else if (!IsValid(m_xSeekRow
))
1996 return DbGridControl_Base::DELETED
;
1998 return DbGridControl_Base::CLEAN
;
2001 //------------------------------------------------------------------------------
2002 void DbGridControl::PaintStatusCell(OutputDevice
& rDev
, const Rectangle
& rRect
) const
2004 DbGridControl_Base::PaintStatusCell(rDev
, rRect
);
2007 //------------------------------------------------------------------------------
2008 void DbGridControl::PaintCell(OutputDevice
& rDev
, const Rectangle
& rRect
, sal_uInt16 nColumnId
) const
2010 if (!IsValid(m_xPaintRow
))
2013 DbGridColumn
* pColumn
= m_aColumns
.GetObject(GetModelColumnPos(nColumnId
));
2016 Rectangle
aArea(rRect
);
2017 if ((GetMode() & BROWSER_CURSOR_WO_FOCUS
) == BROWSER_CURSOR_WO_FOCUS
)
2020 aArea
.Bottom() -= 1;
2022 pColumn
->Paint(rDev
, aArea
, m_xPaintRow
, getNumberFormatter());
2026 //------------------------------------------------------------------------------
2027 sal_Bool
DbGridControl::CursorMoving(long nNewRow
, sal_uInt16 nNewCol
)
2029 DBG_CHKTHIS( DbGridControl
, NULL
);
2031 DeactivateCell( sal_False
);
2034 && ( m_nCurrentPos
!= nNewRow
)
2035 && !SetCurrent( nNewRow
)
2042 if ( !DbGridControl_Base::CursorMoving( nNewRow
, nNewCol
) )
2048 //------------------------------------------------------------------------------
2049 sal_Bool
DbGridControl::SetCurrent(long nNewRow
)
2051 // Each movement of the datacursor must start with BeginCursorAction and end with
2052 // EndCursorAction to block all notifications during the movement
2053 BeginCursorAction();
2057 // Abgleichen der Positionen
2058 if (SeekCursor(nNewRow
))
2060 if (IsFilterRow(nNewRow
)) // special mode for filtering
2062 m_xCurrentRow
= m_xDataRow
= m_xPaintRow
= m_xEmptyRow
;
2063 m_nCurrentPos
= nNewRow
;
2067 sal_Bool bNewRowInserted
= sal_False
;
2068 // Should we go to the insertrow ?
2069 if (IsInsertionRow(nNewRow
))
2071 // to we need to move the cursor to the insert row?
2072 // we need to insert the if the current row isn't the insert row or if the
2073 // cursor triggered the move by itselt and we need a reinitialization of the row
2074 Reference
< XPropertySet
> xCursorProps
= m_pDataCursor
->getPropertySet();
2075 if ( !::comphelper::getBOOL(xCursorProps
->getPropertyValue(FM_PROP_ISNEW
)) )
2077 Reference
< XResultSetUpdate
> xUpdateCursor((Reference
< XInterface
>)*m_pDataCursor
, UNO_QUERY
);
2078 xUpdateCursor
->moveToInsertRow();
2080 bNewRowInserted
= sal_True
;
2085 if ( !m_pSeekCursor
->isBeforeFirst() && !m_pSeekCursor
->isAfterLast() )
2087 Any aBookmark
= m_pSeekCursor
->getBookmark();
2088 if (!m_xCurrentRow
|| m_xCurrentRow
->IsNew() || !CompareBookmark(aBookmark
, m_pDataCursor
->getBookmark()))
2090 // adjust the cursor to the new desired row
2091 if (!m_pDataCursor
->moveToBookmark(aBookmark
))
2099 m_xDataRow
->SetState(m_pDataCursor
, sal_False
);
2100 m_xCurrentRow
= m_xDataRow
;
2102 long nPaintPos
= -1;
2103 // do we have to repaint the last regular row in case of setting defaults or autovalues
2104 if (m_nCurrentPos
>= 0 && m_nCurrentPos
>= (GetRowCount() - 2))
2105 nPaintPos
= m_nCurrentPos
;
2107 m_nCurrentPos
= nNewRow
;
2109 // repaint the new row to display all defaults
2110 if (bNewRowInserted
)
2111 RowModified(m_nCurrentPos
);
2113 RowModified(nPaintPos
);
2118 DBG_ERROR("DbGridControl::SetCurrent : SeekRow failed !");
2123 catch ( const Exception
& )
2125 DBG_UNHANDLED_EXCEPTION();
2134 //------------------------------------------------------------------------------
2135 void DbGridControl::CursorMoved()
2137 DBG_CHKTHIS( DbGridControl
, NULL
);
2139 // CursorBewegung durch loeschen oder einfuegen von Zeilen
2140 if (m_pDataCursor
&& m_nCurrentPos
!= GetCurRow())
2142 DeactivateCell(sal_True
);
2143 SetCurrent(GetCurRow());
2146 DbGridControl_Base::CursorMoved();
2147 m_aBar
.InvalidateAll(m_nCurrentPos
);
2149 // select the new column when they moved
2150 if ( IsDesignMode() && GetSelectedColumnCount() > 0 && GetCurColumnId() )
2152 SelectColumnId( GetCurColumnId() );
2155 if ( m_nLastColId
!= GetCurColumnId() )
2157 m_nLastColId
= GetCurColumnId();
2159 if ( m_nLastRowId
!= GetCurRow() )
2161 m_nLastRowId
= GetCurRow();
2164 //------------------------------------------------------------------------------
2165 void DbGridControl::onRowChange()
2167 // not interested in
2170 //------------------------------------------------------------------------------
2171 void DbGridControl::onColumnChange()
2173 if ( m_pGridListener
)
2174 m_pGridListener
->columnChanged();
2177 //------------------------------------------------------------------------------
2178 void DbGridControl::setDisplaySynchron(sal_Bool bSync
)
2180 if (bSync
!= m_bSynchDisplay
)
2182 m_bSynchDisplay
= bSync
;
2183 if (m_bSynchDisplay
)
2184 AdjustDataSource(sal_False
);
2188 //------------------------------------------------------------------------------
2189 void DbGridControl::forceSyncDisplay()
2191 sal_Bool bOld
= getDisplaySynchron();
2192 setDisplaySynchron(sal_True
);
2194 setDisplaySynchron(bOld
);
2197 //------------------------------------------------------------------------------
2198 void DbGridControl::forceROController(sal_Bool bForce
)
2200 if (m_bForceROController
== bForce
)
2203 m_bForceROController
= bForce
;
2204 // alle Columns durchgehen und denen Bescheid geben
2205 for (sal_uInt16 i
=0; i
<m_aColumns
.Count(); ++i
)
2207 DbGridColumn
* pColumn
= m_aColumns
.GetObject(i
);
2211 CellController
* pReturn
= &pColumn
->GetController();
2215 // nur wenn es eine Edit-Zeile ist, kann ich ihr das forced read-only mitgeben
2216 if (!pReturn
->ISA(EditCellController
) && !pReturn
->ISA(SpinCellController
))
2219 Edit
& rEdit
= (Edit
&)pReturn
->GetWindow();
2220 rEdit
.SetReadOnly(m_bForceROController
);
2221 if (m_bForceROController
)
2222 rEdit
.SetStyle(rEdit
.GetStyle() | WB_NOHIDESELECTION
);
2224 rEdit
.SetStyle(rEdit
.GetStyle() & ~WB_NOHIDESELECTION
);
2227 // die aktive Zelle erneut aktivieren, da sich ihr Controller geaendert haben kann
2234 //------------------------------------------------------------------------------
2235 void DbGridControl::AdjustDataSource(sal_Bool bFull
)
2237 TRACE_RANGE("DbGridControl::AdjustDataSource");
2238 ::vos::OGuard
aGuard(Application::GetSolarMutex());
2239 // wird die aktuelle Zeile gerade neu bestimmt,
2240 // wird kein abgleich vorgenommen
2243 m_xCurrentRow
= NULL
;
2244 // if we are on the same row only repaint
2245 // but this is only possible for rows which are not inserted, in that case the comparision result
2246 // may not be correct
2248 if ( m_xCurrentRow
.Is()
2249 && !m_xCurrentRow
->IsNew()
2250 && !m_pDataCursor
->isBeforeFirst()
2251 && !m_pDataCursor
->isAfterLast()
2252 && !m_pDataCursor
->rowDeleted()
2255 sal_Bool bEqualBookmarks
= CompareBookmark( m_xCurrentRow
->GetBookmark(), m_pDataCursor
->getBookmark() );
2257 sal_Bool bDataCursorIsOnNew
= sal_False
;
2258 m_pDataCursor
->getPropertySet()->getPropertyValue( FM_PROP_ISNEW
) >>= bDataCursorIsOnNew
;
2260 if ( bEqualBookmarks
&& !bDataCursorIsOnNew
)
2262 // position of my data cursor is the same as the position our current row points tpo
2263 // sync the status, repaint, done
2264 DBG_ASSERT(m_xDataRow
== m_xCurrentRow
, "Fehler in den Datenzeilen");
2265 TRACE_RANGE_MESSAGE1("same position, new state : %s", ROWSTATUS(m_xCurrentRow
));
2266 RowModified(m_nCurrentPos
);
2271 // weg von der Row des DatenCursors
2272 if (m_xPaintRow
== m_xCurrentRow
)
2273 m_xPaintRow
= m_xSeekRow
;
2275 // keine aktuelle Zeile dann komplett anpassen
2279 sal_Int32 nNewPos
= AlignSeekCursor();
2280 if (nNewPos
< 0) // keine Position gefunden
2283 m_bInAdjustDataSource
= TRUE
;
2284 if (nNewPos
!= m_nCurrentPos
)
2286 if (m_bSynchDisplay
)
2287 DbGridControl_Base::GoToRow(nNewPos
);
2289 if (!m_xCurrentRow
.Is())
2290 // das tritt zum Beispiel auf, wenn man die n (n>1) letzten Datensaetze geloescht hat, waehrend der Cursor auf dem letzten
2291 // steht : AdjustRows entfernt dann zwei Zeilen aus der BrowseBox, wodurch diese ihre CurrentRow um zwei nach unten
2292 // korrigiert, so dass dann das GoToRow in's Leere laeuft (da wir uns ja angeblich schon an der richtigen Position
2294 SetCurrent(nNewPos
);
2298 SetCurrent(nNewPos
);
2299 RowModified(nNewPos
);
2301 m_bInAdjustDataSource
= FALSE
;
2303 // Wird der DatenCursor von aussen bewegt, wird die selektion aufgehoben
2305 m_aBar
.InvalidateAll(m_nCurrentPos
, m_xCurrentRow
.Is());
2308 //------------------------------------------------------------------------------
2309 sal_Int32
DbGridControl::AlignSeekCursor()
2311 DBG_CHKTHIS( DbGridControl
, NULL
);
2312 // Positioniert den SeekCursor auf den DatenCursor, Daten werden nicht uebertragen
2317 Reference
< XPropertySet
> xSet
= m_pDataCursor
->getPropertySet();
2319 // jetzt den seekcursor an den DatenCursor angleichen
2320 if (::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISNEW
)))
2321 m_nSeekPos
= GetRowCount() - 1;
2326 if ( m_pDataCursor
->isBeforeFirst() )
2328 // this is somewhat strange, but can nevertheless happen
2329 DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (before first)!" );
2330 m_pSeekCursor
->first();
2331 m_pSeekCursor
->previous();
2334 else if ( m_pDataCursor
->isAfterLast() )
2336 DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (after last)!" );
2337 m_pSeekCursor
->last();
2338 m_pSeekCursor
->next();
2343 m_pSeekCursor
->moveToBookmark(m_pDataCursor
->getBookmark());
2344 if (!CompareBookmark(m_pDataCursor
->getBookmark(), m_pSeekCursor
->getBookmark()))
2345 // dummerweise kann das moveToBookmark indirekt dazu fuehren, dass der Seek-Cursor wieder neu positoniert wird (wenn
2346 // naemlich das mit all seinen zu feuernden Events relativ komplexe moveToBookmark irgendwo ein Update ausloest),
2347 // also muss ich es nochmal versuchen
2348 m_pSeekCursor
->moveToBookmark(m_pDataCursor
->getBookmark());
2349 // Nicht dass das jetzt nicht auch schief gegangen sein koennte, aber es ist zumindest unwahrscheinlicher geworden.
2350 // Und die Alternative waere eine Schleife so lange bis es stimmt, und das kann auch nicht die Loesung sein
2351 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2360 //------------------------------------------------------------------------------
2361 sal_Bool
DbGridControl::SeekCursor(long nRow
, sal_Bool bAbsolute
)
2363 DBG_CHKTHIS( DbGridControl
, NULL
);
2364 // Positioniert den SeekCursor, Daten werden nicht uebertragen
2366 // additions for the filtermode
2367 if (IsFilterRow(nRow
))
2376 // Befinden wir uns gerade beim Einfuegen
2377 if (IsValid(m_xCurrentRow
) && m_xCurrentRow
->IsNew() &&
2378 nRow
>= m_nCurrentPos
)
2380 // dann darf auf alle Faelle nicht weiter nach unten gescrollt werden
2381 // da der letzte Datensatz bereits erreicht wurde!
2382 if (nRow
== m_nCurrentPos
)
2384 // auf die aktuelle Zeile bewegt, dann mu� kein abgleich gemacht werden, wenn
2385 // gerade ein Datensatz eingefuegt wird
2388 else if (IsInsertionRow(nRow
)) // Leerzeile zum Einfuegen von Datensaetzen
2391 else if (IsInsertionRow(nRow
)) // Leerzeile zum Einfuegen von Datensaetzen
2393 else if ((-1 == nRow
) && (GetRowCount() == ((m_nOptions
& OPT_INSERT
) ? 1 : 0)) && m_pSeekCursor
->isAfterLast())
2398 sal_Bool bSuccess
=sal_False
;
2402 if ( m_pSeekCursor
->rowDeleted() )
2404 // somebody deleted the current row of the seek cursor. Move it away from this row.
2405 m_pSeekCursor
->next();
2406 if ( m_pSeekCursor
->isAfterLast() || m_pSeekCursor
->isBeforeFirst() )
2407 bAbsolute
= sal_True
;
2412 DBG_ASSERT( !m_pSeekCursor
->isAfterLast() && !m_pSeekCursor
->isBeforeFirst(),
2413 "DbGridControl::SeekCursor: how did the seek cursor get to this position?!" );
2414 nSteps
= nRow
- (m_pSeekCursor
->getRow() - 1);
2415 bAbsolute
= bAbsolute
|| (abs(nSteps
) > 100);
2420 bSuccess
= m_pSeekCursor
->absolute(nRow
+ 1);
2426 if (nSteps
> 0) // auf den letzten benoetigten Datensatz positionieren
2428 if (m_pSeekCursor
->isAfterLast())
2429 bSuccess
= sal_False
;
2430 else if (m_pSeekCursor
->isBeforeFirst())
2431 bSuccess
= m_pSeekCursor
->absolute(nSteps
);
2433 bSuccess
= m_pSeekCursor
->relative(nSteps
);
2435 else if (nSteps
< 0)
2437 if (m_pSeekCursor
->isBeforeFirst())
2438 bSuccess
= sal_False
;
2439 else if (m_pSeekCursor
->isAfterLast())
2440 bSuccess
= m_pSeekCursor
->absolute(nSteps
);
2442 bSuccess
= m_pSeekCursor
->relative(nSteps
);
2453 DBG_ERROR("DbGridControl::SeekCursor : failed ...");
2460 if (bAbsolute
|| nSteps
> 0)
2461 bSuccess
= m_pSeekCursor
->last();
2463 bSuccess
= m_pSeekCursor
->first();
2467 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2473 DBG_ERROR("DbGridControl::SeekCursor : failed ...");
2474 m_nSeekPos
= -1; // kein Datensatz mehr vorhanden
2477 return m_nSeekPos
== nRow
;
2479 //------------------------------------------------------------------------------
2480 void DbGridControl::MoveToFirst()
2482 if (m_pSeekCursor
&& (GetCurRow() != 0))
2486 //------------------------------------------------------------------------------
2487 void DbGridControl::MoveToLast()
2492 if (m_nTotalCount
< 0) // RecordCount steht noch nicht fest
2496 sal_Bool bRes
= m_pSeekCursor
->last();
2500 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2509 // auf den letzen Datensatz positionieren, nicht auf die Leerzeile
2510 if (m_nOptions
& OPT_INSERT
)
2512 if ((GetRowCount() - 1) > 0)
2513 MoveToPosition(GetRowCount() - 2);
2515 else if (GetRowCount())
2516 MoveToPosition(GetRowCount() - 1);
2519 //------------------------------------------------------------------------------
2520 void DbGridControl::MoveToPrev()
2522 long nNewRow
= std::max(GetCurRow() - 1L, 0L);
2523 if (GetCurRow() != nNewRow
)
2524 MoveToPosition(nNewRow
);
2527 //------------------------------------------------------------------------------
2528 void DbGridControl::MoveToNext()
2533 if (m_nTotalCount
> 0)
2535 // move the data cursor to the right position
2536 long nNewRow
= std::min(GetRowCount() - 1, GetCurRow() + 1);
2537 if (GetCurRow() != nNewRow
)
2538 MoveToPosition(nNewRow
);
2542 sal_Bool bOk
= sal_False
;
2545 // try to move to next row
2546 // when not possible our paint cursor is already on the last row
2547 // then we must be sure that the data cursor is on the position
2548 // we call ourself again
2549 bOk
= m_pSeekCursor
->next();
2552 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2553 MoveToPosition(GetCurRow() + 1);
2556 catch(SQLException
&)
2558 DBG_UNHANDLED_EXCEPTION();
2564 if (m_nTotalCount
> 0) // only to avoid infinte recursion
2570 //------------------------------------------------------------------------------
2571 void DbGridControl::MoveToPosition(sal_uInt32 nPos
)
2576 if (m_nTotalCount
< 0 && (long)nPos
>= GetRowCount())
2580 if (!m_pSeekCursor
->absolute(nPos
+ 1))
2588 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2597 DbGridControl_Base::GoToRow(nPos
);
2598 m_aBar
.InvalidateAll(m_nCurrentPos
);
2601 //------------------------------------------------------------------------------
2602 void DbGridControl::AppendNew()
2604 if (!m_pSeekCursor
|| !(m_nOptions
& OPT_INSERT
))
2607 if (m_nTotalCount
< 0) // RecordCount steht noch nicht fest
2611 sal_Bool bRes
= m_pSeekCursor
->last();
2615 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2625 long nNewRow
= m_nTotalCount
+ 1;
2626 if (nNewRow
> 0 && GetCurRow() != nNewRow
)
2627 MoveToPosition(nNewRow
- 1);
2630 //------------------------------------------------------------------------------
2631 void DbGridControl::SetDesignMode(sal_Bool bMode
)
2633 if (IsDesignMode() != bMode
)
2635 // Enable/Disable f�r den Designmode anpassen damit die Headerbar konfigurierbar bleibt
2641 GetDataWindow().Disable();
2646 // komplett disablen
2647 if (!GetDataWindow().IsEnabled())
2651 m_bDesignMode
= bMode
;
2652 GetDataWindow().SetMouseTransparent(bMode
);
2653 SetMouseTransparent(bMode
);
2655 m_aBar
.InvalidateAll(m_nCurrentPos
, sal_True
);
2659 //------------------------------------------------------------------------------
2660 void DbGridControl::SetFilterMode(sal_Bool bMode
)
2662 if (IsFilterMode() != bMode
)
2664 m_bFilterMode
= bMode
;
2668 SetUpdateMode(sal_False
);
2670 // es gibt kein Cursor mehr
2673 RemoveRows(sal_False
);
2675 m_xEmptyRow
= new DbGridRow();
2677 // setting the new filter controls
2678 for (sal_uInt16 i
= 0; i
<m_aColumns
.Count(); ++i
)
2680 DbGridColumn
* pCurCol
= m_aColumns
.GetObject(i
);
2681 if (!pCurCol
->IsHidden())
2682 pCurCol
->UpdateControl();
2685 // one row for filtering
2686 RowInserted(0, 1, sal_True
);
2687 SetUpdateMode(sal_True
);
2690 setDataSource(Reference
< XRowSet
> ());
2693 // -----------------------------------------------------------------------------
2694 String
DbGridControl::GetCellText(long _nRow
, USHORT _nColId
) const
2696 DbGridColumn
* pColumn
= m_aColumns
.GetObject( GetModelColumnPos( _nColId
) );
2698 if ( const_cast<DbGridControl
*>(this)->SeekRow(_nRow
) )
2699 sRet
= GetCurrentRowCellText(pColumn
, m_xPaintRow
);
2702 //------------------------------------------------------------------------------
2703 XubString
DbGridControl::GetCurrentRowCellText(DbGridColumn
* pColumn
,const DbGridRowRef
& _rRow
) const
2705 // Ausgabe des Textes fuer eine Zelle
2707 if ( pColumn
&& IsValid(m_xPaintRow
) )
2708 aText
= pColumn
->GetCellText(_rRow
, m_xFormatter
);
2712 //------------------------------------------------------------------------------
2713 sal_uInt32
DbGridControl::GetTotalCellWidth(long nRow
, sal_uInt16 nColId
)
2717 DbGridColumn
* pColumn
= m_aColumns
.GetObject(GetModelColumnPos(nColId
));
2718 return GetDataWindow().GetTextWidth(GetCurrentRowCellText(pColumn
,m_xPaintRow
));
2724 //------------------------------------------------------------------------------
2725 void DbGridControl::PreExecuteRowContextMenu(sal_uInt16
/*nRow*/, PopupMenu
& rMenu
)
2727 sal_Bool bDelete
= (m_nOptions
& OPT_DELETE
) && GetSelectRowCount() && !IsCurrentAppending();
2728 // ist nur die Leerzeile selektiert, dann nicht loeschen
2729 bDelete
= bDelete
&& !((m_nOptions
& OPT_INSERT
) && GetSelectRowCount() == 1 && IsRowSelected(GetRowCount() - 1));
2731 rMenu
.EnableItem(SID_FM_DELETEROWS
, bDelete
);
2732 rMenu
.EnableItem(SID_FM_RECORD_SAVE
, IsModified());
2734 // the undo is more difficult
2735 sal_Bool bCanUndo
= IsModified();
2737 if (m_aMasterStateProvider
.IsSet())
2738 nState
= m_aMasterStateProvider
.Call((void*)SID_FM_RECORD_UNDO
);
2739 bCanUndo
&= ( 0 != nState
);
2741 rMenu
.EnableItem(SID_FM_RECORD_UNDO
, bCanUndo
);
2744 //------------------------------------------------------------------------------
2745 void DbGridControl::PostExecuteRowContextMenu(sal_uInt16
/*nRow*/, const PopupMenu
& /*rMenu*/, sal_uInt16 nExecutionResult
)
2747 switch (nExecutionResult
)
2749 case SID_FM_DELETEROWS
:
2752 Application::RemoveUserEvent(m_nDeleteEvent
);
2753 m_nDeleteEvent
= Application::PostUserEvent(LINK(this,DbGridControl
,OnDelete
));
2755 case SID_FM_RECORD_UNDO
:
2758 case SID_FM_RECORD_SAVE
:
2766 //------------------------------------------------------------------------------
2767 void DbGridControl::DataSourcePropertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
)
2769 TRACE_RANGE("DbGridControl::DataSourcePropertyChanged");
2770 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
2771 // prop "IsModified" changed ?
2772 // during update don't care about the modified state
2773 if (!IsUpdating() && evt
.PropertyName
.compareTo(FM_PROP_ISMODIFIED
) == COMPARE_EQUAL
)
2775 Reference
< XPropertySet
> xSource(evt
.Source
, UNO_QUERY
);
2776 DBG_ASSERT( xSource
.is(), "DbGridControl::DataSourcePropertyChanged: invalid event source!" );
2777 sal_Bool bIsNew
= sal_False
;
2779 bIsNew
= ::comphelper::getBOOL(xSource
->getPropertyValue(FM_PROP_ISNEW
));
2781 if (bIsNew
&& m_xCurrentRow
.Is())
2783 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 !");
2784 sal_Int32 nRecordCount
= 0;
2785 xSource
->getPropertyValue(FM_PROP_ROWCOUNT
) >>= nRecordCount
;
2786 if (::comphelper::getBOOL(evt
.NewValue
))
2787 { // modified state changed from sal_False to sal_True and we're on a insert row
2788 // -> we've to add a new grid row
2789 if ((nRecordCount
== GetRowCount() - 1) && m_xCurrentRow
->IsNew())
2791 RowInserted(GetRowCount(), 1, sal_True
);
2792 InvalidateStatusCell(m_nCurrentPos
);
2793 m_aBar
.InvalidateAll(m_nCurrentPos
);
2797 { // modified state changed from sal_True to sal_False and we're on a insert row
2798 // we have two "new row"s at the moment : the one we're editing currently (where the current
2799 // column is the only dirty element) and a "new new" row which is completely clean. As the first
2800 // one is about to be cleaned, too, the second one is obsolet now.
2801 if (m_xCurrentRow
->IsNew() && nRecordCount
== (GetRowCount() - 2))
2803 RowRemoved(GetRowCount() - 1, 1, sal_True
);
2804 InvalidateStatusCell(m_nCurrentPos
);
2805 m_aBar
.InvalidateAll(m_nCurrentPos
);
2809 if (m_xCurrentRow
.Is())
2811 m_xCurrentRow
->SetStatus(::comphelper::getBOOL(evt
.NewValue
) ? GRS_MODIFIED
: GRS_CLEAN
);
2812 m_xCurrentRow
->SetNew( bIsNew
);
2813 InvalidateStatusCell(m_nCurrentPos
);
2814 TRACE_RANGE_MESSAGE1("modified flag changed, new state : %s", ROWSTATUS(m_xCurrentRow
));
2819 //------------------------------------------------------------------------------
2820 void DbGridControl::StartDrag( sal_Int8
/*nAction*/, const Point
& rPosPixel
)
2822 if (!m_pSeekCursor
|| IsResizing())
2825 sal_uInt16 nColId
= GetColumnAtXPosPixel(rPosPixel
.X());
2826 long nRow
= GetRowAtYPosPixel(rPosPixel
.Y());
2827 if (nColId
!= HANDLE_ID
&& nRow
>= 0)
2829 if (GetDataWindow().IsMouseCaptured())
2830 GetDataWindow().ReleaseMouse();
2832 DbGridColumn
* pColumn
= m_aColumns
.GetObject(GetModelColumnPos(nColId
));
2833 OStringTransferable
* pTransferable
= new OStringTransferable(GetCurrentRowCellText(pColumn
,m_xPaintRow
));
2834 Reference
< XTransferable
> xEnsureDelete(pTransferable
);
2835 pTransferable
->StartDrag(this, DND_ACTION_COPY
);
2839 //------------------------------------------------------------------------------
2840 sal_Bool
DbGridControl::canCopyCellText(sal_Int32 _nRow
, sal_Int16 _nColId
)
2843 && (_nRow
< GetRowCount())
2844 && (_nColId
> HANDLE_ID
)
2845 && (_nColId
<= ColCount());
2848 //------------------------------------------------------------------------------
2849 void DbGridControl::copyCellText(sal_Int32 _nRow
, sal_Int16 _nColId
)
2851 DBG_ASSERT(canCopyCellText(_nRow
, _nColId
), "DbGridControl::copyCellText: invalid call!");
2852 DbGridColumn
* pColumn
= m_aColumns
.GetObject(GetModelColumnPos(_nColId
));
2854 OStringTransfer::CopyString( GetCurrentRowCellText( pColumn
,m_xPaintRow
), this );
2857 //------------------------------------------------------------------------------
2858 void DbGridControl::executeRowContextMenu( long _nRow
, const Point
& _rPreferredPos
)
2860 PopupMenu
aContextMenu( SVX_RES( RID_SVXMNU_ROWS
) );
2862 PreExecuteRowContextMenu( (sal_uInt16
)_nRow
, aContextMenu
);
2863 aContextMenu
.RemoveDisabledEntries( sal_True
, sal_True
);
2864 PostExecuteRowContextMenu( (sal_uInt16
)_nRow
, aContextMenu
, aContextMenu
.Execute( this, _rPreferredPos
) );
2866 // TODO: why this weird cast to sal_uInt16? What if we really have more than 65535 lines?
2867 // -> change this to sal_uInt32
2870 //------------------------------------------------------------------------------
2871 void DbGridControl::Command(const CommandEvent
& rEvt
)
2873 switch (rEvt
.GetCommand())
2875 case COMMAND_CONTEXTMENU
:
2877 if ( !m_pSeekCursor
)
2879 DbGridControl_Base::Command(rEvt
);
2883 if ( !rEvt
.IsMouseEvent() )
2884 { // context menu requested by keyboard
2885 if ( GetSelectRowCount() )
2887 long nRow
= FirstSelectedRow( );
2889 ::Rectangle
aRowRect( GetRowRectPixel( nRow
, sal_True
) );
2890 executeRowContextMenu( nRow
, aRowRect
.LeftCenter() );
2897 sal_uInt16 nColId
= GetColumnAtXPosPixel(rEvt
.GetMousePosPixel().X());
2898 long nRow
= GetRowAtYPosPixel(rEvt
.GetMousePosPixel().Y());
2900 if (nColId
== HANDLE_ID
)
2902 executeRowContextMenu( nRow
, rEvt
.GetMousePosPixel() );
2904 else if (canCopyCellText(nRow
, nColId
))
2906 PopupMenu
aContextMenu(SVX_RES(RID_SVXMNU_CELL
));
2907 aContextMenu
.RemoveDisabledEntries(sal_True
, sal_True
);
2908 switch (aContextMenu
.Execute(this, rEvt
.GetMousePosPixel()))
2911 copyCellText(nRow
, nColId
);
2917 DbGridControl_Base::Command(rEvt
);
2922 DbGridControl_Base::Command(rEvt
);
2926 //------------------------------------------------------------------------------
2927 IMPL_LINK(DbGridControl
, OnDelete
, void*, /*EMPTYTAG*/ )
2929 DBG_CHKTHIS(DbGridControl
, NULL
);
2931 DeleteSelectedRows();
2935 //------------------------------------------------------------------------------
2936 void DbGridControl::DeleteSelectedRows()
2938 DBG_ASSERT(GetSelection(), "keine selection!!!");
2943 /* Application::EnterWait();
2944 Reference< XPropertySet > xSet = (XPropertySet*)xSeekCursor->queryInterface(XPropertySet::getSmartUik());
2946 // wenn mehr als 25 Datensaetze geloescht werden, wird der Cache abgeschaltet
2947 // da das loeschen ansonsten zu langsam wird
2948 sal_uInt16 nCacheSize = 0;
2949 if (GetSelectRowCount() > 25)
2951 // CacheSize merken und Cache zuruecksetzen
2952 nCacheSize = xSet->getPropertyValue(L"CacheSize").getUINT16();
2954 xSet->setPropertyValue(L"CacheSize", Any(sal_uInt16(0)));
2959 // mu� der Cache wiederhergestellt werden?
2962 // Cache wieder einschalten
2963 xSet->setPropertyValue(L"CacheSize", Any(sal_uInt16(nCacheSize)));
2965 // Browser neu einstellen
2966 RecalcRows(GetTopRow(), GetVisibleRows(), sal_True);
2968 // aktuelle Zeile aktualisieren
2969 SeekCursor(GetCurRow());
2970 if (IsAppendRow(m_nSeekPos))
2971 xDataCursor->addRecord();
2974 Any aBookmark = xSeekCursor->getBookmark();
2975 xDataCursor->moveToBookmark(aBookmark);
2977 m_xCurrentRow = new DbGridRow(xDataCursor);
2978 m_nCurrentPos = m_nSeekPos;
2980 // complett invalidieren
2984 // Browser neu einstellen
2985 RecalcRows(GetTopRow(), GetVisibleRows(), sal_True);
2987 // gibt es keine Selection mehr?
2988 if (!GetSelectRowCount())
2991 m_aBar.InvalidateAll();
2992 Application::LeaveWait();
2994 m_bUpdating = sal_False;
2998 //------------------------------------------------------------------------------
2999 CellController
* DbGridControl::GetController(long /*nRow*/, sal_uInt16 nColumnId
)
3001 if (!IsValid(m_xCurrentRow
) || !IsEnabled())
3004 DbGridColumn
* pColumn
= m_aColumns
.GetObject(GetModelColumnPos(nColumnId
));
3008 CellController
* pReturn
= NULL
;
3010 pReturn
= &pColumn
->GetController();
3013 if (::comphelper::hasProperty(FM_PROP_ENABLED
, pColumn
->getModel()))
3015 if (!::comphelper::getBOOL(pColumn
->getModel()->getPropertyValue(FM_PROP_ENABLED
)))
3019 sal_Bool bInsert
= (m_xCurrentRow
->IsNew() && (m_nOptions
& OPT_INSERT
));
3020 sal_Bool bUpdate
= (!m_xCurrentRow
->IsNew() && (m_nOptions
& OPT_UPDATE
));
3022 if ((bInsert
&& !pColumn
->IsAutoValue()) || bUpdate
|| m_bForceROController
)
3024 pReturn
= &pColumn
->GetController();
3027 // wenn es eine Edit-Zeile ist, kann ich ihr das forced read-only mitgeben
3028 if (!pReturn
->ISA(EditCellController
) && !pReturn
->ISA(SpinCellController
))
3029 // ich konnte den Controller in forceROController nicht auf ReadOnly setzen
3030 if (!bInsert
&& !bUpdate
)
3031 // ich bin nur hier, da m_bForceROController gesetzt war
3032 // -> lieber kein Controller als einer ohne RO
3040 //------------------------------------------------------------------------------
3041 void DbGridControl::InitController(CellControllerRef
& /*rController*/, long /*nRow*/, sal_uInt16 nColumnId
)
3043 DbGridColumn
* pColumn
= m_aColumns
.GetObject(GetModelColumnPos(nColumnId
));
3045 pColumn
->UpdateFromField(m_xCurrentRow
, m_xFormatter
);
3048 //------------------------------------------------------------------------------
3049 void DbGridControl::CellModified()
3051 TRACE_RANGE("DbGridControl::CellModified");
3054 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
3055 if (m_nAsynAdjustEvent
)
3057 TRACE_RANGE_MESSAGE1("forcing a synchron call to ", m_bPendingAdjustRows
? "AdjustRows" : "AdustDataSource");
3058 RemoveUserEvent(m_nAsynAdjustEvent
);
3059 m_nAsynAdjustEvent
= 0;
3061 // force the call : this should be no problem as we're probably running in the solar thread here
3062 // (cell modified is triggered by user actions)
3063 if (m_bPendingAdjustRows
)
3070 if (!IsFilterMode() && IsValid(m_xCurrentRow
) && !m_xCurrentRow
->IsModified())
3072 // Einschalten des Editiermodus
3073 // Datensatz soll eingefuegt werden
3074 if (m_xCurrentRow
->IsNew())
3076 m_xCurrentRow
->SetStatus(GRS_MODIFIED
);
3077 TRACE_RANGE_MESSAGE("current row is new, new state : MODIFIED");
3078 // wenn noch keine Zeile hinzugefuegt wurde, dann neue hinzunehmen
3079 if (m_nCurrentPos
== GetRowCount() - 1)
3081 // RowCount um einen erhoehen
3082 RowInserted(GetRowCount(), 1, sal_True
);
3083 InvalidateStatusCell(m_nCurrentPos
);
3084 m_aBar
.InvalidateAll(m_nCurrentPos
);
3087 else if (m_xCurrentRow
->GetStatus() != GRS_MODIFIED
)
3089 m_xCurrentRow
->SetState(m_pDataCursor
, sal_False
);
3090 TRACE_RANGE_MESSAGE1("current row is not new, after SetState, new state : %s", ROWSTATUS(m_xCurrentRow
));
3091 m_xCurrentRow
->SetStatus(GRS_MODIFIED
);
3092 TRACE_RANGE_MESSAGE("current row is not new, new state : MODIFIED");
3093 InvalidateStatusCell(m_nCurrentPos
);
3098 //------------------------------------------------------------------------------
3099 void DbGridControl::Dispatch(sal_uInt16 nId
)
3101 if (nId
== BROWSER_CURSORENDOFFILE
)
3103 if (m_nOptions
& OPT_INSERT
)
3109 DbGridControl_Base::Dispatch(nId
);
3112 //------------------------------------------------------------------------------
3113 void DbGridControl::Undo()
3115 if (!IsFilterMode() && IsValid(m_xCurrentRow
) && IsModified())
3117 // check if we have somebody doin' the UNDO for us
3119 if (m_aMasterStateProvider
.IsSet())
3120 nState
= m_aMasterStateProvider
.Call((void*)SID_FM_RECORD_UNDO
);
3122 { // yes, we have, and the slot is enabled
3123 DBG_ASSERT(m_aMasterSlotExecutor
.IsSet(), "DbGridControl::Undo : a state, but no execute link ?");
3124 long lResult
= m_aMasterSlotExecutor
.Call((void*)SID_FM_RECORD_UNDO
);
3129 else if (nState
== 0)
3130 // yes, we have, and the slot is disabled
3133 BeginCursorAction();
3135 sal_Bool bAppending
= m_xCurrentRow
->IsNew();
3136 sal_Bool bDirty
= m_xCurrentRow
->IsModified();
3140 // Editieren abbrechen
3141 Reference
< XResultSetUpdate
> xUpdateCursor((Reference
< XInterface
>)*m_pDataCursor
, UNO_QUERY
);
3142 // no effects if we're not updating currently
3144 // just refresh the row
3145 xUpdateCursor
->moveToInsertRow();
3147 xUpdateCursor
->cancelRowUpdates();
3152 DBG_UNHANDLED_EXCEPTION();
3157 m_xDataRow
->SetState(m_pDataCursor
, sal_False
);
3158 if (&m_xPaintRow
== &m_xCurrentRow
)
3159 m_xPaintRow
= m_xCurrentRow
= m_xDataRow
;
3161 m_xCurrentRow
= m_xDataRow
;
3163 if (bAppending
&& (DbGridControl_Base::IsModified() || bDirty
))
3165 if (m_nCurrentPos
== GetRowCount() - 2)
3166 { // maybe we already removed it (in resetCurrentRow, called if the above moveToInsertRow
3167 // caused our data source form to be reset - which should be the usual case ....)
3168 RowRemoved(GetRowCount() - 1, 1, sal_True
);
3169 m_aBar
.InvalidateAll(m_nCurrentPos
);
3172 RowModified(m_nCurrentPos
);
3176 //------------------------------------------------------------------------------
3177 void DbGridControl::resetCurrentRow()
3181 // scenario : we're on the insert row, the row is dirty, and thus there exists a "second" insert row (which
3182 // is clean). Normally in DataSourcePropertyChanged we would remove this second row if the modified state of
3183 // the insert row changes from sal_True to sal_False. But if our current cell is the only modified element (means the
3184 // data source isn't modified) and we're reset this DataSourcePropertyChanged would never be called, so we
3185 // would never delete the obsolet "second insert row". Thus in this special case this method here
3186 // is the only possibility to determine the redundance of the row (resetCurrentRow is called when the
3187 // "first insert row" is about to be cleaned, so of course the "second insert row" is redundant now)
3188 Reference
< XPropertySet
> xDataSource
= getDataSource()->getPropertySet();
3189 if (xDataSource
.is() && !::comphelper::getBOOL(xDataSource
->getPropertyValue(FM_PROP_ISMODIFIED
)))
3191 // are we on a new row currently ?
3192 if (m_xCurrentRow
->IsNew())
3194 if (m_nCurrentPos
== GetRowCount() - 2)
3196 RowRemoved(GetRowCount() - 1, 1, sal_True
);
3197 m_aBar
.InvalidateAll(m_nCurrentPos
);
3203 m_xDataRow
->SetState(m_pDataCursor
, sal_False
);
3204 if (&m_xPaintRow
== &m_xCurrentRow
)
3205 m_xPaintRow
= m_xCurrentRow
= m_xDataRow
;
3207 m_xCurrentRow
= m_xDataRow
;
3210 RowModified(GetCurRow()); // will update the current controller if affected
3213 //------------------------------------------------------------------------------
3214 void DbGridControl::RowModified( long nRow
, sal_uInt16
/*nColId*/ )
3216 if (nRow
== m_nCurrentPos
&& IsEditing())
3218 CellControllerRef aTmpRef
= Controller();
3219 aTmpRef
->ClearModified();
3220 InitController(aTmpRef
, m_nCurrentPos
, GetCurColumnId());
3222 DbGridControl_Base::RowModified(nRow
);
3225 //------------------------------------------------------------------------------
3226 sal_Bool
DbGridControl::IsModified() const
3228 return !IsFilterMode() && IsValid(m_xCurrentRow
) && (m_xCurrentRow
->IsModified() || DbGridControl_Base::IsModified());
3231 //------------------------------------------------------------------------------
3232 sal_Bool
DbGridControl::IsCurrentAppending() const
3234 return m_xCurrentRow
.Is() && m_xCurrentRow
->IsNew();
3237 //------------------------------------------------------------------------------
3238 sal_Bool
DbGridControl::IsInsertionRow(long nRow
) const
3240 return (m_nOptions
& OPT_INSERT
) && m_nTotalCount
>= 0 && (nRow
== GetRowCount() - 1);
3243 //------------------------------------------------------------------------------
3244 sal_Bool
DbGridControl::SaveModified()
3246 TRACE_RANGE("DbGridControl::SaveModified");
3247 DBG_ASSERT(IsValid(m_xCurrentRow
), "GridControl:: Invalid row");
3248 if (!IsValid(m_xCurrentRow
))
3251 // Uebernimmt die Dateneingabe fuer das Feld
3252 // Hat es aenderungen im aktuellen Eingabefeld gegeben ?
3253 if (!DbGridControl_Base::IsModified())
3256 DbGridColumn
* pColumn
= m_aColumns
.GetObject(GetModelColumnPos(GetCurColumnId()));
3257 sal_Bool bOK
= pColumn
->Commit();
3258 DBG_ASSERT( Controller().Is(), "DbGridControl::SaveModified: was modified, by have no controller?!" );
3259 if ( !Controller().Is() )
3260 // this might happen if the callbacks implicitly triggered by Commit
3261 // fiddled with the form or the control ...
3262 // (Note that this here is a workaround, at most. We need a general concept how
3263 // to treat this, you can imagine an arbitrary number of scenarios where a callback
3264 // triggers something which leaves us in an expected state.)
3265 // #i67147# / 2006-07-17 / frank.schoenheit@sun.com
3270 Controller()->ClearModified();
3272 if ( IsValid(m_xCurrentRow
) )
3274 m_xCurrentRow
->SetState(m_pDataCursor
, sal_False
);
3275 TRACE_RANGE_MESSAGE1("explicit SetState, new state : %s", ROWSTATUS(m_xCurrentRow
));
3276 InvalidateStatusCell( m_nCurrentPos
);
3281 TRACE_RANGE_MESSAGE1("no SetState, new state : %s", ROWSTATUS(m_xCurrentRow
));
3287 // reset the modified flag ....
3288 Controller()->SetModified();
3294 //------------------------------------------------------------------------------
3295 sal_Bool
DbGridControl::SaveRow()
3297 TRACE_RANGE("DbGridControl::SaveRow");
3299 if (!IsValid(m_xCurrentRow
) || !IsModified())
3301 // Wert des Controllers noch nicht gespeichert
3302 else if (Controller().Is() && Controller()->IsModified())
3304 if (!SaveModified())
3307 m_bUpdating
= sal_True
;
3309 BeginCursorAction();
3310 sal_Bool bAppending
= m_xCurrentRow
->IsNew();
3311 sal_Bool bSuccess
= sal_False
;
3314 Reference
< XResultSetUpdate
> xUpdateCursor((Reference
< XInterface
>)*m_pDataCursor
, UNO_QUERY
);
3316 xUpdateCursor
->insertRow();
3318 xUpdateCursor
->updateRow();
3319 bSuccess
= sal_True
;
3321 catch(SQLException
& e
)
3323 (void)e
; // make compiler happy
3325 m_bUpdating
= sal_False
;
3333 // if we are appending we still sit on the insert row
3334 // we don't move just clear the flags not to move on the current row
3335 m_xCurrentRow
->SetState(m_pDataCursor
, sal_False
);
3336 TRACE_RANGE_MESSAGE1("explicit SetState after a successfull update, new state : %s", ROWSTATUS(m_xCurrentRow
));
3337 m_xCurrentRow
->SetNew(sal_False
);
3339 // adjust the seekcursor if it is on the same position as the datacursor
3340 if (m_nSeekPos
== m_nCurrentPos
|| bAppending
)
3342 // get the bookmark to refetch the data
3343 // in insert mode we take the new bookmark of the data cursor
3344 Any aBookmark
= bAppending
? m_pDataCursor
->getBookmark() : m_pSeekCursor
->getBookmark();
3345 m_pSeekCursor
->moveToBookmark(aBookmark
);
3347 m_xSeekRow
->SetState(m_pSeekCursor
, sal_True
);
3348 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
3351 // and repaint the row
3352 RowModified(m_nCurrentPos
);
3358 m_bUpdating
= sal_False
;
3361 // The old code returned (nRecords != 0) here.
3362 // Me thinks this is wrong : If something goes wrong while update the record, an exception will be thrown,
3363 // which results in a "return sal_False" (see above). If no exception is thrown, everything is fine. If nRecords
3364 // is zero, this simply means all fields had their original values.
3365 // FS - 06.12.99 - 70502
3369 //------------------------------------------------------------------------------
3370 long DbGridControl::PreNotify(NotifyEvent
& rEvt
)
3372 // keine Events der Navbar behandeln
3373 if (m_aBar
.IsWindowOrChild(rEvt
.GetWindow()))
3374 return BrowseBox::PreNotify(rEvt
);
3376 switch (rEvt
.GetType())
3378 case EVENT_KEYINPUT
:
3380 const KeyEvent
* pKeyEvent
= rEvt
.GetKeyEvent();
3382 sal_uInt16 nCode
= pKeyEvent
->GetKeyCode().GetCode();
3383 sal_Bool bShift
= pKeyEvent
->GetKeyCode().IsShift();
3384 sal_Bool bCtrl
= pKeyEvent
->GetKeyCode().IsMod1();
3385 sal_Bool bAlt
= pKeyEvent
->GetKeyCode().IsMod2();
3386 if ( ( KEY_TAB
== nCode
) && bCtrl
&& !bAlt
)
3388 // Ctrl-Tab is used to step out of the control, without traveling to the
3389 // remaining cells first
3390 // -> build a new key event without the Ctrl-key, and let the very base class handle it
3391 KeyCode
aNewCode( KEY_TAB
, bShift
, sal_False
, sal_False
, sal_False
);
3392 KeyEvent
aNewEvent( pKeyEvent
->GetCharCode(), aNewCode
);
3394 // call the Control - our direct base class will interpret this in a way we do not want (and do
3395 // a cell traveling)
3396 Control::KeyInput( aNewEvent
);
3400 if ( !bShift
&& !bCtrl
&& ( KEY_ESCAPE
== nCode
) )
3408 else if ( ( KEY_DELETE
== nCode
) && !bShift
&& !bCtrl
) // delete rows
3410 if ((m_nOptions
& OPT_DELETE
) && GetSelectRowCount())
3414 Application::RemoveUserEvent(m_nDeleteEvent
);
3415 m_nDeleteEvent
= Application::PostUserEvent(LINK(this,DbGridControl
,OnDelete
));
3421 return DbGridControl_Base::PreNotify(rEvt
);
3425 //------------------------------------------------------------------------------
3426 sal_Bool
DbGridControl::IsTabAllowed(sal_Bool bRight
) const
3429 // Tab nur wenn nicht auf der letzten Zelle
3430 return GetCurRow() < (GetRowCount() - 1) || !m_bRecordCountFinal
||
3431 GetViewColumnPos(GetCurColumnId()) < (GetViewColCount() - 1);
3434 // Tab nur wenn nicht auf der ersten Zelle
3435 return GetCurRow() > 0 || (GetCurColumnId() && GetViewColumnPos(GetCurColumnId()) > 0);
3439 //------------------------------------------------------------------------------
3440 void DbGridControl::KeyInput( const KeyEvent
& rEvt
)
3442 if (rEvt
.GetKeyCode().GetFunction() == KEYFUNC_COPY
)
3444 long nRow
= GetCurRow();
3445 sal_uInt16 nColId
= GetCurColumnId();
3446 if (nRow
>= 0 && nRow
< GetRowCount() && nColId
< ColCount())
3448 DbGridColumn
* pColumn
= m_aColumns
.GetObject(GetModelColumnPos(nColId
));
3449 OStringTransfer::CopyString( GetCurrentRowCellText( pColumn
,m_xPaintRow
), this );
3453 DbGridControl_Base::KeyInput(rEvt
);
3456 //------------------------------------------------------------------------------
3457 void DbGridControl::HideColumn(sal_uInt16 nId
)
3461 // determine the col for the focus to set to after removal
3462 sal_uInt16 nPos
= GetViewColumnPos(nId
);
3463 sal_uInt16 nNewColId
= nPos
== (ColCount()-1)
3464 ? GetColumnIdFromViewPos(nPos
-1) // last col is to be removed -> take the previous
3465 : GetColumnIdFromViewPos(nPos
+1); // take the next
3467 long lCurrentWidth
= GetColumnWidth(nId
);
3468 DbGridControl_Base::RemoveColumn(nId
);
3469 // don't use my own RemoveColumn, this would remove it from m_aColumns, too
3472 DbGridColumn
* pColumn
= m_aColumns
.GetObject(GetModelColumnPos(nId
));
3473 DBG_ASSERT(pColumn
, "DbGridControl::HideColumn : somebody did hide a nonexistent column !");
3476 pColumn
->m_bHidden
= sal_True
;
3477 pColumn
->m_nLastVisibleWidth
= CalcReverseZoom(lCurrentWidth
);
3480 // and reset the focus
3481 if ( nId
== GetCurColumnId() )
3482 GoToColumnId( nNewColId
);
3485 //------------------------------------------------------------------------------
3486 void DbGridControl::ShowColumn(sal_uInt16 nId
)
3488 sal_uInt16 nPos
= GetModelColumnPos(nId
);
3489 DBG_ASSERT(nPos
!= (sal_uInt16
)-1, "DbGridControl::ShowColumn : invalid argument !");
3490 if (nPos
== (sal_uInt16
)-1)
3493 DbGridColumn
* pColumn
= m_aColumns
.GetObject(nPos
);
3494 if (!pColumn
->IsHidden())
3496 DBG_ASSERT(GetViewColumnPos(nId
) != (sal_uInt16
)-1, "DbGridControl::ShowColumn : inconsistent internal state !");
3497 // if the column isn't marked as hidden, it should be visible, shouldn't it ?
3500 DBG_ASSERT(GetViewColumnPos(nId
) == (sal_uInt16
)-1, "DbGridControl::ShowColumn : inconsistent internal state !");
3501 // the opposite situation ...
3503 // to determine the new view position we need an adjacent non-hidden column
3504 sal_uInt16 nNextNonHidden
= (sal_uInt16
)-1;
3505 // first search the cols to the right
3506 for (sal_uInt16 i
= nPos
+ 1; i
<m_aColumns
.Count(); ++i
)
3508 DbGridColumn
* pCurCol
= m_aColumns
.GetObject(i
);
3509 if (!pCurCol
->IsHidden())
3515 if ((nNextNonHidden
== (sal_uInt16
)-1) && (nPos
> 0))
3518 for (sal_uInt16 i
= nPos
; i
>0; --i
)
3520 DbGridColumn
* pCurCol
= m_aColumns
.GetObject(i
-1);
3521 if (!pCurCol
->IsHidden())
3523 nNextNonHidden
= i
-1;
3528 sal_uInt16 nNewViewPos
= (nNextNonHidden
== (sal_uInt16
)-1)
3529 ? 1 // there is no visible column -> insert behinde the handle col
3530 : GetViewColumnPos(m_aColumns
.GetObject(nNextNonHidden
)->GetId()) + 1;
3531 // the first non-handle col has "view pos" 0, but the pos arg for InsertDataColumn expects
3532 // a position 1 for the first non-handle col -> +1
3533 DBG_ASSERT(nNewViewPos
!= (sal_uInt16
)-1, "DbGridControl::ShowColumn : inconsistent internal state !");
3534 // we found a col marked as visible but got no view pos for it ...
3536 if ((nNextNonHidden
<nPos
) && (nNextNonHidden
!= (sal_uInt16
)-1))
3537 // nNextNonHidden is a column to the left, so we want to insert the new col _right_ beside it's pos
3542 ::rtl::OUString aName
;
3543 pColumn
->getModel()->getPropertyValue(FM_PROP_LABEL
) >>= aName
;
3544 InsertDataColumn(nId
, aName
, CalcZoom(pColumn
->m_nLastVisibleWidth
), HIB_CENTER
| HIB_VCENTER
| HIB_CLICKABLE
, nNewViewPos
);
3545 pColumn
->m_bHidden
= sal_False
;
3551 //------------------------------------------------------------------------------
3552 sal_uInt16
DbGridControl::GetColumnIdFromModelPos( sal_uInt16 nPos
) const
3554 if (nPos
>= m_aColumns
.Count())
3556 DBG_ERROR("DbGridControl::GetColumnIdFromModelPos : invalid argument !");
3557 return (sal_uInt16
)-1;
3560 DbGridColumn
* pCol
= m_aColumns
.GetObject(nPos
);
3561 #if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
3562 // in der Debug-Version rechnen wir die ModelPos in eine ViewPos um und vergleichen das mit dem Wert,
3563 // den wir zurueckliefern werden (nId an der entsprechenden Col in m_aColumns)
3565 if (!pCol
->IsHidden())
3566 { // macht nur Sinn, wenn die Spalte sichtbar ist
3567 sal_uInt16 nViewPos
= nPos
;
3568 for (sal_uInt16 i
=0; i
<m_aColumns
.Count() && i
<nPos
; ++i
)
3569 if (m_aColumns
.GetObject(i
)->IsHidden())
3572 DBG_ASSERT(pCol
&& GetColumnIdFromViewPos(nViewPos
) == pCol
->GetId(),
3573 "DbGridControl::GetColumnIdFromModelPos : this isn't consistent .... did I misunderstand something ?");
3576 return pCol
->GetId();
3579 //------------------------------------------------------------------------------
3580 sal_uInt16
DbGridControl::GetModelColumnPos( sal_uInt16 nId
) const
3582 for (sal_uInt16 i
=0; i
<m_aColumns
.Count(); ++i
)
3583 if (m_aColumns
.GetObject(i
)->GetId() == nId
)
3586 return GRID_COLUMN_NOT_FOUND
;
3589 //------------------------------------------------------------------------------
3590 void DbGridControl::implAdjustInSolarThread(BOOL _bRows
)
3592 TRACE_RANGE("DbGridControl::implAdjustInSolarThread");
3593 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
3594 if (::vos::OThread::getCurrentIdentifier() != Application::GetMainThreadIdentifier())
3596 m_nAsynAdjustEvent
= PostUserEvent(LINK(this, DbGridControl
, OnAsyncAdjust
), reinterpret_cast< void* >( _bRows
));
3597 m_bPendingAdjustRows
= _bRows
;
3600 TRACE_RANGE_MESSAGE("posting an AdjustRows")
3602 TRACE_RANGE_MESSAGE("posting an AdjustDataSource")
3609 TRACE_RANGE_MESSAGE("doing an AdjustRows")
3611 TRACE_RANGE_MESSAGE("doing an AdjustDataSource")
3613 // always adjust the rows before adjusting the data source
3614 // If this is not necessary (because the row count did not change), nothing is done
3615 // The problem is that we can't rely on the order of which the calls come in: If the cursor was moved
3616 // to a position behind row count know 'til now, the cursorMoved notification may come before the
3617 // RowCountChanged notification
3618 // 94093 - 02.11.2001 - frank.schoenheit@sun.com
3626 //------------------------------------------------------------------------------
3627 IMPL_LINK(DbGridControl
, OnAsyncAdjust
, void*, pAdjustWhat
)
3629 m_nAsynAdjustEvent
= 0;
3632 // see implAdjustInSolarThread for a comment why we do this every time
3640 //------------------------------------------------------------------------------
3641 void DbGridControl::BeginCursorAction()
3643 if (m_pFieldListeners
)
3645 ColumnFieldValueListeners
* pListeners
= (ColumnFieldValueListeners
*)m_pFieldListeners
;
3646 ConstColumnFieldValueListenersIterator aIter
= pListeners
->begin();
3647 while (aIter
!= pListeners
->end())
3649 GridFieldValueListener
* pCurrent
= (*aIter
).second
;
3651 pCurrent
->suspend();
3656 if (m_pDataSourcePropListener
)
3657 m_pDataSourcePropListener
->suspend();
3660 //------------------------------------------------------------------------------
3661 void DbGridControl::EndCursorAction()
3663 if (m_pFieldListeners
)
3665 ColumnFieldValueListeners
* pListeners
= (ColumnFieldValueListeners
*)m_pFieldListeners
;
3666 ConstColumnFieldValueListenersIterator aIter
= pListeners
->begin();
3667 while (aIter
!= pListeners
->end())
3669 GridFieldValueListener
* pCurrent
= (*aIter
).second
;
3676 if (m_pDataSourcePropListener
)
3677 m_pDataSourcePropListener
->resume();
3680 //------------------------------------------------------------------------------
3681 void DbGridControl::ConnectToFields()
3683 ColumnFieldValueListeners
* pListeners
= (ColumnFieldValueListeners
*)m_pFieldListeners
;
3684 DBG_ASSERT(!pListeners
|| pListeners
->size() == 0, "DbGridControl::ConnectToFields : please call DisconnectFromFields first !");
3688 pListeners
= new ColumnFieldValueListeners
;
3689 m_pFieldListeners
= pListeners
;
3692 for (sal_Int32 i
=0; i
<(sal_Int32
)m_aColumns
.Count(); ++i
)
3694 DbGridColumn
* pCurrent
= m_aColumns
.GetObject(i
);
3695 sal_uInt16 nViewPos
= pCurrent
? GetViewColumnPos(pCurrent
->GetId()) : (sal_uInt16
)-1;
3696 if ((sal_uInt16
)-1 == nViewPos
)
3699 Reference
< XPropertySet
> xField
= pCurrent
->GetField();
3703 // column is visible and bound here
3704 GridFieldValueListener
*& rpListener
= (*pListeners
)[pCurrent
->GetId()];
3705 DBG_ASSERT(!rpListener
, "DbGridControl::ConnectToFields : already a listener for this column ?!");
3706 rpListener
= new GridFieldValueListener(*this, xField
, pCurrent
->GetId());
3710 //------------------------------------------------------------------------------
3711 void DbGridControl::DisconnectFromFields()
3713 if (!m_pFieldListeners
)
3716 ColumnFieldValueListeners
* pListeners
= (ColumnFieldValueListeners
*)m_pFieldListeners
;
3717 while (pListeners
->size())
3720 sal_Int32 nOldSize
= pListeners
->size();
3722 pListeners
->begin()->second
->dispose();
3723 DBG_ASSERT(nOldSize
> (sal_Int32
)pListeners
->size(), "DbGridControl::DisconnectFromFields : dispose on a listener should result in a removal from my list !");
3727 m_pFieldListeners
= NULL
;
3730 //------------------------------------------------------------------------------
3731 void DbGridControl::FieldValueChanged(sal_uInt16 _nId
, const PropertyChangeEvent
& /*_evt*/)
3733 osl::MutexGuard
aPreventDestruction(m_aDestructionSafety
);
3734 // needed as this may run in a thread other than the main one
3735 if (GetRowStatus(GetCurRow()) != DbGridControl_Base::MODIFIED
)
3736 // all other cases are handled elsewhere
3739 DbGridColumn
* pColumn
= m_aColumns
.GetObject(GetModelColumnPos(_nId
));
3742 sal_Bool bAcquiredPaintSafety
= sal_False
;
3743 while (!m_bWantDestruction
&& !bAcquiredPaintSafety
)
3744 bAcquiredPaintSafety
= Application::GetSolarMutex().tryToAcquire();
3746 if (m_bWantDestruction
)
3747 { // at this moment, within another thread, our destructor tries to destroy the listener which called this method
3748 // => don't do anything
3749 // 73365 - 23.02.00 - FS
3750 if (bAcquiredPaintSafety
)
3751 // though the above while-loop suggests that (m_bWantDestruction && bAcquiredPaintSafety) is impossible,
3752 // it isnt't, as m_bWantDestruction isn't protected with any mutex
3753 Application::GetSolarMutex().release();
3756 // here we got the solar mutex, transfer it to a guard for safety reasons
3757 ::vos::OGuard
aPaintSafety(Application::GetSolarMutex());
3758 Application::GetSolarMutex().release();
3760 // and finally do the update ...
3761 pColumn
->UpdateFromField(m_xCurrentRow
, m_xFormatter
);
3762 RowModified(GetCurRow(), _nId
);
3766 //------------------------------------------------------------------------------
3767 void DbGridControl::FieldListenerDisposing(sal_uInt16 _nId
)
3769 ColumnFieldValueListeners
* pListeners
= (ColumnFieldValueListeners
*)m_pFieldListeners
;
3772 DBG_ERROR("DbGridControl::FieldListenerDisposing : invalid call (have no listener array) !");
3776 ColumnFieldValueListenersIterator aPos
= pListeners
->find(_nId
);
3777 if (aPos
== pListeners
->end())
3779 DBG_ERROR("DbGridControl::FieldListenerDisposing : invalid call (did not find the listener) !");
3783 delete aPos
->second
;
3785 pListeners
->erase(aPos
);
3788 //------------------------------------------------------------------------------
3789 void DbGridControl::disposing(sal_uInt16 _nId
, const EventObject
& /*_rEvt*/)
3792 { // the seek cursor is beeing disposed
3793 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
3794 setDataSource(NULL
,0); // our clone was disposed so we set our datasource to null to avoid later acces to it
3795 if (m_nAsynAdjustEvent
)
3797 RemoveUserEvent(m_nAsynAdjustEvent
);
3798 m_nAsynAdjustEvent
= 0;
3802 // -----------------------------------------------------------------------------
3803 sal_Int32
DbGridControl::GetAccessibleControlCount() const
3805 return DbGridControl_Base::GetAccessibleControlCount() + 1; // the navigation control
3807 // -----------------------------------------------------------------------------
3808 Reference
<XAccessible
> DbGridControl::CreateAccessibleControl( sal_Int32 _nIndex
)
3810 Reference
<XAccessible
> xRet
;
3811 if ( _nIndex
== DbGridControl_Base::GetAccessibleControlCount() )
3813 xRet
= m_aBar
.GetAccessible();
3816 xRet
= DbGridControl_Base::CreateAccessibleControl( _nIndex
);
3819 // -----------------------------------------------------------------------------
3820 Reference
< XAccessible
> DbGridControl::CreateAccessibleCell( sal_Int32 _nRow
, sal_uInt16 _nColumnPos
)
3822 USHORT nColumnId
= GetColumnId( _nColumnPos
);
3823 DbGridColumn
* pColumn
= m_aColumns
.GetObject(GetModelColumnPos(nColumnId
));
3826 Reference
< ::com::sun::star::awt::XControl
> xInt(pColumn
->GetCell());
3827 Reference
< ::com::sun::star::awt::XCheckBox
> xBox(xInt
,UNO_QUERY
);
3830 TriState eValue
= STATE_NOCHECK
;
3831 switch( xBox
->getState() )
3834 eValue
= STATE_NOCHECK
;
3837 eValue
= STATE_CHECK
;
3840 eValue
= STATE_DONTKNOW
;
3843 return DbGridControl_Base::CreateAccessibleCheckBoxCell( _nRow
, _nColumnPos
,eValue
,TRUE
);
3846 return DbGridControl_Base::CreateAccessibleCell( _nRow
, _nColumnPos
);
3848 // -----------------------------------------------------------------------------