xref: /aoo42x/main/svx/source/fmcomp/gridctrl.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 
31 #ifndef _SVX_FMHELP_HRC
32 #include "fmhelp.hrc"
33 #endif
34 #include <svx/gridctrl.hxx>
35 #include "gridcell.hxx"
36 #include "svx/dbtoolsclient.hxx"
37 #include "svx/fmtools.hxx"
38 #include <svtools/stringtransfer.hxx>
39 
40 #ifndef _SVX_FMPROP_HRC
41 #include "fmprop.hrc"
42 #endif
43 #include <svtools/stringtransfer.hxx>
44 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
45 #include <com/sun/star/accessibility/XAccessible.hpp>
46 #include <com/sun/star/sdb/XResultSetAccess.hpp>
47 #include <com/sun/star/sdb/RowChangeAction.hpp>
48 #include <com/sun/star/sdb/XRowsChangeBroadcaster.hpp>
49 #include <com/sun/star/sdbc/XResultSetUpdate.hpp>
50 #include <com/sun/star/sdbcx/Privilege.hpp>
51 #include <com/sun/star/container/XChild.hpp>
52 #include <com/sun/star/util/XNumberFormatter.hpp>
53 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
54 #include <com/sun/star/util/XCloneable.hpp>
55 #include <com/sun/star/beans/XPropertySet.hpp>
56 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
57 #include <comphelper/extract.hxx>
58 #include <tools/resid.hxx>
59 #include <tools/diagnose_ex.h>
60 #include <vcl/sound.hxx>
61 #include <vcl/menu.hxx>
62 
63 #ifndef _SVX_FMRESIDS_HRC
64 #include "svx/fmresids.hrc"
65 #endif
66 
67 #ifndef _SVX_SVXIDS_HRC
68 #include <svx/svxids.hrc>
69 #endif
70 #include <tools/shl.hxx>
71 #include <svx/dialmgr.hxx>
72 #include "fmservs.hxx"
73 #include "sdbdatacolumn.hxx"
74 
75 #define HANDLE_ID	0
76 
77 #include <comphelper/stl_types.hxx>
78 #include <comphelper/property.hxx>
79 #include "trace.hxx"
80 
81 #include <algorithm>
82 
83 using namespace ::svxform;
84 using namespace ::svt;
85 using namespace ::com::sun::star::beans;
86 using namespace ::com::sun::star::lang;
87 using namespace ::com::sun::star::uno;
88 using namespace ::com::sun::star::sdbc;
89 using namespace ::com::sun::star::sdbcx;
90 using namespace ::com::sun::star::sdb;
91 using namespace ::com::sun::star::datatransfer;
92 using namespace ::com::sun::star::container;
93 using namespace com::sun::star::accessibility;
94 
95 #define ROWSTATUS(row)	!row.Is() ? "NULL" : row->GetStatus() == GRS_CLEAN ? "CLEAN" : row->GetStatus() == GRS_MODIFIED ? "MODIFIED" : row->GetStatus() == GRS_DELETED ? "DELETED" : "INVALID"
96 
97 
98 #define DEFAULT_BROWSE_MODE             \
99 			  BROWSER_COLUMNSELECTION   \
100 			| BROWSER_MULTISELECTION    \
101             | BROWSER_KEEPSELECTION     \
102 			| BROWSER_TRACKING_TIPS     \
103 			| BROWSER_HLINESFULL        \
104 			| BROWSER_VLINESFULL        \
105 			| BROWSER_HEADERBAR_NEW     \
106 
107 class RowSetEventListener : public ::cppu::WeakImplHelper1<XRowsChangeListener>
108 {
109     DbGridControl* m_pControl;
110 public:
111     RowSetEventListener(DbGridControl* i_pControl) : m_pControl(i_pControl)
112     {
113     }
114 private:
115     // XEventListener
116     virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& /*i_aEvt*/) throw ( RuntimeException )
117     {
118     }
119     virtual void SAL_CALL rowsChanged(const ::com::sun::star::sdb::RowsChangeEvent& i_aEvt) throw ( RuntimeException )
120     {
121         if ( i_aEvt.Action == RowChangeAction::UPDATE )
122         {
123             ::DbGridControl::GrantControlAccess aAccess;
124             CursorWrapper* pSeek = m_pControl->GetSeekCursor(aAccess);
125             const DbGridRowRef& rSeekRow = m_pControl->GetSeekRow(aAccess);
126             const Any* pIter = i_aEvt.Bookmarks.getConstArray();
127             const Any* pEnd  = pIter + i_aEvt.Bookmarks.getLength();
128             for(;pIter != pEnd;++pIter)
129             {
130                 pSeek->moveToBookmark(*pIter);
131 			    // get the data
132 			    rSeekRow->SetState(pSeek, sal_True);
133                 sal_Int32 nSeekPos = pSeek->getRow() - 1;
134 			    m_pControl->SetSeekPos(nSeekPos,aAccess);
135                 m_pControl->RowModified(nSeekPos);
136             }
137         }
138     }
139 };
140 //==============================================================================
141 
142 class GridFieldValueListener;
143 DECLARE_STL_MAP(sal_uInt16, GridFieldValueListener*, ::std::less<sal_uInt16>, ColumnFieldValueListeners);
144 
145 //==============================================================================
146 
147 DBG_NAME(GridFieldValueListener)
148 class GridFieldValueListener : protected ::comphelper::OPropertyChangeListener
149 {
150 	osl::Mutex							m_aMutex;
151 	DbGridControl&						m_rParent;
152 	::comphelper::OPropertyChangeMultiplexer*	m_pRealListener;
153 	sal_uInt16							m_nId;
154 	sal_Int16							m_nSuspended;
155 	sal_Bool							m_bDisposed : 1;
156 
157 public:
158 	GridFieldValueListener(DbGridControl& _rParent, const Reference< XPropertySet >& xField, sal_uInt16 _nId);
159 	virtual ~GridFieldValueListener();
160 
161 	virtual void _propertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException );
162 
163 	void suspend() { ++m_nSuspended; }
164 	void resume() { --m_nSuspended; }
165 
166 	void dispose();
167 };
168 //------------------------------------------------------------------------------
169 GridFieldValueListener::GridFieldValueListener(DbGridControl& _rParent, const Reference< XPropertySet >& _rField, sal_uInt16 _nId)
170 	:OPropertyChangeListener(m_aMutex)
171 	,m_rParent(_rParent)
172     ,m_pRealListener(NULL)
173 	,m_nId(_nId)
174     ,m_nSuspended(0)
175 	,m_bDisposed(sal_False)
176 {
177 	DBG_CTOR(GridFieldValueListener, NULL);
178 	if (_rField.is())
179 	{
180 		m_pRealListener = new ::comphelper::OPropertyChangeMultiplexer(this, _rField);
181 		m_pRealListener->addProperty(FM_PROP_VALUE);
182 		m_pRealListener->acquire();
183 	}
184 }
185 
186 //------------------------------------------------------------------------------
187 GridFieldValueListener::~GridFieldValueListener()
188 {
189 	DBG_DTOR(GridFieldValueListener, NULL);
190 	dispose();
191 }
192 
193 //------------------------------------------------------------------------------
194 void GridFieldValueListener::_propertyChanged(const PropertyChangeEvent& _evt) throw( RuntimeException )
195 {
196 	DBG_ASSERT(m_nSuspended>=0, "GridFieldValueListener::_propertyChanged : resume > suspend !");
197 	if (m_nSuspended <= 0)
198 		m_rParent.FieldValueChanged(m_nId, _evt);
199 }
200 
201 //------------------------------------------------------------------------------
202 void GridFieldValueListener::dispose()
203 {
204 	if (m_bDisposed)
205 	{
206 		DBG_ASSERT(m_pRealListener == NULL, "GridFieldValueListener::dispose : inconsistent !");
207 		return;
208 	}
209 
210 	if (m_pRealListener)
211 	{
212 		m_pRealListener->dispose();
213 		m_pRealListener->release();
214 		m_pRealListener = NULL;
215 	}
216 
217 	m_bDisposed = sal_True;
218 	m_rParent.FieldListenerDisposing(m_nId);
219 }
220 
221 //==============================================================================
222 
223 class DisposeListenerGridBridge : public FmXDisposeListener
224 {
225 	osl::Mutex				m_aMutex;
226 	DbGridControl&			m_rParent;
227 	FmXDisposeMultiplexer*	m_pRealListener;
228 
229 public:
230 	DisposeListenerGridBridge(	DbGridControl& _rParent, const Reference< XComponent >& _rxObject, sal_Int16 _rId = -1);
231 	virtual ~DisposeListenerGridBridge();
232 
233 	virtual void disposing(const EventObject& _rEvent, sal_Int16 _nId) throw( RuntimeException ) { m_rParent.disposing(_nId, _rEvent); }
234 };
235 
236 //==============================================================================
237 
238 
239 DBG_NAME(DisposeListenerGridBridge)
240 //------------------------------------------------------------------------------
241 DisposeListenerGridBridge::DisposeListenerGridBridge(DbGridControl& _rParent, const Reference< XComponent >& _rxObject, sal_Int16 _rId)
242 	:FmXDisposeListener(m_aMutex)
243 	,m_rParent(_rParent)
244 	,m_pRealListener(NULL)
245 {
246 	DBG_CTOR(DisposeListenerGridBridge,NULL);
247 
248 	if (_rxObject.is())
249 	{
250 		m_pRealListener = new FmXDisposeMultiplexer(this, _rxObject, _rId);
251 		m_pRealListener->acquire();
252 	}
253 }
254 
255 //------------------------------------------------------------------------------
256 DisposeListenerGridBridge::~DisposeListenerGridBridge()
257 {
258 	if (m_pRealListener)
259 	{
260 		m_pRealListener->dispose();
261 		m_pRealListener->release();
262 		m_pRealListener = NULL;
263 	}
264 
265 	DBG_DTOR(DisposeListenerGridBridge,NULL);
266 }
267 
268 //==============================================================================
269 
270 static sal_uInt16 ControlMap[] =
271 	{
272 		DbGridControl::NavigationBar::RECORD_TEXT,
273 		DbGridControl::NavigationBar::RECORD_ABSOLUTE,
274 		DbGridControl::NavigationBar::RECORD_OF,
275 		DbGridControl::NavigationBar::RECORD_COUNT,
276 		DbGridControl::NavigationBar::RECORD_FIRST,
277 		DbGridControl::NavigationBar::RECORD_NEXT,
278 		DbGridControl::NavigationBar::RECORD_PREV,
279 		DbGridControl::NavigationBar::RECORD_LAST,
280 		DbGridControl::NavigationBar::RECORD_NEW,
281 		0
282 	};
283 
284 //------------------------------------------------------------------------------
285 sal_Bool CompareBookmark(const Any& aLeft, const Any& aRight)
286 {
287 	return ::comphelper::compare(aLeft, aRight);
288 }
289 
290 //==============================================================================
291 class FmXGridSourcePropListener : public ::comphelper::OPropertyChangeListener
292 {
293 	DbGridControl* m_pParent;
294 
295 	// a DbGridControl has no mutex, so we use our own as the base class expects one
296 	osl::Mutex		m_aMutex;
297 	sal_Int16			m_nSuspended;
298 
299 public:
300 	FmXGridSourcePropListener(DbGridControl* _pParent);
301 
302 	void suspend() { ++m_nSuspended; }
303 	void resume() { --m_nSuspended; }
304 
305 	virtual void _propertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException );
306 };
307 
308 //------------------------------------------------------------------------------
309 FmXGridSourcePropListener::FmXGridSourcePropListener(DbGridControl* _pParent)
310 	:OPropertyChangeListener(m_aMutex)
311 	,m_pParent(_pParent)
312 	,m_nSuspended(0)
313 {
314 	DBG_ASSERT(m_pParent, "FmXGridSourcePropListener::FmXGridSourcePropListener : invalid parent !");
315 }
316 
317 //------------------------------------------------------------------------------
318 void FmXGridSourcePropListener::_propertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException )
319 {
320 	DBG_ASSERT(m_nSuspended>=0, "FmXGridSourcePropListener::_propertyChanged : resume > suspend !");
321 	if (m_nSuspended <= 0)
322 		m_pParent->DataSourcePropertyChanged(evt);
323 }
324 
325 //==============================================================================
326 //------------------------------------------------------------------------------
327 DbGridControl::NavigationBar::AbsolutePos::AbsolutePos(Window* pParent, WinBits nStyle)
328 				   :NumericField(pParent, nStyle)
329 {
330 	SetMin(1);
331 	SetFirst(1);
332 	SetSpinSize(1);
333 
334 	SetDecimalDigits(0);
335 	SetStrictFormat(sal_True);
336 }
337 
338 //------------------------------------------------------------------------------
339 void DbGridControl::NavigationBar::AbsolutePos::KeyInput(const KeyEvent& rEvt)
340 {
341 	if (rEvt.GetKeyCode() == KEY_RETURN && GetText().Len())
342 	{
343 		sal_Int64 nRecord = GetValue();
344 		if (nRecord < GetMin() || nRecord > GetMax())
345 			return;
346 		else
347 			((NavigationBar*)GetParent())->PositionDataSource(static_cast<sal_Int32>(nRecord));
348 	}
349 	else if (rEvt.GetKeyCode() == KEY_TAB)
350 		GetParent()->GetParent()->GrabFocus();
351 	else
352 		NumericField::KeyInput(rEvt);
353 }
354 
355 //------------------------------------------------------------------------------
356 void DbGridControl::NavigationBar::AbsolutePos::LoseFocus()
357 {
358 	NumericField::LoseFocus();
359 	sal_Int64 nRecord = GetValue();
360 	if (nRecord < GetMin() || nRecord > GetMax())
361 		return;
362 	else
363 	{
364 		((NavigationBar*)GetParent())->PositionDataSource(static_cast<sal_Int32>(nRecord));
365 		((NavigationBar*)GetParent())->InvalidateState(NavigationBar::RECORD_ABSOLUTE);
366 	}
367 }
368 
369 //------------------------------------------------------------------------------
370 void DbGridControl::NavigationBar::PositionDataSource(sal_Int32 nRecord)
371 {
372 	if (m_bPositioning)
373 		return;
374 	// the MoveToPosition may cause a LoseFocus which would lead to a second MoveToPosition, so protect agains this
375 	// recursion
376 	// 68167 - 13.08.99 - FS
377 	m_bPositioning = sal_True;
378 	((DbGridControl*)GetParent())->MoveToPosition(nRecord - 1);
379 	m_bPositioning = sal_False;
380 }
381 
382 //------------------------------------------------------------------------------
383 DbGridControl::NavigationBar::NavigationBar(Window* pParent, WinBits nStyle)
384 		  :Control(pParent, nStyle)
385 		  ,m_aRecordText(this, WB_VCENTER)
386 		  ,m_aAbsolute(this, WB_VCENTER)
387 		  ,m_aRecordOf(this, WB_VCENTER)
388 		  ,m_aRecordCount(this, WB_CENTER | WB_VCENTER)
389 		  ,m_aFirstBtn(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)
390 		  ,m_aPrevBtn(this, WB_REPEAT|WB_RECTSTYLE|WB_NOPOINTERFOCUS)
391 		  ,m_aNextBtn(this, WB_REPEAT|WB_RECTSTYLE|WB_NOPOINTERFOCUS)
392 		  ,m_aLastBtn(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)
393 		  ,m_aNewBtn(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)
394 		  ,m_nDefaultWidth(0)
395 		  ,m_nCurrentPos(-1)
396 		  ,m_bPositioning(sal_False)
397 {
398 	m_aFirstBtn.SetSymbol(SYMBOL_FIRST);
399 	m_aPrevBtn.SetSymbol(SYMBOL_PREV);
400 	m_aNextBtn.SetSymbol(SYMBOL_NEXT);
401 	m_aLastBtn.SetSymbol(SYMBOL_LAST);
402 	m_aNewBtn.SetModeImage(((DbGridControl*)pParent)->GetImage(DbGridControl_Base::NEW));
403 
404 	m_aFirstBtn.SetHelpId(HID_GRID_TRAVEL_FIRST);
405 	m_aPrevBtn.SetHelpId(HID_GRID_TRAVEL_PREV);
406 	m_aNextBtn.SetHelpId(HID_GRID_TRAVEL_NEXT);
407 	m_aLastBtn.SetHelpId(HID_GRID_TRAVEL_LAST);
408 	m_aNewBtn.SetHelpId(HID_GRID_TRAVEL_NEW);
409 	m_aAbsolute.SetHelpId(HID_GRID_TRAVEL_ABSOLUTE);
410 	m_aRecordCount.SetHelpId(HID_GRID_NUMBEROFRECORDS);
411 
412 	// Handler fuer Buttons einrichten
413 	m_aFirstBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
414 	m_aPrevBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
415 	m_aNextBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
416 	m_aLastBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
417 	m_aNewBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
418 
419 	m_aRecordText.SetText(XubString(SVX_RES(RID_STR_REC_TEXT)));
420 	m_aRecordOf.SetText(XubString(SVX_RES(RID_STR_REC_FROM_TEXT)));
421 	m_aRecordCount.SetText('?');
422 
423 	m_nDefaultWidth = ArrangeControls();
424 
425 	m_aFirstBtn.Disable();
426 	m_aPrevBtn.Disable();
427 	m_aNextBtn.Disable();
428 	m_aLastBtn.Disable();
429 	m_aNewBtn.Disable();
430 	m_aRecordText.Disable();
431 	m_aRecordOf.Disable();
432 	m_aRecordCount.Disable();
433 	m_aAbsolute.Disable();
434 
435 	AllSettings aSettings = m_aNextBtn.GetSettings();
436 	MouseSettings aMouseSettings = aSettings.GetMouseSettings();
437 	aMouseSettings.SetButtonRepeat(aMouseSettings.GetButtonRepeat() / 4);
438 	aSettings.SetMouseSettings(aMouseSettings);
439 	m_aNextBtn.SetSettings(aSettings, sal_True);
440 	m_aPrevBtn.SetSettings(aSettings, sal_True);
441 
442 	m_aFirstBtn.Show();
443 	m_aPrevBtn.Show();
444 	m_aNextBtn.Show();
445 	m_aLastBtn.Show();
446 	m_aNewBtn.Show();
447 	m_aRecordText.Show();
448 	m_aRecordOf.Show();
449 	m_aRecordCount.Show();
450 	m_aAbsolute.Show();
451 }
452 
453 namespace
454 {
455 	void SetPosAndSize(Button& _rButton,Point& _rPos,const Size& _rSize)
456 	{
457 		_rButton.SetPosPixel( _rPos );
458 		_rButton.SetSizePixel( _rSize );
459 		_rPos.X() += (sal_uInt16)_rSize.Width();
460 	}
461 }
462 //------------------------------------------------------------------------------
463 sal_uInt16 DbGridControl::NavigationBar::ArrangeControls()
464 {
465 	// Positionierung der Controls
466 	// Basisgroessen ermitteln
467 	sal_uInt16		nX = 0;
468 	sal_uInt16		nY = 0;
469 	Rectangle	aRect(((DbGridControl*)GetParent())->GetControlArea());
470 	const long	nH		= aRect.GetSize().Height();
471 	Size		aBorder = LogicToPixel(Size(3, 3),MAP_APPFONT);
472 				aBorder = Size(CalcZoom(aBorder.Width()), CalcZoom(aBorder.Height()));
473 
474 	// Controls Groessen und Positionen setzen
475 	//
476 	XubString aText    = m_aRecordText.GetText();
477 	long nTextWidth = m_aRecordText.GetTextWidth(aText);
478 	m_aRecordText.SetPosPixel(Point(nX,nY) );
479 	m_aRecordText.SetSizePixel(Size(nTextWidth,nH));
480 	nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
481 
482 	m_aAbsolute.SetPosPixel( Point(nX,nY));
483 	m_aAbsolute.SetSizePixel( Size(3*nH,aRect.GetSize().Height()) ); // Heuristik XXXXXXX
484 	nX = sal::static_int_cast< sal_uInt16 >(nX + (3*nH) + aBorder.Width());
485 
486 	aText	   = m_aRecordOf.GetText();
487 	nTextWidth = m_aRecordOf.GetTextWidth(aText);
488 	m_aRecordOf.SetPosPixel(Point(nX,nY) );
489 	m_aRecordOf.SetSizePixel(Size(nTextWidth,nH));
490 	nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
491 
492 	nTextWidth = m_aRecordCount.GetTextWidth( String::CreateFromAscii("0000000 (00000) *") );
493 	m_aRecordCount.SetPosPixel(Point(nX,nY) );
494 	m_aRecordCount.SetSizePixel(Size(nTextWidth,nH));
495 	nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
496 
497 	Point aButtonPos(nX,nY);
498 	Size  aButtonSize(nH,nH);
499 	SetPosAndSize(m_aFirstBtn, aButtonPos, aButtonSize);
500 	SetPosAndSize(m_aPrevBtn, aButtonPos, aButtonSize);
501 	SetPosAndSize(m_aNextBtn, aButtonPos, aButtonSize);
502 	SetPosAndSize(m_aLastBtn, aButtonPos, aButtonSize);
503 	SetPosAndSize(m_aNewBtn, aButtonPos, aButtonSize);
504 
505 	nX = sal::static_int_cast< sal_uInt16 >(
506         aButtonPos.X() + (sal_uInt16)(nH + aBorder.Width()));
507 
508 	// Ist der Font des Edits groesser als das Feld?
509 	Font aOutputFont = m_aAbsolute.GetFont();
510 	if (aOutputFont.GetSize().Height() > nH)
511 	{
512 		Font aApplFont = OutputDevice::GetDefaultFont(
513 			DEFAULTFONT_SANS_UNICODE,
514 			Application::GetSettings().GetUILanguage(),
515 			DEFAULTFONT_FLAGS_ONLYONE,
516 			this
517 		);
518 		aApplFont.SetSize( Size( 0, nH - 2 ) );
519 		m_aAbsolute.SetControlFont( aApplFont );
520 
521 		aApplFont.SetTransparent( sal_True );
522 		m_aRecordText.SetControlFont( aApplFont );
523 		m_aRecordOf.SetControlFont( aApplFont );
524 		m_aRecordCount.SetControlFont( aApplFont );
525 	}
526 	return nX;
527 }
528 
529 //------------------------------------------------------------------------------
530 IMPL_LINK(DbGridControl::NavigationBar, OnClick, Button *, pButton )
531 {
532 	DbGridControl* pParent = (DbGridControl*)GetParent();
533 
534 	if (pParent->m_aMasterSlotExecutor.IsSet())
535 	{
536 		long lResult = 0;
537 		if (pButton == &m_aFirstBtn)
538 			lResult = pParent->m_aMasterSlotExecutor.Call((void*)RECORD_FIRST);
539 		else if( pButton == &m_aPrevBtn )
540 			lResult = pParent->m_aMasterSlotExecutor.Call((void*)RECORD_PREV);
541 		else if( pButton == &m_aNextBtn )
542 			lResult = pParent->m_aMasterSlotExecutor.Call((void*)RECORD_NEXT);
543 		else if( pButton == &m_aLastBtn )
544 			lResult = pParent->m_aMasterSlotExecutor.Call((void*)RECORD_LAST);
545 		else if( pButton == &m_aNewBtn )
546 			lResult = pParent->m_aMasterSlotExecutor.Call((void*)RECORD_NEW);
547 
548 		if (lResult)
549 			// the link already handled it
550 			return 0;
551 	}
552 
553 	if (pButton == &m_aFirstBtn)
554 		pParent->MoveToFirst();
555 	else if( pButton == &m_aPrevBtn )
556 		pParent->MoveToPrev();
557 	else if( pButton == &m_aNextBtn )
558 		pParent->MoveToNext();
559 	else if( pButton == &m_aLastBtn )
560 		pParent->MoveToLast();
561 	else if( pButton == &m_aNewBtn )
562 		pParent->AppendNew();
563 	return 0;
564 }
565 
566 //------------------------------------------------------------------------------
567 void DbGridControl::NavigationBar::InvalidateAll(sal_Int32 nCurrentPos, sal_Bool bAll)
568 {
569 	if (m_nCurrentPos != nCurrentPos || nCurrentPos < 0 || bAll)
570 	{
571 		DbGridControl* pParent = (DbGridControl*)GetParent();
572 
573         sal_Int32 nAdjustedRowCount = pParent->GetRowCount() - ((pParent->GetOptions() & DbGridControl::OPT_INSERT) ? 2 : 1);
574 
575 		// Wann mu� alles invalidiert werden
576         bAll = bAll || m_nCurrentPos <= 0;
577         bAll = bAll || nCurrentPos <= 0;
578         bAll = bAll || m_nCurrentPos >= nAdjustedRowCount;
579         bAll = bAll || nCurrentPos >= nAdjustedRowCount;
580 
581         if ( bAll )
582 		{
583 			m_nCurrentPos = nCurrentPos;
584 			int i = 0;
585 			while (ControlMap[i])
586 				SetState(ControlMap[i++]);
587 		}
588 		else	// befindet sich in der Mitte
589 		{
590 			m_nCurrentPos = nCurrentPos;
591 			SetState(NavigationBar::RECORD_COUNT);
592 			SetState(NavigationBar::RECORD_ABSOLUTE);
593 		}
594 	}
595 }
596 
597 //------------------------------------------------------------------------------
598 sal_Bool DbGridControl::NavigationBar::GetState(sal_uInt16 nWhich) const
599 {
600 	DbGridControl* pParent = (DbGridControl*)GetParent();
601 
602 	if (!pParent->IsOpen() || pParent->IsDesignMode() || !pParent->IsEnabled()
603 		|| pParent->IsFilterMode() )
604 		return sal_False;
605 	else
606 	{
607 		// check if we have a master state provider
608 		if (pParent->m_aMasterStateProvider.IsSet())
609 		{
610 			long nState = pParent->m_aMasterStateProvider.Call(reinterpret_cast< void* >( nWhich ) );
611 			if (nState>=0)
612 				return (nState>0);
613 		}
614 
615 		sal_Bool bAvailable = sal_True;
616 
617 		switch (nWhich)
618 		{
619 			case NavigationBar::RECORD_FIRST:
620 			case NavigationBar::RECORD_PREV:
621 				bAvailable = m_nCurrentPos > 0;
622 				break;
623 			case NavigationBar::RECORD_NEXT:
624 				if(pParent->m_bRecordCountFinal)
625 				{
626 					bAvailable = m_nCurrentPos < pParent->GetRowCount() - 1;
627 					if (!bAvailable && pParent->GetOptions() & DbGridControl::OPT_INSERT)
628 						bAvailable = (m_nCurrentPos == pParent->GetRowCount() - 2) && pParent->IsModified();
629 				}
630 				break;
631 			case NavigationBar::RECORD_LAST:
632 				if(pParent->m_bRecordCountFinal)
633 				{
634 					if (pParent->GetOptions() & DbGridControl::OPT_INSERT)
635 						bAvailable = pParent->IsCurrentAppending() ? pParent->GetRowCount() > 1 :
636 									 m_nCurrentPos != pParent->GetRowCount() - 2;
637 					else
638 						bAvailable = m_nCurrentPos != pParent->GetRowCount() - 1;
639 				}
640 				break;
641 			case NavigationBar::RECORD_NEW:
642 				bAvailable = (pParent->GetOptions() & DbGridControl::OPT_INSERT) && pParent->GetRowCount() && m_nCurrentPos < pParent->GetRowCount() - 1;
643 				break;
644 			case NavigationBar::RECORD_ABSOLUTE:
645 				bAvailable = pParent->GetRowCount() > 0;
646 				break;
647 		}
648 		return bAvailable;
649 	}
650 }
651 
652 //------------------------------------------------------------------------------
653 void DbGridControl::NavigationBar::SetState(sal_uInt16 nWhich)
654 {
655 	sal_Bool bAvailable = GetState(nWhich);
656 	DbGridControl* pParent = (DbGridControl*)GetParent();
657 	Window* pWnd = NULL;
658 	switch (nWhich)
659 	{
660 		case NavigationBar::RECORD_FIRST:
661 			pWnd = &m_aFirstBtn;
662 			break;
663 		case NavigationBar::RECORD_PREV:
664 			pWnd = &m_aPrevBtn;
665 			break;
666 		case NavigationBar::RECORD_NEXT:
667 			pWnd = &m_aNextBtn;
668 			break;
669 		case NavigationBar::RECORD_LAST:
670 			pWnd = &m_aLastBtn;
671 			break;
672 		case NavigationBar::RECORD_NEW:
673 			pWnd = &m_aNewBtn;
674 			break;
675 		case NavigationBar::RECORD_ABSOLUTE:
676 			pWnd = &m_aAbsolute;
677 			if (bAvailable)
678 			{
679 				if (pParent->m_nTotalCount >= 0)
680 				{
681 					if (pParent->IsCurrentAppending())
682 						m_aAbsolute.SetMax(pParent->m_nTotalCount + 1);
683 					else
684 						m_aAbsolute.SetMax(pParent->m_nTotalCount);
685 				}
686 				else
687 					m_aAbsolute.SetMax(LONG_MAX);
688 
689 				m_aAbsolute.SetValue(m_nCurrentPos + 1);
690 			}
691 			else
692 				m_aAbsolute.SetText(String());
693 			break;
694 		case NavigationBar::RECORD_TEXT:
695 			pWnd = &m_aRecordText;
696 			break;
697 		case NavigationBar::RECORD_OF:
698 			pWnd = &m_aRecordOf;
699 			break;
700 		case NavigationBar::RECORD_COUNT:
701 		{
702 			pWnd = &m_aRecordCount;
703 			String aText;
704 			if (bAvailable)
705 			{
706 				if (pParent->GetOptions() & DbGridControl::OPT_INSERT)
707 				{
708 					if (pParent->IsCurrentAppending() && !pParent->IsModified())
709 						aText = String::CreateFromInt32(pParent->GetRowCount());
710 					else
711 						aText = String::CreateFromInt32(pParent->GetRowCount() - 1);
712 				}
713 				else
714 					aText = String::CreateFromInt32(pParent->GetRowCount());
715 				if(!pParent->m_bRecordCountFinal)
716 					aText += String::CreateFromAscii(" *");
717 			}
718 			else
719 				aText = String();
720 
721 			// add the number of selected rows, if applicable
722 			if (pParent->GetSelectRowCount())
723 			{
724 				String aExtendedInfo(aText);
725 				aExtendedInfo.AppendAscii(" (");
726 				aExtendedInfo += String::CreateFromInt32(pParent->GetSelectRowCount());
727 				aExtendedInfo += ')';
728 				pWnd->SetText(aExtendedInfo);
729 			}
730 			else
731 				pWnd->SetText(aText);
732 
733 			pParent->SetRealRowCount(aText);
734 		}	break;
735 	}
736 	DBG_ASSERT(pWnd, "kein Fenster");
737 	if (pWnd && (pWnd->IsEnabled() != bAvailable))
738 		// this "pWnd->IsEnabled() != bAvailable" is a little hack : Window::Enable always generates a user
739 		// event (ImplGenerateMouseMove) even if nothing happened. This may lead to some unwanted effects, so we
740 		// do this check.
741 		// For further explanation see Bug 69900.
742 		// FS - 18.11.99
743 		pWnd->Enable(bAvailable);
744 }
745 
746 //------------------------------------------------------------------------------
747 void DbGridControl::NavigationBar::Resize()
748 {
749 	Control::Resize();
750 	ArrangeControls();
751 }
752 
753 //------------------------------------------------------------------------------
754 void DbGridControl::NavigationBar::Paint(const Rectangle& rRect)
755 {
756 	Control::Paint(rRect);
757 	Point aAbsolutePos = m_aAbsolute.GetPosPixel();
758 	Size  aAbsoluteSize = m_aAbsolute.GetSizePixel();
759 
760 	DrawLine(Point(aAbsolutePos.X() - 1, 0 ),
761 			 Point(aAbsolutePos.X() - 1, aAbsolutePos.Y() + aAbsoluteSize.Height()));
762 
763 	DrawLine(Point(aAbsolutePos.X() + aAbsoluteSize.Width() + 1, 0 ),
764 			 Point(aAbsolutePos.X() + aAbsoluteSize.Width() + 1, aAbsolutePos.Y() + aAbsoluteSize.Height()));
765 }
766 
767 //------------------------------------------------------------------------------
768 void DbGridControl::NavigationBar::StateChanged( StateChangedType nType )
769 {
770 	Control::StateChanged( nType );
771 
772     Window* pWindows[] = {  &m_aRecordText,
773                             &m_aAbsolute,
774                             &m_aRecordOf,
775                             &m_aRecordCount,
776                             &m_aFirstBtn,
777                             &m_aPrevBtn,
778                             &m_aNextBtn,
779                             &m_aLastBtn,
780                             &m_aNewBtn
781                         };
782 
783     switch ( nType )
784     {
785         case STATE_CHANGE_MIRRORING:
786         {
787             sal_Bool bIsRTLEnabled = IsRTLEnabled();
788             for ( size_t i=0; i < sizeof( pWindows ) / sizeof( pWindows[0] ); ++i )
789                 pWindows[i]->EnableRTL( bIsRTLEnabled );
790         }
791         break;
792 
793         case STATE_CHANGE_ZOOM:
794         {
795             Fraction aZoom = GetZoom();
796 
797             // not all of these controls need to know the new zoom, but to be sure ...
798             Font aFont( GetSettings().GetStyleSettings().GetFieldFont() );
799             if ( IsControlFont() )
800                 aFont.Merge( GetControlFont() );
801 
802             for (size_t i=0; i < sizeof(pWindows)/sizeof(pWindows[0]); ++i)
803             {
804                 pWindows[i]->SetZoom(aZoom);
805                 pWindows[i]->SetZoomedPointFont(aFont);
806             }
807 
808             SetZoomedPointFont( aFont );
809 
810             // rearrange the controls
811             m_nDefaultWidth = ArrangeControls();
812         }
813         break;
814     }
815 }
816 
817 //------------------------------------------------------------------------------
818 DbGridRow::DbGridRow(CursorWrapper* pCur, sal_Bool bPaintCursor)
819 		  :m_bIsNew(sal_False)
820 {
821 
822 	if (pCur && pCur->Is())
823 	{
824 		Reference< XIndexAccess >  xColumns(pCur->getColumns(), UNO_QUERY);
825 		DataColumn* pColumn;
826 		for (sal_Int32 i = 0; i < xColumns->getCount(); ++i)
827 		{
828 			Reference< XPropertySet > xColSet;
829 			::cppu::extractInterface(xColSet, xColumns->getByIndex(i));
830 			pColumn = new DataColumn(xColSet);
831 			m_aVariants.Insert(pColumn, LIST_APPEND);
832 		}
833 
834 		if (pCur->rowDeleted())
835 			m_eStatus = GRS_DELETED;
836 		else
837 		{
838 			if (bPaintCursor)
839 				m_eStatus = (pCur->isAfterLast() || pCur->isBeforeFirst()) ? GRS_INVALID : GRS_CLEAN;
840 			else
841 			{
842 				Reference< XPropertySet > xSet = pCur->getPropertySet();
843 				if (xSet.is())
844 				{
845 					m_bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
846 					if (!m_bIsNew && (pCur->isAfterLast() || pCur->isBeforeFirst()))
847 						m_eStatus = GRS_INVALID;
848 					else if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED)))
849 						m_eStatus = GRS_MODIFIED;
850 					else
851 						m_eStatus = GRS_CLEAN;
852 				}
853 				else
854 					m_eStatus = GRS_INVALID;
855 			}
856 		}
857 		if (!m_bIsNew && IsValid())
858 			m_aBookmark = pCur->getBookmark();
859 		else
860 			m_aBookmark = Any();
861 	}
862 	else
863 		m_eStatus = GRS_INVALID;
864 }
865 
866 //------------------------------------------------------------------------------
867 DbGridRow::~DbGridRow()
868 {
869 	sal_uInt32 nCount = m_aVariants.Count();
870 	for (sal_uInt32 i = 0; i < nCount; i++)
871 		delete m_aVariants.GetObject(i);
872 }
873 
874 //------------------------------------------------------------------------------
875 void DbGridRow::SetState(CursorWrapper* pCur, sal_Bool bPaintCursor)
876 {
877 	if (pCur && pCur->Is())
878 	{
879 		if (pCur->rowDeleted())
880 		{
881 			m_eStatus = GRS_DELETED;
882 			m_bIsNew = sal_False;
883 		}
884 		else
885 		{
886 			m_eStatus = GRS_CLEAN;
887 			if (!bPaintCursor)
888 			{
889 				Reference< XPropertySet > xSet = pCur->getPropertySet();
890 				DBG_ASSERT(xSet.is(), "DbGridRow::SetState : invalid cursor !");
891 
892 				if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED)))
893 					m_eStatus = GRS_MODIFIED;
894 				m_bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
895 			}
896 			else
897 				m_bIsNew = sal_False;
898 		}
899 
900         try
901         {
902 		    if (!m_bIsNew && IsValid())
903 			    m_aBookmark = pCur->getBookmark();
904 		    else
905 			    m_aBookmark = Any();
906         }
907         catch(SQLException&)
908         {
909             DBG_UNHANDLED_EXCEPTION();
910             m_aBookmark = Any();
911             m_eStatus = GRS_INVALID;
912 		    m_bIsNew = sal_False;
913         }
914 	}
915 	else
916 	{
917 		m_aBookmark = Any();
918 		m_eStatus = GRS_INVALID;
919 		m_bIsNew = sal_False;
920 	}
921 }
922 
923 DBG_NAME(DbGridControl);
924 //------------------------------------------------------------------------------
925 DbGridControl::DbGridControl(
926 				Reference< XMultiServiceFactory > _rxFactory,
927 				Window* pParent,
928 				WinBits nBits)
929 			:DbGridControl_Base(pParent, EBBF_NONE, nBits, DEFAULT_BROWSE_MODE )
930             ,m_xServiceFactory(_rxFactory)
931             ,m_aBar(this)
932             ,m_nAsynAdjustEvent(0)
933             ,m_pDataSourcePropMultiplexer(NULL)
934             ,m_pDataSourcePropListener(NULL)
935             ,m_pFieldListeners(NULL)
936             ,m_pCursorDisposeListener(NULL)
937             ,m_pGridListener(NULL)
938             ,m_pDataCursor(NULL)
939             ,m_pSeekCursor(NULL)
940             ,m_nSeekPos(-1)
941             ,m_nTotalCount(-1)
942             ,m_aNullDate(OTypeConversionClient().getStandardDate())
943             ,m_nMode(DEFAULT_BROWSE_MODE)
944             ,m_nCurrentPos(-1)
945             ,m_nDeleteEvent(0)
946             ,m_nOptions(OPT_READONLY)
947             ,m_nOptionMask(OPT_INSERT | OPT_UPDATE | OPT_DELETE)
948 	        ,m_nLastColId((sal_uInt16)-1)
949             ,m_nLastRowId(-1)
950             ,m_bDesignMode(sal_False)
951             ,m_bRecordCountFinal(sal_False)
952             ,m_bMultiSelection(sal_True)
953             ,m_bNavigationBar(sal_True)
954             ,m_bSynchDisplay(sal_True)
955             ,m_bForceROController(sal_False)
956             ,m_bHandle(sal_True)
957             ,m_bFilterMode(sal_False)
958             ,m_bWantDestruction(sal_False)
959             ,m_bInAdjustDataSource(sal_False)
960             ,m_bPendingAdjustRows(sal_False)
961             ,m_bHideScrollbars( sal_False )
962             ,m_bUpdating(sal_False)
963 {
964 	DBG_CTOR(DbGridControl,NULL);
965 
966     String sName(SVX_RES(RID_STR_NAVIGATIONBAR));
967     m_aBar.SetAccessibleName(sName);
968     m_aBar.Show();
969     ImplInitWindow( InitAll );
970 }
971 
972 //------------------------------------------------------------------------------
973 void DbGridControl::InsertHandleColumn()
974 {
975 	// Handle Column einfuegen
976 	// Da die BrowseBox ohne handleColums Paintprobleme hat
977 	// wird diese versteckt
978 	if (HasHandle())
979 		BrowseBox::InsertHandleColumn(GetDefaultColumnWidth(String()));
980 	else
981 		BrowseBox::InsertHandleColumn(0);
982 }
983 
984 //------------------------------------------------------------------------------
985 void DbGridControl::Init()
986 {
987 	BrowserHeader* pNewHeader = CreateHeaderBar(this);
988 	pHeader->SetMouseTransparent(sal_False);
989 
990     SetHeaderBar(pNewHeader);
991 	SetMode(m_nMode);
992 	SetCursorColor(Color(0xFF, 0, 0));
993 
994 	InsertHandleColumn();
995 }
996 
997 //------------------------------------------------------------------------------
998 DbGridControl::~DbGridControl()
999 {
1000 	RemoveColumns();
1001 
1002 	{
1003 		m_bWantDestruction = sal_True;
1004 		osl::MutexGuard aGuard(m_aDestructionSafety);
1005 		if (m_pFieldListeners)
1006 			DisconnectFromFields();
1007 		if (m_pCursorDisposeListener)
1008 		{
1009 			delete m_pCursorDisposeListener;
1010 			m_pCursorDisposeListener = NULL;
1011 		}
1012 	}
1013 
1014 	if (m_nDeleteEvent)
1015 		Application::RemoveUserEvent(m_nDeleteEvent);
1016 
1017 	if (m_pDataSourcePropMultiplexer)
1018 	{
1019 		m_pDataSourcePropMultiplexer->dispose();
1020 		m_pDataSourcePropMultiplexer->release();	// this should delete the multiplexer
1021 		delete m_pDataSourcePropListener;
1022 		m_pDataSourcePropMultiplexer = NULL;
1023 		m_pDataSourcePropListener = NULL;
1024 	}
1025     m_xRowSetListener.clear();
1026 
1027 	delete m_pDataCursor;
1028 	delete m_pSeekCursor;
1029 
1030 	DBG_DTOR(DbGridControl,NULL);
1031 }
1032 
1033 //------------------------------------------------------------------------------
1034 void DbGridControl::StateChanged( StateChangedType nType )
1035 {
1036 	DbGridControl_Base::StateChanged( nType );
1037 
1038     switch (nType)
1039 	{
1040         case STATE_CHANGE_MIRRORING:
1041 			ImplInitWindow( InitWritingMode );
1042             Invalidate();
1043             break;
1044 
1045 		case STATE_CHANGE_ZOOM:
1046 		{
1047 			ImplInitWindow( InitFont );
1048 
1049 			// and give it a chance to rearrange
1050 			Point aPoint = GetControlArea().TopLeft();
1051 			sal_uInt16 nX = (sal_uInt16)aPoint.X();
1052 			ArrangeControls(nX, (sal_uInt16)aPoint.Y());
1053 			ReserveControlArea((sal_uInt16)nX);
1054 		}
1055 		break;
1056 		case STATE_CHANGE_CONTROLFONT:
1057 			ImplInitWindow( InitFont );
1058 			Invalidate();
1059 			break;
1060 		case STATE_CHANGE_CONTROLFOREGROUND:
1061 			ImplInitWindow( InitForeground );
1062 			Invalidate();
1063 			break;
1064 		case STATE_CHANGE_CONTROLBACKGROUND:
1065 			ImplInitWindow( InitBackground );
1066 			Invalidate();
1067 			break;
1068 	}
1069 }
1070 
1071 //------------------------------------------------------------------------------
1072 void DbGridControl::DataChanged( const DataChangedEvent& rDCEvt )
1073 {
1074 	DbGridControl_Base::DataChanged( rDCEvt );
1075 	if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS ) &&
1076 		 (rDCEvt.GetFlags() & SETTINGS_STYLE) )
1077 	{
1078 		ImplInitWindow( InitAll );
1079 		Invalidate();
1080 	}
1081 }
1082 
1083 //------------------------------------------------------------------------------
1084 void DbGridControl::Select()
1085 {
1086 	DbGridControl_Base::Select();
1087 
1088 	// as the selected rows may have changed, udate the according display in our navigation bar
1089 	m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
1090 
1091 	if (m_pGridListener)
1092 		m_pGridListener->selectionChanged();
1093 }
1094 
1095 //------------------------------------------------------------------------------
1096 void DbGridControl::ImplInitWindow( const InitWindowFacet _eInitWhat )
1097 {
1098 	for ( sal_uInt32 i = 0; i < m_aColumns.Count(); ++i )
1099 	{
1100 		DbGridColumn* pCol = m_aColumns.GetObject(i);
1101 		if (pCol)
1102 			pCol->ImplInitWindow( GetDataWindow(), _eInitWhat );
1103 	}
1104 
1105     if ( ( _eInitWhat & InitWritingMode ) != 0 )
1106     {
1107 		if ( m_bNavigationBar )
1108         {
1109 			m_aBar.EnableRTL( IsRTLEnabled() );
1110         }
1111     }
1112 
1113     if ( ( _eInitWhat & InitFont ) != 0 )
1114     {
1115 		if ( m_bNavigationBar )
1116         {
1117 	        Font aFont = m_aBar.GetSettings().GetStyleSettings().GetFieldFont();
1118             if ( IsControlFont() )
1119                 m_aBar.SetControlFont( GetControlFont() );
1120             else
1121                 m_aBar.SetControlFont();
1122 
1123 			m_aBar.SetZoom( GetZoom() );
1124         }
1125     }
1126 
1127     if ( ( _eInitWhat & InitBackground ) != 0 )
1128 	{
1129 		if (IsControlBackground())
1130 		{
1131 			GetDataWindow().SetBackground(GetControlBackground());
1132 			GetDataWindow().SetControlBackground(GetControlBackground());
1133 			GetDataWindow().SetFillColor(GetControlBackground());
1134 		}
1135 		else
1136 		{
1137 			GetDataWindow().SetControlBackground();
1138 			GetDataWindow().SetFillColor(GetFillColor());
1139 		}
1140 	}
1141 }
1142 
1143 //------------------------------------------------------------------------------
1144 void DbGridControl::RemoveRows(sal_Bool bNewCursor)
1145 {
1146 	// Hat sich der DatenCursor verandert ?
1147 	if (!bNewCursor)
1148 	{
1149 		DELETEZ(m_pSeekCursor);
1150 		m_xPaintRow = m_xDataRow = m_xEmptyRow	= m_xCurrentRow = m_xSeekRow = NULL;
1151 		m_nCurrentPos = m_nSeekPos = -1;
1152 		m_nOptions	= OPT_READONLY;
1153 
1154 		RowRemoved(0, GetRowCount(), sal_False);
1155 		m_nTotalCount = -1;
1156 	}
1157 	else
1158 	{
1159 		RemoveRows();
1160 	}
1161 }
1162 
1163 //------------------------------------------------------------------------------
1164 void DbGridControl::RemoveRows()
1165 {
1166 	// we're going to remove all columns and all row, so deactivate the current cell
1167 	if (IsEditing())
1168 		DeactivateCell();
1169 
1170 	// alle Columns deinitialisieren
1171 	// existieren Spalten, dann alle Controller freigeben
1172 	for (sal_uInt32 i = 0; i < m_aColumns.Count(); i++)
1173 		m_aColumns.GetObject(i)->Clear();
1174 
1175 	DELETEZ(m_pSeekCursor);
1176 	DELETEZ(m_pDataCursor);
1177 
1178 	m_xPaintRow = m_xDataRow = m_xEmptyRow	= m_xCurrentRow = m_xSeekRow = NULL;
1179 	m_nCurrentPos = m_nSeekPos = m_nTotalCount	= -1;
1180 	m_nOptions	= OPT_READONLY;
1181 
1182 	// Anzahl Saetze im Browser auf 0 zuruecksetzen
1183 	DbGridControl_Base::RemoveRows();
1184 	m_aBar.InvalidateAll(m_nCurrentPos, sal_True);
1185 }
1186 
1187 //------------------------------------------------------------------------------
1188 void DbGridControl::ArrangeControls(sal_uInt16& nX, sal_uInt16 nY)
1189 {
1190 	// Positionierung der Controls
1191 	if (m_bNavigationBar)
1192 	{
1193 		nX = m_aBar.GetDefaultWidth();
1194 		Rectangle	aRect(GetControlArea());
1195 		m_aBar.SetPosSizePixel(Point(0,nY + 1), Size(nX, aRect.GetSize().Height() - 1));
1196 	}
1197 }
1198 
1199 //------------------------------------------------------------------------------
1200 void DbGridControl::EnableHandle(sal_Bool bEnable)
1201 {
1202 	if (m_bHandle == bEnable)
1203 		return;
1204 
1205 	// HandleColumn wird nur ausgeblendet,
1206 	// da es sonst etliche Probleme mit dem Zeichnen gibt
1207 	RemoveColumn(0);
1208 	m_bHandle = bEnable;
1209 	InsertHandleColumn();
1210 }
1211 
1212 //------------------------------------------------------------------------------
1213 namespace
1214 {
1215     bool adjustModeForScrollbars( BrowserMode& _rMode, sal_Bool _bNavigationBar, sal_Bool _bHideScrollbars )
1216     {
1217         BrowserMode nOldMode = _rMode;
1218 
1219 		if ( !_bNavigationBar )
1220         {
1221             _rMode &= ~BROWSER_AUTO_HSCROLL;
1222         }
1223 
1224         if ( _bHideScrollbars )
1225         {
1226             _rMode |= ( BROWSER_NO_HSCROLL | BROWSER_NO_VSCROLL );
1227             _rMode &= ~( BROWSER_AUTO_HSCROLL | BROWSER_AUTO_VSCROLL );
1228         }
1229         else
1230         {
1231             _rMode |= ( BROWSER_AUTO_HSCROLL | BROWSER_AUTO_VSCROLL );
1232             _rMode &= ~( BROWSER_NO_HSCROLL | BROWSER_NO_VSCROLL );
1233         }
1234 
1235         // note: if we have a navigation bar, we always have a AUTO_HSCROLL. In particular,
1236         // _bHideScrollbars is ignored then
1237 		if ( _bNavigationBar )
1238         {
1239 			_rMode |= BROWSER_AUTO_HSCROLL;
1240             _rMode &= ~BROWSER_NO_HSCROLL;
1241         }
1242 
1243         return nOldMode != _rMode;
1244     }
1245 }
1246 
1247 //------------------------------------------------------------------------------
1248 void DbGridControl::EnableNavigationBar(sal_Bool bEnable)
1249 {
1250 	if (m_bNavigationBar == bEnable)
1251 		return;
1252 
1253 	m_bNavigationBar = bEnable;
1254 
1255     if (bEnable)
1256 	{
1257 		m_aBar.Show();
1258 		m_aBar.Enable();
1259 		m_aBar.InvalidateAll(m_nCurrentPos, sal_True);
1260 
1261         if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1262             SetMode( m_nMode );
1263 
1264 		// liefert die Groe�e der Reserved ControlArea
1265 		Point aPoint = GetControlArea().TopLeft();
1266 		sal_uInt16 nX = (sal_uInt16)aPoint.X();
1267 
1268 		ArrangeControls(nX, (sal_uInt16)aPoint.Y());
1269 		ReserveControlArea((sal_uInt16)nX);
1270 	}
1271 	else
1272 	{
1273 		m_aBar.Hide();
1274 		m_aBar.Disable();
1275 
1276         if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1277             SetMode( m_nMode );
1278 
1279 		ReserveControlArea();
1280 	}
1281 }
1282 
1283 //------------------------------------------------------------------------------
1284 sal_uInt16 DbGridControl::SetOptions(sal_uInt16 nOpt)
1285 {
1286 	DBG_ASSERT(!m_xCurrentRow || !m_xCurrentRow->IsModified(),
1287 		"DbGridControl::SetOptions : please do not call when editing a record (things are much easier this way ;) !");
1288 
1289 	// for the next setDataSource (which is triggered by a refresh, for instance)
1290 	m_nOptionMask = nOpt;
1291 
1292 	// normalize the new options
1293 	Reference< XPropertySet > xDataSourceSet = m_pDataCursor->getPropertySet();
1294 	if (xDataSourceSet.is())
1295 	{
1296 		// feststellen welche Updatem�glichkeiten bestehen
1297 		sal_Int32 nPrivileges = 0;
1298 		xDataSourceSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
1299 		if ((nPrivileges & Privilege::INSERT) == 0)
1300 			nOpt &= ~OPT_INSERT;
1301 		if ((nPrivileges & Privilege::UPDATE) == 0)
1302 			nOpt &= ~OPT_UPDATE;
1303 		if ((nPrivileges & Privilege::DELETE) == 0)
1304 			nOpt &= ~OPT_DELETE;
1305 	}
1306 	else
1307 		nOpt = OPT_READONLY;
1308 
1309 	// need to do something after that ?
1310 	if (nOpt == m_nOptions)
1311 		return m_nOptions;
1312 
1313 	// the 'update' option only affects our BrowserMode (with or w/o focus rect)
1314 	BrowserMode nNewMode = m_nMode;
1315 	if ((m_nMode & BROWSER_CURSOR_WO_FOCUS) == 0)
1316 	{
1317 		if (nOpt & OPT_UPDATE)
1318 			nNewMode |= BROWSER_HIDECURSOR;
1319 		else
1320 			nNewMode &= ~BROWSER_HIDECURSOR;
1321 	}
1322 	else
1323 		nNewMode &= ~BROWSER_HIDECURSOR;
1324 		// should not be neccessary if EnablePermanentCursor is used to change the cursor behaviour, but to be sure ...
1325 
1326 	if (nNewMode != m_nMode)
1327 	{
1328 		SetMode(nNewMode);
1329 		m_nMode = nNewMode;
1330 	}
1331 
1332 	// _after_ setting the mode because this results in an ActivateCell
1333 	DeactivateCell();
1334 
1335 	sal_Bool bInsertChanged = (nOpt & OPT_INSERT) != (m_nOptions & OPT_INSERT);
1336 	m_nOptions = nOpt;
1337 		// we need to set this before the code below because it indirectly uses m_nOptions
1338 
1339 	// the 'insert' option affects our empty row
1340 	if (bInsertChanged)
1341 	{
1342 		if (m_nOptions & OPT_INSERT)
1343 		{	// the insert option is to be set
1344 			m_xEmptyRow = new DbGridRow();
1345 			RowInserted(GetRowCount(), 1, sal_True);
1346 		}
1347 		else
1348 		{	// the insert option is to be reset
1349 			m_xEmptyRow = NULL;
1350 			if ((GetCurRow() == GetRowCount() - 1) && (GetCurRow() > 0))
1351 				GoToRowColumnId(GetCurRow() - 1, GetCurColumnId());
1352 			RowRemoved(GetRowCount(), 1, sal_True);
1353 		}
1354 	}
1355 
1356 	// the 'delete' options has no immediate consequences
1357 
1358 	ActivateCell();
1359 	Invalidate();
1360 	return m_nOptions;
1361 }
1362 
1363 //------------------------------------------------------------------------------
1364 void DbGridControl::ForceHideScrollbars( sal_Bool _bForce )
1365 {
1366     if ( m_bHideScrollbars == _bForce )
1367         return;
1368 
1369     m_bHideScrollbars = _bForce;
1370 
1371     if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1372         SetMode( m_nMode );
1373 }
1374 
1375 //------------------------------------------------------------------------------
1376 sal_Bool DbGridControl::IsForceHideScrollbars() const
1377 {
1378     return m_bHideScrollbars;
1379 }
1380 
1381 //------------------------------------------------------------------------------
1382 void DbGridControl::EnablePermanentCursor(sal_Bool bEnable)
1383 {
1384 	if (IsPermanentCursorEnabled() == bEnable)
1385 		return;
1386 
1387 	if (bEnable)
1388 	{
1389 		m_nMode &= ~BROWSER_HIDECURSOR; 	// without this BROWSER_CURSOR_WO_FOCUS won't have any affect
1390 		m_nMode |= BROWSER_CURSOR_WO_FOCUS;
1391 	}
1392 	else
1393 	{
1394 		if (m_nOptions & OPT_UPDATE)
1395 			m_nMode |= BROWSER_HIDECURSOR;		// no cursor at all
1396 		else
1397 			m_nMode &= ~BROWSER_HIDECURSOR; 	// at least the "non-permanent" cursor
1398 
1399 		m_nMode &= ~BROWSER_CURSOR_WO_FOCUS;
1400 	}
1401 	SetMode(m_nMode);
1402 
1403 	sal_Bool bWasEditing = IsEditing();
1404 	DeactivateCell();
1405 	if (bWasEditing)
1406 		ActivateCell();
1407 }
1408 
1409 //------------------------------------------------------------------------------
1410 sal_Bool DbGridControl::IsPermanentCursorEnabled() const
1411 {
1412 	return ((m_nMode & BROWSER_CURSOR_WO_FOCUS) != 0) && ((m_nMode & BROWSER_HIDECURSOR) == 0);
1413 }
1414 
1415 //------------------------------------------------------------------------------
1416 void DbGridControl::refreshController(sal_uInt16 _nColId, GrantControlAccess /*_aAccess*/)
1417 {
1418 	if ((GetCurColumnId() == _nColId) && IsEditing())
1419 	{	// the controller which is currently active needs to be refreshed
1420 		DeactivateCell();
1421 		ActivateCell();
1422 	}
1423 }
1424 
1425 //------------------------------------------------------------------------------
1426 void DbGridControl::SetMultiSelection(sal_Bool bMulti)
1427 {
1428 	m_bMultiSelection = bMulti;
1429 	if (m_bMultiSelection)
1430 		m_nMode |= BROWSER_MULTISELECTION;
1431 	else
1432 		m_nMode &= ~BROWSER_MULTISELECTION;
1433 
1434 	SetMode(m_nMode);
1435 }
1436 
1437 //------------------------------------------------------------------------------
1438 void DbGridControl::setDataSource(const Reference< XRowSet >& _xCursor, sal_uInt16 nOpts)
1439 {
1440 	if (!_xCursor.is() && !m_pDataCursor)
1441 		return;
1442 
1443 	if (m_pDataSourcePropMultiplexer)
1444 	{
1445 		m_pDataSourcePropMultiplexer->dispose();
1446 		m_pDataSourcePropMultiplexer->release();	// this should delete the multiplexer
1447 		delete m_pDataSourcePropListener;
1448 		m_pDataSourcePropMultiplexer = NULL;
1449 		m_pDataSourcePropListener = NULL;
1450 	}
1451     m_xRowSetListener.clear();
1452 
1453 	// is the new cursor valid ?
1454 	// the cursor is only valid if it contains some columns
1455 	// if there is no cursor or the cursor is not valid we have to clean up an leave
1456 	if (!_xCursor.is() || !Reference< XColumnsSupplier > (_xCursor, UNO_QUERY)->getColumns()->hasElements())
1457 	{
1458 		RemoveRows();
1459 		return;
1460 	}
1461 
1462 	// Hat sich der DatenCursor verandert ?
1463 	sal_uInt16 nCurPos = GetColumnPos(GetCurColumnId());
1464 
1465 	SetUpdateMode(sal_False);
1466 	RemoveRows();
1467 	DisconnectFromFields();
1468 
1469 	DELETEZ(m_pCursorDisposeListener);
1470 
1471 	{
1472 		::osl::MutexGuard aGuard(m_aAdjustSafety);
1473 		if (m_nAsynAdjustEvent)
1474 		{
1475 			// the adjust was thought to work with the old cursor which we don't have anymore
1476 			RemoveUserEvent(m_nAsynAdjustEvent);
1477 			m_nAsynAdjustEvent = 0;
1478 		}
1479 	}
1480 
1481 	// get a new formatter and data cursor
1482 	m_xFormatter = NULL;
1483 	OStaticDataAccessTools aStaticTools;
1484 	Reference< ::com::sun::star::util::XNumberFormatsSupplier >  xSupplier = aStaticTools.getNumberFormats(aStaticTools.getRowSetConnection(_xCursor), sal_True);
1485 	if (xSupplier.is() && m_xServiceFactory.is())
1486 	{
1487 		m_xFormatter =	Reference< ::com::sun::star::util::XNumberFormatter >(
1488 			m_xServiceFactory->createInstance(FM_NUMBER_FORMATTER),
1489 			UNO_QUERY);
1490 		if (m_xFormatter.is())
1491 		{
1492 			m_xFormatter->attachNumberFormatsSupplier(xSupplier);
1493 
1494 			// retrieve the datebase of the Numberformatter
1495 			try
1496 			{
1497 				xSupplier->getNumberFormatSettings()->getPropertyValue(rtl::OUString::createFromAscii("NullDate")) >>= m_aNullDate;
1498 			}
1499 			catch(Exception&)
1500 			{
1501 			}
1502 		}
1503 	}
1504 
1505 	m_pDataCursor = new CursorWrapper(_xCursor);
1506 
1507 	// now create a cursor for painting rows
1508 	// we need that cursor only if we are not in insert only mode
1509 	Reference< XResultSet > xClone;
1510 	Reference< XResultSetAccess > xAccess( _xCursor, UNO_QUERY );
1511 	try
1512 	{
1513 		xClone = xAccess.is() ? xAccess->createResultSet() : Reference< XResultSet > ();
1514 	}
1515 	catch(Exception&)
1516 	{
1517 	}
1518 	if (xClone.is())
1519 		m_pSeekCursor = new CursorWrapper(xClone);
1520 
1521 	// property listening on the data source
1522 	// (Normally one class would be sufficient : the multiplexer which could forward the property change to us.
1523 	// But for that we would have been derived from ::comphelper::OPropertyChangeListener, which isn't exported.
1524 	// So we introduce a second class, which is a ::comphelper::OPropertyChangeListener (in the implementation file we know this class)
1525 	// and forwards the property changes to a our special method "DataSourcePropertyChanged".)
1526 	if (m_pDataCursor)
1527 	{
1528 		m_pDataSourcePropListener = new FmXGridSourcePropListener(this);
1529 		m_pDataSourcePropMultiplexer = new ::comphelper::OPropertyChangeMultiplexer(m_pDataSourcePropListener, m_pDataCursor->getPropertySet() );
1530 		m_pDataSourcePropMultiplexer->acquire();
1531 		m_pDataSourcePropMultiplexer->addProperty(FM_PROP_ISMODIFIED);
1532 		m_pDataSourcePropMultiplexer->addProperty(FM_PROP_ISNEW);
1533 	}
1534 
1535 	BrowserMode nOldMode = m_nMode;
1536 	if (m_pSeekCursor)
1537 	{
1538 		try
1539 		{
1540 			Reference< XPropertySet >  xSet(_xCursor, UNO_QUERY);
1541 			if (xSet.is())
1542 			{
1543 				// feststellen welche Updatemoeglichkeiten bestehen
1544 				sal_Int32 nConcurrency = ResultSetConcurrency::READ_ONLY;
1545 				xSet->getPropertyValue(FM_PROP_RESULTSET_CONCURRENCY) >>= nConcurrency;
1546 
1547 				if ( ResultSetConcurrency::UPDATABLE == nConcurrency )
1548 				{
1549 					sal_Int32 nPrivileges = 0;
1550 					xSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
1551 
1552 					// Insert Option should be set if insert only otherwise you won't see any rows
1553 					// and no insertion is possible
1554 					if ((m_nOptionMask & OPT_INSERT) && ((nPrivileges & Privilege::INSERT) == Privilege::INSERT) && (nOpts & OPT_INSERT))
1555 						m_nOptions |= OPT_INSERT;
1556 					if ((m_nOptionMask & OPT_UPDATE) && ((nPrivileges & Privilege::UPDATE) == Privilege::UPDATE) && (nOpts & OPT_UPDATE))
1557 						m_nOptions |= OPT_UPDATE;
1558 					if ((m_nOptionMask & OPT_DELETE) && ((nPrivileges & Privilege::DELETE) == Privilege::DELETE) && (nOpts & OPT_DELETE))
1559 						m_nOptions |= OPT_DELETE;
1560 				}
1561 			}
1562 		}
1563 		catch( const Exception& )
1564 		{
1565             DBG_UNHANDLED_EXCEPTION();
1566 		}
1567 
1568 		sal_Bool bPermanentCursor = IsPermanentCursorEnabled();
1569 		m_nMode = DEFAULT_BROWSE_MODE;
1570 
1571         if ( bPermanentCursor )
1572 		{
1573 			m_nMode |= BROWSER_CURSOR_WO_FOCUS;
1574 			m_nMode &= ~BROWSER_HIDECURSOR;
1575 		}
1576 		else
1577         {
1578 			// Duerfen Updates gemacht werden, kein Focus-RechtEck
1579 			if ( m_nOptions & OPT_UPDATE )
1580 				m_nMode |= BROWSER_HIDECURSOR;
1581         }
1582 
1583 		if ( m_bMultiSelection )
1584 			m_nMode |= BROWSER_MULTISELECTION;
1585         else
1586             m_nMode &= ~BROWSER_MULTISELECTION;
1587 
1588         adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars );
1589 
1590 		Reference< XColumnsSupplier >  xSupplyColumns(_xCursor, UNO_QUERY);
1591 		if (xSupplyColumns.is())
1592 			InitColumnsByFields(Reference< XIndexAccess > (xSupplyColumns->getColumns(), UNO_QUERY));
1593 
1594 		ConnectToFields();
1595 	}
1596 
1597 	sal_uInt32 nRecordCount(0);
1598 
1599 	if (m_pSeekCursor)
1600 	{
1601 		Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
1602 		xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
1603 		m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
1604 
1605         m_xRowSetListener = new RowSetEventListener(this);
1606         Reference< XRowsChangeBroadcaster> xChangeBroad(xSet,UNO_QUERY);
1607         if ( xChangeBroad.is( ) )
1608             xChangeBroad->addRowsChangeListener(m_xRowSetListener);
1609 
1610 
1611 		// insert the currently known rows
1612 		// and one row if we are able to insert rows
1613 		if (m_nOptions & OPT_INSERT)
1614 		{
1615 			// insert the empty row for insertion
1616 			m_xEmptyRow = new DbGridRow();
1617 			++nRecordCount;
1618 		}
1619 		if (nRecordCount)
1620 		{
1621 			m_xPaintRow = m_xSeekRow = new DbGridRow(m_pSeekCursor, sal_True);
1622 			m_xDataRow	= new DbGridRow(m_pDataCursor, sal_False);
1623 			RowInserted(0, nRecordCount, sal_False);
1624 
1625 			if (m_xSeekRow->IsValid())
1626                 try
1627                 {
1628 				    m_nSeekPos = m_pSeekCursor->getRow() - 1;
1629                 }
1630                 catch( const Exception& )
1631                 {
1632                 	DBG_UNHANDLED_EXCEPTION();
1633                     m_nSeekPos = -1;
1634                 }
1635 		}
1636 		else
1637 		{
1638 			// no rows so we don't need a seekcursor
1639 			DELETEZ(m_pSeekCursor);
1640 		}
1641 	}
1642 
1643 	// Zur alten Spalte gehen
1644 	if (!nCurPos || nCurPos >= ColCount())
1645 		nCurPos = 1;
1646 
1647 	// there are rows so go to the selected current column
1648 	if (nRecordCount)
1649 		GoToRowColumnId(0, GetColumnId(nCurPos));
1650 	// else stop the editing if neccessary
1651 	else if (IsEditing())
1652 		DeactivateCell();
1653 
1654 	// now reset the mode
1655 	if (m_nMode != nOldMode)
1656 		SetMode(m_nMode);
1657 
1658 	// beim Resizen wird RecalcRows gerufen
1659 	if (!IsResizing() && GetRowCount())
1660 		RecalcRows(GetTopRow(), GetVisibleRows(), sal_True);
1661 
1662 	m_aBar.InvalidateAll(m_nCurrentPos, sal_True);
1663 	SetUpdateMode(sal_True);
1664 
1665 	// start listening on the seek cursor
1666 	if (m_pSeekCursor)
1667 		m_pCursorDisposeListener = new DisposeListenerGridBridge(*this, Reference< XComponent > ((Reference< XInterface >)*m_pSeekCursor, UNO_QUERY), 0);
1668 }
1669 
1670 //------------------------------------------------------------------------------
1671 void DbGridControl::RemoveColumns()
1672 {
1673 	if ( IsEditing() )
1674 		DeactivateCell();
1675 
1676 	for (sal_uInt32 i = 0; i < m_aColumns.Count(); i++)
1677 		delete m_aColumns.GetObject(i);
1678 	m_aColumns.Clear();
1679 
1680 	DbGridControl_Base::RemoveColumns();
1681 }
1682 
1683 //------------------------------------------------------------------------------
1684 DbGridColumn* DbGridControl::CreateColumn(sal_uInt16 nId) const
1685 {
1686 	return new DbGridColumn(nId, *(DbGridControl*)this);
1687 }
1688 
1689 //------------------------------------------------------------------------------
1690 sal_uInt16 DbGridControl::AppendColumn(const XubString& rName, sal_uInt16 nWidth, sal_uInt16 nModelPos, sal_uInt16 nId)
1691 {
1692 	DBG_ASSERT(nId == (sal_uInt16)-1, "DbGridControl::AppendColumn : I want to set the ID myself ...");
1693 	sal_uInt16 nRealPos = nModelPos;
1694 	if (nModelPos != HEADERBAR_APPEND)
1695 	{
1696 		// calc the view pos. we can't use our converting functions because the new column
1697 		// has no VCL-representation, yet.
1698 		sal_Int16 nViewPos = nModelPos;
1699 		while (nModelPos--)
1700 		{
1701 			if (m_aColumns.GetObject(nModelPos)->IsHidden())
1702 				--nViewPos;
1703 		}
1704 		// restore nModelPos, we need it later
1705 		nModelPos = nRealPos;
1706 		// the position the base class gets is the view pos + 1 (because of the handle column)
1707 		nRealPos = nViewPos + 1;
1708 	}
1709 
1710 	// calculate the new id
1711     for (nId=1; (GetModelColumnPos(nId) != GRID_COLUMN_NOT_FOUND) && (nId<=m_aColumns.Count()); ++nId)
1712 		;
1713 	DBG_ASSERT(GetViewColumnPos(nId) == (sal_uInt16)-1, "DbGridControl::AppendColumn : inconsistent internal state !");
1714 		// my column's models say "there is no column with id nId", but the view (the base class) says "there is a column ..."
1715 
1716 	DbGridControl_Base::AppendColumn(rName, nWidth, nRealPos, nId);
1717 	if (nModelPos == HEADERBAR_APPEND)
1718 		m_aColumns.Insert(CreateColumn(nId), LIST_APPEND);
1719 	else
1720 		m_aColumns.Insert(CreateColumn(nId), nModelPos);
1721 
1722 	return nId;
1723 }
1724 
1725 //------------------------------------------------------------------------------
1726 void DbGridControl::RemoveColumn(sal_uInt16 nId)
1727 {
1728 	sal_Int16 nIndex = GetModelColumnPos(nId);
1729 	DbGridControl_Base::RemoveColumn(nId);
1730 	delete m_aColumns.Remove(nIndex);
1731 }
1732 
1733 //------------------------------------------------------------------------------
1734 void DbGridControl::ColumnMoved(sal_uInt16 nId)
1735 {
1736 	DbGridControl_Base::ColumnMoved(nId);
1737 
1738 	// remove the col from the model
1739 	sal_Int16 nOldModelPos = GetModelColumnPos(nId);
1740 #ifdef DBG_UTIL
1741 	DbGridColumn* pCol = m_aColumns.GetObject((sal_uInt32)nOldModelPos);
1742 	DBG_ASSERT(!pCol->IsHidden(), "DbGridControl::ColumnMoved : moved a hidden col ? how this ?");
1743 #endif
1744 
1745 	// for the new model pos we can't use GetModelColumnPos because we are altering the model at the moment
1746 	// so the method won't work (in fact it would return the old model pos)
1747 
1748 	// the new view pos is calculated easily
1749 	sal_uInt16 nNewViewPos = GetViewColumnPos(nId);
1750 
1751 	// from that we can compute the new model pos
1752 	sal_uInt16 nNewModelPos;
1753 	for (nNewModelPos = 0; nNewModelPos < m_aColumns.Count(); ++nNewModelPos)
1754 	{
1755 		if (!m_aColumns.GetObject(nNewModelPos)->IsHidden())
1756 		{
1757 			if (!nNewViewPos)
1758 				break;
1759 			else
1760 				--nNewViewPos;
1761 		}
1762 	}
1763 	DBG_ASSERT(nNewModelPos<m_aColumns.Count(), "DbGridControl::ColumnMoved : could not find the new model position !");
1764 
1765 	// this will work. of course the model isn't fully consistent with our view right now, but let's
1766 	// look at the situation : a column has been moved with in the VIEW from pos m to n, say m<n (in the
1767 	// other case we can use analogue arguments).
1768 	// All cols k with m<k<=n have been shifted left on pos, the former col m now has pos n.
1769 	// In the model this affects a range of cols x to y, where x<=m and y<=n. And the number of hidden cols
1770 	// within this range is constant, so we may calculate the view pos from the model pos in the above way.
1771 	//
1772 	// for instance, let's look at a grid with six columns where the third one is hidden. this will
1773 	// initially look like this :
1774 	//
1775 	//				+---+---+---+---+---+---+
1776 	// model pos	| 0 | 1 |*2*| 3 | 4 | 5 |
1777 	//				+---+---+---+---+---+---+
1778 	// ID			| 1 | 2 | 3 | 4 | 5 | 6 |
1779 	//				+---+---+---+---+---+---+
1780 	// view pos 	| 0 | 1 | - | 2 | 3 | 4 |
1781 	//				+---+---+---+---+---+---+
1782 	//
1783 	// if we move the column at (view) pos 1 to (view) pos 3 we have :
1784 	//
1785 	//				+---+---+---+---+---+---+
1786 	// model pos	| 0 | 3 |*2*| 4 | 1 | 5 |	// not reflecting the changes, yet
1787 	//				+---+---+---+---+---+---+
1788 	// ID			| 1 | 4 | 3 | 5 | 2 | 6 |	// already reflecting the changes
1789 	//				+---+---+---+---+---+---+
1790 	// view pos 	| 0 | 1 | - | 2 | 3 | 4 |
1791 	//				+---+---+---+---+---+---+
1792 	//
1793 	// or, sorted by the out-of-date model positions :
1794 	//
1795 	//				+---+---+---+---+---+---+
1796 	// model pos	| 0 | 1 |*2*| 3 | 4 | 5 |
1797 	//				+---+---+---+---+---+---+
1798 	// ID			| 1 | 2 | 3 | 4 | 5 | 6 |
1799 	//				+---+---+---+---+---+---+
1800 	// view pos 	| 0 | 3 | - | 1 | 2 | 4 |
1801 	//				+---+---+---+---+---+---+
1802 	//
1803 	// We know the new view pos (3) of the moved column because our base class tells us. So we look at our
1804 	// model for the 4th (the pos is zero-based) visible column, it is at (model) position 4. And this is
1805 	// exactly the pos where we have to re-insert our column's model, so it looks ike this :
1806 	//
1807 	//				+---+---+---+---+---+---+
1808 	// model pos	| 0 |*1*| 2 | 3 | 4 | 5 |
1809 	//				+---+---+---+---+---+---+
1810 	// ID			| 1 | 3 | 4 | 5 | 2 | 6 |
1811 	//				+---+---+---+---+---+---+
1812 	// view pos 	| 0 | - | 1 | 2 | 3 | 4 |
1813 	//				+---+---+---+---+---+---+
1814 	//
1815 	// Now, all is consistent again.
1816 	// (except of the hidden column : The cycling of the cols occured on the model, not on the view. maybe
1817 	// the user expected the latter but there really is no good argument against our method ;) ...)
1818 	//
1819 	// And no, this large explanation isn't just because I wanted to play a board game or something like
1820 	// that. It's because it took me a while to see it myself, and the whole theme (hidden cols, model col
1821 	// positions, view col positions)  is really painful (at least for me) so the above pictures helped me a lot ;)
1822 
1823 	m_aColumns.Insert(m_aColumns.Remove((sal_uInt32)nOldModelPos), nNewModelPos);
1824 }
1825 
1826 //------------------------------------------------------------------------------
1827 sal_Bool DbGridControl::SeekRow(long nRow)
1828 {
1829 	// in filter mode or in insert only mode we don't have any cursor!
1830 	if ( !SeekCursor( nRow ) )
1831         return sal_False;
1832 
1833 	if ( IsFilterMode() )
1834 	{
1835 		DBG_ASSERT( IsFilterRow( nRow ), "DbGridControl::SeekRow(): No filter row, wrong mode" );
1836 		m_xPaintRow = m_xEmptyRow;
1837 	}
1838     else
1839 	{
1840 		// on the current position we have to take the current row for display as we want
1841 		// to have the most recent values for display
1842 		if ( ( nRow == m_nCurrentPos ) && getDisplaySynchron() )
1843 			m_xPaintRow = m_xCurrentRow;
1844 		// seek to the empty insert row
1845 		else if ( IsInsertionRow( nRow ) )
1846 			m_xPaintRow = m_xEmptyRow;
1847 		else
1848 		{
1849 			m_xSeekRow->SetState( m_pSeekCursor, sal_True );
1850 			m_xPaintRow = m_xSeekRow;
1851 		}
1852 	}
1853 
1854     DbGridControl_Base::SeekRow(nRow);
1855 
1856     return m_nSeekPos >= 0;
1857 }
1858 //------------------------------------------------------------------------------
1859 // Wird aufgerufen, wenn die dargestellte Datenmenge sich aendert
1860 //------------------------------------------------------------------------------
1861 void DbGridControl::VisibleRowsChanged( long nNewTopRow, sal_uInt16 nLinesOnScreen )
1862 {
1863 	RecalcRows(nNewTopRow, nLinesOnScreen , sal_False);
1864 }
1865 
1866 //------------------------------------------------------------------------------
1867 void DbGridControl::RecalcRows(long nNewTopRow, sal_uInt16 nLinesOnScreen, sal_Bool bUpdateCursor)
1868 {
1869 	DBG_CHKTHIS( DbGridControl, NULL );
1870 	// Wenn kein Cursor -> keine Rows im Browser.
1871 	if (!m_pSeekCursor)
1872 	{
1873 		DBG_ASSERT(GetRowCount() == 0,"DbGridControl: ohne Cursor darf es keine Rows geben");
1874 		return;
1875 	}
1876 
1877 	// ignore any updates implicit made
1878 	sal_Bool bDisablePaint = !bUpdateCursor && IsPaintEnabled();
1879 	if (bDisablePaint)
1880 		EnablePaint(sal_False);
1881 
1882 	// Cache an den sichtbaren Bereich anpassen
1883 	Reference< XPropertySet > xSet = m_pSeekCursor->getPropertySet();
1884 	sal_Int32 nCacheSize = 0;
1885 	xSet->getPropertyValue(FM_PROP_FETCHSIZE) >>= nCacheSize;
1886 	sal_Bool bCacheAligned	 = sal_False;
1887 	// Nach der Initialisierung (m_nSeekPos < 0) keine Cursorbewegung, da bereits auf den ersten
1888 	// Satz positioniert
1889 	long nDelta = nNewTopRow - GetTopRow();
1890 	// Limit fuer relative Positionierung
1891 	long nLimit = (nCacheSize) ? nCacheSize / 2 : 0;
1892 
1893 	// mehr Zeilen auf dem Bildschirm als im Cache
1894 	if (nLimit < nLinesOnScreen)
1895 	{
1896 		Any aCacheSize;
1897 		aCacheSize <<= sal_Int32(nLinesOnScreen*2);
1898 		xSet->setPropertyValue(FM_PROP_FETCHSIZE, aCacheSize);
1899 		// jetzt auf alle Faelle den Cursor anpassen
1900 		bUpdateCursor = sal_True;
1901 		bCacheAligned = sal_True;
1902 		nLimit = nLinesOnScreen;
1903 	}
1904 
1905 	// Im folgenden werden die Positionierungen so vorgenommen, da� sichergestellt ist
1906 	// da� ausreichend Zeilen im DatenCache vorhanden sind
1907 
1908 	// Fenster geht nach unten, weniger als zwei Fenster Differenz
1909 	// oder Cache angepasst und noch kein Rowcount
1910 	if (nDelta < nLimit && (nDelta > 0
1911 		|| (bCacheAligned && m_nTotalCount < 0)) )
1912 		SeekCursor(nNewTopRow + nLinesOnScreen - 1, sal_False);
1913 	else if (nDelta < 0 && Abs(nDelta) < nLimit)
1914 		SeekCursor(nNewTopRow, sal_False);
1915 	else if (nDelta != 0 || bUpdateCursor)
1916 		SeekCursor(nNewTopRow, sal_True);
1917 
1918 	AdjustRows();
1919 
1920 	// ignore any updates implicit made
1921 	EnablePaint(sal_True);
1922 }
1923 
1924 //------------------------------------------------------------------------------
1925 void DbGridControl::RowInserted(long nRow, long nNumRows, sal_Bool bDoPaint, sal_Bool bKeepSelection)
1926 {
1927 	if (nNumRows)
1928 	{
1929 		if (m_bRecordCountFinal && m_nTotalCount < 0)
1930 		{
1931 			// if we have an insert row we have to reduce to count by 1
1932 			// as the total count reflects only the existing rows in database
1933 			m_nTotalCount = GetRowCount() + nNumRows;
1934 			if (m_xEmptyRow.Is())
1935 				--m_nTotalCount;
1936 		}
1937 		else if (m_nTotalCount >= 0)
1938 			m_nTotalCount += nNumRows;
1939 
1940 		DbGridControl_Base::RowInserted(nRow, nNumRows, bDoPaint, bKeepSelection);
1941 		m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
1942 	}
1943 }
1944 
1945 //------------------------------------------------------------------------------
1946 void DbGridControl::RowRemoved(long nRow, long nNumRows, sal_Bool bDoPaint)
1947 {
1948 	if (nNumRows)
1949 	{
1950 		if (m_bRecordCountFinal && m_nTotalCount < 0)
1951 		{
1952 			m_nTotalCount = GetRowCount() - nNumRows;
1953 			// if we have an insert row reduce by 1
1954 			if (m_xEmptyRow.Is())
1955 				--m_nTotalCount;
1956 		}
1957 		else if (m_nTotalCount >= 0)
1958 			m_nTotalCount -= nNumRows;
1959 
1960 		DbGridControl_Base::RowRemoved(nRow, nNumRows, bDoPaint);
1961 		m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
1962 	}
1963 }
1964 
1965 //------------------------------------------------------------------------------
1966 void DbGridControl::AdjustRows()
1967 {
1968 	if (!m_pSeekCursor)
1969 		return;
1970 
1971 	Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
1972 
1973 	// Aktualisieren des RecordCounts
1974 	sal_Int32 nRecordCount = 0;
1975 	xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
1976 	if (!m_bRecordCountFinal)
1977 		m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
1978 
1979 	// hat sich die aktuelle Anzahl Rows veraendert
1980 	// hierbei muss auch beruecksichtigt werden,
1981 	// das eine zusaetzliche Zeile zum einfuegen von Datensaetzen vorhanden sein kann
1982 
1983 	// zusaetzliche AppendRow fuers einfuegen
1984 	if (m_nOptions & OPT_INSERT)
1985 		++nRecordCount;
1986 
1987 	// wird gerade eingefuegt, dann gehoert die gerade hinzuzufuegende
1988 	// Zeile nicht zum RecordCount und die Appendrow ebenfalls nicht
1989 	if (!IsUpdating() && m_bRecordCountFinal && IsModified() && m_xCurrentRow != m_xEmptyRow &&
1990 		m_xCurrentRow->IsNew())
1991 		++nRecordCount;
1992 	// das ist mit !m_bUpdating abgesichert : innerhalb von SaveRow (m_bUpdating == sal_True) wuerde sonst der Datensatz, den ich editiere
1993 	// (und den SaveRow gerade angefuegt hat, wodurch diese Methode hier getriggert wurde), doppelt zaehlen : einmal ist er schon
1994 	// in dem normalen RecordCount drin, zum zweiten wuerde er hier gezaehlt werden (60787 - FS)
1995 
1996 	if (nRecordCount != GetRowCount())
1997 	{
1998 		long nDelta = GetRowCount() - (long)nRecordCount;
1999 		if (nDelta > 0) 										// zuviele
2000 		{
2001 			RowRemoved(GetRowCount() - nDelta, nDelta, sal_False);
2002 			// es sind Zeilen weggefallen, dann ab der aktuellen Position neu zeichen
2003 			Invalidate();
2004 
2005             sal_Int32 nNewPos = AlignSeekCursor();
2006             if (m_bSynchDisplay)
2007 			    DbGridControl_Base::GoToRow(nNewPos);
2008 
2009             SetCurrent(nNewPos);
2010             // there are rows so go to the selected current column
2011 	        if (nRecordCount)
2012 		        GoToRowColumnId(nNewPos, GetColumnId(GetCurColumnId()));
2013 	        if (!IsResizing() && GetRowCount())
2014 		        RecalcRows(GetTopRow(), GetVisibleRows(), sal_True);
2015             m_aBar.InvalidateAll(m_nCurrentPos, sal_True);
2016 		}
2017 		else													// zuwenig
2018 			RowInserted(GetRowCount(), -nDelta, sal_True);
2019 	}
2020 
2021 	if (m_bRecordCountFinal && m_nTotalCount < 0)
2022 	{
2023 		if (m_nOptions & OPT_INSERT)
2024 			m_nTotalCount = GetRowCount() - 1;
2025 		else
2026 			m_nTotalCount = GetRowCount();
2027 	}
2028 	m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
2029 }
2030 
2031 //------------------------------------------------------------------------------
2032 DbGridControl_Base::RowStatus DbGridControl::GetRowStatus(long nRow) const
2033 {
2034 	if (IsFilterRow(nRow))
2035 		return DbGridControl_Base::FILTER;
2036 	else if (m_nCurrentPos >= 0 && nRow == m_nCurrentPos)
2037 	{
2038 		// neue Zeile
2039 		if (!IsValid(m_xCurrentRow))
2040 			return DbGridControl_Base::DELETED;
2041 		else if (IsModified())
2042 			return DbGridControl_Base::MODIFIED;
2043 		else if (m_xCurrentRow->IsNew())
2044 			return DbGridControl_Base::CURRENTNEW;
2045 		else
2046 			return DbGridControl_Base::CURRENT;
2047 	}
2048 	else if (IsInsertionRow(nRow))
2049 		return DbGridControl_Base::NEW;
2050 	else if (!IsValid(m_xSeekRow))
2051 		return DbGridControl_Base::DELETED;
2052 	else
2053 		return DbGridControl_Base::CLEAN;
2054 }
2055 
2056 //------------------------------------------------------------------------------
2057 void DbGridControl::PaintStatusCell(OutputDevice& rDev, const Rectangle& rRect) const
2058 {
2059 	DbGridControl_Base::PaintStatusCell(rDev, rRect);
2060 }
2061 
2062 //------------------------------------------------------------------------------
2063 void DbGridControl::PaintCell(OutputDevice& rDev, const Rectangle& rRect, sal_uInt16 nColumnId) const
2064 {
2065 	if (!IsValid(m_xPaintRow))
2066 		return;
2067 
2068 	DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColumnId));
2069 	if (pColumn)
2070 	{
2071 		Rectangle aArea(rRect);
2072 		if ((GetMode() & BROWSER_CURSOR_WO_FOCUS) == BROWSER_CURSOR_WO_FOCUS)
2073 		{
2074 			aArea.Top() += 1;
2075 			aArea.Bottom() -= 1;
2076 		}
2077 		pColumn->Paint(rDev, aArea, m_xPaintRow, getNumberFormatter());
2078 	}
2079 }
2080 
2081 //------------------------------------------------------------------------------
2082 sal_Bool DbGridControl::CursorMoving(long nNewRow, sal_uInt16 nNewCol)
2083 {
2084 	DBG_CHKTHIS( DbGridControl, NULL );
2085 
2086     DeactivateCell( sal_False );
2087 
2088 	if  (   m_pDataCursor
2089         &&  ( m_nCurrentPos != nNewRow )
2090         && !SetCurrent( nNewRow )
2091         )
2092     {
2093         ActivateCell();
2094 		return sal_False;
2095     }
2096 
2097     if ( !DbGridControl_Base::CursorMoving( nNewRow, nNewCol ) )
2098         return sal_False;
2099 
2100 	return sal_True;
2101 }
2102 
2103 //------------------------------------------------------------------------------
2104 sal_Bool DbGridControl::SetCurrent(long nNewRow)
2105 {
2106 	// Each movement of the datacursor must start with BeginCursorAction and end with
2107 	// EndCursorAction to block all notifications during the movement
2108 	BeginCursorAction();
2109 
2110 	try
2111 	{
2112 		// Abgleichen der Positionen
2113 		if (SeekCursor(nNewRow))
2114 		{
2115 			if (IsFilterRow(nNewRow))	// special mode for filtering
2116 			{
2117 				m_xCurrentRow = m_xDataRow = m_xPaintRow = m_xEmptyRow;
2118 				m_nCurrentPos = nNewRow;
2119 			}
2120 			else
2121 			{
2122 				sal_Bool bNewRowInserted = sal_False;
2123 				// Should we go to the insertrow ?
2124 				if (IsInsertionRow(nNewRow))
2125 				{
2126 					// to we need to move the cursor to the insert row?
2127 					// we need to insert the if the current row isn't the insert row or if the
2128 					// cursor triggered the move by itselt and we need a reinitialization of the row
2129 					Reference< XPropertySet > xCursorProps = m_pDataCursor->getPropertySet();
2130 					if ( !::comphelper::getBOOL(xCursorProps->getPropertyValue(FM_PROP_ISNEW)) )
2131 					{
2132 						Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
2133 						xUpdateCursor->moveToInsertRow();
2134 					}
2135 					bNewRowInserted = sal_True;
2136 				}
2137 				else
2138 				{
2139 
2140 					if ( !m_pSeekCursor->isBeforeFirst() && !m_pSeekCursor->isAfterLast() )
2141 					{
2142 						Any aBookmark = m_pSeekCursor->getBookmark();
2143 						if (!m_xCurrentRow || m_xCurrentRow->IsNew() || !CompareBookmark(aBookmark, m_pDataCursor->getBookmark()))
2144 						{
2145 							// adjust the cursor to the new desired row
2146 							if (!m_pDataCursor->moveToBookmark(aBookmark))
2147 							{
2148 								EndCursorAction();
2149 								return sal_False;
2150 							}
2151 						}
2152 					}
2153 				}
2154 				m_xDataRow->SetState(m_pDataCursor, sal_False);
2155 				m_xCurrentRow = m_xDataRow;
2156 
2157 				long nPaintPos = -1;
2158 				// do we have to repaint the last regular row in case of setting defaults or autovalues
2159 				if (m_nCurrentPos >= 0 && m_nCurrentPos >= (GetRowCount() - 2))
2160 					nPaintPos = m_nCurrentPos;
2161 
2162 				m_nCurrentPos = nNewRow;
2163 
2164 				// repaint the new row to display all defaults
2165 				if (bNewRowInserted)
2166 					RowModified(m_nCurrentPos);
2167 				if (nPaintPos >= 0)
2168 					RowModified(nPaintPos);
2169 			}
2170 		}
2171 		else
2172 		{
2173 			DBG_ERROR("DbGridControl::SetCurrent : SeekRow failed !");
2174 			EndCursorAction();
2175 			return sal_False;
2176 		}
2177 	}
2178 	catch ( const Exception& )
2179 	{
2180         DBG_UNHANDLED_EXCEPTION();
2181 		EndCursorAction();
2182 		return sal_False;
2183 	}
2184 
2185 	EndCursorAction();
2186 	return sal_True;
2187 }
2188 
2189 //------------------------------------------------------------------------------
2190 void DbGridControl::CursorMoved()
2191 {
2192 	DBG_CHKTHIS( DbGridControl, NULL );
2193 
2194 	// CursorBewegung durch loeschen oder einfuegen von Zeilen
2195 	if (m_pDataCursor && m_nCurrentPos != GetCurRow())
2196 	{
2197 		DeactivateCell(sal_True);
2198 		SetCurrent(GetCurRow());
2199 	}
2200 
2201 	DbGridControl_Base::CursorMoved();
2202 	m_aBar.InvalidateAll(m_nCurrentPos);
2203 
2204 	// select the new column when they moved
2205 	if ( IsDesignMode() && GetSelectedColumnCount() > 0 && GetCurColumnId() )
2206 	{
2207 		SelectColumnId( GetCurColumnId() );
2208 	}
2209 
2210     if ( m_nLastColId != GetCurColumnId() )
2211         onColumnChange();
2212 	m_nLastColId = GetCurColumnId();
2213 
2214     if ( m_nLastRowId != GetCurRow() )
2215         onRowChange();
2216 	m_nLastRowId = GetCurRow();
2217 }
2218 
2219 //------------------------------------------------------------------------------
2220 void DbGridControl::onRowChange()
2221 {
2222     // not interested in
2223 }
2224 
2225 //------------------------------------------------------------------------------
2226 void DbGridControl::onColumnChange()
2227 {
2228     if ( m_pGridListener )
2229 		m_pGridListener->columnChanged();
2230 }
2231 
2232 //------------------------------------------------------------------------------
2233 void DbGridControl::setDisplaySynchron(sal_Bool bSync)
2234 {
2235 	if (bSync != m_bSynchDisplay)
2236 	{
2237 		m_bSynchDisplay = bSync;
2238 		if (m_bSynchDisplay)
2239 			AdjustDataSource(sal_False);
2240 	}
2241 }
2242 
2243 //------------------------------------------------------------------------------
2244 void DbGridControl::forceSyncDisplay()
2245 {
2246 	sal_Bool bOld = getDisplaySynchron();
2247 	setDisplaySynchron(sal_True);
2248 	if (!bOld)
2249 		setDisplaySynchron(bOld);
2250 }
2251 
2252 //------------------------------------------------------------------------------
2253 void DbGridControl::forceROController(sal_Bool bForce)
2254 {
2255 	if (m_bForceROController == bForce)
2256 		return;
2257 
2258 	m_bForceROController = bForce;
2259 	// alle Columns durchgehen und denen Bescheid geben
2260 	for (sal_uInt16 i=0; i<m_aColumns.Count(); ++i)
2261 	{
2262 		DbGridColumn* pColumn = m_aColumns.GetObject(i);
2263 		if (!pColumn)
2264 			continue;
2265 
2266 		CellController* pReturn = &pColumn->GetController();
2267 		if (!pReturn)
2268 			continue;
2269 
2270 		// nur wenn es eine Edit-Zeile ist, kann ich ihr das forced read-only mitgeben
2271 		if (!pReturn->ISA(EditCellController) && !pReturn->ISA(SpinCellController))
2272 			continue;
2273 
2274 		Edit& rEdit = (Edit&)pReturn->GetWindow();
2275 		rEdit.SetReadOnly(m_bForceROController);
2276 		if (m_bForceROController)
2277 			rEdit.SetStyle(rEdit.GetStyle() | WB_NOHIDESELECTION);
2278 		else
2279 			rEdit.SetStyle(rEdit.GetStyle() & ~WB_NOHIDESELECTION);
2280 	}
2281 
2282 	// die aktive Zelle erneut aktivieren, da sich ihr Controller geaendert haben kann
2283 	if (IsEditing())
2284 		DeactivateCell();
2285 	ActivateCell();
2286 }
2287 
2288 
2289 //------------------------------------------------------------------------------
2290 void DbGridControl::AdjustDataSource(sal_Bool bFull)
2291 {
2292 	TRACE_RANGE("DbGridControl::AdjustDataSource");
2293 	::vos::OGuard aGuard(Application::GetSolarMutex());
2294 	// wird die aktuelle Zeile gerade neu bestimmt,
2295 	// wird kein abgleich vorgenommen
2296 
2297 	if (bFull)
2298 		m_xCurrentRow = NULL;
2299 	// if we are on the same row only repaint
2300 	// but this is only possible for rows which are not inserted, in that case the comparision result
2301 	// may not be correct
2302 	else
2303         if  (   m_xCurrentRow.Is()
2304             &&  !m_xCurrentRow->IsNew()
2305             &&  !m_pDataCursor->isBeforeFirst()
2306             &&  !m_pDataCursor->isAfterLast()
2307             &&  !m_pDataCursor->rowDeleted()
2308             )
2309 		{
2310 			sal_Bool bEqualBookmarks = CompareBookmark( m_xCurrentRow->GetBookmark(), m_pDataCursor->getBookmark() );
2311 
2312 			sal_Bool bDataCursorIsOnNew = sal_False;
2313 			m_pDataCursor->getPropertySet()->getPropertyValue( FM_PROP_ISNEW ) >>= bDataCursorIsOnNew;
2314 
2315 			if ( bEqualBookmarks && !bDataCursorIsOnNew )
2316 			{
2317 				// position of my data cursor is the same as the position our current row points tpo
2318 				// sync the status, repaint, done
2319 				DBG_ASSERT(m_xDataRow == m_xCurrentRow, "Fehler in den Datenzeilen");
2320 				TRACE_RANGE_MESSAGE1("same position, new state : %s", ROWSTATUS(m_xCurrentRow));
2321 				RowModified(m_nCurrentPos);
2322 				return;
2323 			}
2324 		}
2325 
2326 	// weg von der Row des DatenCursors
2327 	if (m_xPaintRow == m_xCurrentRow)
2328 		m_xPaintRow = m_xSeekRow;
2329 
2330 	// keine aktuelle Zeile dann komplett anpassen
2331 	if (!m_xCurrentRow)
2332 		AdjustRows();
2333 
2334 	sal_Int32 nNewPos = AlignSeekCursor();
2335 	if (nNewPos < 0)	// keine Position gefunden
2336 		return;
2337 
2338 	m_bInAdjustDataSource = sal_True;
2339 	if (nNewPos != m_nCurrentPos)
2340 	{
2341 		if (m_bSynchDisplay)
2342 			DbGridControl_Base::GoToRow(nNewPos);
2343 
2344 		if (!m_xCurrentRow.Is())
2345 			// das tritt zum Beispiel auf, wenn man die n (n>1) letzten Datensaetze geloescht hat, waehrend der Cursor auf dem letzten
2346 			// steht : AdjustRows entfernt dann zwei Zeilen aus der BrowseBox, wodurch diese ihre CurrentRow um zwei nach unten
2347 			// korrigiert, so dass dann das GoToRow in's Leere laeuft (da wir uns ja angeblich schon an der richtigen Position
2348 			// befinden)
2349 			SetCurrent(nNewPos);
2350 	}
2351 	else
2352 	{
2353 		SetCurrent(nNewPos);
2354 		RowModified(nNewPos);
2355 	}
2356 	m_bInAdjustDataSource = sal_False;
2357 
2358 	// Wird der DatenCursor von aussen bewegt, wird die selektion aufgehoben
2359 	SetNoSelection();
2360 	m_aBar.InvalidateAll(m_nCurrentPos, m_xCurrentRow.Is());
2361 }
2362 
2363 //------------------------------------------------------------------------------
2364 sal_Int32 DbGridControl::AlignSeekCursor()
2365 {
2366 	DBG_CHKTHIS( DbGridControl, NULL );
2367 	// Positioniert den SeekCursor auf den DatenCursor, Daten werden nicht uebertragen
2368 
2369 	if (!m_pSeekCursor)
2370 		return -1;
2371 
2372 	Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
2373 
2374 	// jetzt den seekcursor an den DatenCursor angleichen
2375 	if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW)))
2376 		m_nSeekPos = GetRowCount() - 1;
2377 	else
2378 	{
2379 		try
2380 		{
2381 			if ( m_pDataCursor->isBeforeFirst() )
2382 			{
2383 				// this is somewhat strange, but can nevertheless happen
2384 				DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (before first)!" );
2385 				m_pSeekCursor->first();
2386 				m_pSeekCursor->previous();
2387 				m_nSeekPos = -1;
2388 			}
2389 			else if ( m_pDataCursor->isAfterLast() )
2390 			{
2391 				DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (after last)!" );
2392 				m_pSeekCursor->last();
2393 				m_pSeekCursor->next();
2394 				m_nSeekPos = -1;
2395 			}
2396 			else
2397 			{
2398 				m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
2399 				if (!CompareBookmark(m_pDataCursor->getBookmark(), m_pSeekCursor->getBookmark()))
2400 					// dummerweise kann das moveToBookmark indirekt dazu fuehren, dass der Seek-Cursor wieder neu positoniert wird (wenn
2401 					// naemlich das mit all seinen zu feuernden Events relativ komplexe moveToBookmark irgendwo ein Update ausloest),
2402 					// also muss ich es nochmal versuchen
2403 					m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
2404 					// Nicht dass das jetzt nicht auch schief gegangen sein koennte, aber es ist zumindest unwahrscheinlicher geworden.
2405 					// Und die Alternative waere eine Schleife so lange bis es stimmt, und das kann auch nicht die Loesung sein
2406 				m_nSeekPos = m_pSeekCursor->getRow() - 1;
2407 			}
2408 		}
2409 		catch(Exception&)
2410 		{
2411 		}
2412 	}
2413 	return m_nSeekPos;
2414 }
2415 //------------------------------------------------------------------------------
2416 sal_Bool DbGridControl::SeekCursor(long nRow, sal_Bool bAbsolute)
2417 {
2418 	DBG_CHKTHIS( DbGridControl, NULL );
2419 	// Positioniert den SeekCursor, Daten werden nicht uebertragen
2420 
2421 	// additions for the filtermode
2422 	if (IsFilterRow(nRow))
2423 	{
2424 		m_nSeekPos = 0;
2425 		return sal_True;
2426 	}
2427 
2428 	if (!m_pSeekCursor)
2429 		return sal_False;
2430 
2431 	// Befinden wir uns gerade beim Einfuegen
2432 	if (IsValid(m_xCurrentRow) && m_xCurrentRow->IsNew() &&
2433 		nRow >= m_nCurrentPos)
2434 	{
2435 		// dann darf auf alle Faelle nicht weiter nach unten gescrollt werden
2436 		// da der letzte Datensatz bereits erreicht wurde!
2437 		if (nRow == m_nCurrentPos)
2438 		{
2439 			// auf die aktuelle Zeile bewegt, dann muß kein abgleich gemacht werden, wenn
2440 			// gerade ein Datensatz eingefuegt wird
2441 			m_nSeekPos = nRow;
2442 		}
2443 		else if (IsInsertionRow(nRow))	// Leerzeile zum Einfuegen von Datensaetzen
2444 			m_nSeekPos = nRow;
2445 	}
2446 	else if (IsInsertionRow(nRow))	// Leerzeile zum Einfuegen von Datensaetzen
2447 		m_nSeekPos = nRow;
2448 	else if ((-1 == nRow) && (GetRowCount() == ((m_nOptions & OPT_INSERT) ? 1 : 0)) && m_pSeekCursor->isAfterLast())
2449 		m_nSeekPos = nRow;
2450 	else
2451 	{
2452 
2453 		sal_Bool bSuccess=sal_False;
2454 		long nSteps = 0;
2455 		try
2456 		{
2457             if ( m_pSeekCursor->rowDeleted() )
2458             {
2459                 // somebody deleted the current row of the seek cursor. Move it away from this row.
2460                 m_pSeekCursor->next();
2461                 if ( m_pSeekCursor->isAfterLast() || m_pSeekCursor->isBeforeFirst() )
2462 			        bAbsolute = sal_True;
2463             }
2464 
2465     		if ( !bAbsolute )
2466             {
2467                 DBG_ASSERT( !m_pSeekCursor->isAfterLast() && !m_pSeekCursor->isBeforeFirst(),
2468                     "DbGridControl::SeekCursor: how did the seek cursor get to this position?!" );
2469 			    nSteps = nRow - (m_pSeekCursor->getRow() - 1);
2470 			    bAbsolute = bAbsolute || (abs(nSteps) > 100);
2471             }
2472 
2473             if ( bAbsolute )
2474 			{
2475                 bSuccess = m_pSeekCursor->absolute(nRow + 1);
2476 				if (bSuccess)
2477 					m_nSeekPos = nRow;
2478 			}
2479             else
2480             {
2481                 if (nSteps > 0) 								// auf den letzten benoetigten Datensatz positionieren
2482 				{
2483 					if (m_pSeekCursor->isAfterLast())
2484 						bSuccess = sal_False;
2485 					else if (m_pSeekCursor->isBeforeFirst())
2486 						bSuccess = m_pSeekCursor->absolute(nSteps);
2487 					else
2488 						bSuccess = m_pSeekCursor->relative(nSteps);
2489 				}
2490 				else if (nSteps < 0)
2491 				{
2492 					if (m_pSeekCursor->isBeforeFirst())
2493 						bSuccess = sal_False;
2494 					else if (m_pSeekCursor->isAfterLast())
2495 						bSuccess = m_pSeekCursor->absolute(nSteps);
2496 					else
2497 						bSuccess = m_pSeekCursor->relative(nSteps);
2498 				}
2499 				else
2500 				{
2501 					m_nSeekPos = nRow;
2502 					return sal_True;
2503 				}
2504 			}
2505 		}
2506 		catch(Exception&)
2507 		{
2508 			DBG_ERROR("DbGridControl::SeekCursor : failed ...");
2509 		}
2510 
2511 		try
2512 		{
2513 			if (!bSuccess)
2514 			{
2515 				if (bAbsolute || nSteps > 0)
2516 					bSuccess = m_pSeekCursor->last();
2517 				else
2518 					bSuccess = m_pSeekCursor->first();
2519 			}
2520 
2521 			if (bSuccess)
2522 				m_nSeekPos = m_pSeekCursor->getRow() - 1;
2523 			else
2524 				m_nSeekPos = -1;
2525 		}
2526 		catch(Exception&)
2527 		{
2528 			DBG_ERROR("DbGridControl::SeekCursor : failed ...");
2529 			m_nSeekPos = -1;						// kein Datensatz mehr vorhanden
2530 		}
2531 	}
2532 	return m_nSeekPos == nRow;
2533 }
2534 //------------------------------------------------------------------------------
2535 void DbGridControl::MoveToFirst()
2536 {
2537 	if (m_pSeekCursor && (GetCurRow() != 0))
2538 		MoveToPosition(0);
2539 }
2540 
2541 //------------------------------------------------------------------------------
2542 void DbGridControl::MoveToLast()
2543 {
2544 	if (!m_pSeekCursor)
2545 		return;
2546 
2547 	if (m_nTotalCount < 0)			// RecordCount steht noch nicht fest
2548 	{
2549 		try
2550 		{
2551 			sal_Bool bRes = m_pSeekCursor->last();
2552 
2553 			if (bRes)
2554 			{
2555 				m_nSeekPos = m_pSeekCursor->getRow() - 1;
2556 				AdjustRows();
2557 			}
2558 		}
2559 		catch(Exception&)
2560 		{
2561 		}
2562 	}
2563 
2564 	// auf den letzen Datensatz positionieren, nicht auf die Leerzeile
2565 	if (m_nOptions & OPT_INSERT)
2566 	{
2567 		if ((GetRowCount() - 1) > 0)
2568 			MoveToPosition(GetRowCount() - 2);
2569 	}
2570 	else if (GetRowCount())
2571 		MoveToPosition(GetRowCount() - 1);
2572 }
2573 
2574 //------------------------------------------------------------------------------
2575 void DbGridControl::MoveToPrev()
2576 {
2577 	long nNewRow = std::max(GetCurRow() - 1L, 0L);
2578 	if (GetCurRow() != nNewRow)
2579 		MoveToPosition(nNewRow);
2580 }
2581 
2582 //------------------------------------------------------------------------------
2583 void DbGridControl::MoveToNext()
2584 {
2585 	if (!m_pSeekCursor)
2586 		return;
2587 
2588 	if (m_nTotalCount > 0)
2589 	{
2590 		// move the data cursor to the right position
2591 		long nNewRow = std::min(GetRowCount() - 1, GetCurRow() + 1);
2592 		if (GetCurRow() != nNewRow)
2593 			MoveToPosition(nNewRow);
2594 	}
2595 	else
2596 	{
2597 		sal_Bool bOk = sal_False;
2598 		try
2599 		{
2600 			// try to move to next row
2601 			// when not possible our paint cursor is already on the last row
2602 			// then we must be sure that the data cursor is on the position
2603 			// we call ourself again
2604             bOk = m_pSeekCursor->next();
2605 			if (bOk)
2606 			{
2607 				m_nSeekPos = m_pSeekCursor->getRow() - 1;
2608 				MoveToPosition(GetCurRow() + 1);
2609 			}
2610 		}
2611 		catch(SQLException &)
2612 		{
2613             DBG_UNHANDLED_EXCEPTION();
2614 		}
2615 
2616 		if(!bOk)
2617 		{
2618 			AdjustRows();
2619 			if (m_nTotalCount > 0) // only to avoid infinte recursion
2620 				MoveToNext();
2621 		}
2622 	}
2623 }
2624 
2625 //------------------------------------------------------------------------------
2626 void DbGridControl::MoveToPosition(sal_uInt32 nPos)
2627 {
2628 	if (!m_pSeekCursor)
2629 		return;
2630 
2631     if (m_nTotalCount < 0 && (long)nPos >= GetRowCount())
2632     {
2633         try
2634         {
2635             if (!m_pSeekCursor->absolute(nPos + 1))
2636             {
2637                 AdjustRows();
2638                 Sound::Beep();
2639                 return;
2640             }
2641             else
2642             {
2643                 m_nSeekPos = m_pSeekCursor->getRow() - 1;
2644                 AdjustRows();
2645             }
2646         }
2647         catch(Exception&)
2648         {
2649             return;
2650         }
2651     }
2652     DbGridControl_Base::GoToRow(nPos);
2653     m_aBar.InvalidateAll(m_nCurrentPos);
2654 }
2655 
2656 //------------------------------------------------------------------------------
2657 void DbGridControl::AppendNew()
2658 {
2659 	if (!m_pSeekCursor || !(m_nOptions & OPT_INSERT))
2660 		return;
2661 
2662 	if (m_nTotalCount < 0)			// RecordCount steht noch nicht fest
2663 	{
2664 		try
2665 		{
2666 			sal_Bool bRes = m_pSeekCursor->last();
2667 
2668 			if (bRes)
2669 			{
2670 				m_nSeekPos = m_pSeekCursor->getRow() - 1;
2671 				AdjustRows();
2672 			}
2673 		}
2674 		catch(Exception&)
2675 		{
2676 			return;
2677 		}
2678 	}
2679 
2680 	long nNewRow = m_nTotalCount + 1;
2681 	if (nNewRow > 0 && GetCurRow() != nNewRow)
2682 		MoveToPosition(nNewRow - 1);
2683 }
2684 
2685 //------------------------------------------------------------------------------
2686 void DbGridControl::SetDesignMode(sal_Bool bMode)
2687 {
2688 	if (IsDesignMode() != bMode)
2689 	{
2690 		// Enable/Disable f�r den Designmode anpassen damit die Headerbar konfigurierbar bleibt
2691 		if (bMode)
2692 		{
2693 			if (!IsEnabled())
2694 			{
2695 				Enable();
2696 				GetDataWindow().Disable();
2697 			}
2698 		}
2699 		else
2700 		{
2701 			// komplett disablen
2702 			if (!GetDataWindow().IsEnabled())
2703 				Disable();
2704 		}
2705 
2706 		m_bDesignMode = bMode;
2707 		GetDataWindow().SetMouseTransparent(bMode);
2708 		SetMouseTransparent(bMode);
2709 
2710 		m_aBar.InvalidateAll(m_nCurrentPos, sal_True);
2711 	}
2712 }
2713 
2714 //------------------------------------------------------------------------------
2715 void DbGridControl::SetFilterMode(sal_Bool bMode)
2716 {
2717 	if (IsFilterMode() != bMode)
2718 	{
2719 		m_bFilterMode = bMode;
2720 
2721 		if (bMode)
2722 		{
2723 			SetUpdateMode(sal_False);
2724 
2725 			// es gibt kein Cursor mehr
2726 			if (IsEditing())
2727 				DeactivateCell();
2728 			RemoveRows(sal_False);
2729 
2730 			m_xEmptyRow = new DbGridRow();
2731 
2732 			// setting the new filter controls
2733 			for (sal_uInt16 i = 0; i<m_aColumns.Count(); ++i)
2734 			{
2735 				DbGridColumn* pCurCol = m_aColumns.GetObject(i);
2736 				if (!pCurCol->IsHidden())
2737 					pCurCol->UpdateControl();
2738 			}
2739 
2740 			// one row for filtering
2741 			RowInserted(0, 1, sal_True);
2742 			SetUpdateMode(sal_True);
2743 		}
2744 		else
2745 			setDataSource(Reference< XRowSet > ());
2746 	}
2747 }
2748 // -----------------------------------------------------------------------------
2749 String DbGridControl::GetCellText(long _nRow, sal_uInt16 _nColId) const
2750 {
2751 	DbGridColumn* pColumn = m_aColumns.GetObject( GetModelColumnPos( _nColId ) );
2752 	String sRet;
2753 	if ( const_cast<DbGridControl*>(this)->SeekRow(_nRow) )
2754 		sRet = GetCurrentRowCellText(pColumn, m_xPaintRow);
2755 	return sRet;
2756 }
2757 //------------------------------------------------------------------------------
2758 XubString DbGridControl::GetCurrentRowCellText(DbGridColumn* pColumn,const DbGridRowRef& _rRow) const
2759 {
2760 	// Ausgabe des Textes fuer eine Zelle
2761 	XubString aText;
2762 	if ( pColumn && IsValid(m_xPaintRow) )
2763 		aText = pColumn->GetCellText(_rRow, m_xFormatter);
2764 	return aText;
2765 }
2766 
2767 //------------------------------------------------------------------------------
2768 sal_uInt32 DbGridControl::GetTotalCellWidth(long nRow, sal_uInt16 nColId)
2769 {
2770 	if (SeekRow(nRow))
2771 	{
2772 		DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColId));
2773 		return GetDataWindow().GetTextWidth(GetCurrentRowCellText(pColumn,m_xPaintRow));
2774 	}
2775 	else
2776 		return 30;	//xxxx
2777 }
2778 
2779 //------------------------------------------------------------------------------
2780 void DbGridControl::PreExecuteRowContextMenu(sal_uInt16 /*nRow*/, PopupMenu& rMenu)
2781 {
2782 	sal_Bool bDelete = (m_nOptions & OPT_DELETE) && GetSelectRowCount() && !IsCurrentAppending();
2783 	// ist nur die Leerzeile selektiert, dann nicht loeschen
2784 	bDelete = bDelete && !((m_nOptions & OPT_INSERT) && GetSelectRowCount() == 1 && IsRowSelected(GetRowCount() - 1));
2785 
2786 	rMenu.EnableItem(SID_FM_DELETEROWS, bDelete);
2787 	rMenu.EnableItem(SID_FM_RECORD_SAVE, IsModified());
2788 
2789 	// the undo is more difficult
2790 	sal_Bool bCanUndo = IsModified();
2791 	long nState = -1;
2792 	if (m_aMasterStateProvider.IsSet())
2793 		nState = m_aMasterStateProvider.Call((void*)SID_FM_RECORD_UNDO);
2794 	bCanUndo &= ( 0 != nState );
2795 
2796 	rMenu.EnableItem(SID_FM_RECORD_UNDO, bCanUndo);
2797 }
2798 
2799 //------------------------------------------------------------------------------
2800 void DbGridControl::PostExecuteRowContextMenu(sal_uInt16 /*nRow*/, const PopupMenu& /*rMenu*/, sal_uInt16 nExecutionResult)
2801 {
2802 	switch (nExecutionResult)
2803 	{
2804 		case SID_FM_DELETEROWS:
2805 			// delete asynchron
2806 			if (m_nDeleteEvent)
2807 				Application::RemoveUserEvent(m_nDeleteEvent);
2808 			m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete));
2809 			break;
2810 		case SID_FM_RECORD_UNDO:
2811 			Undo();
2812 			break;
2813 		case SID_FM_RECORD_SAVE:
2814 			SaveRow();
2815 			break;
2816 		default:
2817 			break;
2818 	}
2819 }
2820 
2821 //------------------------------------------------------------------------------
2822 void DbGridControl::DataSourcePropertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException )
2823 {
2824 	TRACE_RANGE("DbGridControl::DataSourcePropertyChanged");
2825 	::vos::OGuard aGuard( Application::GetSolarMutex() );
2826 	// prop "IsModified" changed ?
2827 	// during update don't care about the modified state
2828 	if (!IsUpdating() && evt.PropertyName.compareTo(FM_PROP_ISMODIFIED) == COMPARE_EQUAL)
2829 	{
2830 		Reference< XPropertySet > xSource(evt.Source, UNO_QUERY);
2831 		DBG_ASSERT( xSource.is(), "DbGridControl::DataSourcePropertyChanged: invalid event source!" );
2832 		sal_Bool bIsNew = sal_False;
2833 		if (xSource.is())
2834 			bIsNew = ::comphelper::getBOOL(xSource->getPropertyValue(FM_PROP_ISNEW));
2835 
2836 		if (bIsNew && m_xCurrentRow.Is())
2837 		{
2838 			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 !");
2839 			sal_Int32 nRecordCount = 0;
2840 			xSource->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
2841 			if (::comphelper::getBOOL(evt.NewValue))
2842 			{	// modified state changed from sal_False to sal_True and we're on a insert row
2843 				// -> we've to add a new grid row
2844 				if ((nRecordCount == GetRowCount() - 1)  && m_xCurrentRow->IsNew())
2845 				{
2846 					RowInserted(GetRowCount(), 1, sal_True);
2847 					InvalidateStatusCell(m_nCurrentPos);
2848 					m_aBar.InvalidateAll(m_nCurrentPos);
2849 				}
2850 			}
2851 			else
2852 			{	// modified state changed from sal_True to sal_False and we're on a insert row
2853 				// we have two "new row"s at the moment : the one we're editing currently (where the current
2854 				// column is the only dirty element) and a "new new" row which is completely clean. As the first
2855 				// one is about to be cleaned, too, the second one is obsolet now.
2856 				if (m_xCurrentRow->IsNew() && nRecordCount == (GetRowCount() - 2))
2857 				{
2858 					RowRemoved(GetRowCount() - 1, 1, sal_True);
2859 					InvalidateStatusCell(m_nCurrentPos);
2860 					m_aBar.InvalidateAll(m_nCurrentPos);
2861 				}
2862 			}
2863 		}
2864 		if (m_xCurrentRow.Is())
2865 		{
2866 			m_xCurrentRow->SetStatus(::comphelper::getBOOL(evt.NewValue) ? GRS_MODIFIED : GRS_CLEAN);
2867 			m_xCurrentRow->SetNew( bIsNew );
2868 			InvalidateStatusCell(m_nCurrentPos);
2869 			TRACE_RANGE_MESSAGE1("modified flag changed, new state : %s", ROWSTATUS(m_xCurrentRow));
2870 		}
2871 	}
2872 }
2873 
2874 //------------------------------------------------------------------------------
2875 void DbGridControl::StartDrag( sal_Int8 /*nAction*/, const Point& rPosPixel )
2876 {
2877 	if (!m_pSeekCursor || IsResizing())
2878 		return;
2879 
2880 	sal_uInt16 nColId = GetColumnAtXPosPixel(rPosPixel.X());
2881 	long   nRow = GetRowAtYPosPixel(rPosPixel.Y());
2882 	if (nColId != HANDLE_ID && nRow >= 0)
2883 	{
2884 		if (GetDataWindow().IsMouseCaptured())
2885 			GetDataWindow().ReleaseMouse();
2886 
2887 		DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColId));
2888 		OStringTransferable* pTransferable = new OStringTransferable(GetCurrentRowCellText(pColumn,m_xPaintRow));
2889 		Reference< XTransferable > xEnsureDelete(pTransferable);
2890 		pTransferable->StartDrag(this, DND_ACTION_COPY);
2891 	}
2892 }
2893 
2894 //------------------------------------------------------------------------------
2895 sal_Bool DbGridControl::canCopyCellText(sal_Int32 _nRow, sal_Int16 _nColId)
2896 {
2897 	return	(_nRow >= 0)
2898 		&&	(_nRow < GetRowCount())
2899 		&&	(_nColId > HANDLE_ID)
2900 		&&	(_nColId <= ColCount());
2901 }
2902 
2903 //------------------------------------------------------------------------------
2904 void DbGridControl::copyCellText(sal_Int32 _nRow, sal_Int16 _nColId)
2905 {
2906 	DBG_ASSERT(canCopyCellText(_nRow, _nColId), "DbGridControl::copyCellText: invalid call!");
2907 	DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(_nColId));
2908 	SeekRow(_nRow);
2909 	OStringTransfer::CopyString( GetCurrentRowCellText( pColumn,m_xPaintRow ), this );
2910 }
2911 
2912 //------------------------------------------------------------------------------
2913 void DbGridControl::executeRowContextMenu( long _nRow, const Point& _rPreferredPos )
2914 {
2915 	PopupMenu aContextMenu( SVX_RES( RID_SVXMNU_ROWS ) );
2916 
2917 	PreExecuteRowContextMenu( (sal_uInt16)_nRow, aContextMenu );
2918 	aContextMenu.RemoveDisabledEntries( sal_True, sal_True );
2919 	PostExecuteRowContextMenu( (sal_uInt16)_nRow, aContextMenu, aContextMenu.Execute( this, _rPreferredPos ) );
2920 
2921 	// TODO: why this weird cast to sal_uInt16? What if we really have more than 65535 lines?
2922 	// -> change this to sal_uInt32
2923 }
2924 
2925 //------------------------------------------------------------------------------
2926 void DbGridControl::Command(const CommandEvent& rEvt)
2927 {
2928 	switch (rEvt.GetCommand())
2929 	{
2930 		case COMMAND_CONTEXTMENU:
2931 		{
2932 			if ( !m_pSeekCursor )
2933 			{
2934 				DbGridControl_Base::Command(rEvt);
2935 				return;
2936 			}
2937 
2938 			if ( !rEvt.IsMouseEvent() )
2939 			{	// context menu requested by keyboard
2940 				if ( GetSelectRowCount() )
2941 				{
2942 					long nRow = FirstSelectedRow( );
2943 
2944 					::Rectangle aRowRect( GetRowRectPixel( nRow, sal_True ) );
2945 					executeRowContextMenu( nRow, aRowRect.LeftCenter() );
2946 
2947 					// handled
2948 					return;
2949 				}
2950 			}
2951 
2952 			sal_uInt16 nColId = GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X());
2953 			long   nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y());
2954 
2955 			if (nColId == HANDLE_ID)
2956 			{
2957 				executeRowContextMenu( nRow, rEvt.GetMousePosPixel() );
2958 			}
2959 			else if (canCopyCellText(nRow, nColId))
2960 			{
2961 				PopupMenu aContextMenu(SVX_RES(RID_SVXMNU_CELL));
2962 				aContextMenu.RemoveDisabledEntries(sal_True, sal_True);
2963 				switch (aContextMenu.Execute(this, rEvt.GetMousePosPixel()))
2964 				{
2965 					case SID_COPY:
2966 						copyCellText(nRow, nColId);
2967 						break;
2968 				}
2969 			}
2970 			else
2971 			{
2972 				DbGridControl_Base::Command(rEvt);
2973 				return;
2974 			}
2975 		}
2976 		default:
2977 			DbGridControl_Base::Command(rEvt);
2978 	}
2979 }
2980 
2981 //------------------------------------------------------------------------------
2982 IMPL_LINK(DbGridControl, OnDelete, void*, /*EMPTYTAG*/ )
2983 {
2984 	DBG_CHKTHIS(DbGridControl, NULL );
2985 	m_nDeleteEvent = 0;
2986 	DeleteSelectedRows();
2987 	return 0;
2988 }
2989 
2990 //------------------------------------------------------------------------------
2991 void DbGridControl::DeleteSelectedRows()
2992 {
2993 	DBG_ASSERT(GetSelection(), "keine selection!!!");
2994 
2995 	if (!m_pSeekCursor)
2996 		return;
2997 
2998 /*	Application::EnterWait();
2999 	Reference< XPropertySet >  xSet = (XPropertySet*)xSeekCursor->queryInterface(XPropertySet::getSmartUik());
3000 
3001 	// wenn mehr als 25 Datensaetze geloescht werden, wird der Cache abgeschaltet
3002 	// da das loeschen ansonsten zu langsam wird
3003 	sal_uInt16 nCacheSize = 0;
3004 	if (GetSelectRowCount() > 25)
3005 	{
3006 		// CacheSize merken und Cache zuruecksetzen
3007 		nCacheSize = xSet->getPropertyValue(L"CacheSize").getUINT16();
3008 		if (nCacheSize)
3009 			xSet->setPropertyValue(L"CacheSize", Any(sal_uInt16(0)));
3010 	} */
3011 
3012 
3013 	/*
3014 	// mu� der Cache wiederhergestellt werden?
3015 	if (nCacheSize)
3016 	{
3017 		// Cache wieder einschalten
3018 		xSet->setPropertyValue(L"CacheSize", Any(sal_uInt16(nCacheSize)));
3019 
3020 		// Browser neu einstellen
3021 		RecalcRows(GetTopRow(), GetVisibleRows(), sal_True);
3022 
3023 		// aktuelle Zeile aktualisieren
3024 		SeekCursor(GetCurRow());
3025 		if (IsAppendRow(m_nSeekPos))
3026 			xDataCursor->addRecord();
3027 		else
3028 		{
3029 			Any aBookmark = xSeekCursor->getBookmark();
3030 			xDataCursor->moveToBookmark(aBookmark);
3031 		}
3032 		m_xCurrentRow = new DbGridRow(xDataCursor);
3033 		m_nCurrentPos = m_nSeekPos;
3034 
3035 		// complett invalidieren
3036 		Invalidate();
3037 	}
3038 	else
3039 		// Browser neu einstellen
3040 		RecalcRows(GetTopRow(), GetVisibleRows(), sal_True);
3041 
3042 	// gibt es keine Selection mehr?
3043 	if (!GetSelectRowCount())
3044 		ActivateCell();
3045 
3046 	m_aBar.InvalidateAll();
3047 	Application::LeaveWait();
3048 
3049 	m_bUpdating = sal_False;
3050 */
3051 }
3052 
3053 //------------------------------------------------------------------------------
3054 CellController* DbGridControl::GetController(long /*nRow*/, sal_uInt16 nColumnId)
3055 {
3056 	if (!IsValid(m_xCurrentRow) || !IsEnabled())
3057 		return NULL;
3058 
3059 	DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColumnId));
3060 	if (!pColumn)
3061 		return NULL;
3062 
3063 	CellController* pReturn = NULL;
3064 	if (IsFilterMode())
3065 		pReturn = &pColumn->GetController();
3066 	else
3067 	{
3068 		if (::comphelper::hasProperty(FM_PROP_ENABLED, pColumn->getModel()))
3069 		{
3070 			if (!::comphelper::getBOOL(pColumn->getModel()->getPropertyValue(FM_PROP_ENABLED)))
3071 				return NULL;
3072 		}
3073 
3074 		sal_Bool bInsert = (m_xCurrentRow->IsNew() && (m_nOptions & OPT_INSERT));
3075 		sal_Bool bUpdate = (!m_xCurrentRow->IsNew() && (m_nOptions & OPT_UPDATE));
3076 
3077 		if ((bInsert && !pColumn->IsAutoValue()) || bUpdate || m_bForceROController)
3078 		{
3079 			pReturn = &pColumn->GetController();
3080 			if (pReturn)
3081 			{
3082 				// wenn es eine Edit-Zeile ist, kann ich ihr das forced read-only mitgeben
3083 				if (!pReturn->ISA(EditCellController) && !pReturn->ISA(SpinCellController))
3084 					// ich konnte den Controller in forceROController nicht auf ReadOnly setzen
3085 					if (!bInsert && !bUpdate)
3086 						// ich bin nur hier, da m_bForceROController gesetzt war
3087 						// -> lieber kein Controller als einer ohne RO
3088 						pReturn = NULL;
3089 			}
3090 		}
3091 	}
3092 	return pReturn;
3093 }
3094 
3095 //------------------------------------------------------------------------------
3096 void DbGridControl::InitController(CellControllerRef& /*rController*/, long /*nRow*/, sal_uInt16 nColumnId)
3097 {
3098 	DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColumnId));
3099 	if (pColumn)
3100 		pColumn->UpdateFromField(m_xCurrentRow, m_xFormatter);
3101 }
3102 
3103 //------------------------------------------------------------------------------
3104 void DbGridControl::CellModified()
3105 {
3106 	TRACE_RANGE("DbGridControl::CellModified");
3107 
3108 	{
3109 		::osl::MutexGuard aGuard(m_aAdjustSafety);
3110 		if (m_nAsynAdjustEvent)
3111 		{
3112 			TRACE_RANGE_MESSAGE1("forcing a synchron call to ", m_bPendingAdjustRows ? "AdjustRows" : "AdustDataSource");
3113 			RemoveUserEvent(m_nAsynAdjustEvent);
3114 			m_nAsynAdjustEvent = 0;
3115 
3116 			// force the call : this should be no problem as we're probably running in the solar thread here
3117 			// (cell modified is triggered by user actions)
3118 			if (m_bPendingAdjustRows)
3119 				AdjustRows();
3120 			else
3121 				AdjustDataSource();
3122 		}
3123 	}
3124 
3125 	if (!IsFilterMode() && IsValid(m_xCurrentRow) && !m_xCurrentRow->IsModified())
3126 	{
3127 		// Einschalten des Editiermodus
3128 		// Datensatz soll eingefuegt werden
3129 		if (m_xCurrentRow->IsNew())
3130 		{
3131 			m_xCurrentRow->SetStatus(GRS_MODIFIED);
3132 			TRACE_RANGE_MESSAGE("current row is new, new state : MODIFIED");
3133 			// wenn noch keine Zeile hinzugefuegt wurde, dann neue hinzunehmen
3134 			if (m_nCurrentPos == GetRowCount() - 1)
3135 			{
3136 				// RowCount um einen erhoehen
3137 				RowInserted(GetRowCount(), 1, sal_True);
3138 				InvalidateStatusCell(m_nCurrentPos);
3139 				m_aBar.InvalidateAll(m_nCurrentPos);
3140 			}
3141 		}
3142 		else if (m_xCurrentRow->GetStatus() != GRS_MODIFIED)
3143 		{
3144 			m_xCurrentRow->SetState(m_pDataCursor, sal_False);
3145 			TRACE_RANGE_MESSAGE1("current row is not new, after SetState, new state : %s", ROWSTATUS(m_xCurrentRow));
3146 			m_xCurrentRow->SetStatus(GRS_MODIFIED);
3147 			TRACE_RANGE_MESSAGE("current row is not new, new state : MODIFIED");
3148 			InvalidateStatusCell(m_nCurrentPos);
3149 		}
3150 	}
3151 }
3152 
3153 //------------------------------------------------------------------------------
3154 void DbGridControl::Dispatch(sal_uInt16 nId)
3155 {
3156 	if (nId == BROWSER_CURSORENDOFFILE)
3157 	{
3158 		if (m_nOptions & OPT_INSERT)
3159 			AppendNew();
3160 		else
3161 			MoveToLast();
3162 	}
3163 	else
3164 		DbGridControl_Base::Dispatch(nId);
3165 }
3166 
3167 //------------------------------------------------------------------------------
3168 void DbGridControl::Undo()
3169 {
3170 	if (!IsFilterMode() && IsValid(m_xCurrentRow) && IsModified())
3171 	{
3172 		// check if we have somebody doin' the UNDO for us
3173 		long nState = -1;
3174 		if (m_aMasterStateProvider.IsSet())
3175 			nState = m_aMasterStateProvider.Call((void*)SID_FM_RECORD_UNDO);
3176 		if (nState>0)
3177 		{	// yes, we have, and the slot is enabled
3178 			DBG_ASSERT(m_aMasterSlotExecutor.IsSet(), "DbGridControl::Undo : a state, but no execute link ?");
3179 			long lResult = m_aMasterSlotExecutor.Call((void*)SID_FM_RECORD_UNDO);
3180 			if (lResult)
3181 				// handled
3182 				return;
3183 		}
3184 		else if (nState == 0)
3185 			// yes, we have, and the slot is disabled
3186 			return;
3187 
3188 		BeginCursorAction();
3189 
3190 		sal_Bool bAppending = m_xCurrentRow->IsNew();
3191 		sal_Bool bDirty 	= m_xCurrentRow->IsModified();
3192 
3193 		try
3194 		{
3195 			// Editieren abbrechen
3196 			Reference< XResultSetUpdate >  xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
3197 			// no effects if we're not updating currently
3198 			if (bAppending)
3199 				// just refresh the row
3200 				xUpdateCursor->moveToInsertRow();
3201 			else
3202 				xUpdateCursor->cancelRowUpdates();
3203 
3204 		}
3205 		catch(Exception&)
3206 		{
3207             DBG_UNHANDLED_EXCEPTION();
3208 		}
3209 
3210 		EndCursorAction();
3211 
3212 		m_xDataRow->SetState(m_pDataCursor, sal_False);
3213 		if (&m_xPaintRow == &m_xCurrentRow)
3214 			m_xPaintRow = m_xCurrentRow = m_xDataRow;
3215 		else
3216 			m_xCurrentRow = m_xDataRow;
3217 
3218 		if (bAppending && (DbGridControl_Base::IsModified() || bDirty))
3219 		// remove the row
3220 			if (m_nCurrentPos == GetRowCount() - 2)
3221 			{	// maybe we already removed it (in resetCurrentRow, called if the above moveToInsertRow
3222 				// caused our data source form to be reset - which should be the usual case ....)
3223 				RowRemoved(GetRowCount() - 1, 1, sal_True);
3224 				m_aBar.InvalidateAll(m_nCurrentPos);
3225 			}
3226 
3227 		RowModified(m_nCurrentPos);
3228 	}
3229 }
3230 
3231 //------------------------------------------------------------------------------
3232 void DbGridControl::resetCurrentRow()
3233 {
3234 	if (IsModified())
3235 	{
3236 		// scenario : we're on the insert row, the row is dirty, and thus there exists a "second" insert row (which
3237 		// is clean). Normally in DataSourcePropertyChanged we would remove this second row if the modified state of
3238 		// the insert row changes from sal_True to sal_False. But if our current cell is the only modified element (means the
3239 		// data source isn't modified) and we're reset this DataSourcePropertyChanged would never be called, so we
3240 		// would never delete the obsolet "second insert row". Thus in this special case this method here
3241 		// is the only possibility to determine the redundance of the row (resetCurrentRow is called when the
3242 		// "first insert row" is about to be cleaned, so of course the "second insert row" is redundant now)
3243 		Reference< XPropertySet > xDataSource = getDataSource()->getPropertySet();
3244 		if (xDataSource.is() && !::comphelper::getBOOL(xDataSource->getPropertyValue(FM_PROP_ISMODIFIED)))
3245 		{
3246 			// are we on a new row currently ?
3247 			if (m_xCurrentRow->IsNew())
3248 			{
3249 				if (m_nCurrentPos == GetRowCount() - 2)
3250 				{
3251 					RowRemoved(GetRowCount() - 1, 1, sal_True);
3252 					m_aBar.InvalidateAll(m_nCurrentPos);
3253 				}
3254 			}
3255 		}
3256 
3257 		// update the rows
3258 		m_xDataRow->SetState(m_pDataCursor, sal_False);
3259 		if (&m_xPaintRow == &m_xCurrentRow)
3260 			m_xPaintRow = m_xCurrentRow = m_xDataRow;
3261 		else
3262 			m_xCurrentRow = m_xDataRow;
3263 	}
3264 
3265 	RowModified(GetCurRow());		// will update the current controller if affected
3266 }
3267 
3268 //------------------------------------------------------------------------------
3269 void DbGridControl::RowModified( long nRow, sal_uInt16 /*nColId*/ )
3270 {
3271 	if (nRow == m_nCurrentPos && IsEditing())
3272 	{
3273 		CellControllerRef aTmpRef = Controller();
3274 		aTmpRef->ClearModified();
3275 		InitController(aTmpRef, m_nCurrentPos, GetCurColumnId());
3276 	}
3277 	DbGridControl_Base::RowModified(nRow);
3278 }
3279 
3280 //------------------------------------------------------------------------------
3281 sal_Bool DbGridControl::IsModified() const
3282 {
3283 	return !IsFilterMode() && IsValid(m_xCurrentRow) && (m_xCurrentRow->IsModified() || DbGridControl_Base::IsModified());
3284 }
3285 
3286 //------------------------------------------------------------------------------
3287 sal_Bool DbGridControl::IsCurrentAppending() const
3288 {
3289 	return m_xCurrentRow.Is() && m_xCurrentRow->IsNew();
3290 }
3291 
3292 //------------------------------------------------------------------------------
3293 sal_Bool DbGridControl::IsInsertionRow(long nRow) const
3294 {
3295 	return (m_nOptions & OPT_INSERT) && m_nTotalCount >= 0 && (nRow == GetRowCount() - 1);
3296 }
3297 
3298 //------------------------------------------------------------------------------
3299 sal_Bool DbGridControl::SaveModified()
3300 {
3301 	TRACE_RANGE("DbGridControl::SaveModified");
3302 	DBG_ASSERT(IsValid(m_xCurrentRow), "GridControl:: Invalid row");
3303 	if (!IsValid(m_xCurrentRow))
3304 		return sal_True;
3305 
3306 	// Uebernimmt die Dateneingabe fuer das Feld
3307 	// Hat es aenderungen im aktuellen Eingabefeld gegeben ?
3308 	if (!DbGridControl_Base::IsModified())
3309 		return sal_True;
3310 
3311 	DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(GetCurColumnId()));
3312 	sal_Bool bOK = pColumn->Commit();
3313 	DBG_ASSERT( Controller().Is(), "DbGridControl::SaveModified: was modified, by have no controller?!" );
3314     if ( !Controller().Is() )
3315         // this might happen if the callbacks implicitly triggered by Commit
3316         // fiddled with the form or the control ...
3317         // (Note that this here is a workaround, at most. We need a general concept how
3318         // to treat this, you can imagine an arbitrary number of scenarios where a callback
3319         // triggers something which leaves us in an expected state.)
3320         // #i67147# / 2006-07-17 / frank.schoenheit@sun.com
3321         return bOK;
3322 
3323 	if (bOK)
3324 	{
3325 		Controller()->ClearModified();
3326 
3327 		if ( IsValid(m_xCurrentRow) )
3328 		{
3329 			m_xCurrentRow->SetState(m_pDataCursor, sal_False);
3330 			TRACE_RANGE_MESSAGE1("explicit SetState, new state : %s", ROWSTATUS(m_xCurrentRow));
3331 			InvalidateStatusCell( m_nCurrentPos );
3332 		}
3333 #ifdef DBG_UTIL
3334 		else
3335 		{
3336 			TRACE_RANGE_MESSAGE1("no SetState, new state : %s", ROWSTATUS(m_xCurrentRow));
3337 		}
3338 #endif
3339 	}
3340 	else
3341 	{
3342 		// reset the modified flag ....
3343 		Controller()->SetModified();
3344 	}
3345 
3346 	return bOK;
3347 }
3348 
3349 //------------------------------------------------------------------------------
3350 sal_Bool DbGridControl::SaveRow()
3351 {
3352 	TRACE_RANGE("DbGridControl::SaveRow");
3353 	// gueltige Zeile
3354 	if (!IsValid(m_xCurrentRow) || !IsModified())
3355 		return sal_True;
3356 	// Wert des Controllers noch nicht gespeichert
3357 	else if (Controller().Is() && Controller()->IsModified())
3358 	{
3359 		if (!SaveModified())
3360 			return sal_False;
3361 	}
3362 	m_bUpdating = sal_True;
3363 
3364 	BeginCursorAction();
3365 	sal_Bool bAppending = m_xCurrentRow->IsNew();
3366 	sal_Bool bSuccess = sal_False;
3367 	try
3368 	{
3369 		Reference< XResultSetUpdate >  xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
3370 		if (bAppending)
3371 			xUpdateCursor->insertRow();
3372 		else
3373 			xUpdateCursor->updateRow();
3374 		bSuccess = sal_True;
3375 	}
3376 	catch(SQLException& e)
3377 	{
3378 		(void)e; // make compiler happy
3379 		EndCursorAction();
3380 		m_bUpdating = sal_False;
3381 		return sal_False;
3382 	}
3383 
3384 	try
3385 	{
3386 		if (bSuccess)
3387 		{
3388 			// if we are appending we still sit on the insert row
3389 			// we don't move just clear the flags not to move on the current row
3390 			m_xCurrentRow->SetState(m_pDataCursor, sal_False);
3391 			TRACE_RANGE_MESSAGE1("explicit SetState after a successfull update, new state : %s", ROWSTATUS(m_xCurrentRow));
3392 			m_xCurrentRow->SetNew(sal_False);
3393 
3394 			// adjust the seekcursor if it is on the same position as the datacursor
3395 			if (m_nSeekPos == m_nCurrentPos || bAppending)
3396 			{
3397 				// get the bookmark to refetch the data
3398 				// in insert mode we take the new bookmark of the data cursor
3399 				Any aBookmark = bAppending ? m_pDataCursor->getBookmark() : m_pSeekCursor->getBookmark();
3400 				m_pSeekCursor->moveToBookmark(aBookmark);
3401 				// get the data
3402 				m_xSeekRow->SetState(m_pSeekCursor, sal_True);
3403 				m_nSeekPos = m_pSeekCursor->getRow() - 1;
3404 			}
3405 		}
3406 		// and repaint the row
3407 		RowModified(m_nCurrentPos);
3408 	}
3409 	catch(Exception&)
3410 	{
3411 	}
3412 
3413 	m_bUpdating = sal_False;
3414 	EndCursorAction();
3415 
3416 	// The old code returned (nRecords != 0) here.
3417 	// Me thinks this is wrong : If something goes wrong while update the record, an exception will be thrown,
3418 	// which results in a "return sal_False" (see above). If no exception is thrown, everything is fine. If nRecords
3419 	// is zero, this simply means all fields had their original values.
3420 	// FS - 06.12.99 - 70502
3421 	return sal_True;
3422 }
3423 
3424 //------------------------------------------------------------------------------
3425 long DbGridControl::PreNotify(NotifyEvent& rEvt)
3426 {
3427 	// keine Events der Navbar behandeln
3428 	if (m_aBar.IsWindowOrChild(rEvt.GetWindow()))
3429 		return BrowseBox::PreNotify(rEvt);
3430 
3431 	switch (rEvt.GetType())
3432 	{
3433 		case EVENT_KEYINPUT:
3434 		{
3435 			const KeyEvent* pKeyEvent = rEvt.GetKeyEvent();
3436 
3437 			sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
3438 			sal_Bool   bShift = pKeyEvent->GetKeyCode().IsShift();
3439 			sal_Bool   bCtrl = pKeyEvent->GetKeyCode().IsMod1();
3440 			sal_Bool   bAlt = pKeyEvent->GetKeyCode().IsMod2();
3441 			if ( ( KEY_TAB == nCode ) && bCtrl && !bAlt )
3442 			{
3443 				// Ctrl-Tab is used to step out of the control, without traveling to the
3444 				// remaining cells first
3445 				// -> build a new key event without the Ctrl-key, and let the very base class handle it
3446 				KeyCode aNewCode( KEY_TAB, bShift, sal_False, sal_False, sal_False );
3447 				KeyEvent aNewEvent( pKeyEvent->GetCharCode(), aNewCode );
3448 
3449 				// call the Control - our direct base class will interpret this in a way we do not want (and do
3450 				// a cell traveling)
3451 				Control::KeyInput( aNewEvent );
3452 				return 1;
3453 			}
3454 
3455 			if ( !bShift && !bCtrl && ( KEY_ESCAPE == nCode ) )
3456 			{
3457 				if (IsModified())
3458 				{
3459 					Undo();
3460 					return 1;
3461 				}
3462 			}
3463 			else if ( ( KEY_DELETE == nCode ) && !bShift && !bCtrl )	// delete rows
3464 			{
3465 				if ((m_nOptions & OPT_DELETE) && GetSelectRowCount())
3466 				{
3467 					// delete asynchron
3468 					if (m_nDeleteEvent)
3469 						Application::RemoveUserEvent(m_nDeleteEvent);
3470 					m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete));
3471 					return 1;
3472 				}
3473 			}
3474 		}	// kein break!
3475 		default:
3476 			return DbGridControl_Base::PreNotify(rEvt);
3477 	}
3478 }
3479 
3480 //------------------------------------------------------------------------------
3481 sal_Bool DbGridControl::IsTabAllowed(sal_Bool bRight) const
3482 {
3483 	if (bRight)
3484 		// Tab nur wenn nicht auf der letzten Zelle
3485 		return GetCurRow() < (GetRowCount() - 1) || !m_bRecordCountFinal ||
3486 			   GetViewColumnPos(GetCurColumnId()) < (GetViewColCount() - 1);
3487 	else
3488 	{
3489 		// Tab nur wenn nicht auf der ersten Zelle
3490 		return GetCurRow() > 0 || (GetCurColumnId() && GetViewColumnPos(GetCurColumnId()) > 0);
3491 	}
3492 }
3493 
3494 //------------------------------------------------------------------------------
3495 void DbGridControl::KeyInput( const KeyEvent& rEvt )
3496 {
3497 	if (rEvt.GetKeyCode().GetFunction() == KEYFUNC_COPY)
3498 	{
3499 		long nRow = GetCurRow();
3500 		sal_uInt16 nColId = GetCurColumnId();
3501 		if (nRow >= 0 && nRow < GetRowCount() && nColId < ColCount())
3502 		{
3503 			DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColId));
3504 			OStringTransfer::CopyString( GetCurrentRowCellText( pColumn,m_xPaintRow ), this );
3505 			return;
3506 		}
3507 	}
3508 	DbGridControl_Base::KeyInput(rEvt);
3509 }
3510 
3511 //------------------------------------------------------------------------------
3512 void DbGridControl::HideColumn(sal_uInt16 nId)
3513 {
3514 	DeactivateCell();
3515 
3516 	// determine the col for the focus to set to after removal
3517 	sal_uInt16 nPos = GetViewColumnPos(nId);
3518 	sal_uInt16 nNewColId = nPos == (ColCount()-1)
3519 		? GetColumnIdFromViewPos(nPos-1)	// last col is to be removed -> take the previous
3520 		: GetColumnIdFromViewPos(nPos+1);	// take the next
3521 
3522 	long lCurrentWidth = GetColumnWidth(nId);
3523 	DbGridControl_Base::RemoveColumn(nId);
3524 		// don't use my own RemoveColumn, this would remove it from m_aColumns, too
3525 
3526 	// update my model
3527 	DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nId));
3528 	DBG_ASSERT(pColumn, "DbGridControl::HideColumn : somebody did hide a nonexistent column !");
3529 	if (pColumn)
3530 	{
3531 		pColumn->m_bHidden = sal_True;
3532 		pColumn->m_nLastVisibleWidth = CalcReverseZoom(lCurrentWidth);
3533 	}
3534 
3535 	// and reset the focus
3536 	if ( nId == GetCurColumnId() )
3537 		GoToColumnId( nNewColId );
3538 }
3539 
3540 //------------------------------------------------------------------------------
3541 void DbGridControl::ShowColumn(sal_uInt16 nId)
3542 {
3543 	sal_uInt16 nPos = GetModelColumnPos(nId);
3544 	DBG_ASSERT(nPos != (sal_uInt16)-1, "DbGridControl::ShowColumn : invalid argument !");
3545 	if (nPos == (sal_uInt16)-1)
3546 		return;
3547 
3548 	DbGridColumn* pColumn = m_aColumns.GetObject(nPos);
3549 	if (!pColumn->IsHidden())
3550 	{
3551 		DBG_ASSERT(GetViewColumnPos(nId) != (sal_uInt16)-1, "DbGridControl::ShowColumn : inconsistent internal state !");
3552 			// if the column isn't marked as hidden, it should be visible, shouldn't it ?
3553 		return;
3554 	}
3555 	DBG_ASSERT(GetViewColumnPos(nId) == (sal_uInt16)-1, "DbGridControl::ShowColumn : inconsistent internal state !");
3556 		// the opposite situation ...
3557 
3558 	// to determine the new view position we need an adjacent non-hidden column
3559 	sal_uInt16 nNextNonHidden = (sal_uInt16)-1;
3560 	// first search the cols to the right
3561 	for (sal_uInt16 i = nPos + 1; i<m_aColumns.Count(); ++i)
3562 	{
3563 		DbGridColumn* pCurCol = m_aColumns.GetObject(i);
3564 		if (!pCurCol->IsHidden())
3565 		{
3566 			nNextNonHidden = i;
3567 			break;
3568 		}
3569 	}
3570 	if ((nNextNonHidden == (sal_uInt16)-1) && (nPos > 0))
3571 	{
3572 		// then to the left
3573 		for (sal_uInt16 i = nPos; i>0; --i)
3574 		{
3575 			DbGridColumn* pCurCol = m_aColumns.GetObject(i-1);
3576 			if (!pCurCol->IsHidden())
3577 			{
3578 				nNextNonHidden = i-1;
3579 				break;
3580 			}
3581 		}
3582 	}
3583 	sal_uInt16 nNewViewPos = (nNextNonHidden == (sal_uInt16)-1)
3584 		? 1 // there is no visible column -> insert behinde the handle col
3585 		: GetViewColumnPos(m_aColumns.GetObject(nNextNonHidden)->GetId()) + 1;
3586 			// the first non-handle col has "view pos" 0, but the pos arg for InsertDataColumn expects
3587 			// a position 1 for the first non-handle col -> +1
3588 	DBG_ASSERT(nNewViewPos != (sal_uInt16)-1, "DbGridControl::ShowColumn : inconsistent internal state !");
3589 		// we found a col marked as visible but got no view pos for it ...
3590 
3591 	if ((nNextNonHidden<nPos) && (nNextNonHidden != (sal_uInt16)-1))
3592 		// nNextNonHidden is a column to the left, so we want to insert the new col _right_ beside it's pos
3593 		++nNewViewPos;
3594 
3595 	DeactivateCell();
3596 
3597 	::rtl::OUString aName;
3598 	pColumn->getModel()->getPropertyValue(FM_PROP_LABEL) >>= aName;
3599 	InsertDataColumn(nId, aName, CalcZoom(pColumn->m_nLastVisibleWidth), HIB_CENTER | HIB_VCENTER | HIB_CLICKABLE, nNewViewPos);
3600 	pColumn->m_bHidden = sal_False;
3601 
3602 	ActivateCell();
3603 	Invalidate();
3604 }
3605 
3606 //------------------------------------------------------------------------------
3607 sal_uInt16 DbGridControl::GetColumnIdFromModelPos( sal_uInt16 nPos ) const
3608 {
3609 	if (nPos >= m_aColumns.Count())
3610 	{
3611 		DBG_ERROR("DbGridControl::GetColumnIdFromModelPos : invalid argument !");
3612 		return (sal_uInt16)-1;
3613 	}
3614 
3615 	DbGridColumn* pCol = m_aColumns.GetObject(nPos);
3616 #if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
3617 	// in der Debug-Version rechnen wir die ModelPos in eine ViewPos um und vergleichen das mit dem Wert,
3618 	// den wir zurueckliefern werden (nId an der entsprechenden Col in m_aColumns)
3619 
3620 	if (!pCol->IsHidden())
3621 	{	// macht nur Sinn, wenn die Spalte sichtbar ist
3622 		sal_uInt16 nViewPos = nPos;
3623 		for (sal_uInt16 i=0; i<m_aColumns.Count() && i<nPos; ++i)
3624 			if (m_aColumns.GetObject(i)->IsHidden())
3625 				--nViewPos;
3626 
3627 		DBG_ASSERT(pCol && GetColumnIdFromViewPos(nViewPos) == pCol->GetId(),
3628 			"DbGridControl::GetColumnIdFromModelPos : this isn't consistent .... did I misunderstand something ?");
3629 	}
3630 #endif
3631 	return pCol->GetId();
3632 }
3633 
3634 //------------------------------------------------------------------------------
3635 sal_uInt16 DbGridControl::GetModelColumnPos( sal_uInt16 nId ) const
3636 {
3637 	for (sal_uInt16 i=0; i<m_aColumns.Count(); ++i)
3638 		if (m_aColumns.GetObject(i)->GetId() == nId)
3639 			return i;
3640 
3641     return GRID_COLUMN_NOT_FOUND;
3642 }
3643 
3644 //------------------------------------------------------------------------------
3645 void DbGridControl::implAdjustInSolarThread(sal_Bool _bRows)
3646 {
3647 	TRACE_RANGE("DbGridControl::implAdjustInSolarThread");
3648 	::osl::MutexGuard aGuard(m_aAdjustSafety);
3649 	if (::vos::OThread::getCurrentIdentifier() != Application::GetMainThreadIdentifier())
3650 	{
3651 		m_nAsynAdjustEvent = PostUserEvent(LINK(this, DbGridControl, OnAsyncAdjust), reinterpret_cast< void* >( _bRows ));
3652 		m_bPendingAdjustRows = _bRows;
3653 #ifdef DBG_UTIL
3654 		if (_bRows)
3655 			TRACE_RANGE_MESSAGE("posting an AdjustRows")
3656 		else
3657 			TRACE_RANGE_MESSAGE("posting an AdjustDataSource")
3658 #endif
3659 	}
3660 	else
3661 	{
3662 #ifdef DBG_UTIL
3663 		if (_bRows)
3664 			TRACE_RANGE_MESSAGE("doing an AdjustRows")
3665 		else
3666 			TRACE_RANGE_MESSAGE("doing an AdjustDataSource")
3667 #endif
3668 		// always adjust the rows before adjusting the data source
3669 		// If this is not necessary (because the row count did not change), nothing is done
3670 		// The problem is that we can't rely on the order of which the calls come in: If the cursor was moved
3671 		// to a position behind row count know 'til now, the cursorMoved notification may come before the
3672 		// RowCountChanged notification
3673 		// 94093 - 02.11.2001 - frank.schoenheit@sun.com
3674 		AdjustRows();
3675 
3676 		if ( !_bRows )
3677 			AdjustDataSource();
3678 	}
3679 }
3680 
3681 //------------------------------------------------------------------------------
3682 IMPL_LINK(DbGridControl, OnAsyncAdjust, void*, pAdjustWhat)
3683 {
3684 	m_nAsynAdjustEvent = 0;
3685 
3686 	AdjustRows();
3687 		// see implAdjustInSolarThread for a comment why we do this every time
3688 
3689 	if ( !pAdjustWhat )
3690 		AdjustDataSource();
3691 
3692 	return 0L;
3693 }
3694 
3695 //------------------------------------------------------------------------------
3696 void DbGridControl::BeginCursorAction()
3697 {
3698 	if (m_pFieldListeners)
3699 	{
3700 		ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
3701 		ConstColumnFieldValueListenersIterator aIter = pListeners->begin();
3702 		while (aIter != pListeners->end())
3703 		{
3704 			GridFieldValueListener* pCurrent = (*aIter).second;
3705 			if (pCurrent)
3706 				pCurrent->suspend();
3707 			++aIter;
3708 		}
3709 	}
3710 
3711 	if (m_pDataSourcePropListener)
3712 		m_pDataSourcePropListener->suspend();
3713 }
3714 
3715 //------------------------------------------------------------------------------
3716 void DbGridControl::EndCursorAction()
3717 {
3718 	if (m_pFieldListeners)
3719 	{
3720 		ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
3721 		ConstColumnFieldValueListenersIterator aIter = pListeners->begin();
3722 		while (aIter != pListeners->end())
3723 		{
3724 			GridFieldValueListener* pCurrent = (*aIter).second;
3725 			if (pCurrent)
3726 				pCurrent->resume();
3727 			++aIter;
3728 		}
3729 	}
3730 
3731 	if (m_pDataSourcePropListener)
3732 		m_pDataSourcePropListener->resume();
3733 }
3734 
3735 //------------------------------------------------------------------------------
3736 void DbGridControl::ConnectToFields()
3737 {
3738 	ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
3739 	DBG_ASSERT(!pListeners || pListeners->size() == 0, "DbGridControl::ConnectToFields : please call DisconnectFromFields first !");
3740 
3741 	if (!pListeners)
3742 	{
3743 		pListeners = new ColumnFieldValueListeners;
3744 		m_pFieldListeners = pListeners;
3745 	}
3746 
3747 	for (sal_Int32 i=0; i<(sal_Int32)m_aColumns.Count(); ++i)
3748 	{
3749 		DbGridColumn* pCurrent = m_aColumns.GetObject(i);
3750 		sal_uInt16 nViewPos = pCurrent ? GetViewColumnPos(pCurrent->GetId()) : (sal_uInt16)-1;
3751 		if ((sal_uInt16)-1 == nViewPos)
3752 			continue;
3753 
3754 		Reference< XPropertySet >  xField = pCurrent->GetField();
3755 		if (!xField.is())
3756 			continue;
3757 
3758 		// column is visible and bound here
3759 		GridFieldValueListener*& rpListener = (*pListeners)[pCurrent->GetId()];
3760 		DBG_ASSERT(!rpListener, "DbGridControl::ConnectToFields : already a listener for this column ?!");
3761 		rpListener = new GridFieldValueListener(*this, xField, pCurrent->GetId());
3762 	}
3763 }
3764 
3765 //------------------------------------------------------------------------------
3766 void DbGridControl::DisconnectFromFields()
3767 {
3768 	if (!m_pFieldListeners)
3769 		return;
3770 
3771 	ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
3772 	while (pListeners->size())
3773 	{
3774 #ifdef DBG_UTIL
3775 		sal_Int32 nOldSize = pListeners->size();
3776 #endif
3777 		pListeners->begin()->second->dispose();
3778 		DBG_ASSERT(nOldSize > (sal_Int32)pListeners->size(), "DbGridControl::DisconnectFromFields : dispose on a listener should result in a removal from my list !");
3779 	}
3780 
3781 	delete pListeners;
3782 	m_pFieldListeners = NULL;
3783 }
3784 
3785 //------------------------------------------------------------------------------
3786 void DbGridControl::FieldValueChanged(sal_uInt16 _nId, const PropertyChangeEvent& /*_evt*/)
3787 {
3788 	osl::MutexGuard aPreventDestruction(m_aDestructionSafety);
3789 	// needed as this may run in a thread other than the main one
3790 	if (GetRowStatus(GetCurRow()) != DbGridControl_Base::MODIFIED)
3791 		// all other cases are handled elsewhere
3792 		return;
3793 
3794 	DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(_nId));
3795 	if (pColumn)
3796 	{
3797 		sal_Bool bAcquiredPaintSafety = sal_False;
3798 		while (!m_bWantDestruction && !bAcquiredPaintSafety)
3799 			bAcquiredPaintSafety  = Application::GetSolarMutex().tryToAcquire();
3800 
3801 		if (m_bWantDestruction)
3802 		{	// at this moment, within another thread, our destructor tries to destroy the listener which called this method
3803 			// => don't do anything
3804 			// 73365 - 23.02.00 - FS
3805 			if (bAcquiredPaintSafety)
3806 				// though the above while-loop suggests that (m_bWantDestruction && bAcquiredPaintSafety) is impossible,
3807 				// it isnt't, as m_bWantDestruction isn't protected with any mutex
3808 				Application::GetSolarMutex().release();
3809 			return;
3810 		}
3811 		// here we got the solar mutex, transfer it to a guard for safety reasons
3812 		::vos::OGuard aPaintSafety(Application::GetSolarMutex());
3813 		Application::GetSolarMutex().release();
3814 
3815 		// and finally do the update ...
3816 		pColumn->UpdateFromField(m_xCurrentRow, m_xFormatter);
3817 		RowModified(GetCurRow(), _nId);
3818 	}
3819 }
3820 
3821 //------------------------------------------------------------------------------
3822 void DbGridControl::FieldListenerDisposing(sal_uInt16 _nId)
3823 {
3824 	ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
3825 	if (!pListeners)
3826 	{
3827 		DBG_ERROR("DbGridControl::FieldListenerDisposing : invalid call (have no listener array) !");
3828 		return;
3829 	}
3830 
3831 	ColumnFieldValueListenersIterator aPos = pListeners->find(_nId);
3832 	if (aPos == pListeners->end())
3833 	{
3834 		DBG_ERROR("DbGridControl::FieldListenerDisposing : invalid call (did not find the listener) !");
3835 		return;
3836 	}
3837 
3838 	delete aPos->second;
3839 
3840 	pListeners->erase(aPos);
3841 }
3842 
3843 //------------------------------------------------------------------------------
3844 void DbGridControl::disposing(sal_uInt16 _nId, const EventObject& /*_rEvt*/)
3845 {
3846 	if (_nId == 0)
3847 	{	// the seek cursor is beeing disposed
3848 		::osl::MutexGuard aGuard(m_aAdjustSafety);
3849 		setDataSource(NULL,0); // our clone was disposed so we set our datasource to null to avoid later acces to it
3850 		if (m_nAsynAdjustEvent)
3851 		{
3852 			RemoveUserEvent(m_nAsynAdjustEvent);
3853 			m_nAsynAdjustEvent = 0;
3854 		}
3855 	}
3856 }
3857 // -----------------------------------------------------------------------------
3858 sal_Int32 DbGridControl::GetAccessibleControlCount() const
3859 {
3860 	return DbGridControl_Base::GetAccessibleControlCount() + 1; // the navigation control
3861 }
3862 // -----------------------------------------------------------------------------
3863 Reference<XAccessible > DbGridControl::CreateAccessibleControl( sal_Int32 _nIndex )
3864 {
3865 	Reference<XAccessible > xRet;
3866 	if ( _nIndex == DbGridControl_Base::GetAccessibleControlCount() )
3867 	{
3868 		xRet = m_aBar.GetAccessible();
3869 	}
3870 	else
3871 		xRet = DbGridControl_Base::CreateAccessibleControl( _nIndex );
3872 	return xRet;
3873 }
3874 // -----------------------------------------------------------------------------
3875 Reference< XAccessible > DbGridControl::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
3876 {
3877 	sal_uInt16 nColumnId = GetColumnId( _nColumnPos );
3878 	DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColumnId));
3879 	if ( pColumn )
3880 	{
3881 		Reference< ::com::sun::star::awt::XControl> xInt(pColumn->GetCell());
3882 		Reference< ::com::sun::star::awt::XCheckBox> xBox(xInt,UNO_QUERY);
3883 		if ( xBox.is() )
3884 		{
3885 			TriState eValue = STATE_NOCHECK;
3886 			switch( xBox->getState() )
3887 			{
3888 				case 0:
3889 					eValue = STATE_NOCHECK;
3890 					break;
3891 				case 1:
3892 					eValue = STATE_CHECK;
3893 					break;
3894 				case 2:
3895 					eValue = STATE_DONTKNOW;
3896 					break;
3897 			}
3898 			return DbGridControl_Base::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,eValue,sal_True );
3899 		}
3900 	}
3901 	return DbGridControl_Base::CreateAccessibleCell( _nRow, _nColumnPos );
3902 }
3903 // -----------------------------------------------------------------------------
3904 
3905 
3906