1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/macros.h>
23 #include <svx/gridctrl.hxx>
24 #include "gridcell.hxx"
25 #include "svx/dbtoolsclient.hxx"
26 #include "svx/fmtools.hxx"
27 #include <svtools/stringtransfer.hxx>
30 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
31 #include <com/sun/star/accessibility/XAccessible.hpp>
32 #include <com/sun/star/sdb/XResultSetAccess.hpp>
33 #include <com/sun/star/sdb/RowChangeAction.hpp>
34 #include <com/sun/star/sdb/XRowsChangeBroadcaster.hpp>
35 #include <com/sun/star/sdbc/XResultSetUpdate.hpp>
36 #include <com/sun/star/sdbcx/Privilege.hpp>
37 #include <com/sun/star/container/XChild.hpp>
38 #include <com/sun/star/util/NumberFormatter.hpp>
39 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
40 #include <com/sun/star/util/XCloneable.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
43 #include <comphelper/extract.hxx>
44 #include <comphelper/processfactory.hxx>
45 #include <tools/resid.hxx>
46 #include <tools/diagnose_ex.h>
47 #include <vcl/menu.hxx>
49 #include "svx/fmresids.hrc"
51 #include <svx/svxids.hrc>
52 #include <tools/shl.hxx>
53 #include <svx/dialmgr.hxx>
54 #include "fmservs.hxx"
55 #include "sdbdatacolumn.hxx"
57 #include <comphelper/stl_types.hxx>
58 #include <comphelper/property.hxx>
62 using namespace ::svxform
;
63 using namespace ::svt
;
64 using namespace ::com::sun::star::beans
;
65 using namespace ::com::sun::star::lang
;
66 using namespace ::com::sun::star::uno
;
67 using namespace ::com::sun::star::sdbc
;
68 using namespace ::com::sun::star::sdbcx
;
69 using namespace ::com::sun::star::sdb
;
70 using namespace ::com::sun::star::datatransfer
;
71 using namespace ::com::sun::star::container
;
72 using namespace com::sun::star::accessibility
;
74 #define ROWSTATUS(row) (!row.Is() ? "NULL" : row->GetStatus() == GRS_CLEAN ? "CLEAN" : row->GetStatus() == GRS_MODIFIED ? "MODIFIED" : row->GetStatus() == GRS_DELETED ? "DELETED" : "INVALID")
77 #define DEFAULT_BROWSE_MODE \
78 BROWSER_COLUMNSELECTION \
79 | BROWSER_MULTISELECTION \
80 | BROWSER_KEEPSELECTION \
81 | BROWSER_TRACKING_TIPS \
82 | BROWSER_HLINESFULL \
83 | BROWSER_VLINESFULL \
84 | BROWSER_HEADERBAR_NEW \
86 class RowSetEventListener : public ::cppu::WeakImplHelper1<XRowsChangeListener>
88 DbGridControl
* m_pControl
;
90 RowSetEventListener(DbGridControl
* i_pControl
) : m_pControl(i_pControl
)
95 virtual void SAL_CALL
disposing(const ::com::sun::star::lang::EventObject
& /*i_aEvt*/) throw ( RuntimeException
)
98 virtual void SAL_CALL
rowsChanged(const ::com::sun::star::sdb::RowsChangeEvent
& i_aEvt
) throw ( RuntimeException
)
100 if ( i_aEvt
.Action
== RowChangeAction::UPDATE
)
102 ::DbGridControl::GrantControlAccess aAccess
;
103 CursorWrapper
* pSeek
= m_pControl
->GetSeekCursor(aAccess
);
104 const DbGridRowRef
& rSeekRow
= m_pControl
->GetSeekRow(aAccess
);
105 const Any
* pIter
= i_aEvt
.Bookmarks
.getConstArray();
106 const Any
* pEnd
= pIter
+ i_aEvt
.Bookmarks
.getLength();
107 for(;pIter
!= pEnd
;++pIter
)
109 pSeek
->moveToBookmark(*pIter
);
111 rSeekRow
->SetState(pSeek
, sal_True
);
112 sal_Int32 nSeekPos
= pSeek
->getRow() - 1;
113 m_pControl
->SetSeekPos(nSeekPos
,aAccess
);
114 m_pControl
->RowModified(nSeekPos
);
119 //==============================================================================
121 class GridFieldValueListener
;
122 DECLARE_STL_MAP(sal_uInt16
, GridFieldValueListener
*, ::std::less
<sal_uInt16
>, ColumnFieldValueListeners
);
124 //==============================================================================
126 DBG_NAME(GridFieldValueListener
)
127 class GridFieldValueListener
: protected ::comphelper::OPropertyChangeListener
130 DbGridControl
& m_rParent
;
131 ::comphelper::OPropertyChangeMultiplexer
* m_pRealListener
;
133 sal_Int16 m_nSuspended
;
134 sal_Bool m_bDisposed
: 1;
137 GridFieldValueListener(DbGridControl
& _rParent
, const Reference
< XPropertySet
>& xField
, sal_uInt16 _nId
);
138 virtual ~GridFieldValueListener();
140 virtual void _propertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
);
142 void suspend() { ++m_nSuspended
; }
143 void resume() { --m_nSuspended
; }
147 //------------------------------------------------------------------------------
148 GridFieldValueListener::GridFieldValueListener(DbGridControl
& _rParent
, const Reference
< XPropertySet
>& _rField
, sal_uInt16 _nId
)
149 :OPropertyChangeListener(m_aMutex
)
151 ,m_pRealListener(NULL
)
154 ,m_bDisposed(sal_False
)
156 DBG_CTOR(GridFieldValueListener
, NULL
);
159 m_pRealListener
= new ::comphelper::OPropertyChangeMultiplexer(this, _rField
);
160 m_pRealListener
->addProperty(FM_PROP_VALUE
);
161 m_pRealListener
->acquire();
165 //------------------------------------------------------------------------------
166 GridFieldValueListener::~GridFieldValueListener()
168 DBG_DTOR(GridFieldValueListener
, NULL
);
172 //------------------------------------------------------------------------------
173 void GridFieldValueListener::_propertyChanged(const PropertyChangeEvent
& _evt
) throw( RuntimeException
)
175 DBG_ASSERT(m_nSuspended
>=0, "GridFieldValueListener::_propertyChanged : resume > suspend !");
176 if (m_nSuspended
<= 0)
177 m_rParent
.FieldValueChanged(m_nId
, _evt
);
180 //------------------------------------------------------------------------------
181 void GridFieldValueListener::dispose()
185 DBG_ASSERT(m_pRealListener
== NULL
, "GridFieldValueListener::dispose : inconsistent !");
191 m_pRealListener
->dispose();
192 m_pRealListener
->release();
193 m_pRealListener
= NULL
;
196 m_bDisposed
= sal_True
;
197 m_rParent
.FieldListenerDisposing(m_nId
);
200 //==============================================================================
202 class DisposeListenerGridBridge
: public FmXDisposeListener
205 DbGridControl
& m_rParent
;
206 FmXDisposeMultiplexer
* m_pRealListener
;
209 DisposeListenerGridBridge( DbGridControl
& _rParent
, const Reference
< XComponent
>& _rxObject
, sal_Int16 _rId
= -1);
210 virtual ~DisposeListenerGridBridge();
212 virtual void disposing(const EventObject
& _rEvent
, sal_Int16 _nId
) throw( RuntimeException
) { m_rParent
.disposing(_nId
, _rEvent
); }
215 //==============================================================================
218 DBG_NAME(DisposeListenerGridBridge
)
219 //------------------------------------------------------------------------------
220 DisposeListenerGridBridge::DisposeListenerGridBridge(DbGridControl
& _rParent
, const Reference
< XComponent
>& _rxObject
, sal_Int16 _rId
)
221 :FmXDisposeListener(m_aMutex
)
223 ,m_pRealListener(NULL
)
225 DBG_CTOR(DisposeListenerGridBridge
,NULL
);
229 m_pRealListener
= new FmXDisposeMultiplexer(this, _rxObject
, _rId
);
230 m_pRealListener
->acquire();
234 //------------------------------------------------------------------------------
235 DisposeListenerGridBridge::~DisposeListenerGridBridge()
239 m_pRealListener
->dispose();
240 m_pRealListener
->release();
241 m_pRealListener
= NULL
;
244 DBG_DTOR(DisposeListenerGridBridge
,NULL
);
247 //==============================================================================
249 static sal_uInt16 ControlMap
[] =
251 DbGridControl::NavigationBar::RECORD_TEXT
,
252 DbGridControl::NavigationBar::RECORD_ABSOLUTE
,
253 DbGridControl::NavigationBar::RECORD_OF
,
254 DbGridControl::NavigationBar::RECORD_COUNT
,
255 DbGridControl::NavigationBar::RECORD_FIRST
,
256 DbGridControl::NavigationBar::RECORD_NEXT
,
257 DbGridControl::NavigationBar::RECORD_PREV
,
258 DbGridControl::NavigationBar::RECORD_LAST
,
259 DbGridControl::NavigationBar::RECORD_NEW
,
263 //------------------------------------------------------------------------------
264 sal_Bool
CompareBookmark(const Any
& aLeft
, const Any
& aRight
)
266 return ::comphelper::compare(aLeft
, aRight
);
269 //==============================================================================
270 class FmXGridSourcePropListener
: public ::comphelper::OPropertyChangeListener
272 DbGridControl
* m_pParent
;
274 // a DbGridControl has no mutex, so we use our own as the base class expects one
276 sal_Int16 m_nSuspended
;
279 FmXGridSourcePropListener(DbGridControl
* _pParent
);
281 void suspend() { ++m_nSuspended
; }
282 void resume() { --m_nSuspended
; }
284 virtual void _propertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
);
287 //------------------------------------------------------------------------------
288 FmXGridSourcePropListener::FmXGridSourcePropListener(DbGridControl
* _pParent
)
289 :OPropertyChangeListener(m_aMutex
)
293 DBG_ASSERT(m_pParent
, "FmXGridSourcePropListener::FmXGridSourcePropListener : invalid parent !");
296 //------------------------------------------------------------------------------
297 void FmXGridSourcePropListener::_propertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
)
299 DBG_ASSERT(m_nSuspended
>=0, "FmXGridSourcePropListener::_propertyChanged : resume > suspend !");
300 if (m_nSuspended
<= 0)
301 m_pParent
->DataSourcePropertyChanged(evt
);
304 //==============================================================================
305 //------------------------------------------------------------------------------
306 DbGridControl::NavigationBar::AbsolutePos::AbsolutePos(Window
* pParent
, WinBits nStyle
)
307 :NumericField(pParent
, nStyle
)
314 SetStrictFormat(sal_True
);
317 //------------------------------------------------------------------------------
318 void DbGridControl::NavigationBar::AbsolutePos::KeyInput(const KeyEvent
& rEvt
)
320 if (rEvt
.GetKeyCode() == KEY_RETURN
&& !GetText().isEmpty())
322 sal_Int64 nRecord
= GetValue();
323 if (nRecord
< GetMin() || nRecord
> GetMax())
326 ((NavigationBar
*)GetParent())->PositionDataSource(static_cast<sal_Int32
>(nRecord
));
328 else if (rEvt
.GetKeyCode() == KEY_TAB
)
329 GetParent()->GetParent()->GrabFocus();
331 NumericField::KeyInput(rEvt
);
334 //------------------------------------------------------------------------------
335 void DbGridControl::NavigationBar::AbsolutePos::LoseFocus()
337 NumericField::LoseFocus();
338 sal_Int64 nRecord
= GetValue();
339 if (nRecord
< GetMin() || nRecord
> GetMax())
343 ((NavigationBar
*)GetParent())->PositionDataSource(static_cast<sal_Int32
>(nRecord
));
344 ((NavigationBar
*)GetParent())->InvalidateState(NavigationBar::RECORD_ABSOLUTE
);
348 //------------------------------------------------------------------------------
349 void DbGridControl::NavigationBar::PositionDataSource(sal_Int32 nRecord
)
353 // the MoveToPosition may cause a LoseFocus which would lead to a second MoveToPosition, so protect agains this
355 // 68167 - 13.08.99 - FS
356 m_bPositioning
= sal_True
;
357 ((DbGridControl
*)GetParent())->MoveToPosition(nRecord
- 1);
358 m_bPositioning
= sal_False
;
361 //------------------------------------------------------------------------------
362 DbGridControl::NavigationBar::NavigationBar(Window
* pParent
, WinBits nStyle
)
363 :Control(pParent
, nStyle
)
364 ,m_aRecordText(this, WB_VCENTER
)
365 ,m_aAbsolute(this, WB_CENTER
| WB_VCENTER
)
366 ,m_aRecordOf(this, WB_VCENTER
)
367 ,m_aRecordCount(this, WB_VCENTER
)
368 ,m_aFirstBtn(this, WB_RECTSTYLE
|WB_NOPOINTERFOCUS
)
369 ,m_aPrevBtn(this, WB_REPEAT
|WB_RECTSTYLE
|WB_NOPOINTERFOCUS
)
370 ,m_aNextBtn(this, WB_REPEAT
|WB_RECTSTYLE
|WB_NOPOINTERFOCUS
)
371 ,m_aLastBtn(this, WB_RECTSTYLE
|WB_NOPOINTERFOCUS
)
372 ,m_aNewBtn(this, WB_RECTSTYLE
|WB_NOPOINTERFOCUS
)
375 ,m_bPositioning(sal_False
)
377 m_aFirstBtn
.SetSymbol(SYMBOL_FIRST
);
378 m_aPrevBtn
.SetSymbol(SYMBOL_PREV
);
379 m_aNextBtn
.SetSymbol(SYMBOL_NEXT
);
380 m_aLastBtn
.SetSymbol(SYMBOL_LAST
);
381 m_aNewBtn
.SetModeImage(((DbGridControl
*)pParent
)->GetImage(DbGridControl_Base::NEW
));
383 m_aFirstBtn
.SetHelpId(HID_GRID_TRAVEL_FIRST
);
384 m_aPrevBtn
.SetHelpId(HID_GRID_TRAVEL_PREV
);
385 m_aNextBtn
.SetHelpId(HID_GRID_TRAVEL_NEXT
);
386 m_aLastBtn
.SetHelpId(HID_GRID_TRAVEL_LAST
);
387 m_aNewBtn
.SetHelpId(HID_GRID_TRAVEL_NEW
);
388 m_aAbsolute
.SetHelpId(HID_GRID_TRAVEL_ABSOLUTE
);
389 m_aRecordCount
.SetHelpId(HID_GRID_NUMBEROFRECORDS
);
391 // Handler fuer Buttons einrichten
392 m_aFirstBtn
.SetClickHdl(LINK(this,NavigationBar
,OnClick
));
393 m_aPrevBtn
.SetClickHdl(LINK(this,NavigationBar
,OnClick
));
394 m_aNextBtn
.SetClickHdl(LINK(this,NavigationBar
,OnClick
));
395 m_aLastBtn
.SetClickHdl(LINK(this,NavigationBar
,OnClick
));
396 m_aNewBtn
.SetClickHdl(LINK(this,NavigationBar
,OnClick
));
398 m_aRecordText
.SetText(XubString(SVX_RES(RID_STR_REC_TEXT
)));
399 m_aRecordOf
.SetText(XubString(SVX_RES(RID_STR_REC_FROM_TEXT
)));
400 m_aRecordCount
.SetText(OUString('?'));
402 m_nDefaultWidth
= ArrangeControls();
404 m_aFirstBtn
.Disable();
405 m_aPrevBtn
.Disable();
406 m_aNextBtn
.Disable();
407 m_aLastBtn
.Disable();
409 m_aRecordText
.Disable();
410 m_aRecordOf
.Disable();
411 m_aRecordCount
.Disable();
412 m_aAbsolute
.Disable();
414 AllSettings aSettings
= m_aNextBtn
.GetSettings();
415 MouseSettings aMouseSettings
= aSettings
.GetMouseSettings();
416 aMouseSettings
.SetButtonRepeat(aMouseSettings
.GetButtonRepeat() / 4);
417 aSettings
.SetMouseSettings(aMouseSettings
);
418 m_aNextBtn
.SetSettings(aSettings
, sal_True
);
419 m_aPrevBtn
.SetSettings(aSettings
, sal_True
);
426 m_aRecordText
.Show();
428 m_aRecordCount
.Show();
434 void SetPosAndSize(Button
& _rButton
,Point
& _rPos
,const Size
& _rSize
)
436 _rButton
.SetPosPixel( _rPos
);
437 _rButton
.SetSizePixel( _rSize
);
438 _rPos
.X() += (sal_uInt16
)_rSize
.Width();
441 //------------------------------------------------------------------------------
442 sal_uInt16
DbGridControl::NavigationBar::ArrangeControls()
444 // Positionierung der Controls
445 // Basisgroessen ermitteln
446 Rectangle
aRect(((DbGridControl
*)GetParent())->GetControlArea());
447 const long nH
= aRect
.GetSize().Height();
448 Size aBorder
= LogicToPixel(Size(2, 2),MAP_APPFONT
);
449 aBorder
= Size(CalcZoom(aBorder
.Width()), CalcZoom(aBorder
.Height()));
453 // Ist der Font des Edits groesser als das Feld?
454 if (m_aAbsolute
.GetTextHeight() > nH
)
456 Font
aApplFont (m_aAbsolute
.GetFont());
457 const Size
pointAbsoluteSize(m_aAbsolute
.PixelToLogic( Size( 0, nH
- 2 ), MapMode(MAP_POINT
) ));
458 aApplFont
.SetSize( pointAbsoluteSize
);
459 m_aAbsolute
.SetControlFont( aApplFont
);
461 aApplFont
.SetTransparent( sal_True
);
462 m_aRecordText
.SetControlFont( aApplFont
);
463 m_aRecordOf
.SetControlFont( aApplFont
);
464 m_aRecordCount
.SetControlFont( aApplFont
);
467 // Controls Groessen und Positionen setzen
469 XubString aText
= m_aRecordText
.GetText();
470 long nTextWidth
= m_aRecordText
.GetTextWidth(aText
);
471 m_aRecordText
.SetPosPixel(Point(nX
,nY
));
472 m_aRecordText
.SetSizePixel(Size(nTextWidth
,nH
));
473 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ nTextWidth
+ aBorder
.Width());
475 // count an extra hairspace (U+200A) left and right
476 const OUString
sevenDigits(m_aAbsolute
.CreateFieldText(6000000));
477 const OUString
hairSpace(static_cast<sal_Unicode
>(0x200A));
478 OUString
textPattern(hairSpace
);
479 textPattern
+= sevenDigits
;
480 textPattern
+= hairSpace
;
481 nTextWidth
= m_aAbsolute
.GetTextWidth( textPattern
);
482 m_aAbsolute
.SetPosPixel(Point(nX
,nY
));
483 m_aAbsolute
.SetSizePixel(Size(nTextWidth
, nH
));
484 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ nTextWidth
+ aBorder
.Width());
486 aText
= m_aRecordOf
.GetText();
487 nTextWidth
= m_aRecordOf
.GetTextWidth(aText
);
488 m_aRecordOf
.SetPosPixel(Point(nX
,nY
));
489 m_aRecordOf
.SetSizePixel(Size(nTextWidth
,nH
));
490 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ nTextWidth
+ aBorder
.Width());
492 textPattern
= sevenDigits
+ " * (" + sevenDigits
+ ")";
493 nTextWidth
= m_aRecordCount
.GetTextWidth( textPattern
);
494 m_aRecordCount
.SetPosPixel(Point(nX
,nY
));
495 m_aRecordCount
.SetSizePixel(Size(nTextWidth
,nH
));
496 nX
= sal::static_int_cast
< sal_uInt16
>(nX
+ nTextWidth
+ aBorder
.Width());
498 Point
aButtonPos(nX
,nY
);
499 const Size
aButtonSize(nH
,nH
);
500 SetPosAndSize(m_aFirstBtn
, aButtonPos
, aButtonSize
);
501 SetPosAndSize(m_aPrevBtn
, aButtonPos
, aButtonSize
);
502 SetPosAndSize(m_aNextBtn
, aButtonPos
, aButtonSize
);
503 SetPosAndSize(m_aLastBtn
, aButtonPos
, aButtonSize
);
504 SetPosAndSize(m_aNewBtn
, aButtonPos
, aButtonSize
);
506 nX
= sal::static_int_cast
< sal_uInt16
>(aButtonPos
.X() + 1);
511 //------------------------------------------------------------------------------
512 IMPL_LINK(DbGridControl::NavigationBar
, OnClick
, Button
*, pButton
)
514 DbGridControl
* pParent
= (DbGridControl
*)GetParent();
516 if (pParent
->m_aMasterSlotExecutor
.IsSet())
519 if (pButton
== &m_aFirstBtn
)
520 lResult
= pParent
->m_aMasterSlotExecutor
.Call((void*)RECORD_FIRST
);
521 else if( pButton
== &m_aPrevBtn
)
522 lResult
= pParent
->m_aMasterSlotExecutor
.Call((void*)RECORD_PREV
);
523 else if( pButton
== &m_aNextBtn
)
524 lResult
= pParent
->m_aMasterSlotExecutor
.Call((void*)RECORD_NEXT
);
525 else if( pButton
== &m_aLastBtn
)
526 lResult
= pParent
->m_aMasterSlotExecutor
.Call((void*)RECORD_LAST
);
527 else if( pButton
== &m_aNewBtn
)
528 lResult
= pParent
->m_aMasterSlotExecutor
.Call((void*)RECORD_NEW
);
531 // the link already handled it
535 if (pButton
== &m_aFirstBtn
)
536 pParent
->MoveToFirst();
537 else if( pButton
== &m_aPrevBtn
)
538 pParent
->MoveToPrev();
539 else if( pButton
== &m_aNextBtn
)
540 pParent
->MoveToNext();
541 else if( pButton
== &m_aLastBtn
)
542 pParent
->MoveToLast();
543 else if( pButton
== &m_aNewBtn
)
544 pParent
->AppendNew();
548 //------------------------------------------------------------------------------
549 void DbGridControl::NavigationBar::InvalidateAll(sal_Int32 nCurrentPos
, sal_Bool bAll
)
551 if (m_nCurrentPos
!= nCurrentPos
|| nCurrentPos
< 0 || bAll
)
553 DbGridControl
* pParent
= (DbGridControl
*)GetParent();
555 sal_Int32 nAdjustedRowCount
= pParent
->GetRowCount() - ((pParent
->GetOptions() & DbGridControl::OPT_INSERT
) ? 2 : 1);
557 // Wann muß alles invalidiert werden
558 bAll
= bAll
|| m_nCurrentPos
<= 0;
559 bAll
= bAll
|| nCurrentPos
<= 0;
560 bAll
= bAll
|| m_nCurrentPos
>= nAdjustedRowCount
;
561 bAll
= bAll
|| nCurrentPos
>= nAdjustedRowCount
;
565 m_nCurrentPos
= nCurrentPos
;
567 while (ControlMap
[i
])
568 SetState(ControlMap
[i
++]);
570 else // befindet sich in der Mitte
572 m_nCurrentPos
= nCurrentPos
;
573 SetState(NavigationBar::RECORD_COUNT
);
574 SetState(NavigationBar::RECORD_ABSOLUTE
);
579 //------------------------------------------------------------------------------
580 sal_Bool
DbGridControl::NavigationBar::GetState(sal_uInt16 nWhich
) const
582 DbGridControl
* pParent
= (DbGridControl
*)GetParent();
584 if (!pParent
->IsOpen() || pParent
->IsDesignMode() || !pParent
->IsEnabled()
585 || pParent
->IsFilterMode() )
589 // check if we have a master state provider
590 if (pParent
->m_aMasterStateProvider
.IsSet())
592 long nState
= pParent
->m_aMasterStateProvider
.Call(reinterpret_cast< void* >( nWhich
) );
597 sal_Bool bAvailable
= sal_True
;
601 case NavigationBar::RECORD_FIRST
:
602 case NavigationBar::RECORD_PREV
:
603 bAvailable
= m_nCurrentPos
> 0;
605 case NavigationBar::RECORD_NEXT
:
606 if(pParent
->m_bRecordCountFinal
)
608 bAvailable
= m_nCurrentPos
< pParent
->GetRowCount() - 1;
609 if (!bAvailable
&& pParent
->GetOptions() & DbGridControl::OPT_INSERT
)
610 bAvailable
= (m_nCurrentPos
== pParent
->GetRowCount() - 2) && pParent
->IsModified();
613 case NavigationBar::RECORD_LAST
:
614 if(pParent
->m_bRecordCountFinal
)
616 if (pParent
->GetOptions() & DbGridControl::OPT_INSERT
)
617 bAvailable
= pParent
->IsCurrentAppending() ? pParent
->GetRowCount() > 1 :
618 m_nCurrentPos
!= pParent
->GetRowCount() - 2;
620 bAvailable
= m_nCurrentPos
!= pParent
->GetRowCount() - 1;
623 case NavigationBar::RECORD_NEW
:
624 bAvailable
= (pParent
->GetOptions() & DbGridControl::OPT_INSERT
) && pParent
->GetRowCount() && m_nCurrentPos
< pParent
->GetRowCount() - 1;
626 case NavigationBar::RECORD_ABSOLUTE
:
627 bAvailable
= pParent
->GetRowCount() > 0;
634 //------------------------------------------------------------------------------
635 void DbGridControl::NavigationBar::SetState(sal_uInt16 nWhich
)
637 sal_Bool bAvailable
= GetState(nWhich
);
638 DbGridControl
* pParent
= (DbGridControl
*)GetParent();
642 case NavigationBar::RECORD_FIRST
:
645 case NavigationBar::RECORD_PREV
:
648 case NavigationBar::RECORD_NEXT
:
651 case NavigationBar::RECORD_LAST
:
654 case NavigationBar::RECORD_NEW
:
657 case NavigationBar::RECORD_ABSOLUTE
:
661 if (pParent
->m_nTotalCount
>= 0)
663 if (pParent
->IsCurrentAppending())
664 m_aAbsolute
.SetMax(pParent
->m_nTotalCount
+ 1);
666 m_aAbsolute
.SetMax(pParent
->m_nTotalCount
);
669 m_aAbsolute
.SetMax(LONG_MAX
);
671 m_aAbsolute
.SetValue(m_nCurrentPos
+ 1);
674 m_aAbsolute
.SetText(String());
676 case NavigationBar::RECORD_TEXT
:
677 pWnd
= &m_aRecordText
;
679 case NavigationBar::RECORD_OF
:
682 case NavigationBar::RECORD_COUNT
:
684 pWnd
= &m_aRecordCount
;
688 if (pParent
->GetOptions() & DbGridControl::OPT_INSERT
)
690 if (pParent
->IsCurrentAppending() && !pParent
->IsModified())
691 aText
= m_aAbsolute
.CreateFieldText(pParent
->GetRowCount());
693 aText
= m_aAbsolute
.CreateFieldText(pParent
->GetRowCount() - 1);
696 aText
= m_aAbsolute
.CreateFieldText(pParent
->GetRowCount());
697 if(!pParent
->m_bRecordCountFinal
)
698 aText
+= OUString(" *");
703 // add the number of selected rows, if applicable
704 if (pParent
->GetSelectRowCount())
706 String
aExtendedInfo(aText
);
707 aExtendedInfo
.AppendAscii(" (");
708 aExtendedInfo
+= m_aAbsolute
.CreateFieldText(pParent
->GetSelectRowCount());
709 aExtendedInfo
+= ')';
710 pWnd
->SetText(aExtendedInfo
);
713 pWnd
->SetText(aText
);
715 pParent
->SetRealRowCount(aText
);
718 DBG_ASSERT(pWnd
, "kein Fenster");
719 if (pWnd
&& (pWnd
->IsEnabled() != bAvailable
))
720 // this "pWnd->IsEnabled() != bAvailable" is a little hack : Window::Enable always generates a user
721 // event (ImplGenerateMouseMove) even if nothing happened. This may lead to some unwanted effects, so we
723 // For further explanation see Bug 69900.
724 pWnd
->Enable(bAvailable
);
727 //------------------------------------------------------------------------------
728 void DbGridControl::NavigationBar::Resize()
734 //------------------------------------------------------------------------------
735 void DbGridControl::NavigationBar::Paint(const Rectangle
& rRect
)
737 Control::Paint(rRect
);
738 Point aAbsolutePos
= m_aAbsolute
.GetPosPixel();
739 Size aAbsoluteSize
= m_aAbsolute
.GetSizePixel();
741 DrawLine(Point(aAbsolutePos
.X() - 1, 0 ),
742 Point(aAbsolutePos
.X() - 1, aAbsolutePos
.Y() + aAbsoluteSize
.Height()));
744 DrawLine(Point(aAbsolutePos
.X() + aAbsoluteSize
.Width() + 1, 0 ),
745 Point(aAbsolutePos
.X() + aAbsoluteSize
.Width() + 1, aAbsolutePos
.Y() + aAbsoluteSize
.Height()));
748 //------------------------------------------------------------------------------
749 void DbGridControl::NavigationBar::StateChanged( StateChangedType nType
)
751 Control::StateChanged( nType
);
753 Window
* pWindows
[] = { &m_aRecordText
,
766 case STATE_CHANGE_MIRRORING
:
768 sal_Bool bIsRTLEnabled
= IsRTLEnabled();
769 for ( size_t i
=0; i
< (sizeof (pWindows
) / sizeof(pWindows
[0])); ++i
)
770 pWindows
[i
]->EnableRTL( bIsRTLEnabled
);
774 case STATE_CHANGE_ZOOM
:
776 Fraction aZoom
= GetZoom();
778 // not all of these controls need to know the new zoom, but to be sure ...
779 Font
aFont( GetSettings().GetStyleSettings().GetFieldFont() );
780 if ( IsControlFont() )
781 aFont
.Merge( GetControlFont() );
783 for (size_t i
=0; i
< sizeof(pWindows
)/sizeof(pWindows
[0]); ++i
)
785 pWindows
[i
]->SetZoom(aZoom
);
786 pWindows
[i
]->SetZoomedPointFont(aFont
);
789 SetZoomedPointFont( aFont
);
791 // rearrange the controls
792 m_nDefaultWidth
= ArrangeControls();
798 //------------------------------------------------------------------------------
799 DbGridRow::DbGridRow(CursorWrapper
* pCur
, sal_Bool bPaintCursor
)
803 if (pCur
&& pCur
->Is())
805 Reference
< XIndexAccess
> xColumns(pCur
->getColumns(), UNO_QUERY
);
807 for (sal_Int32 i
= 0; i
< xColumns
->getCount(); ++i
)
809 Reference
< XPropertySet
> xColSet
;
810 ::cppu::extractInterface(xColSet
, xColumns
->getByIndex(i
));
811 pColumn
= new DataColumn(xColSet
);
812 m_aVariants
.push_back( pColumn
);
815 if (pCur
->rowDeleted())
816 m_eStatus
= GRS_DELETED
;
820 m_eStatus
= (pCur
->isAfterLast() || pCur
->isBeforeFirst()) ? GRS_INVALID
: GRS_CLEAN
;
823 Reference
< XPropertySet
> xSet
= pCur
->getPropertySet();
826 m_bIsNew
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISNEW
));
827 if (!m_bIsNew
&& (pCur
->isAfterLast() || pCur
->isBeforeFirst()))
828 m_eStatus
= GRS_INVALID
;
829 else if (::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISMODIFIED
)))
830 m_eStatus
= GRS_MODIFIED
;
832 m_eStatus
= GRS_CLEAN
;
835 m_eStatus
= GRS_INVALID
;
838 if (!m_bIsNew
&& IsValid())
839 m_aBookmark
= pCur
->getBookmark();
844 m_eStatus
= GRS_INVALID
;
847 //------------------------------------------------------------------------------
848 DbGridRow::~DbGridRow()
850 for ( size_t i
= 0, n
= m_aVariants
.size(); i
< n
; ++i
)
851 delete m_aVariants
[ i
];
855 //------------------------------------------------------------------------------
856 void DbGridRow::SetState(CursorWrapper
* pCur
, sal_Bool bPaintCursor
)
858 if (pCur
&& pCur
->Is())
860 if (pCur
->rowDeleted())
862 m_eStatus
= GRS_DELETED
;
863 m_bIsNew
= sal_False
;
867 m_eStatus
= GRS_CLEAN
;
870 Reference
< XPropertySet
> xSet
= pCur
->getPropertySet();
871 DBG_ASSERT(xSet
.is(), "DbGridRow::SetState : invalid cursor !");
873 if (::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISMODIFIED
)))
874 m_eStatus
= GRS_MODIFIED
;
875 m_bIsNew
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISNEW
));
878 m_bIsNew
= sal_False
;
883 if (!m_bIsNew
&& IsValid())
884 m_aBookmark
= pCur
->getBookmark();
890 DBG_UNHANDLED_EXCEPTION();
892 m_eStatus
= GRS_INVALID
;
893 m_bIsNew
= sal_False
;
899 m_eStatus
= GRS_INVALID
;
900 m_bIsNew
= sal_False
;
904 DBG_NAME(DbGridControl
);
905 //------------------------------------------------------------------------------
906 DbGridControl::DbGridControl(
907 Reference
< XComponentContext
> _rxContext
,
910 :DbGridControl_Base(pParent
, EBBF_NONE
, nBits
, DEFAULT_BROWSE_MODE
)
911 ,m_xContext(_rxContext
)
913 ,m_nAsynAdjustEvent(0)
914 ,m_pDataSourcePropMultiplexer(NULL
)
915 ,m_pDataSourcePropListener(NULL
)
916 ,m_pFieldListeners(NULL
)
917 ,m_pCursorDisposeListener(NULL
)
918 ,m_pGridListener(NULL
)
923 ,m_aNullDate(OTypeConversionClient().getStandardDate())
924 ,m_nMode(DEFAULT_BROWSE_MODE
)
927 ,m_nOptions(OPT_READONLY
)
928 ,m_nOptionMask(OPT_INSERT
| OPT_UPDATE
| OPT_DELETE
)
929 ,m_nLastColId((sal_uInt16
)-1)
931 ,m_bDesignMode(sal_False
)
932 ,m_bRecordCountFinal(sal_False
)
933 ,m_bMultiSelection(sal_True
)
934 ,m_bNavigationBar(sal_True
)
935 ,m_bSynchDisplay(sal_True
)
936 ,m_bForceROController(sal_False
)
938 ,m_bFilterMode(sal_False
)
939 ,m_bWantDestruction(sal_False
)
940 ,m_bInAdjustDataSource(sal_False
)
941 ,m_bPendingAdjustRows(sal_False
)
942 ,m_bHideScrollbars( sal_False
)
943 ,m_bUpdating(sal_False
)
945 DBG_CTOR(DbGridControl
,NULL
);
947 String
sName(SVX_RES(RID_STR_NAVIGATIONBAR
));
948 m_aBar
.SetAccessibleName(sName
);
950 ImplInitWindow( InitAll
);
953 //------------------------------------------------------------------------------
954 void DbGridControl::InsertHandleColumn()
956 // Handle Column einfuegen
957 // Da die BrowseBox ohne handleColums Paintprobleme hat
958 // wird diese versteckt
960 BrowseBox::InsertHandleColumn(GetDefaultColumnWidth(String()));
962 BrowseBox::InsertHandleColumn(0);
965 //------------------------------------------------------------------------------
966 void DbGridControl::Init()
968 BrowserHeader
* pNewHeader
= CreateHeaderBar(this);
969 pHeader
->SetMouseTransparent(sal_False
);
971 SetHeaderBar(pNewHeader
);
973 SetCursorColor(Color(0xFF, 0, 0));
975 InsertHandleColumn();
978 //------------------------------------------------------------------------------
979 DbGridControl::~DbGridControl()
984 m_bWantDestruction
= sal_True
;
985 osl::MutexGuard
aGuard(m_aDestructionSafety
);
986 if (m_pFieldListeners
)
987 DisconnectFromFields();
988 if (m_pCursorDisposeListener
)
990 delete m_pCursorDisposeListener
;
991 m_pCursorDisposeListener
= NULL
;
996 Application::RemoveUserEvent(m_nDeleteEvent
);
998 if (m_pDataSourcePropMultiplexer
)
1000 m_pDataSourcePropMultiplexer
->dispose();
1001 m_pDataSourcePropMultiplexer
->release(); // this should delete the multiplexer
1002 delete m_pDataSourcePropListener
;
1003 m_pDataSourcePropMultiplexer
= NULL
;
1004 m_pDataSourcePropListener
= NULL
;
1006 m_xRowSetListener
.clear();
1008 delete m_pDataCursor
;
1009 delete m_pSeekCursor
;
1011 DBG_DTOR(DbGridControl
,NULL
);
1014 //------------------------------------------------------------------------------
1015 void DbGridControl::StateChanged( StateChangedType nType
)
1017 DbGridControl_Base::StateChanged( nType
);
1021 case STATE_CHANGE_MIRRORING
:
1022 ImplInitWindow( InitWritingMode
);
1026 case STATE_CHANGE_ZOOM
:
1028 ImplInitWindow( InitFont
);
1030 // and give it a chance to rearrange
1031 Point aPoint
= GetControlArea().TopLeft();
1032 sal_uInt16 nX
= (sal_uInt16
)aPoint
.X();
1033 ArrangeControls(nX
, (sal_uInt16
)aPoint
.Y());
1034 ReserveControlArea((sal_uInt16
)nX
);
1037 case STATE_CHANGE_CONTROLFONT
:
1038 ImplInitWindow( InitFont
);
1041 case STATE_CHANGE_CONTROLFOREGROUND
:
1042 ImplInitWindow( InitForeground
);
1045 case STATE_CHANGE_CONTROLBACKGROUND
:
1046 ImplInitWindow( InitBackground
);
1052 //------------------------------------------------------------------------------
1053 void DbGridControl::DataChanged( const DataChangedEvent
& rDCEvt
)
1055 DbGridControl_Base::DataChanged( rDCEvt
);
1056 if ( (rDCEvt
.GetType() == DATACHANGED_SETTINGS
) &&
1057 (rDCEvt
.GetFlags() & SETTINGS_STYLE
) )
1059 ImplInitWindow( InitAll
);
1064 //------------------------------------------------------------------------------
1065 void DbGridControl::Select()
1067 DbGridControl_Base::Select();
1069 // as the selected rows may have changed, udate the according display in our navigation bar
1070 m_aBar
.InvalidateState(NavigationBar::RECORD_COUNT
);
1072 if (m_pGridListener
)
1073 m_pGridListener
->selectionChanged();
1076 //------------------------------------------------------------------------------
1077 void DbGridControl::ImplInitWindow( const InitWindowFacet _eInitWhat
)
1079 for ( size_t i
= 0; i
< m_aColumns
.size(); ++i
)
1081 DbGridColumn
* pCol
= m_aColumns
[ i
];
1083 pCol
->ImplInitWindow( GetDataWindow(), _eInitWhat
);
1086 if ( ( _eInitWhat
& InitWritingMode
) != 0 )
1088 if ( m_bNavigationBar
)
1090 m_aBar
.EnableRTL( IsRTLEnabled() );
1094 if ( ( _eInitWhat
& InitFont
) != 0 )
1096 if ( m_bNavigationBar
)
1098 Font aFont
= m_aBar
.GetSettings().GetStyleSettings().GetFieldFont();
1099 if ( IsControlFont() )
1100 m_aBar
.SetControlFont( GetControlFont() );
1102 m_aBar
.SetControlFont();
1104 m_aBar
.SetZoom( GetZoom() );
1108 if ( ( _eInitWhat
& InitBackground
) != 0 )
1110 if (IsControlBackground())
1112 GetDataWindow().SetBackground(GetControlBackground());
1113 GetDataWindow().SetControlBackground(GetControlBackground());
1114 GetDataWindow().SetFillColor(GetControlBackground());
1118 GetDataWindow().SetControlBackground();
1119 GetDataWindow().SetFillColor(GetFillColor());
1124 //------------------------------------------------------------------------------
1125 void DbGridControl::RemoveRows(sal_Bool bNewCursor
)
1127 // Hat sich der DatenCursor verandert ?
1130 DELETEZ(m_pSeekCursor
);
1131 m_xPaintRow
= m_xDataRow
= m_xEmptyRow
= m_xCurrentRow
= m_xSeekRow
= NULL
;
1132 m_nCurrentPos
= m_nSeekPos
= -1;
1133 m_nOptions
= OPT_READONLY
;
1135 RowRemoved(0, GetRowCount(), sal_False
);
1144 //------------------------------------------------------------------------------
1145 void DbGridControl::RemoveRows()
1147 // we're going to remove all columns and all row, so deactivate the current cell
1151 // alle Columns deinitialisieren
1152 // existieren Spalten, dann alle Controller freigeben
1153 for (size_t i
= 0; i
< m_aColumns
.size(); i
++)
1154 m_aColumns
[ i
]->Clear();
1156 DELETEZ(m_pSeekCursor
);
1157 DELETEZ(m_pDataCursor
);
1159 m_xPaintRow
= m_xDataRow
= m_xEmptyRow
= m_xCurrentRow
= m_xSeekRow
= NULL
;
1160 m_nCurrentPos
= m_nSeekPos
= m_nTotalCount
= -1;
1161 m_nOptions
= OPT_READONLY
;
1163 // Anzahl Saetze im Browser auf 0 zuruecksetzen
1164 DbGridControl_Base::RemoveRows();
1165 m_aBar
.InvalidateAll(m_nCurrentPos
, sal_True
);
1168 //------------------------------------------------------------------------------
1169 void DbGridControl::ArrangeControls(sal_uInt16
& nX
, sal_uInt16 nY
)
1171 // Positionierung der Controls
1172 if (m_bNavigationBar
)
1174 nX
= m_aBar
.GetDefaultWidth();
1175 Rectangle
aRect(GetControlArea());
1176 m_aBar
.SetPosSizePixel(Point(0,nY
+ 1), Size(nX
, aRect
.GetSize().Height() - 1));
1180 //------------------------------------------------------------------------------
1181 void DbGridControl::EnableHandle(sal_Bool bEnable
)
1183 if (m_bHandle
== bEnable
)
1186 // HandleColumn wird nur ausgeblendet,
1187 // da es sonst etliche Probleme mit dem Zeichnen gibt
1188 RemoveColumn( HandleColumnId
);
1189 m_bHandle
= bEnable
;
1190 InsertHandleColumn();
1193 //------------------------------------------------------------------------------
1196 bool adjustModeForScrollbars( BrowserMode
& _rMode
, sal_Bool _bNavigationBar
, sal_Bool _bHideScrollbars
)
1198 BrowserMode nOldMode
= _rMode
;
1200 if ( !_bNavigationBar
)
1202 _rMode
&= ~BROWSER_AUTO_HSCROLL
;
1205 if ( _bHideScrollbars
)
1207 _rMode
|= ( BROWSER_NO_HSCROLL
| BROWSER_NO_VSCROLL
);
1208 _rMode
&= ~( BROWSER_AUTO_HSCROLL
| BROWSER_AUTO_VSCROLL
);
1212 _rMode
|= ( BROWSER_AUTO_HSCROLL
| BROWSER_AUTO_VSCROLL
);
1213 _rMode
&= ~( BROWSER_NO_HSCROLL
| BROWSER_NO_VSCROLL
);
1216 // note: if we have a navigation bar, we always have a AUTO_HSCROLL. In particular,
1217 // _bHideScrollbars is ignored then
1218 if ( _bNavigationBar
)
1220 _rMode
|= BROWSER_AUTO_HSCROLL
;
1221 _rMode
&= ~BROWSER_NO_HSCROLL
;
1224 return nOldMode
!= _rMode
;
1228 //------------------------------------------------------------------------------
1229 void DbGridControl::EnableNavigationBar(sal_Bool bEnable
)
1231 if (m_bNavigationBar
== bEnable
)
1234 m_bNavigationBar
= bEnable
;
1240 m_aBar
.InvalidateAll(m_nCurrentPos
, sal_True
);
1242 if ( adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
) )
1245 // liefert die Groe�e der Reserved ControlArea
1246 Point aPoint
= GetControlArea().TopLeft();
1247 sal_uInt16 nX
= (sal_uInt16
)aPoint
.X();
1249 ArrangeControls(nX
, (sal_uInt16
)aPoint
.Y());
1250 ReserveControlArea((sal_uInt16
)nX
);
1257 if ( adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
) )
1260 ReserveControlArea();
1264 //------------------------------------------------------------------------------
1265 sal_uInt16
DbGridControl::SetOptions(sal_uInt16 nOpt
)
1267 DBG_ASSERT(!m_xCurrentRow
|| !m_xCurrentRow
->IsModified(),
1268 "DbGridControl::SetOptions : please do not call when editing a record (things are much easier this way ;) !");
1270 // for the next setDataSource (which is triggered by a refresh, for instance)
1271 m_nOptionMask
= nOpt
;
1273 // normalize the new options
1274 Reference
< XPropertySet
> xDataSourceSet
= m_pDataCursor
->getPropertySet();
1275 if (xDataSourceSet
.is())
1277 // feststellen welche Updatem�glichkeiten bestehen
1278 sal_Int32 nPrivileges
= 0;
1279 xDataSourceSet
->getPropertyValue(FM_PROP_PRIVILEGES
) >>= nPrivileges
;
1280 if ((nPrivileges
& Privilege::INSERT
) == 0)
1281 nOpt
&= ~OPT_INSERT
;
1282 if ((nPrivileges
& Privilege::UPDATE
) == 0)
1283 nOpt
&= ~OPT_UPDATE
;
1284 if ((nPrivileges
& Privilege::DELETE
) == 0)
1285 nOpt
&= ~OPT_DELETE
;
1288 nOpt
= OPT_READONLY
;
1290 // need to do something after that ?
1291 if (nOpt
== m_nOptions
)
1294 // the 'update' option only affects our BrowserMode (with or w/o focus rect)
1295 BrowserMode nNewMode
= m_nMode
;
1296 if ((m_nMode
& BROWSER_CURSOR_WO_FOCUS
) == 0)
1298 if (nOpt
& OPT_UPDATE
)
1299 nNewMode
|= BROWSER_HIDECURSOR
;
1301 nNewMode
&= ~BROWSER_HIDECURSOR
;
1304 nNewMode
&= ~BROWSER_HIDECURSOR
;
1305 // should not be necessary if EnablePermanentCursor is used to change the cursor behaviour, but to be sure ...
1307 if (nNewMode
!= m_nMode
)
1313 // _after_ setting the mode because this results in an ActivateCell
1316 sal_Bool bInsertChanged
= (nOpt
& OPT_INSERT
) != (m_nOptions
& OPT_INSERT
);
1318 // we need to set this before the code below because it indirectly uses m_nOptions
1320 // the 'insert' option affects our empty row
1323 if (m_nOptions
& OPT_INSERT
)
1324 { // the insert option is to be set
1325 m_xEmptyRow
= new DbGridRow();
1326 RowInserted(GetRowCount(), 1, sal_True
);
1329 { // the insert option is to be reset
1331 if ((GetCurRow() == GetRowCount() - 1) && (GetCurRow() > 0))
1332 GoToRowColumnId(GetCurRow() - 1, GetCurColumnId());
1333 RowRemoved(GetRowCount(), 1, sal_True
);
1337 // the 'delete' options has no immediate consequences
1344 //------------------------------------------------------------------------------
1345 void DbGridControl::ForceHideScrollbars( sal_Bool _bForce
)
1347 if ( m_bHideScrollbars
== _bForce
)
1350 m_bHideScrollbars
= _bForce
;
1352 if ( adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
) )
1356 //------------------------------------------------------------------------------
1357 void DbGridControl::EnablePermanentCursor(sal_Bool bEnable
)
1359 if (IsPermanentCursorEnabled() == bEnable
)
1364 m_nMode
&= ~BROWSER_HIDECURSOR
; // without this BROWSER_CURSOR_WO_FOCUS won't have any affect
1365 m_nMode
|= BROWSER_CURSOR_WO_FOCUS
;
1369 if (m_nOptions
& OPT_UPDATE
)
1370 m_nMode
|= BROWSER_HIDECURSOR
; // no cursor at all
1372 m_nMode
&= ~BROWSER_HIDECURSOR
; // at least the "non-permanent" cursor
1374 m_nMode
&= ~BROWSER_CURSOR_WO_FOCUS
;
1378 sal_Bool bWasEditing
= IsEditing();
1384 //------------------------------------------------------------------------------
1385 sal_Bool
DbGridControl::IsPermanentCursorEnabled() const
1387 return ((m_nMode
& BROWSER_CURSOR_WO_FOCUS
) != 0) && ((m_nMode
& BROWSER_HIDECURSOR
) == 0);
1390 //------------------------------------------------------------------------------
1391 void DbGridControl::refreshController(sal_uInt16 _nColId
, GrantControlAccess
/*_aAccess*/)
1393 if ((GetCurColumnId() == _nColId
) && IsEditing())
1394 { // the controller which is currently active needs to be refreshed
1400 //------------------------------------------------------------------------------
1401 void DbGridControl::setDataSource(const Reference
< XRowSet
>& _xCursor
, sal_uInt16 nOpts
)
1403 if (!_xCursor
.is() && !m_pDataCursor
)
1406 if (m_pDataSourcePropMultiplexer
)
1408 m_pDataSourcePropMultiplexer
->dispose();
1409 m_pDataSourcePropMultiplexer
->release(); // this should delete the multiplexer
1410 delete m_pDataSourcePropListener
;
1411 m_pDataSourcePropMultiplexer
= NULL
;
1412 m_pDataSourcePropListener
= NULL
;
1414 m_xRowSetListener
.clear();
1416 // is the new cursor valid ?
1417 // the cursor is only valid if it contains some columns
1418 // if there is no cursor or the cursor is not valid we have to clean up an leave
1419 if (!_xCursor
.is() || !Reference
< XColumnsSupplier
> (_xCursor
, UNO_QUERY
)->getColumns()->hasElements())
1425 // Hat sich der DatenCursor verandert ?
1426 sal_uInt16 nCurPos
= GetColumnPos(GetCurColumnId());
1428 SetUpdateMode(sal_False
);
1430 DisconnectFromFields();
1432 DELETEZ(m_pCursorDisposeListener
);
1435 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
1436 if (m_nAsynAdjustEvent
)
1438 // the adjust was thought to work with the old cursor which we don't have anymore
1439 RemoveUserEvent(m_nAsynAdjustEvent
);
1440 m_nAsynAdjustEvent
= 0;
1444 // get a new formatter and data cursor
1445 m_xFormatter
= NULL
;
1446 OStaticDataAccessTools aStaticTools
;
1447 Reference
< ::com::sun::star::util::XNumberFormatsSupplier
> xSupplier
= aStaticTools
.getNumberFormats(aStaticTools
.getRowSetConnection(_xCursor
), sal_True
);
1450 m_xFormatter
= Reference
< ::com::sun::star::util::XNumberFormatter
>(
1451 ::com::sun::star::util::NumberFormatter::create(m_xContext
),
1453 m_xFormatter
->attachNumberFormatsSupplier(xSupplier
);
1455 // retrieve the datebase of the Numberformatter
1458 xSupplier
->getNumberFormatSettings()->getPropertyValue(OUString("NullDate")) >>= m_aNullDate
;
1465 m_pDataCursor
= new CursorWrapper(_xCursor
);
1467 // now create a cursor for painting rows
1468 // we need that cursor only if we are not in insert only mode
1469 Reference
< XResultSet
> xClone
;
1470 Reference
< XResultSetAccess
> xAccess( _xCursor
, UNO_QUERY
);
1473 xClone
= xAccess
.is() ? xAccess
->createResultSet() : Reference
< XResultSet
> ();
1479 m_pSeekCursor
= new CursorWrapper(xClone
);
1481 // property listening on the data source
1482 // (Normally one class would be sufficient : the multiplexer which could forward the property change to us.
1483 // But for that we would have been derived from ::comphelper::OPropertyChangeListener, which isn't exported.
1484 // So we introduce a second class, which is a ::comphelper::OPropertyChangeListener (in the implementation file we know this class)
1485 // and forwards the property changes to a our special method "DataSourcePropertyChanged".)
1488 m_pDataSourcePropListener
= new FmXGridSourcePropListener(this);
1489 m_pDataSourcePropMultiplexer
= new ::comphelper::OPropertyChangeMultiplexer(m_pDataSourcePropListener
, m_pDataCursor
->getPropertySet() );
1490 m_pDataSourcePropMultiplexer
->acquire();
1491 m_pDataSourcePropMultiplexer
->addProperty(FM_PROP_ISMODIFIED
);
1492 m_pDataSourcePropMultiplexer
->addProperty(FM_PROP_ISNEW
);
1495 BrowserMode nOldMode
= m_nMode
;
1500 Reference
< XPropertySet
> xSet(_xCursor
, UNO_QUERY
);
1503 // feststellen welche Updatemoeglichkeiten bestehen
1504 sal_Int32 nConcurrency
= ResultSetConcurrency::READ_ONLY
;
1505 xSet
->getPropertyValue(FM_PROP_RESULTSET_CONCURRENCY
) >>= nConcurrency
;
1507 if ( ResultSetConcurrency::UPDATABLE
== nConcurrency
)
1509 sal_Int32 nPrivileges
= 0;
1510 xSet
->getPropertyValue(FM_PROP_PRIVILEGES
) >>= nPrivileges
;
1512 // Insert Option should be set if insert only otherwise you won't see any rows
1513 // and no insertion is possible
1514 if ((m_nOptionMask
& OPT_INSERT
) && ((nPrivileges
& Privilege::INSERT
) == Privilege::INSERT
) && (nOpts
& OPT_INSERT
))
1515 m_nOptions
|= OPT_INSERT
;
1516 if ((m_nOptionMask
& OPT_UPDATE
) && ((nPrivileges
& Privilege::UPDATE
) == Privilege::UPDATE
) && (nOpts
& OPT_UPDATE
))
1517 m_nOptions
|= OPT_UPDATE
;
1518 if ((m_nOptionMask
& OPT_DELETE
) && ((nPrivileges
& Privilege::DELETE
) == Privilege::DELETE
) && (nOpts
& OPT_DELETE
))
1519 m_nOptions
|= OPT_DELETE
;
1523 catch( const Exception
& )
1525 DBG_UNHANDLED_EXCEPTION();
1528 sal_Bool bPermanentCursor
= IsPermanentCursorEnabled();
1529 m_nMode
= DEFAULT_BROWSE_MODE
;
1531 if ( bPermanentCursor
)
1533 m_nMode
|= BROWSER_CURSOR_WO_FOCUS
;
1534 m_nMode
&= ~BROWSER_HIDECURSOR
;
1538 // Duerfen Updates gemacht werden, kein Focus-RechtEck
1539 if ( m_nOptions
& OPT_UPDATE
)
1540 m_nMode
|= BROWSER_HIDECURSOR
;
1543 if ( m_bMultiSelection
)
1544 m_nMode
|= BROWSER_MULTISELECTION
;
1546 m_nMode
&= ~BROWSER_MULTISELECTION
;
1548 adjustModeForScrollbars( m_nMode
, m_bNavigationBar
, m_bHideScrollbars
);
1550 Reference
< XColumnsSupplier
> xSupplyColumns(_xCursor
, UNO_QUERY
);
1551 if (xSupplyColumns
.is())
1552 InitColumnsByFields(Reference
< XIndexAccess
> (xSupplyColumns
->getColumns(), UNO_QUERY
));
1557 sal_uInt32
nRecordCount(0);
1561 Reference
< XPropertySet
> xSet
= m_pDataCursor
->getPropertySet();
1562 xSet
->getPropertyValue(FM_PROP_ROWCOUNT
) >>= nRecordCount
;
1563 m_bRecordCountFinal
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ROWCOUNTFINAL
));
1565 m_xRowSetListener
= new RowSetEventListener(this);
1566 Reference
< XRowsChangeBroadcaster
> xChangeBroad(xSet
,UNO_QUERY
);
1567 if ( xChangeBroad
.is( ) )
1568 xChangeBroad
->addRowsChangeListener(m_xRowSetListener
);
1571 // insert the currently known rows
1572 // and one row if we are able to insert rows
1573 if (m_nOptions
& OPT_INSERT
)
1575 // insert the empty row for insertion
1576 m_xEmptyRow
= new DbGridRow();
1581 m_xPaintRow
= m_xSeekRow
= new DbGridRow(m_pSeekCursor
, sal_True
);
1582 m_xDataRow
= new DbGridRow(m_pDataCursor
, sal_False
);
1583 RowInserted(0, nRecordCount
, sal_False
);
1585 if (m_xSeekRow
->IsValid())
1588 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
1590 catch( const Exception
& )
1592 DBG_UNHANDLED_EXCEPTION();
1598 // no rows so we don't need a seekcursor
1599 DELETEZ(m_pSeekCursor
);
1603 // Zur alten Spalte gehen
1604 if (nCurPos
== BROWSER_INVALIDID
|| nCurPos
>= ColCount())
1607 // Column zero is a valid choice and guaranteed to exist,
1608 // but invisible to the user; if we have at least one
1609 // user-visible column, go to that one.
1610 if (nCurPos
== 0 && ColCount() > 1)
1613 // there are rows so go to the selected current column
1615 GoToRowColumnId(0, GetColumnId(nCurPos
));
1616 // else stop the editing if necessary
1617 else if (IsEditing())
1620 // now reset the mode
1621 if (m_nMode
!= nOldMode
)
1624 // beim Resizen wird RecalcRows gerufen
1625 if (!IsResizing() && GetRowCount())
1626 RecalcRows(GetTopRow(), GetVisibleRows(), sal_True
);
1628 m_aBar
.InvalidateAll(m_nCurrentPos
, sal_True
);
1629 SetUpdateMode(sal_True
);
1631 // start listening on the seek cursor
1633 m_pCursorDisposeListener
= new DisposeListenerGridBridge(*this, Reference
< XComponent
> ((Reference
< XInterface
>)*m_pSeekCursor
, UNO_QUERY
), 0);
1636 //------------------------------------------------------------------------------
1637 void DbGridControl::RemoveColumns()
1642 for (size_t i
= 0, n
= m_aColumns
.size(); i
< n
; i
++)
1643 delete m_aColumns
[ i
];
1646 DbGridControl_Base::RemoveColumns();
1649 //------------------------------------------------------------------------------
1650 DbGridColumn
* DbGridControl::CreateColumn(sal_uInt16 nId
) const
1652 return new DbGridColumn(nId
, *(DbGridControl
*)this);
1655 //------------------------------------------------------------------------------
1656 sal_uInt16
DbGridControl::AppendColumn(const XubString
& rName
, sal_uInt16 nWidth
, sal_uInt16 nModelPos
, sal_uInt16 nId
)
1658 DBG_ASSERT(nId
== BROWSER_INVALIDID
, "DbGridControl::AppendColumn : I want to set the ID myself ...");
1659 sal_uInt16 nRealPos
= nModelPos
;
1660 if (nModelPos
!= HEADERBAR_APPEND
)
1662 // calc the view pos. we can't use our converting functions because the new column
1663 // has no VCL-representation, yet.
1664 sal_Int16 nViewPos
= nModelPos
;
1667 if ( m_aColumns
[ nModelPos
]->IsHidden() )
1670 // restore nModelPos, we need it later
1671 nModelPos
= nRealPos
;
1672 // the position the base class gets is the view pos + 1 (because of the handle column)
1673 nRealPos
= nViewPos
+ 1;
1676 // calculate the new id
1677 for (nId
=1; (GetModelColumnPos(nId
) != GRID_COLUMN_NOT_FOUND
) && (nId
<= m_aColumns
.size()); ++nId
)
1679 DBG_ASSERT(GetViewColumnPos(nId
) == GRID_COLUMN_NOT_FOUND
, "DbGridControl::AppendColumn : inconsistent internal state !");
1680 // my column's models say "there is no column with id nId", but the view (the base class) says "there is a column ..."
1682 DbGridControl_Base::AppendColumn(rName
, nWidth
, nRealPos
, nId
);
1683 if (nModelPos
== HEADERBAR_APPEND
)
1684 m_aColumns
.push_back( CreateColumn(nId
) );
1687 DbGridColumns::iterator it
= m_aColumns
.begin();
1688 ::std::advance( it
, nModelPos
);
1689 m_aColumns
.insert( it
, CreateColumn(nId
) );
1695 //------------------------------------------------------------------------------
1696 void DbGridControl::RemoveColumn(sal_uInt16 nId
)
1698 DbGridControl_Base::RemoveColumn(nId
);
1700 const sal_uInt16 nIndex
= GetModelColumnPos(nId
);
1701 if(nIndex
!= GRID_COLUMN_NOT_FOUND
)
1703 delete m_aColumns
[nIndex
];
1704 m_aColumns
.erase( m_aColumns
.begin()+nIndex
);
1708 //------------------------------------------------------------------------------
1709 void DbGridControl::ColumnMoved(sal_uInt16 nId
)
1711 DbGridControl_Base::ColumnMoved(nId
);
1713 // remove the col from the model
1714 sal_uInt16 nOldModelPos
= GetModelColumnPos(nId
);
1716 DbGridColumn
* pCol
= m_aColumns
[ (sal_uInt32
)nOldModelPos
];
1717 DBG_ASSERT(!pCol
->IsHidden(), "DbGridControl::ColumnMoved : moved a hidden col ? how this ?");
1720 // for the new model pos we can't use GetModelColumnPos because we are altering the model at the moment
1721 // so the method won't work (in fact it would return the old model pos)
1723 // the new view pos is calculated easily
1724 sal_uInt16 nNewViewPos
= GetViewColumnPos(nId
);
1726 // from that we can compute the new model pos
1727 sal_uInt16 nNewModelPos
;
1728 for (nNewModelPos
= 0; nNewModelPos
< m_aColumns
.size(); ++nNewModelPos
)
1730 if (!m_aColumns
[ nNewModelPos
]->IsHidden())
1738 DBG_ASSERT( nNewModelPos
< m_aColumns
.size(), "DbGridControl::ColumnMoved : could not find the new model position !");
1740 // this will work. of course the model isn't fully consistent with our view right now, but let's
1741 // look at the situation : a column has been moved with in the VIEW from pos m to n, say m<n (in the
1742 // other case we can use analogue arguments).
1743 // All cols k with m<k<=n have been shifted left on pos, the former col m now has pos n.
1744 // In the model this affects a range of cols x to y, where x<=m and y<=n. And the number of hidden cols
1745 // within this range is constant, so we may calculate the view pos from the model pos in the above way.
1747 // for instance, let's look at a grid with six columns where the third one is hidden. this will
1748 // initially look like this :
1750 // +---+---+---+---+---+---+
1751 // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1752 // +---+---+---+---+---+---+
1753 // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1754 // +---+---+---+---+---+---+
1755 // view pos | 0 | 1 | - | 2 | 3 | 4 |
1756 // +---+---+---+---+---+---+
1758 // if we move the column at (view) pos 1 to (view) pos 3 we have :
1760 // +---+---+---+---+---+---+
1761 // model pos | 0 | 3 |*2*| 4 | 1 | 5 | // not reflecting the changes, yet
1762 // +---+---+---+---+---+---+
1763 // ID | 1 | 4 | 3 | 5 | 2 | 6 | // already reflecting the changes
1764 // +---+---+---+---+---+---+
1765 // view pos | 0 | 1 | - | 2 | 3 | 4 |
1766 // +---+---+---+---+---+---+
1768 // or, sorted by the out-of-date model positions :
1770 // +---+---+---+---+---+---+
1771 // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1772 // +---+---+---+---+---+---+
1773 // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1774 // +---+---+---+---+---+---+
1775 // view pos | 0 | 3 | - | 1 | 2 | 4 |
1776 // +---+---+---+---+---+---+
1778 // We know the new view pos (3) of the moved column because our base class tells us. So we look at our
1779 // model for the 4th (the pos is zero-based) visible column, it is at (model) position 4. And this is
1780 // exactly the pos where we have to re-insert our column's model, so it looks ike this :
1782 // +---+---+---+---+---+---+
1783 // model pos | 0 |*1*| 2 | 3 | 4 | 5 |
1784 // +---+---+---+---+---+---+
1785 // ID | 1 | 3 | 4 | 5 | 2 | 6 |
1786 // +---+---+---+---+---+---+
1787 // view pos | 0 | - | 1 | 2 | 3 | 4 |
1788 // +---+---+---+---+---+---+
1790 // Now, all is consistent again.
1791 // (except of the hidden column : The cycling of the cols occurred on the model, not on the view. maybe
1792 // the user expected the latter but there really is no good argument against our method ;) ...)
1794 // And no, this large explanation isn't just because I wanted to play a board game or something like
1795 // that. It's because it took me a while to see it myself, and the whole theme (hidden cols, model col
1796 // positions, view col positions) is really painful (at least for me) so the above pictures helped me a lot ;)
1799 DbGridColumn
* temp
= m_aColumns
[ nOldModelPos
];
1801 DbGridColumns::iterator it
= m_aColumns
.begin();
1802 ::std::advance( it
, nOldModelPos
);
1803 m_aColumns
.erase( it
);
1805 it
= m_aColumns
.begin();
1806 ::std::advance( it
, nNewModelPos
);
1807 m_aColumns
.insert( it
, temp
);
1810 //------------------------------------------------------------------------------
1811 sal_Bool
DbGridControl::SeekRow(long nRow
)
1813 // in filter mode or in insert only mode we don't have any cursor!
1814 if ( !SeekCursor( nRow
) )
1817 if ( IsFilterMode() )
1819 DBG_ASSERT( IsFilterRow( nRow
), "DbGridControl::SeekRow(): No filter row, wrong mode" );
1820 m_xPaintRow
= m_xEmptyRow
;
1824 // on the current position we have to take the current row for display as we want
1825 // to have the most recent values for display
1826 if ( ( nRow
== m_nCurrentPos
) && getDisplaySynchron() )
1827 m_xPaintRow
= m_xCurrentRow
;
1828 // seek to the empty insert row
1829 else if ( IsInsertionRow( nRow
) )
1830 m_xPaintRow
= m_xEmptyRow
;
1833 m_xSeekRow
->SetState( m_pSeekCursor
, sal_True
);
1834 m_xPaintRow
= m_xSeekRow
;
1838 DbGridControl_Base::SeekRow(nRow
);
1840 return m_nSeekPos
>= 0;
1842 //------------------------------------------------------------------------------
1843 // Wird aufgerufen, wenn die dargestellte Datenmenge sich aendert
1844 //------------------------------------------------------------------------------
1845 void DbGridControl::VisibleRowsChanged( long nNewTopRow
, sal_uInt16 nLinesOnScreen
)
1847 RecalcRows(nNewTopRow
, nLinesOnScreen
, sal_False
);
1850 //------------------------------------------------------------------------------
1851 void DbGridControl::RecalcRows(long nNewTopRow
, sal_uInt16 nLinesOnScreen
, sal_Bool bUpdateCursor
)
1853 DBG_CHKTHIS( DbGridControl
, NULL
);
1854 // Wenn kein Cursor -> keine Rows im Browser.
1857 DBG_ASSERT(GetRowCount() == 0,"DbGridControl: ohne Cursor darf es keine Rows geben");
1861 // ignore any updates implicit made
1862 sal_Bool bDisablePaint
= !bUpdateCursor
&& IsPaintEnabled();
1864 EnablePaint(sal_False
);
1866 // Cache an den sichtbaren Bereich anpassen
1867 Reference
< XPropertySet
> xSet
= m_pSeekCursor
->getPropertySet();
1868 sal_Int32 nCacheSize
= 0;
1869 xSet
->getPropertyValue(FM_PROP_FETCHSIZE
) >>= nCacheSize
;
1870 sal_Bool bCacheAligned
= sal_False
;
1871 // Nach der Initialisierung (m_nSeekPos < 0) keine Cursorbewegung, da bereits auf den ersten
1872 // Satz positioniert
1873 long nDelta
= nNewTopRow
- GetTopRow();
1874 // Limit fuer relative Positionierung
1875 long nLimit
= (nCacheSize
) ? nCacheSize
/ 2 : 0;
1877 // mehr Zeilen auf dem Bildschirm als im Cache
1878 if (nLimit
< nLinesOnScreen
)
1881 aCacheSize
<<= sal_Int32(nLinesOnScreen
*2);
1882 xSet
->setPropertyValue(FM_PROP_FETCHSIZE
, aCacheSize
);
1883 // jetzt auf alle Faelle den Cursor anpassen
1884 bUpdateCursor
= sal_True
;
1885 bCacheAligned
= sal_True
;
1886 nLimit
= nLinesOnScreen
;
1889 // Im folgenden werden die Positionierungen so vorgenommen, da� sichergestellt ist
1890 // da� ausreichend Zeilen im DatenCache vorhanden sind
1892 // Fenster geht nach unten, weniger als zwei Fenster Differenz
1893 // oder Cache angepasst und noch kein Rowcount
1894 if (nDelta
< nLimit
&& (nDelta
> 0
1895 || (bCacheAligned
&& m_nTotalCount
< 0)) )
1896 SeekCursor(nNewTopRow
+ nLinesOnScreen
- 1, sal_False
);
1897 else if (nDelta
< 0 && std::abs(nDelta
) < nLimit
)
1898 SeekCursor(nNewTopRow
, sal_False
);
1899 else if (nDelta
!= 0 || bUpdateCursor
)
1900 SeekCursor(nNewTopRow
, sal_True
);
1904 // ignore any updates implicit made
1905 EnablePaint(sal_True
);
1908 //------------------------------------------------------------------------------
1909 void DbGridControl::RowInserted(long nRow
, long nNumRows
, sal_Bool bDoPaint
, sal_Bool bKeepSelection
)
1913 if (m_bRecordCountFinal
&& m_nTotalCount
< 0)
1915 // if we have an insert row we have to reduce to count by 1
1916 // as the total count reflects only the existing rows in database
1917 m_nTotalCount
= GetRowCount() + nNumRows
;
1918 if (m_xEmptyRow
.Is())
1921 else if (m_nTotalCount
>= 0)
1922 m_nTotalCount
+= nNumRows
;
1924 DbGridControl_Base::RowInserted(nRow
, nNumRows
, bDoPaint
, bKeepSelection
);
1925 m_aBar
.InvalidateState(NavigationBar::RECORD_COUNT
);
1929 //------------------------------------------------------------------------------
1930 void DbGridControl::RowRemoved(long nRow
, long nNumRows
, sal_Bool bDoPaint
)
1934 if (m_bRecordCountFinal
&& m_nTotalCount
< 0)
1936 m_nTotalCount
= GetRowCount() - nNumRows
;
1937 // if we have an insert row reduce by 1
1938 if (m_xEmptyRow
.Is())
1941 else if (m_nTotalCount
>= 0)
1942 m_nTotalCount
-= nNumRows
;
1944 DbGridControl_Base::RowRemoved(nRow
, nNumRows
, bDoPaint
);
1945 m_aBar
.InvalidateState(NavigationBar::RECORD_COUNT
);
1949 //------------------------------------------------------------------------------
1950 void DbGridControl::AdjustRows()
1955 Reference
< XPropertySet
> xSet
= m_pDataCursor
->getPropertySet();
1957 // Aktualisieren des RecordCounts
1958 sal_Int32 nRecordCount
= 0;
1959 xSet
->getPropertyValue(FM_PROP_ROWCOUNT
) >>= nRecordCount
;
1960 if (!m_bRecordCountFinal
)
1961 m_bRecordCountFinal
= ::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ROWCOUNTFINAL
));
1963 // hat sich die aktuelle Anzahl Rows veraendert
1964 // hierbei muss auch beruecksichtigt werden,
1965 // das eine zusaetzliche Zeile zum einfuegen von Datensaetzen vorhanden sein kann
1967 // zusaetzliche AppendRow fuers einfuegen
1968 if (m_nOptions
& OPT_INSERT
)
1971 // wird gerade eingefuegt, dann gehoert die gerade hinzuzufuegende
1972 // Zeile nicht zum RecordCount und die Appendrow ebenfalls nicht
1973 if (!IsUpdating() && m_bRecordCountFinal
&& IsModified() && m_xCurrentRow
!= m_xEmptyRow
&&
1974 m_xCurrentRow
->IsNew())
1976 // das ist mit !m_bUpdating abgesichert : innerhalb von SaveRow (m_bUpdating == sal_True) wuerde sonst der Datensatz, den ich editiere
1977 // (und den SaveRow gerade angefuegt hat, wodurch diese Methode hier getriggert wurde), doppelt zaehlen : einmal ist er schon
1978 // in dem normalen RecordCount drin, zum zweiten wuerde er hier gezaehlt werden (60787 - FS)
1980 if (nRecordCount
!= GetRowCount())
1982 long nDelta
= GetRowCount() - (long)nRecordCount
;
1983 if (nDelta
> 0) // zuviele
1985 RowRemoved(GetRowCount() - nDelta
, nDelta
, sal_False
);
1986 // es sind Zeilen weggefallen, dann ab der aktuellen Position neu zeichen
1989 sal_Int32 nNewPos
= AlignSeekCursor();
1990 if (m_bSynchDisplay
)
1991 DbGridControl_Base::GoToRow(nNewPos
);
1993 SetCurrent(nNewPos
);
1994 // there are rows so go to the selected current column
1996 GoToRowColumnId(nNewPos
, GetColumnId(GetCurColumnId()));
1997 if (!IsResizing() && GetRowCount())
1998 RecalcRows(GetTopRow(), GetVisibleRows(), sal_True
);
1999 m_aBar
.InvalidateAll(m_nCurrentPos
, sal_True
);
2002 RowInserted(GetRowCount(), -nDelta
, sal_True
);
2005 if (m_bRecordCountFinal
&& m_nTotalCount
< 0)
2007 if (m_nOptions
& OPT_INSERT
)
2008 m_nTotalCount
= GetRowCount() - 1;
2010 m_nTotalCount
= GetRowCount();
2012 m_aBar
.InvalidateState(NavigationBar::RECORD_COUNT
);
2015 //------------------------------------------------------------------------------
2016 DbGridControl_Base::RowStatus
DbGridControl::GetRowStatus(long nRow
) const
2018 if (IsFilterRow(nRow
))
2019 return DbGridControl_Base::FILTER
;
2020 else if (m_nCurrentPos
>= 0 && nRow
== m_nCurrentPos
)
2023 if (!IsValid(m_xCurrentRow
))
2024 return DbGridControl_Base::DELETED
;
2025 else if (IsModified())
2026 return DbGridControl_Base::MODIFIED
;
2027 else if (m_xCurrentRow
->IsNew())
2028 return DbGridControl_Base::CURRENTNEW
;
2030 return DbGridControl_Base::CURRENT
;
2032 else if (IsInsertionRow(nRow
))
2033 return DbGridControl_Base::NEW
;
2034 else if (!IsValid(m_xSeekRow
))
2035 return DbGridControl_Base::DELETED
;
2037 return DbGridControl_Base::CLEAN
;
2040 //------------------------------------------------------------------------------
2041 void DbGridControl::PaintStatusCell(OutputDevice
& rDev
, const Rectangle
& rRect
) const
2043 DbGridControl_Base::PaintStatusCell(rDev
, rRect
);
2046 //------------------------------------------------------------------------------
2047 void DbGridControl::PaintCell(OutputDevice
& rDev
, const Rectangle
& rRect
, sal_uInt16 nColumnId
) const
2049 if (!IsValid(m_xPaintRow
))
2052 size_t Location
= GetModelColumnPos(nColumnId
);
2053 DbGridColumn
* pColumn
= (Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
2056 Rectangle
aArea(rRect
);
2057 if ((GetMode() & BROWSER_CURSOR_WO_FOCUS
) == BROWSER_CURSOR_WO_FOCUS
)
2060 aArea
.Bottom() -= 1;
2062 pColumn
->Paint(rDev
, aArea
, m_xPaintRow
, getNumberFormatter());
2066 //------------------------------------------------------------------------------
2067 sal_Bool
DbGridControl::CursorMoving(long nNewRow
, sal_uInt16 nNewCol
)
2069 DBG_CHKTHIS( DbGridControl
, NULL
);
2071 DeactivateCell( sal_False
);
2074 && ( m_nCurrentPos
!= nNewRow
)
2075 && !SetCurrent( nNewRow
)
2082 if ( !DbGridControl_Base::CursorMoving( nNewRow
, nNewCol
) )
2088 //------------------------------------------------------------------------------
2089 sal_Bool
DbGridControl::SetCurrent(long nNewRow
)
2091 // Each movement of the datacursor must start with BeginCursorAction and end with
2092 // EndCursorAction to block all notifications during the movement
2093 BeginCursorAction();
2097 // Abgleichen der Positionen
2098 if (SeekCursor(nNewRow
))
2100 if (IsFilterRow(nNewRow
)) // special mode for filtering
2102 m_xCurrentRow
= m_xDataRow
= m_xPaintRow
= m_xEmptyRow
;
2103 m_nCurrentPos
= nNewRow
;
2107 sal_Bool bNewRowInserted
= sal_False
;
2108 // Should we go to the insertrow ?
2109 if (IsInsertionRow(nNewRow
))
2111 // to we need to move the cursor to the insert row?
2112 // we need to insert the if the current row isn't the insert row or if the
2113 // cursor triggered the move by itselt and we need a reinitialization of the row
2114 Reference
< XPropertySet
> xCursorProps
= m_pDataCursor
->getPropertySet();
2115 if ( !::comphelper::getBOOL(xCursorProps
->getPropertyValue(FM_PROP_ISNEW
)) )
2117 Reference
< XResultSetUpdate
> xUpdateCursor((Reference
< XInterface
>)*m_pDataCursor
, UNO_QUERY
);
2118 xUpdateCursor
->moveToInsertRow();
2120 bNewRowInserted
= sal_True
;
2125 if ( !m_pSeekCursor
->isBeforeFirst() && !m_pSeekCursor
->isAfterLast() )
2127 Any aBookmark
= m_pSeekCursor
->getBookmark();
2128 if (!m_xCurrentRow
|| m_xCurrentRow
->IsNew() || !CompareBookmark(aBookmark
, m_pDataCursor
->getBookmark()))
2130 // adjust the cursor to the new desired row
2131 if (!m_pDataCursor
->moveToBookmark(aBookmark
))
2139 m_xDataRow
->SetState(m_pDataCursor
, sal_False
);
2140 m_xCurrentRow
= m_xDataRow
;
2142 long nPaintPos
= -1;
2143 // do we have to repaint the last regular row in case of setting defaults or autovalues
2144 if (m_nCurrentPos
>= 0 && m_nCurrentPos
>= (GetRowCount() - 2))
2145 nPaintPos
= m_nCurrentPos
;
2147 m_nCurrentPos
= nNewRow
;
2149 // repaint the new row to display all defaults
2150 if (bNewRowInserted
)
2151 RowModified(m_nCurrentPos
);
2153 RowModified(nPaintPos
);
2158 OSL_FAIL("DbGridControl::SetCurrent : SeekRow failed !");
2163 catch ( const Exception
& )
2165 DBG_UNHANDLED_EXCEPTION();
2174 //------------------------------------------------------------------------------
2175 void DbGridControl::CursorMoved()
2177 DBG_CHKTHIS( DbGridControl
, NULL
);
2179 // CursorBewegung durch loeschen oder einfuegen von Zeilen
2180 if (m_pDataCursor
&& m_nCurrentPos
!= GetCurRow())
2182 DeactivateCell(sal_True
);
2183 SetCurrent(GetCurRow());
2186 DbGridControl_Base::CursorMoved();
2187 m_aBar
.InvalidateAll(m_nCurrentPos
);
2189 // select the new column when they moved
2190 if ( IsDesignMode() && GetSelectedColumnCount() > 0 && GetCurColumnId() )
2192 SelectColumnId( GetCurColumnId() );
2195 if ( m_nLastColId
!= GetCurColumnId() )
2197 m_nLastColId
= GetCurColumnId();
2199 if ( m_nLastRowId
!= GetCurRow() )
2201 m_nLastRowId
= GetCurRow();
2204 //------------------------------------------------------------------------------
2205 void DbGridControl::onRowChange()
2207 // not interested in
2210 //------------------------------------------------------------------------------
2211 void DbGridControl::onColumnChange()
2213 if ( m_pGridListener
)
2214 m_pGridListener
->columnChanged();
2217 //------------------------------------------------------------------------------
2218 void DbGridControl::setDisplaySynchron(sal_Bool bSync
)
2220 if (bSync
!= m_bSynchDisplay
)
2222 m_bSynchDisplay
= bSync
;
2223 if (m_bSynchDisplay
)
2224 AdjustDataSource(sal_False
);
2228 //------------------------------------------------------------------------------
2229 void DbGridControl::AdjustDataSource(sal_Bool bFull
)
2231 SAL_INFO("svx.fmcomp", "DbGridControl::AdjustDataSource");
2232 SolarMutexGuard aGuard
;
2233 // wird die aktuelle Zeile gerade neu bestimmt,
2234 // wird kein abgleich vorgenommen
2237 m_xCurrentRow
= NULL
;
2238 // if we are on the same row only repaint
2239 // but this is only possible for rows which are not inserted, in that case the comparision result
2240 // may not be correct
2242 if ( m_xCurrentRow
.Is()
2243 && !m_xCurrentRow
->IsNew()
2244 && !m_pDataCursor
->isBeforeFirst()
2245 && !m_pDataCursor
->isAfterLast()
2246 && !m_pDataCursor
->rowDeleted()
2249 sal_Bool bEqualBookmarks
= CompareBookmark( m_xCurrentRow
->GetBookmark(), m_pDataCursor
->getBookmark() );
2251 sal_Bool bDataCursorIsOnNew
= sal_False
;
2252 m_pDataCursor
->getPropertySet()->getPropertyValue( FM_PROP_ISNEW
) >>= bDataCursorIsOnNew
;
2254 if ( bEqualBookmarks
&& !bDataCursorIsOnNew
)
2256 // position of my data cursor is the same as the position our current row points tpo
2257 // sync the status, repaint, done
2258 DBG_ASSERT(m_xDataRow
== m_xCurrentRow
, "Fehler in den Datenzeilen");
2259 SAL_INFO("svx.fmcomp", "same position, new state: " << ROWSTATUS(m_xCurrentRow
));
2260 RowModified(m_nCurrentPos
);
2265 // weg von der Row des DatenCursors
2266 if (m_xPaintRow
== m_xCurrentRow
)
2267 m_xPaintRow
= m_xSeekRow
;
2269 // keine aktuelle Zeile dann komplett anpassen
2273 sal_Int32 nNewPos
= AlignSeekCursor();
2274 if (nNewPos
< 0) // keine Position gefunden
2277 m_bInAdjustDataSource
= sal_True
;
2278 if (nNewPos
!= m_nCurrentPos
)
2280 if (m_bSynchDisplay
)
2281 DbGridControl_Base::GoToRow(nNewPos
);
2283 if (!m_xCurrentRow
.Is())
2284 // das tritt zum Beispiel auf, wenn man die n (n>1) letzten Datensaetze geloescht hat, waehrend der Cursor auf dem letzten
2285 // steht : AdjustRows entfernt dann zwei Zeilen aus der BrowseBox, wodurch diese ihre CurrentRow um zwei nach unten
2286 // korrigiert, so dass dann das GoToRow in's Leere laeuft (da wir uns ja angeblich schon an der richtigen Position
2288 SetCurrent(nNewPos
);
2292 SetCurrent(nNewPos
);
2293 RowModified(nNewPos
);
2295 m_bInAdjustDataSource
= sal_False
;
2297 // Wird der DatenCursor von aussen bewegt, wird die selektion aufgehoben
2299 m_aBar
.InvalidateAll(m_nCurrentPos
, m_xCurrentRow
.Is());
2302 //------------------------------------------------------------------------------
2303 sal_Int32
DbGridControl::AlignSeekCursor()
2305 DBG_CHKTHIS( DbGridControl
, NULL
);
2306 // Positioniert den SeekCursor auf den DatenCursor, Daten werden nicht uebertragen
2311 Reference
< XPropertySet
> xSet
= m_pDataCursor
->getPropertySet();
2313 // jetzt den seekcursor an den DatenCursor angleichen
2314 if (::comphelper::getBOOL(xSet
->getPropertyValue(FM_PROP_ISNEW
)))
2315 m_nSeekPos
= GetRowCount() - 1;
2320 if ( m_pDataCursor
->isBeforeFirst() )
2322 // this is somewhat strange, but can nevertheless happen
2323 DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (before first)!" );
2324 m_pSeekCursor
->first();
2325 m_pSeekCursor
->previous();
2328 else if ( m_pDataCursor
->isAfterLast() )
2330 DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (after last)!" );
2331 m_pSeekCursor
->last();
2332 m_pSeekCursor
->next();
2337 m_pSeekCursor
->moveToBookmark(m_pDataCursor
->getBookmark());
2338 if (!CompareBookmark(m_pDataCursor
->getBookmark(), m_pSeekCursor
->getBookmark()))
2339 // dummerweise kann das moveToBookmark indirekt dazu fuehren, dass der Seek-Cursor wieder neu positoniert wird (wenn
2340 // naemlich das mit all seinen zu feuernden Events relativ komplexe moveToBookmark irgendwo ein Update ausloest),
2341 // also muss ich es nochmal versuchen
2342 m_pSeekCursor
->moveToBookmark(m_pDataCursor
->getBookmark());
2343 // Nicht dass das jetzt nicht auch schief gegangen sein koennte, aber es ist zumindest unwahrscheinlicher geworden.
2344 // Und die Alternative waere eine Schleife so lange bis es stimmt, und das kann auch nicht die Loesung sein
2345 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2354 //------------------------------------------------------------------------------
2355 sal_Bool
DbGridControl::SeekCursor(long nRow
, sal_Bool bAbsolute
)
2357 DBG_CHKTHIS( DbGridControl
, NULL
);
2358 // Positioniert den SeekCursor, Daten werden nicht uebertragen
2360 // additions for the filtermode
2361 if (IsFilterRow(nRow
))
2370 // Befinden wir uns gerade beim Einfuegen
2371 if (IsValid(m_xCurrentRow
) && m_xCurrentRow
->IsNew() &&
2372 nRow
>= m_nCurrentPos
)
2374 // dann darf auf alle Faelle nicht weiter nach unten gescrollt werden
2375 // da der letzte Datensatz bereits erreicht wurde!
2376 if (nRow
== m_nCurrentPos
)
2378 // auf die aktuelle Zeile bewegt, dann muß kein abgleich gemacht werden, wenn
2379 // gerade ein Datensatz eingefuegt wird
2382 else if (IsInsertionRow(nRow
)) // Leerzeile zum Einfuegen von Datensaetzen
2385 else if (IsInsertionRow(nRow
)) // Leerzeile zum Einfuegen von Datensaetzen
2387 else if ((-1 == nRow
) && (GetRowCount() == ((m_nOptions
& OPT_INSERT
) ? 1 : 0)) && m_pSeekCursor
->isAfterLast())
2392 sal_Bool bSuccess
=sal_False
;
2396 if ( m_pSeekCursor
->rowDeleted() )
2398 // somebody deleted the current row of the seek cursor. Move it away from this row.
2399 m_pSeekCursor
->next();
2400 if ( m_pSeekCursor
->isAfterLast() || m_pSeekCursor
->isBeforeFirst() )
2401 bAbsolute
= sal_True
;
2406 DBG_ASSERT( !m_pSeekCursor
->isAfterLast() && !m_pSeekCursor
->isBeforeFirst(),
2407 "DbGridControl::SeekCursor: how did the seek cursor get to this position?!" );
2408 nSteps
= nRow
- (m_pSeekCursor
->getRow() - 1);
2409 bAbsolute
= bAbsolute
|| (abs(nSteps
) > 100);
2414 bSuccess
= m_pSeekCursor
->absolute(nRow
+ 1);
2420 if (nSteps
> 0) // auf den letzten benoetigten Datensatz positionieren
2422 if (m_pSeekCursor
->isAfterLast())
2423 bSuccess
= sal_False
;
2424 else if (m_pSeekCursor
->isBeforeFirst())
2425 bSuccess
= m_pSeekCursor
->absolute(nSteps
);
2427 bSuccess
= m_pSeekCursor
->relative(nSteps
);
2429 else if (nSteps
< 0)
2431 if (m_pSeekCursor
->isBeforeFirst())
2432 bSuccess
= sal_False
;
2433 else if (m_pSeekCursor
->isAfterLast())
2434 bSuccess
= m_pSeekCursor
->absolute(nSteps
);
2436 bSuccess
= m_pSeekCursor
->relative(nSteps
);
2447 OSL_FAIL("DbGridControl::SeekCursor : failed ...");
2454 if (bAbsolute
|| nSteps
> 0)
2456 if (m_pSeekCursor
->isLast())
2459 bSuccess
= m_pSeekCursor
->last();
2463 if (m_pSeekCursor
->isFirst())
2464 bSuccess
= sal_True
;
2466 bSuccess
= m_pSeekCursor
->first();
2471 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2477 OSL_FAIL("DbGridControl::SeekCursor : failed ...");
2478 DBG_UNHANDLED_EXCEPTION();
2479 m_nSeekPos
= -1; // kein Datensatz mehr vorhanden
2482 return m_nSeekPos
== nRow
;
2484 //------------------------------------------------------------------------------
2485 void DbGridControl::MoveToFirst()
2487 if (m_pSeekCursor
&& (GetCurRow() != 0))
2491 //------------------------------------------------------------------------------
2492 void DbGridControl::MoveToLast()
2497 if (m_nTotalCount
< 0) // RecordCount steht noch nicht fest
2501 sal_Bool bRes
= m_pSeekCursor
->last();
2505 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2514 // auf den letzen Datensatz positionieren, nicht auf die Leerzeile
2515 if (m_nOptions
& OPT_INSERT
)
2517 if ((GetRowCount() - 1) > 0)
2518 MoveToPosition(GetRowCount() - 2);
2520 else if (GetRowCount())
2521 MoveToPosition(GetRowCount() - 1);
2524 //------------------------------------------------------------------------------
2525 void DbGridControl::MoveToPrev()
2527 long nNewRow
= std::max(GetCurRow() - 1L, 0L);
2528 if (GetCurRow() != nNewRow
)
2529 MoveToPosition(nNewRow
);
2532 //------------------------------------------------------------------------------
2533 void DbGridControl::MoveToNext()
2538 if (m_nTotalCount
> 0)
2540 // move the data cursor to the right position
2541 long nNewRow
= std::min(GetRowCount() - 1, GetCurRow() + 1);
2542 if (GetCurRow() != nNewRow
)
2543 MoveToPosition(nNewRow
);
2547 sal_Bool bOk
= sal_False
;
2550 // try to move to next row
2551 // when not possible our paint cursor is already on the last row
2552 // then we must be sure that the data cursor is on the position
2553 // we call ourself again
2554 bOk
= m_pSeekCursor
->next();
2557 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2558 MoveToPosition(GetCurRow() + 1);
2561 catch(SQLException
&)
2563 DBG_UNHANDLED_EXCEPTION();
2569 if (m_nTotalCount
> 0) // only to avoid infinte recursion
2575 //------------------------------------------------------------------------------
2576 void DbGridControl::MoveToPosition(sal_uInt32 nPos
)
2581 if (m_nTotalCount
< 0 && (long)nPos
>= GetRowCount())
2585 if (!m_pSeekCursor
->absolute(nPos
+ 1))
2592 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2601 DbGridControl_Base::GoToRow(nPos
);
2602 m_aBar
.InvalidateAll(m_nCurrentPos
);
2605 //------------------------------------------------------------------------------
2606 void DbGridControl::AppendNew()
2608 if (!m_pSeekCursor
|| !(m_nOptions
& OPT_INSERT
))
2611 if (m_nTotalCount
< 0) // RecordCount steht noch nicht fest
2615 sal_Bool bRes
= m_pSeekCursor
->last();
2619 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
2629 long nNewRow
= m_nTotalCount
+ 1;
2630 if (nNewRow
> 0 && GetCurRow() != nNewRow
)
2631 MoveToPosition(nNewRow
- 1);
2634 //------------------------------------------------------------------------------
2635 void DbGridControl::SetDesignMode(sal_Bool bMode
)
2637 if (IsDesignMode() != bMode
)
2639 // Enable/Disable f�r den Designmode anpassen damit die Headerbar konfigurierbar bleibt
2645 GetDataWindow().Disable();
2650 // komplett disablen
2651 if (!GetDataWindow().IsEnabled())
2655 m_bDesignMode
= bMode
;
2656 GetDataWindow().SetMouseTransparent(bMode
);
2657 SetMouseTransparent(bMode
);
2659 m_aBar
.InvalidateAll(m_nCurrentPos
, sal_True
);
2663 //------------------------------------------------------------------------------
2664 void DbGridControl::SetFilterMode(sal_Bool bMode
)
2666 if (IsFilterMode() != bMode
)
2668 m_bFilterMode
= bMode
;
2672 SetUpdateMode(sal_False
);
2674 // es gibt kein Cursor mehr
2677 RemoveRows(sal_False
);
2679 m_xEmptyRow
= new DbGridRow();
2681 // setting the new filter controls
2682 for ( size_t i
= 0; i
< m_aColumns
.size(); ++i
)
2684 DbGridColumn
* pCurCol
= m_aColumns
[ i
];
2685 if (!pCurCol
->IsHidden())
2686 pCurCol
->UpdateControl();
2689 // one row for filtering
2690 RowInserted(0, 1, sal_True
);
2691 SetUpdateMode(sal_True
);
2694 setDataSource(Reference
< XRowSet
> ());
2697 // -----------------------------------------------------------------------------
2698 String
DbGridControl::GetCellText(long _nRow
, sal_uInt16 _nColId
) const
2700 size_t Location
= GetModelColumnPos( _nColId
);
2701 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
2703 if ( const_cast<DbGridControl
*>(this)->SeekRow(_nRow
) )
2704 sRet
= GetCurrentRowCellText(pColumn
, m_xPaintRow
);
2707 //------------------------------------------------------------------------------
2708 XubString
DbGridControl::GetCurrentRowCellText(DbGridColumn
* pColumn
,const DbGridRowRef
& _rRow
) const
2710 // Ausgabe des Textes fuer eine Zelle
2712 if ( pColumn
&& IsValid(_rRow
) )
2713 aText
= pColumn
->GetCellText(_rRow
, m_xFormatter
);
2717 //------------------------------------------------------------------------------
2718 sal_uInt32
DbGridControl::GetTotalCellWidth(long nRow
, sal_uInt16 nColId
)
2722 size_t Location
= GetModelColumnPos( nColId
);
2723 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
2724 return GetDataWindow().GetTextWidth(GetCurrentRowCellText(pColumn
,m_xPaintRow
));
2730 //------------------------------------------------------------------------------
2731 void DbGridControl::PreExecuteRowContextMenu(sal_uInt16
/*nRow*/, PopupMenu
& rMenu
)
2733 sal_Bool bDelete
= (m_nOptions
& OPT_DELETE
) && GetSelectRowCount() && !IsCurrentAppending();
2734 // ist nur die Leerzeile selektiert, dann nicht loeschen
2735 bDelete
= bDelete
&& !((m_nOptions
& OPT_INSERT
) && GetSelectRowCount() == 1 && IsRowSelected(GetRowCount() - 1));
2737 rMenu
.EnableItem(SID_FM_DELETEROWS
, bDelete
);
2738 rMenu
.EnableItem(SID_FM_RECORD_SAVE
, IsModified());
2740 // the undo is more difficult
2741 sal_Bool bCanUndo
= IsModified();
2743 if (m_aMasterStateProvider
.IsSet())
2744 nState
= m_aMasterStateProvider
.Call((void*)SID_FM_RECORD_UNDO
);
2745 bCanUndo
&= ( 0 != nState
);
2747 rMenu
.EnableItem(SID_FM_RECORD_UNDO
, bCanUndo
);
2750 //------------------------------------------------------------------------------
2751 void DbGridControl::PostExecuteRowContextMenu(sal_uInt16
/*nRow*/, const PopupMenu
& /*rMenu*/, sal_uInt16 nExecutionResult
)
2753 switch (nExecutionResult
)
2755 case SID_FM_DELETEROWS
:
2758 Application::RemoveUserEvent(m_nDeleteEvent
);
2759 m_nDeleteEvent
= Application::PostUserEvent(LINK(this,DbGridControl
,OnDelete
));
2761 case SID_FM_RECORD_UNDO
:
2764 case SID_FM_RECORD_SAVE
:
2772 //------------------------------------------------------------------------------
2773 void DbGridControl::DataSourcePropertyChanged(const PropertyChangeEvent
& evt
) throw( RuntimeException
)
2775 SAL_INFO("svx.fmcomp", "DbGridControl::DataSourcePropertyChanged");
2776 SolarMutexGuard aGuard
;
2777 // prop "IsModified" changed ?
2778 // during update don't care about the modified state
2779 if (!IsUpdating() && evt
.PropertyName
== FM_PROP_ISMODIFIED
)
2781 Reference
< XPropertySet
> xSource(evt
.Source
, UNO_QUERY
);
2782 DBG_ASSERT( xSource
.is(), "DbGridControl::DataSourcePropertyChanged: invalid event source!" );
2783 sal_Bool bIsNew
= sal_False
;
2785 bIsNew
= ::comphelper::getBOOL(xSource
->getPropertyValue(FM_PROP_ISNEW
));
2787 if (bIsNew
&& m_xCurrentRow
.Is())
2789 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 !");
2790 sal_Int32 nRecordCount
= 0;
2791 xSource
->getPropertyValue(FM_PROP_ROWCOUNT
) >>= nRecordCount
;
2792 if (::comphelper::getBOOL(evt
.NewValue
))
2793 { // modified state changed from sal_False to sal_True and we're on a insert row
2794 // -> we've to add a new grid row
2795 if ((nRecordCount
== GetRowCount() - 1) && m_xCurrentRow
->IsNew())
2797 RowInserted(GetRowCount(), 1, sal_True
);
2798 InvalidateStatusCell(m_nCurrentPos
);
2799 m_aBar
.InvalidateAll(m_nCurrentPos
);
2803 { // modified state changed from sal_True to sal_False and we're on a insert row
2804 // we have two "new row"s at the moment : the one we're editing currently (where the current
2805 // column is the only dirty element) and a "new new" row which is completely clean. As the first
2806 // one is about to be cleaned, too, the second one is obsolet now.
2807 if (m_xCurrentRow
->IsNew() && nRecordCount
== (GetRowCount() - 2))
2809 RowRemoved(GetRowCount() - 1, 1, sal_True
);
2810 InvalidateStatusCell(m_nCurrentPos
);
2811 m_aBar
.InvalidateAll(m_nCurrentPos
);
2815 if (m_xCurrentRow
.Is())
2817 m_xCurrentRow
->SetStatus(::comphelper::getBOOL(evt
.NewValue
) ? GRS_MODIFIED
: GRS_CLEAN
);
2818 m_xCurrentRow
->SetNew( bIsNew
);
2819 InvalidateStatusCell(m_nCurrentPos
);
2820 SAL_INFO("svx.fmcomp", "modified flag changed, new state: " << ROWSTATUS(m_xCurrentRow
));
2825 //------------------------------------------------------------------------------
2826 void DbGridControl::StartDrag( sal_Int8
/*nAction*/, const Point
& rPosPixel
)
2828 if (!m_pSeekCursor
|| IsResizing())
2831 sal_uInt16 nColId
= GetColumnAtXPosPixel(rPosPixel
.X());
2832 long nRow
= GetRowAtYPosPixel(rPosPixel
.Y());
2833 if (nColId
!= HandleColumnId
&& nRow
>= 0)
2835 if (GetDataWindow().IsMouseCaptured())
2836 GetDataWindow().ReleaseMouse();
2838 size_t Location
= GetModelColumnPos( nColId
);
2839 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
2840 OStringTransferable
* pTransferable
= new OStringTransferable(GetCurrentRowCellText(pColumn
,m_xPaintRow
));
2841 Reference
< XTransferable
> xEnsureDelete(pTransferable
);
2842 pTransferable
->StartDrag(this, DND_ACTION_COPY
);
2846 //------------------------------------------------------------------------------
2847 sal_Bool
DbGridControl::canCopyCellText(sal_Int32 _nRow
, sal_Int16 _nColId
)
2850 && (_nRow
< GetRowCount())
2851 && (_nColId
!= HandleColumnId
)
2852 && (_nColId
<= ColCount());
2855 //------------------------------------------------------------------------------
2856 void DbGridControl::copyCellText(sal_Int32 _nRow
, sal_Int16 _nColId
)
2858 DBG_ASSERT(canCopyCellText(_nRow
, _nColId
), "DbGridControl::copyCellText: invalid call!");
2859 DbGridColumn
* pColumn
= m_aColumns
[ GetModelColumnPos(_nColId
) ];
2861 OStringTransfer::CopyString( GetCurrentRowCellText( pColumn
,m_xPaintRow
), this );
2864 //------------------------------------------------------------------------------
2865 void DbGridControl::executeRowContextMenu( long _nRow
, const Point
& _rPreferredPos
)
2867 PopupMenu
aContextMenu( SVX_RES( RID_SVXMNU_ROWS
) );
2869 PreExecuteRowContextMenu( (sal_uInt16
)_nRow
, aContextMenu
);
2870 aContextMenu
.RemoveDisabledEntries( sal_True
, sal_True
);
2871 PostExecuteRowContextMenu( (sal_uInt16
)_nRow
, aContextMenu
, aContextMenu
.Execute( this, _rPreferredPos
) );
2873 // TODO: why this weird cast to sal_uInt16? What if we really have more than 65535 lines?
2874 // -> change this to sal_uInt32
2877 //------------------------------------------------------------------------------
2878 void DbGridControl::Command(const CommandEvent
& rEvt
)
2880 switch (rEvt
.GetCommand())
2882 case COMMAND_CONTEXTMENU
:
2884 if ( !m_pSeekCursor
)
2886 DbGridControl_Base::Command(rEvt
);
2890 if ( !rEvt
.IsMouseEvent() )
2891 { // context menu requested by keyboard
2892 if ( GetSelectRowCount() )
2894 long nRow
= FirstSelectedRow( );
2896 ::Rectangle
aRowRect( GetRowRectPixel( nRow
, sal_True
) );
2897 executeRowContextMenu( nRow
, aRowRect
.LeftCenter() );
2904 sal_uInt16 nColId
= GetColumnAtXPosPixel(rEvt
.GetMousePosPixel().X());
2905 long nRow
= GetRowAtYPosPixel(rEvt
.GetMousePosPixel().Y());
2907 if (nColId
== HandleColumnId
)
2909 executeRowContextMenu( nRow
, rEvt
.GetMousePosPixel() );
2911 else if (canCopyCellText(nRow
, nColId
))
2913 PopupMenu
aContextMenu(SVX_RES(RID_SVXMNU_CELL
));
2914 aContextMenu
.RemoveDisabledEntries(sal_True
, sal_True
);
2915 switch (aContextMenu
.Execute(this, rEvt
.GetMousePosPixel()))
2918 copyCellText(nRow
, nColId
);
2924 DbGridControl_Base::Command(rEvt
);
2929 DbGridControl_Base::Command(rEvt
);
2933 //------------------------------------------------------------------------------
2934 IMPL_LINK(DbGridControl
, OnDelete
, void*, /*EMPTYTAG*/ )
2936 DBG_CHKTHIS(DbGridControl
, NULL
);
2938 DeleteSelectedRows();
2942 //------------------------------------------------------------------------------
2943 void DbGridControl::DeleteSelectedRows()
2945 DBG_ASSERT(GetSelection(), "keine selection!!!");
2951 //------------------------------------------------------------------------------
2952 CellController
* DbGridControl::GetController(long /*nRow*/, sal_uInt16 nColumnId
)
2954 if (!IsValid(m_xCurrentRow
) || !IsEnabled())
2957 size_t Location
= GetModelColumnPos(nColumnId
);
2958 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
2962 CellController
* pReturn
= NULL
;
2964 pReturn
= &pColumn
->GetController();
2967 if (::comphelper::hasProperty(FM_PROP_ENABLED
, pColumn
->getModel()))
2969 if (!::comphelper::getBOOL(pColumn
->getModel()->getPropertyValue(FM_PROP_ENABLED
)))
2973 sal_Bool bInsert
= (m_xCurrentRow
->IsNew() && (m_nOptions
& OPT_INSERT
));
2974 sal_Bool bUpdate
= (!m_xCurrentRow
->IsNew() && (m_nOptions
& OPT_UPDATE
));
2976 if ((bInsert
&& !pColumn
->IsAutoValue()) || bUpdate
|| m_bForceROController
)
2978 pReturn
= &pColumn
->GetController();
2981 // wenn es eine Edit-Zeile ist, kann ich ihr das forced read-only mitgeben
2982 if (!pReturn
->ISA(EditCellController
) && !pReturn
->ISA(SpinCellController
))
2983 // ich konnte den Controller in forceROController nicht auf ReadOnly setzen
2984 if (!bInsert
&& !bUpdate
)
2985 // ich bin nur hier, da m_bForceROController gesetzt war
2986 // -> lieber kein Controller als einer ohne RO
2994 //------------------------------------------------------------------------------
2995 void DbGridControl::InitController(CellControllerRef
& /*rController*/, long /*nRow*/, sal_uInt16 nColumnId
)
2997 size_t Location
= GetModelColumnPos(nColumnId
);
2998 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
3000 pColumn
->UpdateFromField(m_xCurrentRow
, m_xFormatter
);
3003 //------------------------------------------------------------------------------
3004 void DbGridControl::CellModified()
3006 SAL_INFO("svx.fmcomp", "DbGridControl::CellModified");
3009 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
3010 if (m_nAsynAdjustEvent
)
3012 SAL_INFO("svx.fmcomp", "forcing a synchron call to " << (m_bPendingAdjustRows
? "AdjustRows" : "AdustDataSource"));
3013 RemoveUserEvent(m_nAsynAdjustEvent
);
3014 m_nAsynAdjustEvent
= 0;
3016 // force the call : this should be no problem as we're probably running in the solar thread here
3017 // (cell modified is triggered by user actions)
3018 if (m_bPendingAdjustRows
)
3025 if (!IsFilterMode() && IsValid(m_xCurrentRow
) && !m_xCurrentRow
->IsModified())
3027 // Einschalten des Editiermodus
3028 // Datensatz soll eingefuegt werden
3029 if (m_xCurrentRow
->IsNew())
3031 m_xCurrentRow
->SetStatus(GRS_MODIFIED
);
3032 SAL_INFO("svx.fmcomp", "current row is new, new state: MODIFIED");
3033 // wenn noch keine Zeile hinzugefuegt wurde, dann neue hinzunehmen
3034 if (m_nCurrentPos
== GetRowCount() - 1)
3036 // RowCount um einen erhoehen
3037 RowInserted(GetRowCount(), 1, sal_True
);
3038 InvalidateStatusCell(m_nCurrentPos
);
3039 m_aBar
.InvalidateAll(m_nCurrentPos
);
3042 else if (m_xCurrentRow
->GetStatus() != GRS_MODIFIED
)
3044 m_xCurrentRow
->SetState(m_pDataCursor
, sal_False
);
3045 SAL_INFO("svx.fmcomp", "current row is not new, after SetState, new state: " << ROWSTATUS(m_xCurrentRow
));
3046 m_xCurrentRow
->SetStatus(GRS_MODIFIED
);
3047 SAL_INFO("svx.fmcomp", "current row is not new, new state: MODIFIED");
3048 InvalidateStatusCell(m_nCurrentPos
);
3053 //------------------------------------------------------------------------------
3054 void DbGridControl::Dispatch(sal_uInt16 nId
)
3056 if (nId
== BROWSER_CURSORENDOFFILE
)
3058 if (m_nOptions
& OPT_INSERT
)
3064 DbGridControl_Base::Dispatch(nId
);
3067 //------------------------------------------------------------------------------
3068 void DbGridControl::Undo()
3070 if (!IsFilterMode() && IsValid(m_xCurrentRow
) && IsModified())
3072 // check if we have somebody doin' the UNDO for us
3074 if (m_aMasterStateProvider
.IsSet())
3075 nState
= m_aMasterStateProvider
.Call((void*)SID_FM_RECORD_UNDO
);
3077 { // yes, we have, and the slot is enabled
3078 DBG_ASSERT(m_aMasterSlotExecutor
.IsSet(), "DbGridControl::Undo : a state, but no execute link ?");
3079 long lResult
= m_aMasterSlotExecutor
.Call((void*)SID_FM_RECORD_UNDO
);
3084 else if (nState
== 0)
3085 // yes, we have, and the slot is disabled
3088 BeginCursorAction();
3090 sal_Bool bAppending
= m_xCurrentRow
->IsNew();
3091 sal_Bool bDirty
= m_xCurrentRow
->IsModified();
3095 // Editieren abbrechen
3096 Reference
< XResultSetUpdate
> xUpdateCursor((Reference
< XInterface
>)*m_pDataCursor
, UNO_QUERY
);
3097 // no effects if we're not updating currently
3099 // just refresh the row
3100 xUpdateCursor
->moveToInsertRow();
3102 xUpdateCursor
->cancelRowUpdates();
3107 DBG_UNHANDLED_EXCEPTION();
3112 m_xDataRow
->SetState(m_pDataCursor
, sal_False
);
3113 if (&m_xPaintRow
== &m_xCurrentRow
)
3114 m_xPaintRow
= m_xCurrentRow
= m_xDataRow
;
3116 m_xCurrentRow
= m_xDataRow
;
3118 if (bAppending
&& (DbGridControl_Base::IsModified() || bDirty
))
3120 if (m_nCurrentPos
== GetRowCount() - 2)
3121 { // maybe we already removed it (in resetCurrentRow, called if the above moveToInsertRow
3122 // caused our data source form to be reset - which should be the usual case ....)
3123 RowRemoved(GetRowCount() - 1, 1, sal_True
);
3124 m_aBar
.InvalidateAll(m_nCurrentPos
);
3127 RowModified(m_nCurrentPos
);
3131 //------------------------------------------------------------------------------
3132 void DbGridControl::resetCurrentRow()
3136 // scenario : we're on the insert row, the row is dirty, and thus there exists a "second" insert row (which
3137 // is clean). Normally in DataSourcePropertyChanged we would remove this second row if the modified state of
3138 // the insert row changes from sal_True to sal_False. But if our current cell is the only modified element (means the
3139 // data source isn't modified) and we're reset this DataSourcePropertyChanged would never be called, so we
3140 // would never delete the obsolet "second insert row". Thus in this special case this method here
3141 // is the only possibility to determine the redundance of the row (resetCurrentRow is called when the
3142 // "first insert row" is about to be cleaned, so of course the "second insert row" is redundant now)
3143 Reference
< XPropertySet
> xDataSource
= getDataSource()->getPropertySet();
3144 if (xDataSource
.is() && !::comphelper::getBOOL(xDataSource
->getPropertyValue(FM_PROP_ISMODIFIED
)))
3146 // are we on a new row currently ?
3147 if (m_xCurrentRow
->IsNew())
3149 if (m_nCurrentPos
== GetRowCount() - 2)
3151 RowRemoved(GetRowCount() - 1, 1, sal_True
);
3152 m_aBar
.InvalidateAll(m_nCurrentPos
);
3158 m_xDataRow
->SetState(m_pDataCursor
, sal_False
);
3159 if (&m_xPaintRow
== &m_xCurrentRow
)
3160 m_xPaintRow
= m_xCurrentRow
= m_xDataRow
;
3162 m_xCurrentRow
= m_xDataRow
;
3165 RowModified(GetCurRow()); // will update the current controller if affected
3168 //------------------------------------------------------------------------------
3169 void DbGridControl::RowModified( long nRow
, sal_uInt16
/*nColId*/ )
3171 if (nRow
== m_nCurrentPos
&& IsEditing())
3173 CellControllerRef aTmpRef
= Controller();
3174 aTmpRef
->ClearModified();
3175 InitController(aTmpRef
, m_nCurrentPos
, GetCurColumnId());
3177 DbGridControl_Base::RowModified(nRow
);
3180 //------------------------------------------------------------------------------
3181 sal_Bool
DbGridControl::IsModified() const
3183 return !IsFilterMode() && IsValid(m_xCurrentRow
) && (m_xCurrentRow
->IsModified() || DbGridControl_Base::IsModified());
3186 //------------------------------------------------------------------------------
3187 sal_Bool
DbGridControl::IsCurrentAppending() const
3189 return m_xCurrentRow
.Is() && m_xCurrentRow
->IsNew();
3192 //------------------------------------------------------------------------------
3193 sal_Bool
DbGridControl::IsInsertionRow(long nRow
) const
3195 return (m_nOptions
& OPT_INSERT
) && m_nTotalCount
>= 0 && (nRow
== GetRowCount() - 1);
3198 //------------------------------------------------------------------------------
3199 sal_Bool
DbGridControl::SaveModified()
3201 SAL_INFO("svx.fmcomp", "DbGridControl::SaveModified");
3202 DBG_ASSERT(IsValid(m_xCurrentRow
), "GridControl:: Invalid row");
3203 if (!IsValid(m_xCurrentRow
))
3206 // Uebernimmt die Dateneingabe fuer das Feld
3207 // Hat es aenderungen im aktuellen Eingabefeld gegeben ?
3208 if (!DbGridControl_Base::IsModified())
3211 size_t Location
= GetModelColumnPos( GetCurColumnId() );
3212 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
3213 sal_Bool bOK
= pColumn
->Commit();
3214 DBG_ASSERT( Controller().Is(), "DbGridControl::SaveModified: was modified, by have no controller?!" );
3215 if ( !Controller().Is() )
3216 // this might happen if the callbacks implicitly triggered by Commit
3217 // fiddled with the form or the control ...
3218 // (Note that this here is a workaround, at most. We need a general concept how
3219 // to treat this, you can imagine an arbitrary number of scenarios where a callback
3220 // triggers something which leaves us in an expected state.)
3221 // #i67147# / 2006-07-17 / frank.schoenheit@sun.com
3226 Controller()->ClearModified();
3228 if ( IsValid(m_xCurrentRow
) )
3230 m_xCurrentRow
->SetState(m_pDataCursor
, sal_False
);
3231 SAL_INFO("svx.fmcomp", "explicit SetState, new state: " << ROWSTATUS(m_xCurrentRow
));
3232 InvalidateStatusCell( m_nCurrentPos
);
3236 SAL_INFO("svx.fmcomp", "no SetState, new state: " << ROWSTATUS(m_xCurrentRow
));
3241 // reset the modified flag ....
3242 Controller()->SetModified();
3248 //------------------------------------------------------------------------------
3249 sal_Bool
DbGridControl::SaveRow()
3251 SAL_INFO("svx.fmcomp", "DbGridControl::SaveRow");
3253 if (!IsValid(m_xCurrentRow
) || !IsModified())
3255 // Wert des Controllers noch nicht gespeichert
3256 else if (Controller().Is() && Controller()->IsModified())
3258 if (!SaveModified())
3261 m_bUpdating
= sal_True
;
3263 BeginCursorAction();
3264 sal_Bool bAppending
= m_xCurrentRow
->IsNew();
3265 sal_Bool bSuccess
= sal_False
;
3268 Reference
< XResultSetUpdate
> xUpdateCursor((Reference
< XInterface
>)*m_pDataCursor
, UNO_QUERY
);
3270 xUpdateCursor
->insertRow();
3272 xUpdateCursor
->updateRow();
3273 bSuccess
= sal_True
;
3275 catch(SQLException
&)
3278 m_bUpdating
= sal_False
;
3286 // if we are appending we still sit on the insert row
3287 // we don't move just clear the flags not to move on the current row
3288 m_xCurrentRow
->SetState(m_pDataCursor
, sal_False
);
3289 SAL_INFO("svx.fmcomp", "explicit SetState after a successful update, new state: " << ROWSTATUS(m_xCurrentRow
));
3290 m_xCurrentRow
->SetNew(sal_False
);
3292 // adjust the seekcursor if it is on the same position as the datacursor
3293 if (m_nSeekPos
== m_nCurrentPos
|| bAppending
)
3295 // get the bookmark to refetch the data
3296 // in insert mode we take the new bookmark of the data cursor
3297 Any aBookmark
= bAppending
? m_pDataCursor
->getBookmark() : m_pSeekCursor
->getBookmark();
3298 m_pSeekCursor
->moveToBookmark(aBookmark
);
3300 m_xSeekRow
->SetState(m_pSeekCursor
, sal_True
);
3301 m_nSeekPos
= m_pSeekCursor
->getRow() - 1;
3304 // and repaint the row
3305 RowModified(m_nCurrentPos
);
3311 m_bUpdating
= sal_False
;
3314 // The old code returned (nRecords != 0) here.
3315 // Me thinks this is wrong : If something goes wrong while update the record, an exception will be thrown,
3316 // which results in a "return sal_False" (see above). If no exception is thrown, everything is fine. If nRecords
3317 // is zero, this simply means all fields had their original values.
3318 // FS - 06.12.99 - 70502
3322 //------------------------------------------------------------------------------
3323 long DbGridControl::PreNotify(NotifyEvent
& rEvt
)
3325 // keine Events der Navbar behandeln
3326 if (m_aBar
.IsWindowOrChild(rEvt
.GetWindow()))
3327 return BrowseBox::PreNotify(rEvt
);
3329 switch (rEvt
.GetType())
3331 case EVENT_KEYINPUT
:
3333 const KeyEvent
* pKeyEvent
= rEvt
.GetKeyEvent();
3335 sal_uInt16 nCode
= pKeyEvent
->GetKeyCode().GetCode();
3336 sal_Bool bShift
= pKeyEvent
->GetKeyCode().IsShift();
3337 sal_Bool bCtrl
= pKeyEvent
->GetKeyCode().IsMod1();
3338 sal_Bool bAlt
= pKeyEvent
->GetKeyCode().IsMod2();
3339 if ( ( KEY_TAB
== nCode
) && bCtrl
&& !bAlt
)
3341 // Ctrl-Tab is used to step out of the control, without traveling to the
3342 // remaining cells first
3343 // -> build a new key event without the Ctrl-key, and let the very base class handle it
3344 KeyCode
aNewCode( KEY_TAB
, bShift
, sal_False
, sal_False
, sal_False
);
3345 KeyEvent
aNewEvent( pKeyEvent
->GetCharCode(), aNewCode
);
3347 // call the Control - our direct base class will interpret this in a way we do not want (and do
3348 // a cell traveling)
3349 Control::KeyInput( aNewEvent
);
3353 if ( !bShift
&& !bCtrl
&& ( KEY_ESCAPE
== nCode
) )
3361 else if ( ( KEY_DELETE
== nCode
) && !bShift
&& !bCtrl
) // delete rows
3363 if ((m_nOptions
& OPT_DELETE
) && GetSelectRowCount())
3367 Application::RemoveUserEvent(m_nDeleteEvent
);
3368 m_nDeleteEvent
= Application::PostUserEvent(LINK(this,DbGridControl
,OnDelete
));
3374 return DbGridControl_Base::PreNotify(rEvt
);
3378 //------------------------------------------------------------------------------
3379 sal_Bool
DbGridControl::IsTabAllowed(sal_Bool bRight
) const
3382 // Tab nur wenn nicht auf der letzten Zelle
3383 return GetCurRow() < (GetRowCount() - 1) || !m_bRecordCountFinal
||
3384 GetViewColumnPos(GetCurColumnId()) < (GetViewColCount() - 1);
3387 // Tab nur wenn nicht auf der ersten Zelle
3388 return GetCurRow() > 0 || (GetCurColumnId() && GetViewColumnPos(GetCurColumnId()) > 0);
3392 //------------------------------------------------------------------------------
3393 void DbGridControl::KeyInput( const KeyEvent
& rEvt
)
3395 if (rEvt
.GetKeyCode().GetFunction() == KEYFUNC_COPY
)
3397 long nRow
= GetCurRow();
3398 sal_uInt16 nColId
= GetCurColumnId();
3399 if (nRow
>= 0 && nRow
< GetRowCount() && nColId
< ColCount())
3401 size_t Location
= GetModelColumnPos( nColId
);
3402 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
3403 OStringTransfer::CopyString( GetCurrentRowCellText( pColumn
, m_xCurrentRow
), this );
3407 DbGridControl_Base::KeyInput(rEvt
);
3410 //------------------------------------------------------------------------------
3411 void DbGridControl::HideColumn(sal_uInt16 nId
)
3415 // determine the col for the focus to set to after removal
3416 sal_uInt16 nPos
= GetViewColumnPos(nId
);
3417 sal_uInt16 nNewColId
= nPos
== (ColCount()-1)
3418 ? GetColumnIdFromViewPos(nPos
-1) // last col is to be removed -> take the previous
3419 : GetColumnIdFromViewPos(nPos
+1); // take the next
3421 long lCurrentWidth
= GetColumnWidth(nId
);
3422 DbGridControl_Base::RemoveColumn(nId
);
3423 // don't use my own RemoveColumn, this would remove it from m_aColumns, too
3426 size_t Location
= GetModelColumnPos( nId
);
3427 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
3428 DBG_ASSERT(pColumn
, "DbGridControl::HideColumn : somebody did hide a nonexistent column !");
3431 pColumn
->m_bHidden
= sal_True
;
3432 pColumn
->m_nLastVisibleWidth
= CalcReverseZoom(lCurrentWidth
);
3435 // and reset the focus
3436 if ( nId
== GetCurColumnId() )
3437 GoToColumnId( nNewColId
);
3440 //------------------------------------------------------------------------------
3441 void DbGridControl::ShowColumn(sal_uInt16 nId
)
3443 sal_uInt16 nPos
= GetModelColumnPos(nId
);
3444 DBG_ASSERT(nPos
!= GRID_COLUMN_NOT_FOUND
, "DbGridControl::ShowColumn : invalid argument !");
3445 if (nPos
== GRID_COLUMN_NOT_FOUND
)
3448 DbGridColumn
* pColumn
= m_aColumns
[ nPos
];
3449 if (!pColumn
->IsHidden())
3451 DBG_ASSERT(GetViewColumnPos(nId
) != GRID_COLUMN_NOT_FOUND
, "DbGridControl::ShowColumn : inconsistent internal state !");
3452 // if the column isn't marked as hidden, it should be visible, shouldn't it ?
3455 DBG_ASSERT(GetViewColumnPos(nId
) == GRID_COLUMN_NOT_FOUND
, "DbGridControl::ShowColumn : inconsistent internal state !");
3456 // the opposite situation ...
3458 // to determine the new view position we need an adjacent non-hidden column
3459 sal_uInt16 nNextNonHidden
= BROWSER_INVALIDID
;
3460 // first search the cols to the right
3461 for ( size_t i
= nPos
+ 1; i
< m_aColumns
.size(); ++i
)
3463 DbGridColumn
* pCurCol
= m_aColumns
[ i
];
3464 if (!pCurCol
->IsHidden())
3470 if ((nNextNonHidden
== BROWSER_INVALIDID
) && (nPos
> 0))
3473 for ( size_t i
= nPos
; i
> 0; --i
)
3475 DbGridColumn
* pCurCol
= m_aColumns
[ i
-1 ];
3476 if (!pCurCol
->IsHidden())
3478 nNextNonHidden
= i
-1;
3483 sal_uInt16 nNewViewPos
= (nNextNonHidden
== BROWSER_INVALIDID
)
3484 ? 1 // there is no visible column -> insert behinde the handle col
3485 : GetViewColumnPos( m_aColumns
[ nNextNonHidden
]->GetId() ) + 1;
3486 // the first non-handle col has "view pos" 0, but the pos arg for InsertDataColumn expects
3487 // a position 1 for the first non-handle col -> +1
3488 DBG_ASSERT(nNewViewPos
!= GRID_COLUMN_NOT_FOUND
, "DbGridControl::ShowColumn : inconsistent internal state !");
3489 // we found a col marked as visible but got no view pos for it ...
3491 if ((nNextNonHidden
<nPos
) && (nNextNonHidden
!= BROWSER_INVALIDID
))
3492 // nNextNonHidden is a column to the left, so we want to insert the new col _right_ beside it's pos
3498 pColumn
->getModel()->getPropertyValue(FM_PROP_LABEL
) >>= aName
;
3499 InsertDataColumn(nId
, aName
, CalcZoom(pColumn
->m_nLastVisibleWidth
), HIB_CENTER
| HIB_VCENTER
| HIB_CLICKABLE
, nNewViewPos
);
3500 pColumn
->m_bHidden
= sal_False
;
3506 //------------------------------------------------------------------------------
3507 sal_uInt16
DbGridControl::GetColumnIdFromModelPos( sal_uInt16 nPos
) const
3509 if (nPos
>= m_aColumns
.size())
3511 OSL_FAIL("DbGridControl::GetColumnIdFromModelPos : invalid argument !");
3512 return GRID_COLUMN_NOT_FOUND
;
3515 DbGridColumn
* pCol
= m_aColumns
[ nPos
];
3516 #if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
3517 // in der Debug-Version rechnen wir die ModelPos in eine ViewPos um und vergleichen das mit dem Wert,
3518 // den wir zurueckliefern werden (nId an der entsprechenden Col in m_aColumns)
3520 if (!pCol
->IsHidden())
3521 { // macht nur Sinn, wenn die Spalte sichtbar ist
3522 sal_uInt16 nViewPos
= nPos
;
3523 for ( size_t i
= 0; i
< m_aColumns
.size() && i
< nPos
; ++i
)
3524 if ( m_aColumns
[ i
]->IsHidden())
3527 DBG_ASSERT(pCol
&& GetColumnIdFromViewPos(nViewPos
) == pCol
->GetId(),
3528 "DbGridControl::GetColumnIdFromModelPos : this isn't consistent .... did I misunderstand something ?");
3531 return pCol
->GetId();
3534 //------------------------------------------------------------------------------
3535 sal_uInt16
DbGridControl::GetModelColumnPos( sal_uInt16 nId
) const
3537 for ( size_t i
= 0; i
< m_aColumns
.size(); ++i
)
3538 if ( m_aColumns
[ i
]->GetId() == nId
)
3541 return GRID_COLUMN_NOT_FOUND
;
3544 //------------------------------------------------------------------------------
3545 void DbGridControl::implAdjustInSolarThread(sal_Bool _bRows
)
3547 SAL_INFO("svx.fmcomp", "DbGridControl::implAdjustInSolarThread");
3548 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
3549 if (::osl::Thread::getCurrentIdentifier() != Application::GetMainThreadIdentifier())
3551 m_nAsynAdjustEvent
= PostUserEvent(LINK(this, DbGridControl
, OnAsyncAdjust
), reinterpret_cast< void* >( _bRows
));
3552 m_bPendingAdjustRows
= _bRows
;
3554 SAL_INFO("svx.fmcomp", "posting an AdjustRows");
3556 SAL_INFO("svx.fmcomp", "posting an AdjustDataSource");
3561 SAL_INFO("svx.fmcomp", "doing an AdjustRows");
3563 SAL_INFO("svx.fmcomp", "doing an AdjustDataSource");
3564 // always adjust the rows before adjusting the data source
3565 // If this is not necessary (because the row count did not change), nothing is done
3566 // The problem is that we can't rely on the order of which the calls come in: If the cursor was moved
3567 // to a position behind row count know 'til now, the cursorMoved notification may come before the
3568 // RowCountChanged notification
3569 // 94093 - 02.11.2001 - frank.schoenheit@sun.com
3577 //------------------------------------------------------------------------------
3578 IMPL_LINK(DbGridControl
, OnAsyncAdjust
, void*, pAdjustWhat
)
3580 m_nAsynAdjustEvent
= 0;
3583 // see implAdjustInSolarThread for a comment why we do this every time
3591 //------------------------------------------------------------------------------
3592 void DbGridControl::BeginCursorAction()
3594 if (m_pFieldListeners
)
3596 ColumnFieldValueListeners
* pListeners
= (ColumnFieldValueListeners
*)m_pFieldListeners
;
3597 ConstColumnFieldValueListenersIterator aIter
= pListeners
->begin();
3598 while (aIter
!= pListeners
->end())
3600 GridFieldValueListener
* pCurrent
= (*aIter
).second
;
3602 pCurrent
->suspend();
3607 if (m_pDataSourcePropListener
)
3608 m_pDataSourcePropListener
->suspend();
3611 //------------------------------------------------------------------------------
3612 void DbGridControl::EndCursorAction()
3614 if (m_pFieldListeners
)
3616 ColumnFieldValueListeners
* pListeners
= (ColumnFieldValueListeners
*)m_pFieldListeners
;
3617 ConstColumnFieldValueListenersIterator aIter
= pListeners
->begin();
3618 while (aIter
!= pListeners
->end())
3620 GridFieldValueListener
* pCurrent
= (*aIter
).second
;
3627 if (m_pDataSourcePropListener
)
3628 m_pDataSourcePropListener
->resume();
3631 //------------------------------------------------------------------------------
3632 void DbGridControl::ConnectToFields()
3634 ColumnFieldValueListeners
* pListeners
= (ColumnFieldValueListeners
*)m_pFieldListeners
;
3635 DBG_ASSERT(!pListeners
|| pListeners
->empty(), "DbGridControl::ConnectToFields : please call DisconnectFromFields first !");
3639 pListeners
= new ColumnFieldValueListeners
;
3640 m_pFieldListeners
= pListeners
;
3643 for ( size_t i
= 0; i
< m_aColumns
.size(); ++i
)
3645 DbGridColumn
* pCurrent
= m_aColumns
[ i
];
3646 sal_uInt16 nViewPos
= pCurrent
? GetViewColumnPos(pCurrent
->GetId()) : GRID_COLUMN_NOT_FOUND
;
3647 if (GRID_COLUMN_NOT_FOUND
== nViewPos
)
3650 Reference
< XPropertySet
> xField
= pCurrent
->GetField();
3654 // column is visible and bound here
3655 GridFieldValueListener
*& rpListener
= (*pListeners
)[pCurrent
->GetId()];
3656 DBG_ASSERT(!rpListener
, "DbGridControl::ConnectToFields : already a listener for this column ?!");
3657 rpListener
= new GridFieldValueListener(*this, xField
, pCurrent
->GetId());
3661 //------------------------------------------------------------------------------
3662 void DbGridControl::DisconnectFromFields()
3664 if (!m_pFieldListeners
)
3667 ColumnFieldValueListeners
* pListeners
= (ColumnFieldValueListeners
*)m_pFieldListeners
;
3668 while (pListeners
->size())
3671 sal_Int32 nOldSize
= pListeners
->size();
3673 pListeners
->begin()->second
->dispose();
3674 DBG_ASSERT(nOldSize
> (sal_Int32
)pListeners
->size(), "DbGridControl::DisconnectFromFields : dispose on a listener should result in a removal from my list !");
3678 m_pFieldListeners
= NULL
;
3681 //------------------------------------------------------------------------------
3682 void DbGridControl::FieldValueChanged(sal_uInt16 _nId
, const PropertyChangeEvent
& /*_evt*/)
3684 osl::MutexGuard
aPreventDestruction(m_aDestructionSafety
);
3685 // needed as this may run in a thread other than the main one
3686 if (GetRowStatus(GetCurRow()) != DbGridControl_Base::MODIFIED
)
3687 // all other cases are handled elsewhere
3690 size_t Location
= GetModelColumnPos( _nId
);
3691 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
3694 sal_Bool bAcquiredPaintSafety
= sal_False
;
3695 while (!m_bWantDestruction
&& !bAcquiredPaintSafety
)
3696 bAcquiredPaintSafety
= Application::GetSolarMutex().tryToAcquire();
3698 if (m_bWantDestruction
)
3699 { // at this moment, within another thread, our destructor tries to destroy the listener which called this method
3700 // => don't do anything
3701 // 73365 - 23.02.00 - FS
3702 if (bAcquiredPaintSafety
)
3703 // though the above while-loop suggests that (m_bWantDestruction && bAcquiredPaintSafety) is impossible,
3704 // it isnt't, as m_bWantDestruction isn't protected with any mutex
3705 Application::GetSolarMutex().release();
3708 // here we got the solar mutex, transfer it to a guard for safety reasons
3709 SolarMutexGuard aPaintSafety
;
3710 Application::GetSolarMutex().release();
3712 // and finally do the update ...
3713 pColumn
->UpdateFromField(m_xCurrentRow
, m_xFormatter
);
3714 RowModified(GetCurRow(), _nId
);
3718 //------------------------------------------------------------------------------
3719 void DbGridControl::FieldListenerDisposing(sal_uInt16 _nId
)
3721 ColumnFieldValueListeners
* pListeners
= (ColumnFieldValueListeners
*)m_pFieldListeners
;
3724 OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (have no listener array) !");
3728 ColumnFieldValueListenersIterator aPos
= pListeners
->find(_nId
);
3729 if (aPos
== pListeners
->end())
3731 OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (did not find the listener) !");
3735 delete aPos
->second
;
3737 pListeners
->erase(aPos
);
3740 //------------------------------------------------------------------------------
3741 void DbGridControl::disposing(sal_uInt16 _nId
, const EventObject
& /*_rEvt*/)
3744 { // the seek cursor is beeing disposed
3745 ::osl::MutexGuard
aGuard(m_aAdjustSafety
);
3746 setDataSource(NULL
,0); // our clone was disposed so we set our datasource to null to avoid later acces to it
3747 if (m_nAsynAdjustEvent
)
3749 RemoveUserEvent(m_nAsynAdjustEvent
);
3750 m_nAsynAdjustEvent
= 0;
3754 // -----------------------------------------------------------------------------
3755 sal_Int32
DbGridControl::GetAccessibleControlCount() const
3757 return DbGridControl_Base::GetAccessibleControlCount() + 1; // the navigation control
3759 // -----------------------------------------------------------------------------
3760 Reference
<XAccessible
> DbGridControl::CreateAccessibleControl( sal_Int32 _nIndex
)
3762 Reference
<XAccessible
> xRet
;
3763 if ( _nIndex
== DbGridControl_Base::GetAccessibleControlCount() )
3765 xRet
= m_aBar
.GetAccessible();
3768 xRet
= DbGridControl_Base::CreateAccessibleControl( _nIndex
);
3771 // -----------------------------------------------------------------------------
3772 Reference
< XAccessible
> DbGridControl::CreateAccessibleCell( sal_Int32 _nRow
, sal_uInt16 _nColumnPos
)
3774 sal_uInt16 nColumnId
= GetColumnId( _nColumnPos
);
3775 size_t Location
= GetModelColumnPos(nColumnId
);
3776 DbGridColumn
* pColumn
= ( Location
< m_aColumns
.size() ) ? m_aColumns
[ Location
] : NULL
;
3779 Reference
< ::com::sun::star::awt::XControl
> xInt(pColumn
->GetCell());
3780 Reference
< ::com::sun::star::awt::XCheckBox
> xBox(xInt
,UNO_QUERY
);
3783 TriState eValue
= STATE_NOCHECK
;
3784 switch( xBox
->getState() )
3787 eValue
= STATE_NOCHECK
;
3790 eValue
= STATE_CHECK
;
3793 eValue
= STATE_DONTKNOW
;
3796 return DbGridControl_Base::CreateAccessibleCheckBoxCell( _nRow
, _nColumnPos
,eValue
);
3799 return DbGridControl_Base::CreateAccessibleCell( _nRow
, _nColumnPos
);
3801 // -----------------------------------------------------------------------------
3804 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */