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