summaryrefslogtreecommitdiff
path: root/svx/source/fmcomp/gridctrl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/fmcomp/gridctrl.cxx')
-rw-r--r--svx/source/fmcomp/gridctrl.cxx3893
1 files changed, 3893 insertions, 0 deletions
diff --git a/svx/source/fmcomp/gridctrl.cxx b/svx/source/fmcomp/gridctrl.cxx
new file mode 100644
index 000000000000..1944bd47dad5
--- /dev/null
+++ b/svx/source/fmcomp/gridctrl.cxx
@@ -0,0 +1,3893 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svx.hxx"
+
+#ifndef _SVX_FMHELP_HRC
+#include "fmhelp.hrc"
+#endif
+#include <svx/gridctrl.hxx>
+#include "gridcell.hxx"
+#include "svx/dbtoolsclient.hxx"
+#include "svx/fmtools.hxx"
+#include <svtools/stringtransfer.hxx>
+
+#ifndef _SVX_FMPROP_HRC
+#include "fmprop.hrc"
+#endif
+#include <svtools/stringtransfer.hxx>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/sdb/XResultSetAccess.hpp>
+#include <com/sun/star/sdb/RowChangeAction.hpp>
+#include <com/sun/star/sdb/XRowsChangeBroadcaster.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyChangeEvent.hpp>
+#include <comphelper/extract.hxx>
+#include <tools/resid.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/sound.hxx>
+#include <vcl/menu.hxx>
+
+#ifndef _SVX_FMRESIDS_HRC
+#include "fmresids.hrc"
+#endif
+
+#ifndef _SVX_SVXIDS_HRC
+#include <svx/svxids.hrc>
+#endif
+#include <tools/shl.hxx>
+#include <svx/dialmgr.hxx>
+#include "fmservs.hxx"
+#include "sdbdatacolumn.hxx"
+
+#define HANDLE_ID 0
+
+#include <comphelper/stl_types.hxx>
+#include <comphelper/property.hxx>
+#include "trace.hxx"
+
+#include <algorithm>
+
+using namespace ::svxform;
+using namespace ::svt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::container;
+using namespace com::sun::star::accessibility;
+
+#define ROWSTATUS(row) !row.Is() ? "NULL" : row->GetStatus() == GRS_CLEAN ? "CLEAN" : row->GetStatus() == GRS_MODIFIED ? "MODIFIED" : row->GetStatus() == GRS_DELETED ? "DELETED" : "INVALID"
+
+
+#define DEFAULT_BROWSE_MODE \
+ BROWSER_COLUMNSELECTION \
+ | BROWSER_MULTISELECTION \
+ | BROWSER_KEEPSELECTION \
+ | BROWSER_TRACKING_TIPS \
+ | BROWSER_HLINESFULL \
+ | BROWSER_VLINESFULL \
+ | BROWSER_HEADERBAR_NEW \
+
+class RowSetEventListener : public ::cppu::WeakImplHelper1<XRowsChangeListener>
+{
+ DbGridControl* m_pControl;
+public:
+ RowSetEventListener(DbGridControl* i_pControl) : m_pControl(i_pControl)
+ {
+ }
+private:
+ // XEventListener
+ virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& /*i_aEvt*/) throw ( RuntimeException )
+ {
+ }
+ virtual void SAL_CALL rowsChanged(const ::com::sun::star::sdb::RowsChangeEvent& i_aEvt) throw ( RuntimeException )
+ {
+ if ( i_aEvt.Action == RowChangeAction::UPDATE )
+ {
+ ::DbGridControl::GrantControlAccess aAccess;
+ CursorWrapper* pSeek = m_pControl->GetSeekCursor(aAccess);
+ const DbGridRowRef& rSeekRow = m_pControl->GetSeekRow(aAccess);
+ const Any* pIter = i_aEvt.Bookmarks.getConstArray();
+ const Any* pEnd = pIter + i_aEvt.Bookmarks.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ pSeek->moveToBookmark(*pIter);
+ // get the data
+ rSeekRow->SetState(pSeek, sal_True);
+ sal_Int32 nSeekPos = pSeek->getRow() - 1;
+ m_pControl->SetSeekPos(nSeekPos,aAccess);
+ m_pControl->RowModified(nSeekPos);
+ }
+ }
+ }
+};
+//==============================================================================
+
+class GridFieldValueListener;
+DECLARE_STL_MAP(sal_uInt16, GridFieldValueListener*, ::std::less<sal_uInt16>, ColumnFieldValueListeners);
+
+//==============================================================================
+
+DBG_NAME(GridFieldValueListener)
+class GridFieldValueListener : protected ::comphelper::OPropertyChangeListener
+{
+ osl::Mutex m_aMutex;
+ DbGridControl& m_rParent;
+ ::comphelper::OPropertyChangeMultiplexer* m_pRealListener;
+ sal_uInt16 m_nId;
+ sal_Int16 m_nSuspended;
+ sal_Bool m_bDisposed : 1;
+
+public:
+ GridFieldValueListener(DbGridControl& _rParent, const Reference< XPropertySet >& xField, sal_uInt16 _nId);
+ virtual ~GridFieldValueListener();
+
+ virtual void _propertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException );
+
+ void suspend() { ++m_nSuspended; }
+ void resume() { --m_nSuspended; }
+
+ void dispose();
+};
+//------------------------------------------------------------------------------
+GridFieldValueListener::GridFieldValueListener(DbGridControl& _rParent, const Reference< XPropertySet >& _rField, sal_uInt16 _nId)
+ :OPropertyChangeListener(m_aMutex)
+ ,m_rParent(_rParent)
+ ,m_pRealListener(NULL)
+ ,m_nId(_nId)
+ ,m_nSuspended(0)
+ ,m_bDisposed(sal_False)
+{
+ DBG_CTOR(GridFieldValueListener, NULL);
+ if (_rField.is())
+ {
+ m_pRealListener = new ::comphelper::OPropertyChangeMultiplexer(this, _rField);
+ m_pRealListener->addProperty(FM_PROP_VALUE);
+ m_pRealListener->acquire();
+ }
+}
+
+//------------------------------------------------------------------------------
+GridFieldValueListener::~GridFieldValueListener()
+{
+ DBG_DTOR(GridFieldValueListener, NULL);
+ dispose();
+}
+
+//------------------------------------------------------------------------------
+void GridFieldValueListener::_propertyChanged(const PropertyChangeEvent& _evt) throw( RuntimeException )
+{
+ DBG_ASSERT(m_nSuspended>=0, "GridFieldValueListener::_propertyChanged : resume > suspend !");
+ if (m_nSuspended <= 0)
+ m_rParent.FieldValueChanged(m_nId, _evt);
+}
+
+//------------------------------------------------------------------------------
+void GridFieldValueListener::dispose()
+{
+ if (m_bDisposed)
+ {
+ DBG_ASSERT(m_pRealListener == NULL, "GridFieldValueListener::dispose : inconsistent !");
+ return;
+ }
+
+ if (m_pRealListener)
+ {
+ m_pRealListener->dispose();
+ m_pRealListener->release();
+ m_pRealListener = NULL;
+ }
+
+ m_bDisposed = sal_True;
+ m_rParent.FieldListenerDisposing(m_nId);
+}
+
+//==============================================================================
+
+class DisposeListenerGridBridge : public FmXDisposeListener
+{
+ osl::Mutex m_aMutex;
+ DbGridControl& m_rParent;
+ FmXDisposeMultiplexer* m_pRealListener;
+
+public:
+ DisposeListenerGridBridge( DbGridControl& _rParent, const Reference< XComponent >& _rxObject, sal_Int16 _rId = -1);
+ virtual ~DisposeListenerGridBridge();
+
+ virtual void disposing(const EventObject& _rEvent, sal_Int16 _nId) throw( RuntimeException ) { m_rParent.disposing(_nId, _rEvent); }
+};
+
+//==============================================================================
+
+
+DBG_NAME(DisposeListenerGridBridge)
+//------------------------------------------------------------------------------
+DisposeListenerGridBridge::DisposeListenerGridBridge(DbGridControl& _rParent, const Reference< XComponent >& _rxObject, sal_Int16 _rId)
+ :FmXDisposeListener(m_aMutex)
+ ,m_rParent(_rParent)
+ ,m_pRealListener(NULL)
+{
+ DBG_CTOR(DisposeListenerGridBridge,NULL);
+
+ if (_rxObject.is())
+ {
+ m_pRealListener = new FmXDisposeMultiplexer(this, _rxObject, _rId);
+ m_pRealListener->acquire();
+ }
+}
+
+//------------------------------------------------------------------------------
+DisposeListenerGridBridge::~DisposeListenerGridBridge()
+{
+ if (m_pRealListener)
+ {
+ m_pRealListener->dispose();
+ m_pRealListener->release();
+ m_pRealListener = NULL;
+ }
+
+ DBG_DTOR(DisposeListenerGridBridge,NULL);
+}
+
+//==============================================================================
+
+static sal_uInt16 ControlMap[] =
+ {
+ DbGridControl::NavigationBar::RECORD_TEXT,
+ DbGridControl::NavigationBar::RECORD_ABSOLUTE,
+ DbGridControl::NavigationBar::RECORD_OF,
+ DbGridControl::NavigationBar::RECORD_COUNT,
+ DbGridControl::NavigationBar::RECORD_FIRST,
+ DbGridControl::NavigationBar::RECORD_NEXT,
+ DbGridControl::NavigationBar::RECORD_PREV,
+ DbGridControl::NavigationBar::RECORD_LAST,
+ DbGridControl::NavigationBar::RECORD_NEW,
+ 0
+ };
+
+//------------------------------------------------------------------------------
+sal_Bool CompareBookmark(const Any& aLeft, const Any& aRight)
+{
+ return ::comphelper::compare(aLeft, aRight);
+}
+
+//==============================================================================
+class FmXGridSourcePropListener : public ::comphelper::OPropertyChangeListener
+{
+ DbGridControl* m_pParent;
+
+ // a DbGridControl has no mutex, so we use our own as the base class expects one
+ osl::Mutex m_aMutex;
+ sal_Int16 m_nSuspended;
+
+public:
+ FmXGridSourcePropListener(DbGridControl* _pParent);
+
+ void suspend() { ++m_nSuspended; }
+ void resume() { --m_nSuspended; }
+
+ virtual void _propertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException );
+};
+
+//------------------------------------------------------------------------------
+FmXGridSourcePropListener::FmXGridSourcePropListener(DbGridControl* _pParent)
+ :OPropertyChangeListener(m_aMutex)
+ ,m_pParent(_pParent)
+ ,m_nSuspended(0)
+{
+ DBG_ASSERT(m_pParent, "FmXGridSourcePropListener::FmXGridSourcePropListener : invalid parent !");
+}
+
+//------------------------------------------------------------------------------
+void FmXGridSourcePropListener::_propertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException )
+{
+ DBG_ASSERT(m_nSuspended>=0, "FmXGridSourcePropListener::_propertyChanged : resume > suspend !");
+ if (m_nSuspended <= 0)
+ m_pParent->DataSourcePropertyChanged(evt);
+}
+
+//==============================================================================
+//------------------------------------------------------------------------------
+DbGridControl::NavigationBar::AbsolutePos::AbsolutePos(Window* pParent, WinBits nStyle)
+ :NumericField(pParent, nStyle)
+{
+ SetMin(1);
+ SetFirst(1);
+ SetSpinSize(1);
+
+ SetDecimalDigits(0);
+ SetStrictFormat(sal_True);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::NavigationBar::AbsolutePos::KeyInput(const KeyEvent& rEvt)
+{
+ if (rEvt.GetKeyCode() == KEY_RETURN && GetText().Len())
+ {
+ sal_Int64 nRecord = GetValue();
+ if (nRecord < GetMin() || nRecord > GetMax())
+ return;
+ else
+ ((NavigationBar*)GetParent())->PositionDataSource(static_cast<sal_Int32>(nRecord));
+ }
+ else if (rEvt.GetKeyCode() == KEY_TAB)
+ GetParent()->GetParent()->GrabFocus();
+ else
+ NumericField::KeyInput(rEvt);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::NavigationBar::AbsolutePos::LoseFocus()
+{
+ NumericField::LoseFocus();
+ sal_Int64 nRecord = GetValue();
+ if (nRecord < GetMin() || nRecord > GetMax())
+ return;
+ else
+ {
+ ((NavigationBar*)GetParent())->PositionDataSource(static_cast<sal_Int32>(nRecord));
+ ((NavigationBar*)GetParent())->InvalidateState(NavigationBar::RECORD_ABSOLUTE);
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::NavigationBar::PositionDataSource(sal_Int32 nRecord)
+{
+ if (m_bPositioning)
+ return;
+ // the MoveToPosition may cause a LoseFocus which would lead to a second MoveToPosition, so protect agains this
+ // recursion
+ // 68167 - 13.08.99 - FS
+ m_bPositioning = sal_True;
+ ((DbGridControl*)GetParent())->MoveToPosition(nRecord - 1);
+ m_bPositioning = sal_False;
+}
+
+//------------------------------------------------------------------------------
+DbGridControl::NavigationBar::NavigationBar(Window* pParent, WinBits nStyle)
+ :Control(pParent, nStyle)
+ ,m_aRecordText(this, WB_VCENTER)
+ ,m_aAbsolute(this, WB_VCENTER)
+ ,m_aRecordOf(this, WB_VCENTER)
+ ,m_aRecordCount(this, WB_CENTER | WB_VCENTER)
+ ,m_aFirstBtn(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)
+ ,m_aPrevBtn(this, WB_REPEAT|WB_RECTSTYLE|WB_NOPOINTERFOCUS)
+ ,m_aNextBtn(this, WB_REPEAT|WB_RECTSTYLE|WB_NOPOINTERFOCUS)
+ ,m_aLastBtn(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)
+ ,m_aNewBtn(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)
+ ,m_nDefaultWidth(0)
+ ,m_nCurrentPos(-1)
+ ,m_bPositioning(sal_False)
+{
+ m_aFirstBtn.SetSymbol(SYMBOL_FIRST);
+ m_aPrevBtn.SetSymbol(SYMBOL_PREV);
+ m_aNextBtn.SetSymbol(SYMBOL_NEXT);
+ m_aLastBtn.SetSymbol(SYMBOL_LAST);
+ m_aNewBtn.SetModeImage(((DbGridControl*)pParent)->GetImage(DbGridControl_Base::NEW));
+
+ m_aFirstBtn.SetHelpId(HID_GRID_TRAVEL_FIRST);
+ m_aPrevBtn.SetHelpId(HID_GRID_TRAVEL_PREV);
+ m_aNextBtn.SetHelpId(HID_GRID_TRAVEL_NEXT);
+ m_aLastBtn.SetHelpId(HID_GRID_TRAVEL_LAST);
+ m_aNewBtn.SetHelpId(HID_GRID_TRAVEL_NEW);
+ m_aAbsolute.SetHelpId(HID_GRID_TRAVEL_ABSOLUTE);
+ m_aRecordCount.SetHelpId(HID_GRID_NUMBEROFRECORDS);
+
+ // Handler fuer Buttons einrichten
+ m_aFirstBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
+ m_aPrevBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
+ m_aNextBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
+ m_aLastBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
+ m_aNewBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
+
+ m_aRecordText.SetText(XubString(SVX_RES(RID_STR_REC_TEXT)));
+ m_aRecordOf.SetText(XubString(SVX_RES(RID_STR_REC_FROM_TEXT)));
+ m_aRecordCount.SetText('?');
+
+ m_nDefaultWidth = ArrangeControls();
+
+ m_aFirstBtn.Disable();
+ m_aPrevBtn.Disable();
+ m_aNextBtn.Disable();
+ m_aLastBtn.Disable();
+ m_aNewBtn.Disable();
+ m_aRecordText.Disable();
+ m_aRecordOf.Disable();
+ m_aRecordCount.Disable();
+ m_aAbsolute.Disable();
+
+ AllSettings aSettings = m_aNextBtn.GetSettings();
+ MouseSettings aMouseSettings = aSettings.GetMouseSettings();
+ aMouseSettings.SetButtonRepeat(aMouseSettings.GetButtonRepeat() / 4);
+ aSettings.SetMouseSettings(aMouseSettings);
+ m_aNextBtn.SetSettings(aSettings, sal_True);
+ m_aPrevBtn.SetSettings(aSettings, sal_True);
+
+ m_aFirstBtn.Show();
+ m_aPrevBtn.Show();
+ m_aNextBtn.Show();
+ m_aLastBtn.Show();
+ m_aNewBtn.Show();
+ m_aRecordText.Show();
+ m_aRecordOf.Show();
+ m_aRecordCount.Show();
+ m_aAbsolute.Show();
+}
+
+namespace
+{
+ void SetPosAndSize(Button& _rButton,Point& _rPos,const Size& _rSize)
+ {
+ _rButton.SetPosPixel( _rPos );
+ _rButton.SetSizePixel( _rSize );
+ _rPos.X() += (sal_uInt16)_rSize.Width();
+ }
+}
+//------------------------------------------------------------------------------
+sal_uInt16 DbGridControl::NavigationBar::ArrangeControls()
+{
+ // Positionierung der Controls
+ // Basisgroessen ermitteln
+ sal_uInt16 nX = 0;
+ sal_uInt16 nY = 0;
+ Rectangle aRect(((DbGridControl*)GetParent())->GetControlArea());
+ const long nH = aRect.GetSize().Height();
+ Size aBorder = LogicToPixel(Size(3, 3),MAP_APPFONT);
+ aBorder = Size(CalcZoom(aBorder.Width()), CalcZoom(aBorder.Height()));
+
+ // Controls Groessen und Positionen setzen
+ //
+ XubString aText = m_aRecordText.GetText();
+ long nTextWidth = m_aRecordText.GetTextWidth(aText);
+ m_aRecordText.SetPosPixel(Point(nX,nY) );
+ m_aRecordText.SetSizePixel(Size(nTextWidth,nH));
+ nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
+
+ m_aAbsolute.SetPosPixel( Point(nX,nY));
+ m_aAbsolute.SetSizePixel( Size(3*nH,aRect.GetSize().Height()) ); // Heuristik XXXXXXX
+ nX = sal::static_int_cast< sal_uInt16 >(nX + (3*nH) + aBorder.Width());
+
+ aText = m_aRecordOf.GetText();
+ nTextWidth = m_aRecordOf.GetTextWidth(aText);
+ m_aRecordOf.SetPosPixel(Point(nX,nY) );
+ m_aRecordOf.SetSizePixel(Size(nTextWidth,nH));
+ nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
+
+ nTextWidth = m_aRecordCount.GetTextWidth( String::CreateFromAscii("0000000 (00000) *") );
+ m_aRecordCount.SetPosPixel(Point(nX,nY) );
+ m_aRecordCount.SetSizePixel(Size(nTextWidth,nH));
+ nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
+
+ Point aButtonPos(nX,nY);
+ Size aButtonSize(nH,nH);
+ SetPosAndSize(m_aFirstBtn, aButtonPos, aButtonSize);
+ SetPosAndSize(m_aPrevBtn, aButtonPos, aButtonSize);
+ SetPosAndSize(m_aNextBtn, aButtonPos, aButtonSize);
+ SetPosAndSize(m_aLastBtn, aButtonPos, aButtonSize);
+ SetPosAndSize(m_aNewBtn, aButtonPos, aButtonSize);
+
+ nX = sal::static_int_cast< sal_uInt16 >(
+ aButtonPos.X() + (sal_uInt16)(nH + aBorder.Width()));
+
+ // Ist der Font des Edits groesser als das Feld?
+ Font aOutputFont = m_aAbsolute.GetFont();
+ if (aOutputFont.GetSize().Height() > nH)
+ {
+ Font aApplFont = OutputDevice::GetDefaultFont(
+ DEFAULTFONT_SANS_UNICODE,
+ Application::GetSettings().GetUILanguage(),
+ DEFAULTFONT_FLAGS_ONLYONE,
+ this
+ );
+ aApplFont.SetSize( Size( 0, nH - 2 ) );
+ m_aAbsolute.SetControlFont( aApplFont );
+
+ aApplFont.SetTransparent( sal_True );
+ m_aRecordText.SetControlFont( aApplFont );
+ m_aRecordOf.SetControlFont( aApplFont );
+ m_aRecordCount.SetControlFont( aApplFont );
+ }
+ return nX;
+}
+
+//------------------------------------------------------------------------------
+IMPL_LINK(DbGridControl::NavigationBar, OnClick, Button *, pButton )
+{
+ DbGridControl* pParent = (DbGridControl*)GetParent();
+
+ if (pParent->m_aMasterSlotExecutor.IsSet())
+ {
+ long lResult = 0;
+ if (pButton == &m_aFirstBtn)
+ lResult = pParent->m_aMasterSlotExecutor.Call((void*)RECORD_FIRST);
+ else if( pButton == &m_aPrevBtn )
+ lResult = pParent->m_aMasterSlotExecutor.Call((void*)RECORD_PREV);
+ else if( pButton == &m_aNextBtn )
+ lResult = pParent->m_aMasterSlotExecutor.Call((void*)RECORD_NEXT);
+ else if( pButton == &m_aLastBtn )
+ lResult = pParent->m_aMasterSlotExecutor.Call((void*)RECORD_LAST);
+ else if( pButton == &m_aNewBtn )
+ lResult = pParent->m_aMasterSlotExecutor.Call((void*)RECORD_NEW);
+
+ if (lResult)
+ // the link already handled it
+ return 0;
+ }
+
+ if (pButton == &m_aFirstBtn)
+ pParent->MoveToFirst();
+ else if( pButton == &m_aPrevBtn )
+ pParent->MoveToPrev();
+ else if( pButton == &m_aNextBtn )
+ pParent->MoveToNext();
+ else if( pButton == &m_aLastBtn )
+ pParent->MoveToLast();
+ else if( pButton == &m_aNewBtn )
+ pParent->AppendNew();
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::NavigationBar::InvalidateAll(sal_Int32 nCurrentPos, sal_Bool bAll)
+{
+ if (m_nCurrentPos != nCurrentPos || nCurrentPos < 0 || bAll)
+ {
+ DbGridControl* pParent = (DbGridControl*)GetParent();
+
+ sal_Int32 nAdjustedRowCount = pParent->GetRowCount() - ((pParent->GetOptions() & DbGridControl::OPT_INSERT) ? 2 : 1);
+
+ // Wann mu� alles invalidiert werden
+ bAll = bAll || m_nCurrentPos <= 0;
+ bAll = bAll || nCurrentPos <= 0;
+ bAll = bAll || m_nCurrentPos >= nAdjustedRowCount;
+ bAll = bAll || nCurrentPos >= nAdjustedRowCount;
+
+ if ( bAll )
+ {
+ m_nCurrentPos = nCurrentPos;
+ int i = 0;
+ while (ControlMap[i])
+ SetState(ControlMap[i++]);
+ }
+ else // befindet sich in der Mitte
+ {
+ m_nCurrentPos = nCurrentPos;
+ SetState(NavigationBar::RECORD_COUNT);
+ SetState(NavigationBar::RECORD_ABSOLUTE);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::NavigationBar::GetState(sal_uInt16 nWhich) const
+{
+ DbGridControl* pParent = (DbGridControl*)GetParent();
+
+ if (!pParent->IsOpen() || pParent->IsDesignMode() || !pParent->IsEnabled()
+ || pParent->IsFilterMode() )
+ return sal_False;
+ else
+ {
+ // check if we have a master state provider
+ if (pParent->m_aMasterStateProvider.IsSet())
+ {
+ long nState = pParent->m_aMasterStateProvider.Call(reinterpret_cast< void* >( nWhich ) );
+ if (nState>=0)
+ return (nState>0);
+ }
+
+ sal_Bool bAvailable = sal_True;
+
+ switch (nWhich)
+ {
+ case NavigationBar::RECORD_FIRST:
+ case NavigationBar::RECORD_PREV:
+ bAvailable = m_nCurrentPos > 0;
+ break;
+ case NavigationBar::RECORD_NEXT:
+ if(pParent->m_bRecordCountFinal)
+ {
+ bAvailable = m_nCurrentPos < pParent->GetRowCount() - 1;
+ if (!bAvailable && pParent->GetOptions() & DbGridControl::OPT_INSERT)
+ bAvailable = (m_nCurrentPos == pParent->GetRowCount() - 2) && pParent->IsModified();
+ }
+ break;
+ case NavigationBar::RECORD_LAST:
+ if(pParent->m_bRecordCountFinal)
+ {
+ if (pParent->GetOptions() & DbGridControl::OPT_INSERT)
+ bAvailable = pParent->IsCurrentAppending() ? pParent->GetRowCount() > 1 :
+ m_nCurrentPos != pParent->GetRowCount() - 2;
+ else
+ bAvailable = m_nCurrentPos != pParent->GetRowCount() - 1;
+ }
+ break;
+ case NavigationBar::RECORD_NEW:
+ bAvailable = (pParent->GetOptions() & DbGridControl::OPT_INSERT) && pParent->GetRowCount() && m_nCurrentPos < pParent->GetRowCount() - 1;
+ break;
+ case NavigationBar::RECORD_ABSOLUTE:
+ bAvailable = pParent->GetRowCount() > 0;
+ break;
+ }
+ return bAvailable;
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::NavigationBar::SetState(sal_uInt16 nWhich)
+{
+ sal_Bool bAvailable = GetState(nWhich);
+ DbGridControl* pParent = (DbGridControl*)GetParent();
+ Window* pWnd = NULL;
+ switch (nWhich)
+ {
+ case NavigationBar::RECORD_FIRST:
+ pWnd = &m_aFirstBtn;
+ break;
+ case NavigationBar::RECORD_PREV:
+ pWnd = &m_aPrevBtn;
+ break;
+ case NavigationBar::RECORD_NEXT:
+ pWnd = &m_aNextBtn;
+ break;
+ case NavigationBar::RECORD_LAST:
+ pWnd = &m_aLastBtn;
+ break;
+ case NavigationBar::RECORD_NEW:
+ pWnd = &m_aNewBtn;
+ break;
+ case NavigationBar::RECORD_ABSOLUTE:
+ pWnd = &m_aAbsolute;
+ if (bAvailable)
+ {
+ if (pParent->m_nTotalCount >= 0)
+ {
+ if (pParent->IsCurrentAppending())
+ m_aAbsolute.SetMax(pParent->m_nTotalCount + 1);
+ else
+ m_aAbsolute.SetMax(pParent->m_nTotalCount);
+ }
+ else
+ m_aAbsolute.SetMax(LONG_MAX);
+
+ m_aAbsolute.SetValue(m_nCurrentPos + 1);
+ }
+ else
+ m_aAbsolute.SetText(String());
+ break;
+ case NavigationBar::RECORD_TEXT:
+ pWnd = &m_aRecordText;
+ break;
+ case NavigationBar::RECORD_OF:
+ pWnd = &m_aRecordOf;
+ break;
+ case NavigationBar::RECORD_COUNT:
+ {
+ pWnd = &m_aRecordCount;
+ String aText;
+ if (bAvailable)
+ {
+ if (pParent->GetOptions() & DbGridControl::OPT_INSERT)
+ {
+ if (pParent->IsCurrentAppending() && !pParent->IsModified())
+ aText = String::CreateFromInt32(pParent->GetRowCount());
+ else
+ aText = String::CreateFromInt32(pParent->GetRowCount() - 1);
+ }
+ else
+ aText = String::CreateFromInt32(pParent->GetRowCount());
+ if(!pParent->m_bRecordCountFinal)
+ aText += String::CreateFromAscii(" *");
+ }
+ else
+ aText = String();
+
+ // add the number of selected rows, if applicable
+ if (pParent->GetSelectRowCount())
+ {
+ String aExtendedInfo(aText);
+ aExtendedInfo.AppendAscii(" (");
+ aExtendedInfo += String::CreateFromInt32(pParent->GetSelectRowCount());
+ aExtendedInfo += ')';
+ pWnd->SetText(aExtendedInfo);
+ }
+ else
+ pWnd->SetText(aText);
+
+ pParent->SetRealRowCount(aText);
+ } break;
+ }
+ DBG_ASSERT(pWnd, "kein Fenster");
+ if (pWnd && (pWnd->IsEnabled() != bAvailable))
+ // this "pWnd->IsEnabled() != bAvailable" is a little hack : Window::Enable always generates a user
+ // event (ImplGenerateMouseMove) even if nothing happened. This may lead to some unwanted effects, so we
+ // do this check.
+ // For further explanation see Bug 69900.
+ // FS - 18.11.99
+ pWnd->Enable(bAvailable);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::NavigationBar::Resize()
+{
+ Control::Resize();
+ ArrangeControls();
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::NavigationBar::Paint(const Rectangle& rRect)
+{
+ Control::Paint(rRect);
+ Point aAbsolutePos = m_aAbsolute.GetPosPixel();
+ Size aAbsoluteSize = m_aAbsolute.GetSizePixel();
+
+ DrawLine(Point(aAbsolutePos.X() - 1, 0 ),
+ Point(aAbsolutePos.X() - 1, aAbsolutePos.Y() + aAbsoluteSize.Height()));
+
+ DrawLine(Point(aAbsolutePos.X() + aAbsoluteSize.Width() + 1, 0 ),
+ Point(aAbsolutePos.X() + aAbsoluteSize.Width() + 1, aAbsolutePos.Y() + aAbsoluteSize.Height()));
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::NavigationBar::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ Window* pWindows[] = { &m_aRecordText,
+ &m_aAbsolute,
+ &m_aRecordOf,
+ &m_aRecordCount,
+ &m_aFirstBtn,
+ &m_aPrevBtn,
+ &m_aNextBtn,
+ &m_aLastBtn,
+ &m_aNewBtn
+ };
+
+ switch ( nType )
+ {
+ case STATE_CHANGE_MIRRORING:
+ {
+ BOOL bIsRTLEnabled = IsRTLEnabled();
+ for ( size_t i=0; i < sizeof( pWindows ) / sizeof( pWindows[0] ); ++i )
+ pWindows[i]->EnableRTL( bIsRTLEnabled );
+ }
+ break;
+
+ case STATE_CHANGE_ZOOM:
+ {
+ Fraction aZoom = GetZoom();
+
+ // not all of these controls need to know the new zoom, but to be sure ...
+ Font aFont( GetSettings().GetStyleSettings().GetFieldFont() );
+ if ( IsControlFont() )
+ aFont.Merge( GetControlFont() );
+
+ for (size_t i=0; i < sizeof(pWindows)/sizeof(pWindows[0]); ++i)
+ {
+ pWindows[i]->SetZoom(aZoom);
+ pWindows[i]->SetZoomedPointFont(aFont);
+ }
+
+ SetZoomedPointFont( aFont );
+
+ // rearrange the controls
+ m_nDefaultWidth = ArrangeControls();
+ }
+ break;
+ }
+}
+
+//------------------------------------------------------------------------------
+DbGridRow::DbGridRow(CursorWrapper* pCur, sal_Bool bPaintCursor)
+ :m_bIsNew(sal_False)
+{
+
+ if (pCur && pCur->Is())
+ {
+ Reference< XIndexAccess > xColumns(pCur->getColumns(), UNO_QUERY);
+ DataColumn* pColumn;
+ for (sal_Int32 i = 0; i < xColumns->getCount(); ++i)
+ {
+ Reference< XPropertySet > xColSet;
+ ::cppu::extractInterface(xColSet, xColumns->getByIndex(i));
+ pColumn = new DataColumn(xColSet);
+ m_aVariants.Insert(pColumn, LIST_APPEND);
+ }
+
+ if (pCur->rowDeleted())
+ m_eStatus = GRS_DELETED;
+ else
+ {
+ if (bPaintCursor)
+ m_eStatus = (pCur->isAfterLast() || pCur->isBeforeFirst()) ? GRS_INVALID : GRS_CLEAN;
+ else
+ {
+ Reference< XPropertySet > xSet = pCur->getPropertySet();
+ if (xSet.is())
+ {
+ m_bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
+ if (!m_bIsNew && (pCur->isAfterLast() || pCur->isBeforeFirst()))
+ m_eStatus = GRS_INVALID;
+ else if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED)))
+ m_eStatus = GRS_MODIFIED;
+ else
+ m_eStatus = GRS_CLEAN;
+ }
+ else
+ m_eStatus = GRS_INVALID;
+ }
+ }
+ if (!m_bIsNew && IsValid())
+ m_aBookmark = pCur->getBookmark();
+ else
+ m_aBookmark = Any();
+ }
+ else
+ m_eStatus = GRS_INVALID;
+}
+
+//------------------------------------------------------------------------------
+DbGridRow::~DbGridRow()
+{
+ sal_uInt32 nCount = m_aVariants.Count();
+ for (sal_uInt32 i = 0; i < nCount; i++)
+ delete m_aVariants.GetObject(i);
+}
+
+//------------------------------------------------------------------------------
+void DbGridRow::SetState(CursorWrapper* pCur, sal_Bool bPaintCursor)
+{
+ if (pCur && pCur->Is())
+ {
+ if (pCur->rowDeleted())
+ {
+ m_eStatus = GRS_DELETED;
+ m_bIsNew = sal_False;
+ }
+ else
+ {
+ m_eStatus = GRS_CLEAN;
+ if (!bPaintCursor)
+ {
+ Reference< XPropertySet > xSet = pCur->getPropertySet();
+ DBG_ASSERT(xSet.is(), "DbGridRow::SetState : invalid cursor !");
+
+ if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED)))
+ m_eStatus = GRS_MODIFIED;
+ m_bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
+ }
+ else
+ m_bIsNew = sal_False;
+ }
+
+ try
+ {
+ if (!m_bIsNew && IsValid())
+ m_aBookmark = pCur->getBookmark();
+ else
+ m_aBookmark = Any();
+ }
+ catch(SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ m_aBookmark = Any();
+ m_eStatus = GRS_INVALID;
+ m_bIsNew = sal_False;
+ }
+ }
+ else
+ {
+ m_aBookmark = Any();
+ m_eStatus = GRS_INVALID;
+ m_bIsNew = sal_False;
+ }
+}
+
+DBG_NAME(DbGridControl);
+//------------------------------------------------------------------------------
+DbGridControl::DbGridControl(
+ Reference< XMultiServiceFactory > _rxFactory,
+ Window* pParent,
+ WinBits nBits)
+ :DbGridControl_Base(pParent, EBBF_NONE, nBits, DEFAULT_BROWSE_MODE )
+ ,m_xServiceFactory(_rxFactory)
+ ,m_aBar(this)
+ ,m_nAsynAdjustEvent(0)
+ ,m_pDataSourcePropMultiplexer(NULL)
+ ,m_pDataSourcePropListener(NULL)
+ ,m_pFieldListeners(NULL)
+ ,m_pCursorDisposeListener(NULL)
+ ,m_pGridListener(NULL)
+ ,m_pDataCursor(NULL)
+ ,m_pSeekCursor(NULL)
+ ,m_nSeekPos(-1)
+ ,m_nTotalCount(-1)
+ ,m_aNullDate(OTypeConversionClient().getStandardDate())
+ ,m_nMode(DEFAULT_BROWSE_MODE)
+ ,m_nCurrentPos(-1)
+ ,m_nDeleteEvent(0)
+ ,m_nOptions(OPT_READONLY)
+ ,m_nOptionMask(OPT_INSERT | OPT_UPDATE | OPT_DELETE)
+ ,m_nLastColId((USHORT)-1)
+ ,m_nLastRowId(-1)
+ ,m_bDesignMode(sal_False)
+ ,m_bRecordCountFinal(sal_False)
+ ,m_bMultiSelection(sal_True)
+ ,m_bNavigationBar(sal_True)
+ ,m_bSynchDisplay(sal_True)
+ ,m_bForceROController(sal_False)
+ ,m_bHandle(sal_True)
+ ,m_bFilterMode(sal_False)
+ ,m_bWantDestruction(sal_False)
+ ,m_bInAdjustDataSource(sal_False)
+ ,m_bPendingAdjustRows(sal_False)
+ ,m_bHideScrollbars( sal_False )
+ ,m_bUpdating(sal_False)
+{
+ DBG_CTOR(DbGridControl,NULL);
+
+ String sName(SVX_RES(RID_STR_NAVIGATIONBAR));
+ m_aBar.SetAccessibleName(sName);
+ m_aBar.Show();
+ ImplInitWindow( InitAll );
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::InsertHandleColumn()
+{
+ // Handle Column einfuegen
+ // Da die BrowseBox ohne handleColums Paintprobleme hat
+ // wird diese versteckt
+ if (HasHandle())
+ BrowseBox::InsertHandleColumn(GetDefaultColumnWidth(String()));
+ else
+ BrowseBox::InsertHandleColumn(0);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::Init()
+{
+ BrowserHeader* pNewHeader = CreateHeaderBar(this);
+ pHeader->SetMouseTransparent(sal_False);
+
+ SetHeaderBar(pNewHeader);
+ SetMode(m_nMode);
+ SetCursorColor(Color(0xFF, 0, 0));
+
+ InsertHandleColumn();
+}
+
+//------------------------------------------------------------------------------
+DbGridControl::~DbGridControl()
+{
+ RemoveColumns();
+
+ {
+ m_bWantDestruction = sal_True;
+ osl::MutexGuard aGuard(m_aDestructionSafety);
+ if (m_pFieldListeners)
+ DisconnectFromFields();
+ if (m_pCursorDisposeListener)
+ {
+ delete m_pCursorDisposeListener;
+ m_pCursorDisposeListener = NULL;
+ }
+ }
+
+ if (m_nDeleteEvent)
+ Application::RemoveUserEvent(m_nDeleteEvent);
+
+ if (m_pDataSourcePropMultiplexer)
+ {
+ m_pDataSourcePropMultiplexer->dispose();
+ m_pDataSourcePropMultiplexer->release(); // this should delete the multiplexer
+ delete m_pDataSourcePropListener;
+ m_pDataSourcePropMultiplexer = NULL;
+ m_pDataSourcePropListener = NULL;
+ }
+ m_xRowSetListener.clear();
+
+ delete m_pDataCursor;
+ delete m_pSeekCursor;
+
+ DBG_DTOR(DbGridControl,NULL);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::StateChanged( StateChangedType nType )
+{
+ DbGridControl_Base::StateChanged( nType );
+
+ switch (nType)
+ {
+ case STATE_CHANGE_MIRRORING:
+ ImplInitWindow( InitWritingMode );
+ Invalidate();
+ break;
+
+ case STATE_CHANGE_ZOOM:
+ {
+ ImplInitWindow( InitFont );
+
+ // and give it a chance to rearrange
+ Point aPoint = GetControlArea().TopLeft();
+ sal_uInt16 nX = (sal_uInt16)aPoint.X();
+ ArrangeControls(nX, (sal_uInt16)aPoint.Y());
+ ReserveControlArea((sal_uInt16)nX);
+ }
+ break;
+ case STATE_CHANGE_CONTROLFONT:
+ ImplInitWindow( InitFont );
+ Invalidate();
+ break;
+ case STATE_CHANGE_CONTROLFOREGROUND:
+ ImplInitWindow( InitForeground );
+ Invalidate();
+ break;
+ case STATE_CHANGE_CONTROLBACKGROUND:
+ ImplInitWindow( InitBackground );
+ Invalidate();
+ break;
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ DbGridControl_Base::DataChanged( rDCEvt );
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS ) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitWindow( InitAll );
+ Invalidate();
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::Select()
+{
+ DbGridControl_Base::Select();
+
+ // as the selected rows may have changed, udate the according display in our navigation bar
+ m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
+
+ if (m_pGridListener)
+ m_pGridListener->selectionChanged();
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::ImplInitWindow( const InitWindowFacet _eInitWhat )
+{
+ for ( sal_uInt32 i = 0; i < m_aColumns.Count(); ++i )
+ {
+ DbGridColumn* pCol = m_aColumns.GetObject(i);
+ if (pCol)
+ pCol->ImplInitWindow( GetDataWindow(), _eInitWhat );
+ }
+
+ if ( ( _eInitWhat & InitWritingMode ) != 0 )
+ {
+ if ( m_bNavigationBar )
+ {
+ m_aBar.EnableRTL( IsRTLEnabled() );
+ }
+ }
+
+ if ( ( _eInitWhat & InitFont ) != 0 )
+ {
+ if ( m_bNavigationBar )
+ {
+ Font aFont = m_aBar.GetSettings().GetStyleSettings().GetFieldFont();
+ if ( IsControlFont() )
+ m_aBar.SetControlFont( GetControlFont() );
+ else
+ m_aBar.SetControlFont();
+
+ m_aBar.SetZoom( GetZoom() );
+ }
+ }
+
+ if ( ( _eInitWhat & InitBackground ) != 0 )
+ {
+ if (IsControlBackground())
+ {
+ GetDataWindow().SetBackground(GetControlBackground());
+ GetDataWindow().SetControlBackground(GetControlBackground());
+ GetDataWindow().SetFillColor(GetControlBackground());
+ }
+ else
+ {
+ GetDataWindow().SetControlBackground();
+ GetDataWindow().SetFillColor(GetFillColor());
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::RemoveRows(sal_Bool bNewCursor)
+{
+ // Hat sich der DatenCursor verandert ?
+ if (!bNewCursor)
+ {
+ DELETEZ(m_pSeekCursor);
+ m_xPaintRow = m_xDataRow = m_xEmptyRow = m_xCurrentRow = m_xSeekRow = NULL;
+ m_nCurrentPos = m_nSeekPos = -1;
+ m_nOptions = OPT_READONLY;
+
+ RowRemoved(0, GetRowCount(), sal_False);
+ m_nTotalCount = -1;
+ }
+ else
+ {
+ RemoveRows();
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::RemoveRows()
+{
+ // we're going to remove all columns and all row, so deactivate the current cell
+ if (IsEditing())
+ DeactivateCell();
+
+ // alle Columns deinitialisieren
+ // existieren Spalten, dann alle Controller freigeben
+ for (sal_uInt32 i = 0; i < m_aColumns.Count(); i++)
+ m_aColumns.GetObject(i)->Clear();
+
+ DELETEZ(m_pSeekCursor);
+ DELETEZ(m_pDataCursor);
+
+ m_xPaintRow = m_xDataRow = m_xEmptyRow = m_xCurrentRow = m_xSeekRow = NULL;
+ m_nCurrentPos = m_nSeekPos = m_nTotalCount = -1;
+ m_nOptions = OPT_READONLY;
+
+ // Anzahl Saetze im Browser auf 0 zuruecksetzen
+ DbGridControl_Base::RemoveRows();
+ m_aBar.InvalidateAll(m_nCurrentPos, sal_True);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::ArrangeControls(sal_uInt16& nX, sal_uInt16 nY)
+{
+ // Positionierung der Controls
+ if (m_bNavigationBar)
+ {
+ nX = m_aBar.GetDefaultWidth();
+ Rectangle aRect(GetControlArea());
+ m_aBar.SetPosSizePixel(Point(0,nY + 1), Size(nX, aRect.GetSize().Height() - 1));
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::EnableHandle(sal_Bool bEnable)
+{
+ if (m_bHandle == bEnable)
+ return;
+
+ // HandleColumn wird nur ausgeblendet,
+ // da es sonst etliche Probleme mit dem Zeichnen gibt
+ RemoveColumn(0);
+ m_bHandle = bEnable;
+ InsertHandleColumn();
+}
+
+//------------------------------------------------------------------------------
+namespace
+{
+ bool adjustModeForScrollbars( BrowserMode& _rMode, sal_Bool _bNavigationBar, sal_Bool _bHideScrollbars )
+ {
+ BrowserMode nOldMode = _rMode;
+
+ if ( !_bNavigationBar )
+ {
+ _rMode &= ~BROWSER_AUTO_HSCROLL;
+ }
+
+ if ( _bHideScrollbars )
+ {
+ _rMode |= ( BROWSER_NO_HSCROLL | BROWSER_NO_VSCROLL );
+ _rMode &= ~( BROWSER_AUTO_HSCROLL | BROWSER_AUTO_VSCROLL );
+ }
+ else
+ {
+ _rMode |= ( BROWSER_AUTO_HSCROLL | BROWSER_AUTO_VSCROLL );
+ _rMode &= ~( BROWSER_NO_HSCROLL | BROWSER_NO_VSCROLL );
+ }
+
+ // note: if we have a navigation bar, we always have a AUTO_HSCROLL. In particular,
+ // _bHideScrollbars is ignored then
+ if ( _bNavigationBar )
+ {
+ _rMode |= BROWSER_AUTO_HSCROLL;
+ _rMode &= ~BROWSER_NO_HSCROLL;
+ }
+
+ return nOldMode != _rMode;
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::EnableNavigationBar(sal_Bool bEnable)
+{
+ if (m_bNavigationBar == bEnable)
+ return;
+
+ m_bNavigationBar = bEnable;
+
+ if (bEnable)
+ {
+ m_aBar.Show();
+ m_aBar.Enable();
+ m_aBar.InvalidateAll(m_nCurrentPos, sal_True);
+
+ if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
+ SetMode( m_nMode );
+
+ // liefert die Groe�e der Reserved ControlArea
+ Point aPoint = GetControlArea().TopLeft();
+ sal_uInt16 nX = (sal_uInt16)aPoint.X();
+
+ ArrangeControls(nX, (sal_uInt16)aPoint.Y());
+ ReserveControlArea((sal_uInt16)nX);
+ }
+ else
+ {
+ m_aBar.Hide();
+ m_aBar.Disable();
+
+ if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
+ SetMode( m_nMode );
+
+ ReserveControlArea();
+ }
+}
+
+//------------------------------------------------------------------------------
+sal_uInt16 DbGridControl::SetOptions(sal_uInt16 nOpt)
+{
+ DBG_ASSERT(!m_xCurrentRow || !m_xCurrentRow->IsModified(),
+ "DbGridControl::SetOptions : please do not call when editing a record (things are much easier this way ;) !");
+
+ // for the next setDataSource (which is triggered by a refresh, for instance)
+ m_nOptionMask = nOpt;
+
+ // normalize the new options
+ Reference< XPropertySet > xDataSourceSet = m_pDataCursor->getPropertySet();
+ if (xDataSourceSet.is())
+ {
+ // feststellen welche Updatem�glichkeiten bestehen
+ sal_Int32 nPrivileges = 0;
+ xDataSourceSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
+ if ((nPrivileges & Privilege::INSERT) == 0)
+ nOpt &= ~OPT_INSERT;
+ if ((nPrivileges & Privilege::UPDATE) == 0)
+ nOpt &= ~OPT_UPDATE;
+ if ((nPrivileges & Privilege::DELETE) == 0)
+ nOpt &= ~OPT_DELETE;
+ }
+ else
+ nOpt = OPT_READONLY;
+
+ // need to do something after that ?
+ if (nOpt == m_nOptions)
+ return m_nOptions;
+
+ // the 'update' option only affects our BrowserMode (with or w/o focus rect)
+ BrowserMode nNewMode = m_nMode;
+ if ((m_nMode & BROWSER_CURSOR_WO_FOCUS) == 0)
+ {
+ if (nOpt & OPT_UPDATE)
+ nNewMode |= BROWSER_HIDECURSOR;
+ else
+ nNewMode &= ~BROWSER_HIDECURSOR;
+ }
+ else
+ nNewMode &= ~BROWSER_HIDECURSOR;
+ // should not be neccessary if EnablePermanentCursor is used to change the cursor behaviour, but to be sure ...
+
+ if (nNewMode != m_nMode)
+ {
+ SetMode(nNewMode);
+ m_nMode = nNewMode;
+ }
+
+ // _after_ setting the mode because this results in an ActivateCell
+ DeactivateCell();
+
+ sal_Bool bInsertChanged = (nOpt & OPT_INSERT) != (m_nOptions & OPT_INSERT);
+ m_nOptions = nOpt;
+ // we need to set this before the code below because it indirectly uses m_nOptions
+
+ // the 'insert' option affects our empty row
+ if (bInsertChanged)
+ {
+ if (m_nOptions & OPT_INSERT)
+ { // the insert option is to be set
+ m_xEmptyRow = new DbGridRow();
+ RowInserted(GetRowCount(), 1, sal_True);
+ }
+ else
+ { // the insert option is to be reset
+ m_xEmptyRow = NULL;
+ if ((GetCurRow() == GetRowCount() - 1) && (GetCurRow() > 0))
+ GoToRowColumnId(GetCurRow() - 1, GetCurColumnId());
+ RowRemoved(GetRowCount(), 1, sal_True);
+ }
+ }
+
+ // the 'delete' options has no immediate consequences
+
+ ActivateCell();
+ Invalidate();
+ return m_nOptions;
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::ForceHideScrollbars( sal_Bool _bForce )
+{
+ if ( m_bHideScrollbars == _bForce )
+ return;
+
+ m_bHideScrollbars = _bForce;
+
+ if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
+ SetMode( m_nMode );
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::IsForceHideScrollbars() const
+{
+ return m_bHideScrollbars;
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::EnablePermanentCursor(sal_Bool bEnable)
+{
+ if (IsPermanentCursorEnabled() == bEnable)
+ return;
+
+ if (bEnable)
+ {
+ m_nMode &= ~BROWSER_HIDECURSOR; // without this BROWSER_CURSOR_WO_FOCUS won't have any affect
+ m_nMode |= BROWSER_CURSOR_WO_FOCUS;
+ }
+ else
+ {
+ if (m_nOptions & OPT_UPDATE)
+ m_nMode |= BROWSER_HIDECURSOR; // no cursor at all
+ else
+ m_nMode &= ~BROWSER_HIDECURSOR; // at least the "non-permanent" cursor
+
+ m_nMode &= ~BROWSER_CURSOR_WO_FOCUS;
+ }
+ SetMode(m_nMode);
+
+ sal_Bool bWasEditing = IsEditing();
+ DeactivateCell();
+ if (bWasEditing)
+ ActivateCell();
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::IsPermanentCursorEnabled() const
+{
+ return ((m_nMode & BROWSER_CURSOR_WO_FOCUS) != 0) && ((m_nMode & BROWSER_HIDECURSOR) == 0);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::refreshController(sal_uInt16 _nColId, GrantControlAccess /*_aAccess*/)
+{
+ if ((GetCurColumnId() == _nColId) && IsEditing())
+ { // the controller which is currently active needs to be refreshed
+ DeactivateCell();
+ ActivateCell();
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::SetMultiSelection(sal_Bool bMulti)
+{
+ m_bMultiSelection = bMulti;
+ if (m_bMultiSelection)
+ m_nMode |= BROWSER_MULTISELECTION;
+ else
+ m_nMode &= ~BROWSER_MULTISELECTION;
+
+ SetMode(m_nMode);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::setDataSource(const Reference< XRowSet >& _xCursor, sal_uInt16 nOpts)
+{
+ if (!_xCursor.is() && !m_pDataCursor)
+ return;
+
+ if (m_pDataSourcePropMultiplexer)
+ {
+ m_pDataSourcePropMultiplexer->dispose();
+ m_pDataSourcePropMultiplexer->release(); // this should delete the multiplexer
+ delete m_pDataSourcePropListener;
+ m_pDataSourcePropMultiplexer = NULL;
+ m_pDataSourcePropListener = NULL;
+ }
+ m_xRowSetListener.clear();
+
+ // is the new cursor valid ?
+ // the cursor is only valid if it contains some columns
+ // if there is no cursor or the cursor is not valid we have to clean up an leave
+ if (!_xCursor.is() || !Reference< XColumnsSupplier > (_xCursor, UNO_QUERY)->getColumns()->hasElements())
+ {
+ RemoveRows();
+ return;
+ }
+
+ // Hat sich der DatenCursor verandert ?
+ sal_uInt16 nCurPos = GetColumnPos(GetCurColumnId());
+
+ SetUpdateMode(sal_False);
+ RemoveRows();
+ DisconnectFromFields();
+
+ DELETEZ(m_pCursorDisposeListener);
+
+ {
+ ::osl::MutexGuard aGuard(m_aAdjustSafety);
+ if (m_nAsynAdjustEvent)
+ {
+ // the adjust was thought to work with the old cursor which we don't have anymore
+ RemoveUserEvent(m_nAsynAdjustEvent);
+ m_nAsynAdjustEvent = 0;
+ }
+ }
+
+ // get a new formatter and data cursor
+ m_xFormatter = NULL;
+ OStaticDataAccessTools aStaticTools;
+ Reference< ::com::sun::star::util::XNumberFormatsSupplier > xSupplier = aStaticTools.getNumberFormats(aStaticTools.getRowSetConnection(_xCursor), sal_True);
+ if (xSupplier.is() && m_xServiceFactory.is())
+ {
+ m_xFormatter = Reference< ::com::sun::star::util::XNumberFormatter >(
+ m_xServiceFactory->createInstance(FM_NUMBER_FORMATTER),
+ UNO_QUERY);
+ if (m_xFormatter.is())
+ {
+ m_xFormatter->attachNumberFormatsSupplier(xSupplier);
+
+ // retrieve the datebase of the Numberformatter
+ try
+ {
+ xSupplier->getNumberFormatSettings()->getPropertyValue(rtl::OUString::createFromAscii("NullDate")) >>= m_aNullDate;
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ }
+
+ m_pDataCursor = new CursorWrapper(_xCursor);
+
+ // now create a cursor for painting rows
+ // we need that cursor only if we are not in insert only mode
+ Reference< XResultSet > xClone;
+ Reference< XResultSetAccess > xAccess( _xCursor, UNO_QUERY );
+ try
+ {
+ xClone = xAccess.is() ? xAccess->createResultSet() : Reference< XResultSet > ();
+ }
+ catch(Exception&)
+ {
+ }
+ if (xClone.is())
+ m_pSeekCursor = new CursorWrapper(xClone);
+
+ // property listening on the data source
+ // (Normally one class would be sufficient : the multiplexer which could forward the property change to us.
+ // But for that we would have been derived from ::comphelper::OPropertyChangeListener, which isn't exported.
+ // So we introduce a second class, which is a ::comphelper::OPropertyChangeListener (in the implementation file we know this class)
+ // and forwards the property changes to a our special method "DataSourcePropertyChanged".)
+ if (m_pDataCursor)
+ {
+ m_pDataSourcePropListener = new FmXGridSourcePropListener(this);
+ m_pDataSourcePropMultiplexer = new ::comphelper::OPropertyChangeMultiplexer(m_pDataSourcePropListener, m_pDataCursor->getPropertySet() );
+ m_pDataSourcePropMultiplexer->acquire();
+ m_pDataSourcePropMultiplexer->addProperty(FM_PROP_ISMODIFIED);
+ m_pDataSourcePropMultiplexer->addProperty(FM_PROP_ISNEW);
+ }
+
+ BrowserMode nOldMode = m_nMode;
+ if (m_pSeekCursor)
+ {
+ try
+ {
+ Reference< XPropertySet > xSet(_xCursor, UNO_QUERY);
+ if (xSet.is())
+ {
+ // feststellen welche Updatemoeglichkeiten bestehen
+ sal_Int32 nConcurrency = ResultSetConcurrency::READ_ONLY;
+ xSet->getPropertyValue(FM_PROP_RESULTSET_CONCURRENCY) >>= nConcurrency;
+
+ if ( ResultSetConcurrency::UPDATABLE == nConcurrency )
+ {
+ sal_Int32 nPrivileges = 0;
+ xSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
+
+ // Insert Option should be set if insert only otherwise you won't see any rows
+ // and no insertion is possible
+ if ((m_nOptionMask & OPT_INSERT) && ((nPrivileges & Privilege::INSERT) == Privilege::INSERT) && (nOpts & OPT_INSERT))
+ m_nOptions |= OPT_INSERT;
+ if ((m_nOptionMask & OPT_UPDATE) && ((nPrivileges & Privilege::UPDATE) == Privilege::UPDATE) && (nOpts & OPT_UPDATE))
+ m_nOptions |= OPT_UPDATE;
+ if ((m_nOptionMask & OPT_DELETE) && ((nPrivileges & Privilege::DELETE) == Privilege::DELETE) && (nOpts & OPT_DELETE))
+ m_nOptions |= OPT_DELETE;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ }
+
+ sal_Bool bPermanentCursor = IsPermanentCursorEnabled();
+ m_nMode = DEFAULT_BROWSE_MODE;
+
+ if ( bPermanentCursor )
+ {
+ m_nMode |= BROWSER_CURSOR_WO_FOCUS;
+ m_nMode &= ~BROWSER_HIDECURSOR;
+ }
+ else
+ {
+ // Duerfen Updates gemacht werden, kein Focus-RechtEck
+ if ( m_nOptions & OPT_UPDATE )
+ m_nMode |= BROWSER_HIDECURSOR;
+ }
+
+ if ( m_bMultiSelection )
+ m_nMode |= BROWSER_MULTISELECTION;
+ else
+ m_nMode &= ~BROWSER_MULTISELECTION;
+
+ adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars );
+
+ Reference< XColumnsSupplier > xSupplyColumns(_xCursor, UNO_QUERY);
+ if (xSupplyColumns.is())
+ InitColumnsByFields(Reference< XIndexAccess > (xSupplyColumns->getColumns(), UNO_QUERY));
+
+ ConnectToFields();
+ }
+
+ sal_uInt32 nRecordCount(0);
+
+ if (m_pSeekCursor)
+ {
+ Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
+ xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
+ m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
+
+ m_xRowSetListener = new RowSetEventListener(this);
+ Reference< XRowsChangeBroadcaster> xChangeBroad(xSet,UNO_QUERY);
+ if ( xChangeBroad.is( ) )
+ xChangeBroad->addRowsChangeListener(m_xRowSetListener);
+
+
+ // insert the currently known rows
+ // and one row if we are able to insert rows
+ if (m_nOptions & OPT_INSERT)
+ {
+ // insert the empty row for insertion
+ m_xEmptyRow = new DbGridRow();
+ ++nRecordCount;
+ }
+ if (nRecordCount)
+ {
+ m_xPaintRow = m_xSeekRow = new DbGridRow(m_pSeekCursor, sal_True);
+ m_xDataRow = new DbGridRow(m_pDataCursor, sal_False);
+ RowInserted(0, nRecordCount, sal_False);
+
+ if (m_xSeekRow->IsValid())
+ try
+ {
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ m_nSeekPos = -1;
+ }
+ }
+ else
+ {
+ // no rows so we don't need a seekcursor
+ DELETEZ(m_pSeekCursor);
+ }
+ }
+
+ // Zur alten Spalte gehen
+ if (!nCurPos || nCurPos >= ColCount())
+ nCurPos = 1;
+
+ // there are rows so go to the selected current column
+ if (nRecordCount)
+ GoToRowColumnId(0, GetColumnId(nCurPos));
+ // else stop the editing if neccessary
+ else if (IsEditing())
+ DeactivateCell();
+
+ // now reset the mode
+ if (m_nMode != nOldMode)
+ SetMode(m_nMode);
+
+ // beim Resizen wird RecalcRows gerufen
+ if (!IsResizing() && GetRowCount())
+ RecalcRows(GetTopRow(), GetVisibleRows(), sal_True);
+
+ m_aBar.InvalidateAll(m_nCurrentPos, sal_True);
+ SetUpdateMode(sal_True);
+
+ // start listening on the seek cursor
+ if (m_pSeekCursor)
+ m_pCursorDisposeListener = new DisposeListenerGridBridge(*this, Reference< XComponent > ((Reference< XInterface >)*m_pSeekCursor, UNO_QUERY), 0);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::RemoveColumns()
+{
+ if ( IsEditing() )
+ DeactivateCell();
+
+ for (sal_uInt32 i = 0; i < m_aColumns.Count(); i++)
+ delete m_aColumns.GetObject(i);
+ m_aColumns.Clear();
+
+ DbGridControl_Base::RemoveColumns();
+}
+
+//------------------------------------------------------------------------------
+DbGridColumn* DbGridControl::CreateColumn(sal_uInt16 nId) const
+{
+ return new DbGridColumn(nId, *(DbGridControl*)this);
+}
+
+//------------------------------------------------------------------------------
+sal_uInt16 DbGridControl::AppendColumn(const XubString& rName, sal_uInt16 nWidth, sal_uInt16 nModelPos, sal_uInt16 nId)
+{
+ DBG_ASSERT(nId == (sal_uInt16)-1, "DbGridControl::AppendColumn : I want to set the ID myself ...");
+ sal_uInt16 nRealPos = nModelPos;
+ if (nModelPos != HEADERBAR_APPEND)
+ {
+ // calc the view pos. we can't use our converting functions because the new column
+ // has no VCL-representation, yet.
+ sal_Int16 nViewPos = nModelPos;
+ while (nModelPos--)
+ {
+ if (m_aColumns.GetObject(nModelPos)->IsHidden())
+ --nViewPos;
+ }
+ // restore nModelPos, we need it later
+ nModelPos = nRealPos;
+ // the position the base class gets is the view pos + 1 (because of the handle column)
+ nRealPos = nViewPos + 1;
+ }
+
+ // calculate the new id
+ for (nId=1; (GetModelColumnPos(nId) != GRID_COLUMN_NOT_FOUND) && (nId<=m_aColumns.Count()); ++nId)
+ ;
+ DBG_ASSERT(GetViewColumnPos(nId) == (sal_uInt16)-1, "DbGridControl::AppendColumn : inconsistent internal state !");
+ // my column's models say "there is no column with id nId", but the view (the base class) says "there is a column ..."
+
+ DbGridControl_Base::AppendColumn(rName, nWidth, nRealPos, nId);
+ if (nModelPos == HEADERBAR_APPEND)
+ m_aColumns.Insert(CreateColumn(nId), LIST_APPEND);
+ else
+ m_aColumns.Insert(CreateColumn(nId), nModelPos);
+
+ return nId;
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::RemoveColumn(sal_uInt16 nId)
+{
+ sal_Int16 nIndex = GetModelColumnPos(nId);
+ DbGridControl_Base::RemoveColumn(nId);
+ delete m_aColumns.Remove(nIndex);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::ColumnMoved(sal_uInt16 nId)
+{
+ DbGridControl_Base::ColumnMoved(nId);
+
+ // remove the col from the model
+ sal_Int16 nOldModelPos = GetModelColumnPos(nId);
+#ifdef DBG_UTIL
+ DbGridColumn* pCol = m_aColumns.GetObject((sal_uInt32)nOldModelPos);
+ DBG_ASSERT(!pCol->IsHidden(), "DbGridControl::ColumnMoved : moved a hidden col ? how this ?");
+#endif
+
+ // for the new model pos we can't use GetModelColumnPos because we are altering the model at the moment
+ // so the method won't work (in fact it would return the old model pos)
+
+ // the new view pos is calculated easily
+ sal_uInt16 nNewViewPos = GetViewColumnPos(nId);
+
+ // from that we can compute the new model pos
+ sal_uInt16 nNewModelPos;
+ for (nNewModelPos = 0; nNewModelPos < m_aColumns.Count(); ++nNewModelPos)
+ {
+ if (!m_aColumns.GetObject(nNewModelPos)->IsHidden())
+ {
+ if (!nNewViewPos)
+ break;
+ else
+ --nNewViewPos;
+ }
+ }
+ DBG_ASSERT(nNewModelPos<m_aColumns.Count(), "DbGridControl::ColumnMoved : could not find the new model position !");
+
+ // this will work. of course the model isn't fully consistent with our view right now, but let's
+ // look at the situation : a column has been moved with in the VIEW from pos m to n, say m<n (in the
+ // other case we can use analogue arguments).
+ // All cols k with m<k<=n have been shifted left on pos, the former col m now has pos n.
+ // In the model this affects a range of cols x to y, where x<=m and y<=n. And the number of hidden cols
+ // within this range is constant, so we may calculate the view pos from the model pos in the above way.
+ //
+ // for instance, let's look at a grid with six columns where the third one is hidden. this will
+ // initially look like this :
+ //
+ // +---+---+---+---+---+---+
+ // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
+ // +---+---+---+---+---+---+
+ // ID | 1 | 2 | 3 | 4 | 5 | 6 |
+ // +---+---+---+---+---+---+
+ // view pos | 0 | 1 | - | 2 | 3 | 4 |
+ // +---+---+---+---+---+---+
+ //
+ // if we move the column at (view) pos 1 to (view) pos 3 we have :
+ //
+ // +---+---+---+---+---+---+
+ // model pos | 0 | 3 |*2*| 4 | 1 | 5 | // not reflecting the changes, yet
+ // +---+---+---+---+---+---+
+ // ID | 1 | 4 | 3 | 5 | 2 | 6 | // already reflecting the changes
+ // +---+---+---+---+---+---+
+ // view pos | 0 | 1 | - | 2 | 3 | 4 |
+ // +---+---+---+---+---+---+
+ //
+ // or, sorted by the out-of-date model positions :
+ //
+ // +---+---+---+---+---+---+
+ // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
+ // +---+---+---+---+---+---+
+ // ID | 1 | 2 | 3 | 4 | 5 | 6 |
+ // +---+---+---+---+---+---+
+ // view pos | 0 | 3 | - | 1 | 2 | 4 |
+ // +---+---+---+---+---+---+
+ //
+ // We know the new view pos (3) of the moved column because our base class tells us. So we look at our
+ // model for the 4th (the pos is zero-based) visible column, it is at (model) position 4. And this is
+ // exactly the pos where we have to re-insert our column's model, so it looks ike this :
+ //
+ // +---+---+---+---+---+---+
+ // model pos | 0 |*1*| 2 | 3 | 4 | 5 |
+ // +---+---+---+---+---+---+
+ // ID | 1 | 3 | 4 | 5 | 2 | 6 |
+ // +---+---+---+---+---+---+
+ // view pos | 0 | - | 1 | 2 | 3 | 4 |
+ // +---+---+---+---+---+---+
+ //
+ // Now, all is consistent again.
+ // (except of the hidden column : The cycling of the cols occured on the model, not on the view. maybe
+ // the user expected the latter but there really is no good argument against our method ;) ...)
+ //
+ // And no, this large explanation isn't just because I wanted to play a board game or something like
+ // that. It's because it took me a while to see it myself, and the whole theme (hidden cols, model col
+ // positions, view col positions) is really painful (at least for me) so the above pictures helped me a lot ;)
+
+ m_aColumns.Insert(m_aColumns.Remove((sal_uInt32)nOldModelPos), nNewModelPos);
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::SeekRow(long nRow)
+{
+ // in filter mode or in insert only mode we don't have any cursor!
+ if ( !SeekCursor( nRow ) )
+ return sal_False;
+
+ if ( IsFilterMode() )
+ {
+ DBG_ASSERT( IsFilterRow( nRow ), "DbGridControl::SeekRow(): No filter row, wrong mode" );
+ m_xPaintRow = m_xEmptyRow;
+ }
+ else
+ {
+ // on the current position we have to take the current row for display as we want
+ // to have the most recent values for display
+ if ( ( nRow == m_nCurrentPos ) && getDisplaySynchron() )
+ m_xPaintRow = m_xCurrentRow;
+ // seek to the empty insert row
+ else if ( IsInsertionRow( nRow ) )
+ m_xPaintRow = m_xEmptyRow;
+ else
+ {
+ m_xSeekRow->SetState( m_pSeekCursor, sal_True );
+ m_xPaintRow = m_xSeekRow;
+ }
+ }
+
+ DbGridControl_Base::SeekRow(nRow);
+
+ return m_nSeekPos >= 0;
+}
+//------------------------------------------------------------------------------
+// Wird aufgerufen, wenn die dargestellte Datenmenge sich aendert
+//------------------------------------------------------------------------------
+void DbGridControl::VisibleRowsChanged( long nNewTopRow, sal_uInt16 nLinesOnScreen )
+{
+ RecalcRows(nNewTopRow, nLinesOnScreen , sal_False);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::RecalcRows(long nNewTopRow, sal_uInt16 nLinesOnScreen, sal_Bool bUpdateCursor)
+{
+ DBG_CHKTHIS( DbGridControl, NULL );
+ // Wenn kein Cursor -> keine Rows im Browser.
+ if (!m_pSeekCursor)
+ {
+ DBG_ASSERT(GetRowCount() == 0,"DbGridControl: ohne Cursor darf es keine Rows geben");
+ return;
+ }
+
+ // ignore any updates implicit made
+ sal_Bool bDisablePaint = !bUpdateCursor && IsPaintEnabled();
+ if (bDisablePaint)
+ EnablePaint(sal_False);
+
+ // Cache an den sichtbaren Bereich anpassen
+ Reference< XPropertySet > xSet = m_pSeekCursor->getPropertySet();
+ sal_Int32 nCacheSize = 0;
+ xSet->getPropertyValue(FM_PROP_FETCHSIZE) >>= nCacheSize;
+ sal_Bool bCacheAligned = sal_False;
+ // Nach der Initialisierung (m_nSeekPos < 0) keine Cursorbewegung, da bereits auf den ersten
+ // Satz positioniert
+ long nDelta = nNewTopRow - GetTopRow();
+ // Limit fuer relative Positionierung
+ long nLimit = (nCacheSize) ? nCacheSize / 2 : 0;
+
+ // mehr Zeilen auf dem Bildschirm als im Cache
+ if (nLimit < nLinesOnScreen)
+ {
+ Any aCacheSize;
+ aCacheSize <<= sal_Int32(nLinesOnScreen*2);
+ xSet->setPropertyValue(FM_PROP_FETCHSIZE, aCacheSize);
+ // jetzt auf alle Faelle den Cursor anpassen
+ bUpdateCursor = sal_True;
+ bCacheAligned = sal_True;
+ nLimit = nLinesOnScreen;
+ }
+
+ // Im folgenden werden die Positionierungen so vorgenommen, da� sichergestellt ist
+ // da� ausreichend Zeilen im DatenCache vorhanden sind
+
+ // Fenster geht nach unten, weniger als zwei Fenster Differenz
+ // oder Cache angepasst und noch kein Rowcount
+ if (nDelta < nLimit && (nDelta > 0
+ || (bCacheAligned && m_nTotalCount < 0)) )
+ SeekCursor(nNewTopRow + nLinesOnScreen - 1, sal_False);
+ else if (nDelta < 0 && Abs(nDelta) < nLimit)
+ SeekCursor(nNewTopRow, sal_False);
+ else if (nDelta != 0 || bUpdateCursor)
+ SeekCursor(nNewTopRow, sal_True);
+
+ AdjustRows();
+
+ // ignore any updates implicit made
+ EnablePaint(sal_True);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::RowInserted(long nRow, long nNumRows, sal_Bool bDoPaint, sal_Bool bKeepSelection)
+{
+ if (nNumRows)
+ {
+ if (m_bRecordCountFinal && m_nTotalCount < 0)
+ {
+ // if we have an insert row we have to reduce to count by 1
+ // as the total count reflects only the existing rows in database
+ m_nTotalCount = GetRowCount() + nNumRows;
+ if (m_xEmptyRow.Is())
+ --m_nTotalCount;
+ }
+ else if (m_nTotalCount >= 0)
+ m_nTotalCount += nNumRows;
+
+ DbGridControl_Base::RowInserted(nRow, nNumRows, bDoPaint, bKeepSelection);
+ m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::RowRemoved(long nRow, long nNumRows, sal_Bool bDoPaint)
+{
+ if (nNumRows)
+ {
+ if (m_bRecordCountFinal && m_nTotalCount < 0)
+ {
+ m_nTotalCount = GetRowCount() - nNumRows;
+ // if we have an insert row reduce by 1
+ if (m_xEmptyRow.Is())
+ --m_nTotalCount;
+ }
+ else if (m_nTotalCount >= 0)
+ m_nTotalCount -= nNumRows;
+
+ DbGridControl_Base::RowRemoved(nRow, nNumRows, bDoPaint);
+ m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::AdjustRows()
+{
+ if (!m_pSeekCursor)
+ return;
+
+ Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
+
+ // Aktualisieren des RecordCounts
+ sal_Int32 nRecordCount = 0;
+ xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
+ if (!m_bRecordCountFinal)
+ m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
+
+ // hat sich die aktuelle Anzahl Rows veraendert
+ // hierbei muss auch beruecksichtigt werden,
+ // das eine zusaetzliche Zeile zum einfuegen von Datensaetzen vorhanden sein kann
+
+ // zusaetzliche AppendRow fuers einfuegen
+ if (m_nOptions & OPT_INSERT)
+ ++nRecordCount;
+
+ // wird gerade eingefuegt, dann gehoert die gerade hinzuzufuegende
+ // Zeile nicht zum RecordCount und die Appendrow ebenfalls nicht
+ if (!IsUpdating() && m_bRecordCountFinal && IsModified() && m_xCurrentRow != m_xEmptyRow &&
+ m_xCurrentRow->IsNew())
+ ++nRecordCount;
+ // das ist mit !m_bUpdating abgesichert : innerhalb von SaveRow (m_bUpdating == sal_True) wuerde sonst der Datensatz, den ich editiere
+ // (und den SaveRow gerade angefuegt hat, wodurch diese Methode hier getriggert wurde), doppelt zaehlen : einmal ist er schon
+ // in dem normalen RecordCount drin, zum zweiten wuerde er hier gezaehlt werden (60787 - FS)
+
+ if (nRecordCount != GetRowCount())
+ {
+ long nDelta = GetRowCount() - (long)nRecordCount;
+ if (nDelta > 0) // zuviele
+ {
+ RowRemoved(GetRowCount() - nDelta, nDelta, sal_False);
+ // es sind Zeilen weggefallen, dann ab der aktuellen Position neu zeichen
+ Invalidate();
+ }
+ else // zuwenig
+ RowInserted(GetRowCount(), -nDelta, sal_True);
+ }
+
+ if (m_bRecordCountFinal && m_nTotalCount < 0)
+ {
+ if (m_nOptions & OPT_INSERT)
+ m_nTotalCount = GetRowCount() - 1;
+ else
+ m_nTotalCount = GetRowCount();
+ }
+ m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
+}
+
+//------------------------------------------------------------------------------
+DbGridControl_Base::RowStatus DbGridControl::GetRowStatus(long nRow) const
+{
+ if (IsFilterRow(nRow))
+ return DbGridControl_Base::FILTER;
+ else if (m_nCurrentPos >= 0 && nRow == m_nCurrentPos)
+ {
+ // neue Zeile
+ if (!IsValid(m_xCurrentRow))
+ return DbGridControl_Base::DELETED;
+ else if (IsModified())
+ return DbGridControl_Base::MODIFIED;
+ else if (m_xCurrentRow->IsNew())
+ return DbGridControl_Base::CURRENTNEW;
+ else
+ return DbGridControl_Base::CURRENT;
+ }
+ else if (IsInsertionRow(nRow))
+ return DbGridControl_Base::NEW;
+ else if (!IsValid(m_xSeekRow))
+ return DbGridControl_Base::DELETED;
+ else
+ return DbGridControl_Base::CLEAN;
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::PaintStatusCell(OutputDevice& rDev, const Rectangle& rRect) const
+{
+ DbGridControl_Base::PaintStatusCell(rDev, rRect);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::PaintCell(OutputDevice& rDev, const Rectangle& rRect, sal_uInt16 nColumnId) const
+{
+ if (!IsValid(m_xPaintRow))
+ return;
+
+ DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColumnId));
+ if (pColumn)
+ {
+ Rectangle aArea(rRect);
+ if ((GetMode() & BROWSER_CURSOR_WO_FOCUS) == BROWSER_CURSOR_WO_FOCUS)
+ {
+ aArea.Top() += 1;
+ aArea.Bottom() -= 1;
+ }
+ pColumn->Paint(rDev, aArea, m_xPaintRow, getNumberFormatter());
+ }
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::CursorMoving(long nNewRow, sal_uInt16 nNewCol)
+{
+ DBG_CHKTHIS( DbGridControl, NULL );
+
+ DeactivateCell( sal_False );
+
+ if ( m_pDataCursor
+ && ( m_nCurrentPos != nNewRow )
+ && !SetCurrent( nNewRow )
+ )
+ {
+ ActivateCell();
+ return sal_False;
+ }
+
+ if ( !DbGridControl_Base::CursorMoving( nNewRow, nNewCol ) )
+ return sal_False;
+
+ return sal_True;
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::SetCurrent(long nNewRow)
+{
+ // Each movement of the datacursor must start with BeginCursorAction and end with
+ // EndCursorAction to block all notifications during the movement
+ BeginCursorAction();
+
+ try
+ {
+ // Abgleichen der Positionen
+ if (SeekCursor(nNewRow))
+ {
+ if (IsFilterRow(nNewRow)) // special mode for filtering
+ {
+ m_xCurrentRow = m_xDataRow = m_xPaintRow = m_xEmptyRow;
+ m_nCurrentPos = nNewRow;
+ }
+ else
+ {
+ sal_Bool bNewRowInserted = sal_False;
+ // Should we go to the insertrow ?
+ if (IsInsertionRow(nNewRow))
+ {
+ // to we need to move the cursor to the insert row?
+ // we need to insert the if the current row isn't the insert row or if the
+ // cursor triggered the move by itselt and we need a reinitialization of the row
+ Reference< XPropertySet > xCursorProps = m_pDataCursor->getPropertySet();
+ if ( !::comphelper::getBOOL(xCursorProps->getPropertyValue(FM_PROP_ISNEW)) )
+ {
+ Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
+ xUpdateCursor->moveToInsertRow();
+ }
+ bNewRowInserted = sal_True;
+ }
+ else
+ {
+
+ if ( !m_pSeekCursor->isBeforeFirst() && !m_pSeekCursor->isAfterLast() )
+ {
+ Any aBookmark = m_pSeekCursor->getBookmark();
+ if (!m_xCurrentRow || m_xCurrentRow->IsNew() || !CompareBookmark(aBookmark, m_pDataCursor->getBookmark()))
+ {
+ // adjust the cursor to the new desired row
+ if (!m_pDataCursor->moveToBookmark(aBookmark))
+ {
+ EndCursorAction();
+ return sal_False;
+ }
+ }
+ }
+ }
+ m_xDataRow->SetState(m_pDataCursor, sal_False);
+ m_xCurrentRow = m_xDataRow;
+
+ long nPaintPos = -1;
+ // do we have to repaint the last regular row in case of setting defaults or autovalues
+ if (m_nCurrentPos >= 0 && m_nCurrentPos >= (GetRowCount() - 2))
+ nPaintPos = m_nCurrentPos;
+
+ m_nCurrentPos = nNewRow;
+
+ // repaint the new row to display all defaults
+ if (bNewRowInserted)
+ RowModified(m_nCurrentPos);
+ if (nPaintPos >= 0)
+ RowModified(nPaintPos);
+ }
+ }
+ else
+ {
+ DBG_ERROR("DbGridControl::SetCurrent : SeekRow failed !");
+ EndCursorAction();
+ return sal_False;
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ EndCursorAction();
+ return sal_False;
+ }
+
+ EndCursorAction();
+ return sal_True;
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::CursorMoved()
+{
+ DBG_CHKTHIS( DbGridControl, NULL );
+
+ // CursorBewegung durch loeschen oder einfuegen von Zeilen
+ if (m_pDataCursor && m_nCurrentPos != GetCurRow())
+ {
+ DeactivateCell(sal_True);
+ SetCurrent(GetCurRow());
+ }
+
+ DbGridControl_Base::CursorMoved();
+ m_aBar.InvalidateAll(m_nCurrentPos);
+
+ // select the new column when they moved
+ if ( IsDesignMode() && GetSelectedColumnCount() > 0 && GetCurColumnId() )
+ {
+ SelectColumnId( GetCurColumnId() );
+ }
+
+ if ( m_nLastColId != GetCurColumnId() )
+ onColumnChange();
+ m_nLastColId = GetCurColumnId();
+
+ if ( m_nLastRowId != GetCurRow() )
+ onRowChange();
+ m_nLastRowId = GetCurRow();
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::onRowChange()
+{
+ // not interested in
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::onColumnChange()
+{
+ if ( m_pGridListener )
+ m_pGridListener->columnChanged();
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::setDisplaySynchron(sal_Bool bSync)
+{
+ if (bSync != m_bSynchDisplay)
+ {
+ m_bSynchDisplay = bSync;
+ if (m_bSynchDisplay)
+ AdjustDataSource(sal_False);
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::forceSyncDisplay()
+{
+ sal_Bool bOld = getDisplaySynchron();
+ setDisplaySynchron(sal_True);
+ if (!bOld)
+ setDisplaySynchron(bOld);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::forceROController(sal_Bool bForce)
+{
+ if (m_bForceROController == bForce)
+ return;
+
+ m_bForceROController = bForce;
+ // alle Columns durchgehen und denen Bescheid geben
+ for (sal_uInt16 i=0; i<m_aColumns.Count(); ++i)
+ {
+ DbGridColumn* pColumn = m_aColumns.GetObject(i);
+ if (!pColumn)
+ continue;
+
+ CellController* pReturn = &pColumn->GetController();
+ if (!pReturn)
+ continue;
+
+ // nur wenn es eine Edit-Zeile ist, kann ich ihr das forced read-only mitgeben
+ if (!pReturn->ISA(EditCellController) && !pReturn->ISA(SpinCellController))
+ continue;
+
+ Edit& rEdit = (Edit&)pReturn->GetWindow();
+ rEdit.SetReadOnly(m_bForceROController);
+ if (m_bForceROController)
+ rEdit.SetStyle(rEdit.GetStyle() | WB_NOHIDESELECTION);
+ else
+ rEdit.SetStyle(rEdit.GetStyle() & ~WB_NOHIDESELECTION);
+ }
+
+ // die aktive Zelle erneut aktivieren, da sich ihr Controller geaendert haben kann
+ if (IsEditing())
+ DeactivateCell();
+ ActivateCell();
+}
+
+
+//------------------------------------------------------------------------------
+void DbGridControl::AdjustDataSource(sal_Bool bFull)
+{
+ TRACE_RANGE("DbGridControl::AdjustDataSource");
+ ::vos::OGuard aGuard(Application::GetSolarMutex());
+ // wird die aktuelle Zeile gerade neu bestimmt,
+ // wird kein abgleich vorgenommen
+
+ if (bFull)
+ m_xCurrentRow = NULL;
+ // if we are on the same row only repaint
+ // but this is only possible for rows which are not inserted, in that case the comparision result
+ // may not be correct
+ else
+ if ( m_xCurrentRow.Is()
+ && !m_xCurrentRow->IsNew()
+ && !m_pDataCursor->isBeforeFirst()
+ && !m_pDataCursor->isAfterLast()
+ && !m_pDataCursor->rowDeleted()
+ )
+ {
+ sal_Bool bEqualBookmarks = CompareBookmark( m_xCurrentRow->GetBookmark(), m_pDataCursor->getBookmark() );
+
+ sal_Bool bDataCursorIsOnNew = sal_False;
+ m_pDataCursor->getPropertySet()->getPropertyValue( FM_PROP_ISNEW ) >>= bDataCursorIsOnNew;
+
+ if ( bEqualBookmarks && !bDataCursorIsOnNew )
+ {
+ // position of my data cursor is the same as the position our current row points tpo
+ // sync the status, repaint, done
+ DBG_ASSERT(m_xDataRow == m_xCurrentRow, "Fehler in den Datenzeilen");
+ TRACE_RANGE_MESSAGE1("same position, new state : %s", ROWSTATUS(m_xCurrentRow));
+ RowModified(m_nCurrentPos);
+ return;
+ }
+ }
+
+ // weg von der Row des DatenCursors
+ if (m_xPaintRow == m_xCurrentRow)
+ m_xPaintRow = m_xSeekRow;
+
+ // keine aktuelle Zeile dann komplett anpassen
+ if (!m_xCurrentRow)
+ AdjustRows();
+
+ sal_Int32 nNewPos = AlignSeekCursor();
+ if (nNewPos < 0) // keine Position gefunden
+ return;
+
+ m_bInAdjustDataSource = TRUE;
+ if (nNewPos != m_nCurrentPos)
+ {
+ if (m_bSynchDisplay)
+ DbGridControl_Base::GoToRow(nNewPos);
+
+ if (!m_xCurrentRow.Is())
+ // das tritt zum Beispiel auf, wenn man die n (n>1) letzten Datensaetze geloescht hat, waehrend der Cursor auf dem letzten
+ // steht : AdjustRows entfernt dann zwei Zeilen aus der BrowseBox, wodurch diese ihre CurrentRow um zwei nach unten
+ // korrigiert, so dass dann das GoToRow in's Leere laeuft (da wir uns ja angeblich schon an der richtigen Position
+ // befinden)
+ SetCurrent(nNewPos);
+ }
+ else
+ {
+ SetCurrent(nNewPos);
+ RowModified(nNewPos);
+ }
+ m_bInAdjustDataSource = FALSE;
+
+ // Wird der DatenCursor von aussen bewegt, wird die selektion aufgehoben
+ SetNoSelection();
+ m_aBar.InvalidateAll(m_nCurrentPos, m_xCurrentRow.Is());
+}
+
+//------------------------------------------------------------------------------
+sal_Int32 DbGridControl::AlignSeekCursor()
+{
+ DBG_CHKTHIS( DbGridControl, NULL );
+ // Positioniert den SeekCursor auf den DatenCursor, Daten werden nicht uebertragen
+
+ if (!m_pSeekCursor)
+ return -1;
+
+ Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
+
+ // jetzt den seekcursor an den DatenCursor angleichen
+ if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW)))
+ m_nSeekPos = GetRowCount() - 1;
+ else
+ {
+ try
+ {
+ if ( m_pDataCursor->isBeforeFirst() )
+ {
+ // this is somewhat strange, but can nevertheless happen
+ DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (before first)!" );
+ m_pSeekCursor->first();
+ m_pSeekCursor->previous();
+ m_nSeekPos = -1;
+ }
+ else if ( m_pDataCursor->isAfterLast() )
+ {
+ DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (after last)!" );
+ m_pSeekCursor->last();
+ m_pSeekCursor->next();
+ m_nSeekPos = -1;
+ }
+ else
+ {
+ m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
+ if (!CompareBookmark(m_pDataCursor->getBookmark(), m_pSeekCursor->getBookmark()))
+ // dummerweise kann das moveToBookmark indirekt dazu fuehren, dass der Seek-Cursor wieder neu positoniert wird (wenn
+ // naemlich das mit all seinen zu feuernden Events relativ komplexe moveToBookmark irgendwo ein Update ausloest),
+ // also muss ich es nochmal versuchen
+ m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
+ // Nicht dass das jetzt nicht auch schief gegangen sein koennte, aber es ist zumindest unwahrscheinlicher geworden.
+ // Und die Alternative waere eine Schleife so lange bis es stimmt, und das kann auch nicht die Loesung sein
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ }
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ return m_nSeekPos;
+}
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::SeekCursor(long nRow, sal_Bool bAbsolute)
+{
+ DBG_CHKTHIS( DbGridControl, NULL );
+ // Positioniert den SeekCursor, Daten werden nicht uebertragen
+
+ // additions for the filtermode
+ if (IsFilterRow(nRow))
+ {
+ m_nSeekPos = 0;
+ return sal_True;
+ }
+
+ if (!m_pSeekCursor)
+ return sal_False;
+
+ // Befinden wir uns gerade beim Einfuegen
+ if (IsValid(m_xCurrentRow) && m_xCurrentRow->IsNew() &&
+ nRow >= m_nCurrentPos)
+ {
+ // dann darf auf alle Faelle nicht weiter nach unten gescrollt werden
+ // da der letzte Datensatz bereits erreicht wurde!
+ if (nRow == m_nCurrentPos)
+ {
+ // auf die aktuelle Zeile bewegt, dann muß kein abgleich gemacht werden, wenn
+ // gerade ein Datensatz eingefuegt wird
+ m_nSeekPos = nRow;
+ }
+ else if (IsInsertionRow(nRow)) // Leerzeile zum Einfuegen von Datensaetzen
+ m_nSeekPos = nRow;
+ }
+ else if (IsInsertionRow(nRow)) // Leerzeile zum Einfuegen von Datensaetzen
+ m_nSeekPos = nRow;
+ else if ((-1 == nRow) && (GetRowCount() == ((m_nOptions & OPT_INSERT) ? 1 : 0)) && m_pSeekCursor->isAfterLast())
+ m_nSeekPos = nRow;
+ else
+ {
+
+ sal_Bool bSuccess=sal_False;
+ long nSteps = 0;
+ try
+ {
+ if ( m_pSeekCursor->rowDeleted() )
+ {
+ // somebody deleted the current row of the seek cursor. Move it away from this row.
+ m_pSeekCursor->next();
+ if ( m_pSeekCursor->isAfterLast() || m_pSeekCursor->isBeforeFirst() )
+ bAbsolute = sal_True;
+ }
+
+ if ( !bAbsolute )
+ {
+ DBG_ASSERT( !m_pSeekCursor->isAfterLast() && !m_pSeekCursor->isBeforeFirst(),
+ "DbGridControl::SeekCursor: how did the seek cursor get to this position?!" );
+ nSteps = nRow - (m_pSeekCursor->getRow() - 1);
+ bAbsolute = bAbsolute || (abs(nSteps) > 100);
+ }
+
+ if ( bAbsolute )
+ {
+ bSuccess = m_pSeekCursor->absolute(nRow + 1);
+ if (bSuccess)
+ m_nSeekPos = nRow;
+ }
+ else
+ {
+ if (nSteps > 0) // auf den letzten benoetigten Datensatz positionieren
+ {
+ if (m_pSeekCursor->isAfterLast())
+ bSuccess = sal_False;
+ else if (m_pSeekCursor->isBeforeFirst())
+ bSuccess = m_pSeekCursor->absolute(nSteps);
+ else
+ bSuccess = m_pSeekCursor->relative(nSteps);
+ }
+ else if (nSteps < 0)
+ {
+ if (m_pSeekCursor->isBeforeFirst())
+ bSuccess = sal_False;
+ else if (m_pSeekCursor->isAfterLast())
+ bSuccess = m_pSeekCursor->absolute(nSteps);
+ else
+ bSuccess = m_pSeekCursor->relative(nSteps);
+ }
+ else
+ {
+ m_nSeekPos = nRow;
+ return sal_True;
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ DBG_ERROR("DbGridControl::SeekCursor : failed ...");
+ }
+
+ try
+ {
+ if (!bSuccess)
+ {
+ if (bAbsolute || nSteps > 0)
+ bSuccess = m_pSeekCursor->last();
+ else
+ bSuccess = m_pSeekCursor->first();
+ }
+
+ if (bSuccess)
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ else
+ m_nSeekPos = -1;
+ }
+ catch(Exception&)
+ {
+ DBG_ERROR("DbGridControl::SeekCursor : failed ...");
+ m_nSeekPos = -1; // kein Datensatz mehr vorhanden
+ }
+ }
+ return m_nSeekPos == nRow;
+}
+//------------------------------------------------------------------------------
+void DbGridControl::MoveToFirst()
+{
+ if (m_pSeekCursor && (GetCurRow() != 0))
+ MoveToPosition(0);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::MoveToLast()
+{
+ if (!m_pSeekCursor)
+ return;
+
+ if (m_nTotalCount < 0) // RecordCount steht noch nicht fest
+ {
+ try
+ {
+ sal_Bool bRes = m_pSeekCursor->last();
+
+ if (bRes)
+ {
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ AdjustRows();
+ }
+ }
+ catch(Exception&)
+ {
+ }
+ }
+
+ // auf den letzen Datensatz positionieren, nicht auf die Leerzeile
+ if (m_nOptions & OPT_INSERT)
+ {
+ if ((GetRowCount() - 1) > 0)
+ MoveToPosition(GetRowCount() - 2);
+ }
+ else if (GetRowCount())
+ MoveToPosition(GetRowCount() - 1);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::MoveToPrev()
+{
+ long nNewRow = std::max(GetCurRow() - 1L, 0L);
+ if (GetCurRow() != nNewRow)
+ MoveToPosition(nNewRow);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::MoveToNext()
+{
+ if (!m_pSeekCursor)
+ return;
+
+ if (m_nTotalCount > 0)
+ {
+ // move the data cursor to the right position
+ long nNewRow = std::min(GetRowCount() - 1, GetCurRow() + 1);
+ if (GetCurRow() != nNewRow)
+ MoveToPosition(nNewRow);
+ }
+ else
+ {
+ sal_Bool bOk = sal_False;
+ try
+ {
+ // try to move to next row
+ // when not possible our paint cursor is already on the last row
+ // then we must be sure that the data cursor is on the position
+ // we call ourself again
+ bOk = m_pSeekCursor->next();
+ if (bOk)
+ {
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ MoveToPosition(GetCurRow() + 1);
+ }
+ }
+ catch(SQLException &)
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ }
+
+ if(!bOk)
+ {
+ AdjustRows();
+ if (m_nTotalCount > 0) // only to avoid infinte recursion
+ MoveToNext();
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::MoveToPosition(sal_uInt32 nPos)
+{
+ if (!m_pSeekCursor)
+ return;
+
+ if (m_nTotalCount < 0 && (long)nPos >= GetRowCount())
+ {
+ try
+ {
+ if (!m_pSeekCursor->absolute(nPos + 1))
+ {
+ AdjustRows();
+ Sound::Beep();
+ return;
+ }
+ else
+ {
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ AdjustRows();
+ }
+ }
+ catch(Exception&)
+ {
+ return;
+ }
+ }
+ DbGridControl_Base::GoToRow(nPos);
+ m_aBar.InvalidateAll(m_nCurrentPos);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::AppendNew()
+{
+ if (!m_pSeekCursor || !(m_nOptions & OPT_INSERT))
+ return;
+
+ if (m_nTotalCount < 0) // RecordCount steht noch nicht fest
+ {
+ try
+ {
+ sal_Bool bRes = m_pSeekCursor->last();
+
+ if (bRes)
+ {
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ AdjustRows();
+ }
+ }
+ catch(Exception&)
+ {
+ return;
+ }
+ }
+
+ long nNewRow = m_nTotalCount + 1;
+ if (nNewRow > 0 && GetCurRow() != nNewRow)
+ MoveToPosition(nNewRow - 1);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::SetDesignMode(sal_Bool bMode)
+{
+ if (IsDesignMode() != bMode)
+ {
+ // Enable/Disable f�r den Designmode anpassen damit die Headerbar konfigurierbar bleibt
+ if (bMode)
+ {
+ if (!IsEnabled())
+ {
+ Enable();
+ GetDataWindow().Disable();
+ }
+ }
+ else
+ {
+ // komplett disablen
+ if (!GetDataWindow().IsEnabled())
+ Disable();
+ }
+
+ m_bDesignMode = bMode;
+ GetDataWindow().SetMouseTransparent(bMode);
+ SetMouseTransparent(bMode);
+
+ m_aBar.InvalidateAll(m_nCurrentPos, sal_True);
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::SetFilterMode(sal_Bool bMode)
+{
+ if (IsFilterMode() != bMode)
+ {
+ m_bFilterMode = bMode;
+
+ if (bMode)
+ {
+ SetUpdateMode(sal_False);
+
+ // es gibt kein Cursor mehr
+ if (IsEditing())
+ DeactivateCell();
+ RemoveRows(sal_False);
+
+ m_xEmptyRow = new DbGridRow();
+
+ // setting the new filter controls
+ for (sal_uInt16 i = 0; i<m_aColumns.Count(); ++i)
+ {
+ DbGridColumn* pCurCol = m_aColumns.GetObject(i);
+ if (!pCurCol->IsHidden())
+ pCurCol->UpdateControl();
+ }
+
+ // one row for filtering
+ RowInserted(0, 1, sal_True);
+ SetUpdateMode(sal_True);
+ }
+ else
+ setDataSource(Reference< XRowSet > ());
+ }
+}
+// -----------------------------------------------------------------------------
+String DbGridControl::GetCellText(long _nRow, USHORT _nColId) const
+{
+ DbGridColumn* pColumn = m_aColumns.GetObject( GetModelColumnPos( _nColId ) );
+ String sRet;
+ if ( const_cast<DbGridControl*>(this)->SeekRow(_nRow) )
+ sRet = GetCurrentRowCellText(pColumn, m_xPaintRow);
+ return sRet;
+}
+//------------------------------------------------------------------------------
+XubString DbGridControl::GetCurrentRowCellText(DbGridColumn* pColumn,const DbGridRowRef& _rRow) const
+{
+ // Ausgabe des Textes fuer eine Zelle
+ XubString aText;
+ if ( pColumn && IsValid(m_xPaintRow) )
+ aText = pColumn->GetCellText(_rRow, m_xFormatter);
+ return aText;
+}
+
+//------------------------------------------------------------------------------
+sal_uInt32 DbGridControl::GetTotalCellWidth(long nRow, sal_uInt16 nColId)
+{
+ if (SeekRow(nRow))
+ {
+ DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColId));
+ return GetDataWindow().GetTextWidth(GetCurrentRowCellText(pColumn,m_xPaintRow));
+ }
+ else
+ return 30; //xxxx
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::PreExecuteRowContextMenu(sal_uInt16 /*nRow*/, PopupMenu& rMenu)
+{
+ sal_Bool bDelete = (m_nOptions & OPT_DELETE) && GetSelectRowCount() && !IsCurrentAppending();
+ // ist nur die Leerzeile selektiert, dann nicht loeschen
+ bDelete = bDelete && !((m_nOptions & OPT_INSERT) && GetSelectRowCount() == 1 && IsRowSelected(GetRowCount() - 1));
+
+ rMenu.EnableItem(SID_FM_DELETEROWS, bDelete);
+ rMenu.EnableItem(SID_FM_RECORD_SAVE, IsModified());
+
+ // the undo is more difficult
+ sal_Bool bCanUndo = IsModified();
+ long nState = -1;
+ if (m_aMasterStateProvider.IsSet())
+ nState = m_aMasterStateProvider.Call((void*)SID_FM_RECORD_UNDO);
+ bCanUndo &= ( 0 != nState );
+
+ rMenu.EnableItem(SID_FM_RECORD_UNDO, bCanUndo);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::PostExecuteRowContextMenu(sal_uInt16 /*nRow*/, const PopupMenu& /*rMenu*/, sal_uInt16 nExecutionResult)
+{
+ switch (nExecutionResult)
+ {
+ case SID_FM_DELETEROWS:
+ // delete asynchron
+ if (m_nDeleteEvent)
+ Application::RemoveUserEvent(m_nDeleteEvent);
+ m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete));
+ break;
+ case SID_FM_RECORD_UNDO:
+ Undo();
+ break;
+ case SID_FM_RECORD_SAVE:
+ SaveRow();
+ break;
+ default:
+ break;
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::DataSourcePropertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException )
+{
+ TRACE_RANGE("DbGridControl::DataSourcePropertyChanged");
+ ::vos::OGuard aGuard( Application::GetSolarMutex() );
+ // prop "IsModified" changed ?
+ // during update don't care about the modified state
+ if (!IsUpdating() && evt.PropertyName.compareTo(FM_PROP_ISMODIFIED) == COMPARE_EQUAL)
+ {
+ Reference< XPropertySet > xSource(evt.Source, UNO_QUERY);
+ DBG_ASSERT( xSource.is(), "DbGridControl::DataSourcePropertyChanged: invalid event source!" );
+ sal_Bool bIsNew = sal_False;
+ if (xSource.is())
+ bIsNew = ::comphelper::getBOOL(xSource->getPropertyValue(FM_PROP_ISNEW));
+
+ if (bIsNew && m_xCurrentRow.Is())
+ {
+ 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 !");
+ sal_Int32 nRecordCount = 0;
+ xSource->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
+ if (::comphelper::getBOOL(evt.NewValue))
+ { // modified state changed from sal_False to sal_True and we're on a insert row
+ // -> we've to add a new grid row
+ if ((nRecordCount == GetRowCount() - 1) && m_xCurrentRow->IsNew())
+ {
+ RowInserted(GetRowCount(), 1, sal_True);
+ InvalidateStatusCell(m_nCurrentPos);
+ m_aBar.InvalidateAll(m_nCurrentPos);
+ }
+ }
+ else
+ { // modified state changed from sal_True to sal_False and we're on a insert row
+ // we have two "new row"s at the moment : the one we're editing currently (where the current
+ // column is the only dirty element) and a "new new" row which is completely clean. As the first
+ // one is about to be cleaned, too, the second one is obsolet now.
+ if (m_xCurrentRow->IsNew() && nRecordCount == (GetRowCount() - 2))
+ {
+ RowRemoved(GetRowCount() - 1, 1, sal_True);
+ InvalidateStatusCell(m_nCurrentPos);
+ m_aBar.InvalidateAll(m_nCurrentPos);
+ }
+ }
+ }
+ if (m_xCurrentRow.Is())
+ {
+ m_xCurrentRow->SetStatus(::comphelper::getBOOL(evt.NewValue) ? GRS_MODIFIED : GRS_CLEAN);
+ m_xCurrentRow->SetNew( bIsNew );
+ InvalidateStatusCell(m_nCurrentPos);
+ TRACE_RANGE_MESSAGE1("modified flag changed, new state : %s", ROWSTATUS(m_xCurrentRow));
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::StartDrag( sal_Int8 /*nAction*/, const Point& rPosPixel )
+{
+ if (!m_pSeekCursor || IsResizing())
+ return;
+
+ sal_uInt16 nColId = GetColumnAtXPosPixel(rPosPixel.X());
+ long nRow = GetRowAtYPosPixel(rPosPixel.Y());
+ if (nColId != HANDLE_ID && nRow >= 0)
+ {
+ if (GetDataWindow().IsMouseCaptured())
+ GetDataWindow().ReleaseMouse();
+
+ DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColId));
+ OStringTransferable* pTransferable = new OStringTransferable(GetCurrentRowCellText(pColumn,m_xPaintRow));
+ Reference< XTransferable > xEnsureDelete(pTransferable);
+ pTransferable->StartDrag(this, DND_ACTION_COPY);
+ }
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::canCopyCellText(sal_Int32 _nRow, sal_Int16 _nColId)
+{
+ return (_nRow >= 0)
+ && (_nRow < GetRowCount())
+ && (_nColId > HANDLE_ID)
+ && (_nColId <= ColCount());
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::copyCellText(sal_Int32 _nRow, sal_Int16 _nColId)
+{
+ DBG_ASSERT(canCopyCellText(_nRow, _nColId), "DbGridControl::copyCellText: invalid call!");
+ DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(_nColId));
+ SeekRow(_nRow);
+ OStringTransfer::CopyString( GetCurrentRowCellText( pColumn,m_xPaintRow ), this );
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::executeRowContextMenu( long _nRow, const Point& _rPreferredPos )
+{
+ PopupMenu aContextMenu( SVX_RES( RID_SVXMNU_ROWS ) );
+
+ PreExecuteRowContextMenu( (sal_uInt16)_nRow, aContextMenu );
+ aContextMenu.RemoveDisabledEntries( sal_True, sal_True );
+ PostExecuteRowContextMenu( (sal_uInt16)_nRow, aContextMenu, aContextMenu.Execute( this, _rPreferredPos ) );
+
+ // TODO: why this weird cast to sal_uInt16? What if we really have more than 65535 lines?
+ // -> change this to sal_uInt32
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::Command(const CommandEvent& rEvt)
+{
+ switch (rEvt.GetCommand())
+ {
+ case COMMAND_CONTEXTMENU:
+ {
+ if ( !m_pSeekCursor )
+ {
+ DbGridControl_Base::Command(rEvt);
+ return;
+ }
+
+ if ( !rEvt.IsMouseEvent() )
+ { // context menu requested by keyboard
+ if ( GetSelectRowCount() )
+ {
+ long nRow = FirstSelectedRow( );
+
+ ::Rectangle aRowRect( GetRowRectPixel( nRow, sal_True ) );
+ executeRowContextMenu( nRow, aRowRect.LeftCenter() );
+
+ // handled
+ return;
+ }
+ }
+
+ sal_uInt16 nColId = GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X());
+ long nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y());
+
+ if (nColId == HANDLE_ID)
+ {
+ executeRowContextMenu( nRow, rEvt.GetMousePosPixel() );
+ }
+ else if (canCopyCellText(nRow, nColId))
+ {
+ PopupMenu aContextMenu(SVX_RES(RID_SVXMNU_CELL));
+ aContextMenu.RemoveDisabledEntries(sal_True, sal_True);
+ switch (aContextMenu.Execute(this, rEvt.GetMousePosPixel()))
+ {
+ case SID_COPY:
+ copyCellText(nRow, nColId);
+ break;
+ }
+ }
+ else
+ {
+ DbGridControl_Base::Command(rEvt);
+ return;
+ }
+ }
+ default:
+ DbGridControl_Base::Command(rEvt);
+ }
+}
+
+//------------------------------------------------------------------------------
+IMPL_LINK(DbGridControl, OnDelete, void*, /*EMPTYTAG*/ )
+{
+ DBG_CHKTHIS(DbGridControl, NULL );
+ m_nDeleteEvent = 0;
+ DeleteSelectedRows();
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::DeleteSelectedRows()
+{
+ DBG_ASSERT(GetSelection(), "keine selection!!!");
+
+ if (!m_pSeekCursor)
+ return;
+
+/* Application::EnterWait();
+ Reference< XPropertySet > xSet = (XPropertySet*)xSeekCursor->queryInterface(XPropertySet::getSmartUik());
+
+ // wenn mehr als 25 Datensaetze geloescht werden, wird der Cache abgeschaltet
+ // da das loeschen ansonsten zu langsam wird
+ sal_uInt16 nCacheSize = 0;
+ if (GetSelectRowCount() > 25)
+ {
+ // CacheSize merken und Cache zuruecksetzen
+ nCacheSize = xSet->getPropertyValue(L"CacheSize").getUINT16();
+ if (nCacheSize)
+ xSet->setPropertyValue(L"CacheSize", Any(sal_uInt16(0)));
+ } */
+
+
+ /*
+ // mu� der Cache wiederhergestellt werden?
+ if (nCacheSize)
+ {
+ // Cache wieder einschalten
+ xSet->setPropertyValue(L"CacheSize", Any(sal_uInt16(nCacheSize)));
+
+ // Browser neu einstellen
+ RecalcRows(GetTopRow(), GetVisibleRows(), sal_True);
+
+ // aktuelle Zeile aktualisieren
+ SeekCursor(GetCurRow());
+ if (IsAppendRow(m_nSeekPos))
+ xDataCursor->addRecord();
+ else
+ {
+ Any aBookmark = xSeekCursor->getBookmark();
+ xDataCursor->moveToBookmark(aBookmark);
+ }
+ m_xCurrentRow = new DbGridRow(xDataCursor);
+ m_nCurrentPos = m_nSeekPos;
+
+ // complett invalidieren
+ Invalidate();
+ }
+ else
+ // Browser neu einstellen
+ RecalcRows(GetTopRow(), GetVisibleRows(), sal_True);
+
+ // gibt es keine Selection mehr?
+ if (!GetSelectRowCount())
+ ActivateCell();
+
+ m_aBar.InvalidateAll();
+ Application::LeaveWait();
+
+ m_bUpdating = sal_False;
+*/
+}
+
+//------------------------------------------------------------------------------
+CellController* DbGridControl::GetController(long /*nRow*/, sal_uInt16 nColumnId)
+{
+ if (!IsValid(m_xCurrentRow) || !IsEnabled())
+ return NULL;
+
+ DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColumnId));
+ if (!pColumn)
+ return NULL;
+
+ CellController* pReturn = NULL;
+ if (IsFilterMode())
+ pReturn = &pColumn->GetController();
+ else
+ {
+ if (::comphelper::hasProperty(FM_PROP_ENABLED, pColumn->getModel()))
+ {
+ if (!::comphelper::getBOOL(pColumn->getModel()->getPropertyValue(FM_PROP_ENABLED)))
+ return NULL;
+ }
+
+ sal_Bool bInsert = (m_xCurrentRow->IsNew() && (m_nOptions & OPT_INSERT));
+ sal_Bool bUpdate = (!m_xCurrentRow->IsNew() && (m_nOptions & OPT_UPDATE));
+
+ if ((bInsert && !pColumn->IsAutoValue()) || bUpdate || m_bForceROController)
+ {
+ pReturn = &pColumn->GetController();
+ if (pReturn)
+ {
+ // wenn es eine Edit-Zeile ist, kann ich ihr das forced read-only mitgeben
+ if (!pReturn->ISA(EditCellController) && !pReturn->ISA(SpinCellController))
+ // ich konnte den Controller in forceROController nicht auf ReadOnly setzen
+ if (!bInsert && !bUpdate)
+ // ich bin nur hier, da m_bForceROController gesetzt war
+ // -> lieber kein Controller als einer ohne RO
+ pReturn = NULL;
+ }
+ }
+ }
+ return pReturn;
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::InitController(CellControllerRef& /*rController*/, long /*nRow*/, sal_uInt16 nColumnId)
+{
+ DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColumnId));
+ if (pColumn)
+ pColumn->UpdateFromField(m_xCurrentRow, m_xFormatter);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::CellModified()
+{
+ TRACE_RANGE("DbGridControl::CellModified");
+
+ {
+ ::osl::MutexGuard aGuard(m_aAdjustSafety);
+ if (m_nAsynAdjustEvent)
+ {
+ TRACE_RANGE_MESSAGE1("forcing a synchron call to ", m_bPendingAdjustRows ? "AdjustRows" : "AdustDataSource");
+ RemoveUserEvent(m_nAsynAdjustEvent);
+ m_nAsynAdjustEvent = 0;
+
+ // force the call : this should be no problem as we're probably running in the solar thread here
+ // (cell modified is triggered by user actions)
+ if (m_bPendingAdjustRows)
+ AdjustRows();
+ else
+ AdjustDataSource();
+ }
+ }
+
+ if (!IsFilterMode() && IsValid(m_xCurrentRow) && !m_xCurrentRow->IsModified())
+ {
+ // Einschalten des Editiermodus
+ // Datensatz soll eingefuegt werden
+ if (m_xCurrentRow->IsNew())
+ {
+ m_xCurrentRow->SetStatus(GRS_MODIFIED);
+ TRACE_RANGE_MESSAGE("current row is new, new state : MODIFIED");
+ // wenn noch keine Zeile hinzugefuegt wurde, dann neue hinzunehmen
+ if (m_nCurrentPos == GetRowCount() - 1)
+ {
+ // RowCount um einen erhoehen
+ RowInserted(GetRowCount(), 1, sal_True);
+ InvalidateStatusCell(m_nCurrentPos);
+ m_aBar.InvalidateAll(m_nCurrentPos);
+ }
+ }
+ else if (m_xCurrentRow->GetStatus() != GRS_MODIFIED)
+ {
+ m_xCurrentRow->SetState(m_pDataCursor, sal_False);
+ TRACE_RANGE_MESSAGE1("current row is not new, after SetState, new state : %s", ROWSTATUS(m_xCurrentRow));
+ m_xCurrentRow->SetStatus(GRS_MODIFIED);
+ TRACE_RANGE_MESSAGE("current row is not new, new state : MODIFIED");
+ InvalidateStatusCell(m_nCurrentPos);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::Dispatch(sal_uInt16 nId)
+{
+ if (nId == BROWSER_CURSORENDOFFILE)
+ {
+ if (m_nOptions & OPT_INSERT)
+ AppendNew();
+ else
+ MoveToLast();
+ }
+ else
+ DbGridControl_Base::Dispatch(nId);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::Undo()
+{
+ if (!IsFilterMode() && IsValid(m_xCurrentRow) && IsModified())
+ {
+ // check if we have somebody doin' the UNDO for us
+ long nState = -1;
+ if (m_aMasterStateProvider.IsSet())
+ nState = m_aMasterStateProvider.Call((void*)SID_FM_RECORD_UNDO);
+ if (nState>0)
+ { // yes, we have, and the slot is enabled
+ DBG_ASSERT(m_aMasterSlotExecutor.IsSet(), "DbGridControl::Undo : a state, but no execute link ?");
+ long lResult = m_aMasterSlotExecutor.Call((void*)SID_FM_RECORD_UNDO);
+ if (lResult)
+ // handled
+ return;
+ }
+ else if (nState == 0)
+ // yes, we have, and the slot is disabled
+ return;
+
+ BeginCursorAction();
+
+ sal_Bool bAppending = m_xCurrentRow->IsNew();
+ sal_Bool bDirty = m_xCurrentRow->IsModified();
+
+ try
+ {
+ // Editieren abbrechen
+ Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
+ // no effects if we're not updating currently
+ if (bAppending)
+ // just refresh the row
+ xUpdateCursor->moveToInsertRow();
+ else
+ xUpdateCursor->cancelRowUpdates();
+
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ }
+
+ EndCursorAction();
+
+ m_xDataRow->SetState(m_pDataCursor, sal_False);
+ if (&m_xPaintRow == &m_xCurrentRow)
+ m_xPaintRow = m_xCurrentRow = m_xDataRow;
+ else
+ m_xCurrentRow = m_xDataRow;
+
+ if (bAppending && (DbGridControl_Base::IsModified() || bDirty))
+ // remove the row
+ if (m_nCurrentPos == GetRowCount() - 2)
+ { // maybe we already removed it (in resetCurrentRow, called if the above moveToInsertRow
+ // caused our data source form to be reset - which should be the usual case ....)
+ RowRemoved(GetRowCount() - 1, 1, sal_True);
+ m_aBar.InvalidateAll(m_nCurrentPos);
+ }
+
+ RowModified(m_nCurrentPos);
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::resetCurrentRow()
+{
+ if (IsModified())
+ {
+ // scenario : we're on the insert row, the row is dirty, and thus there exists a "second" insert row (which
+ // is clean). Normally in DataSourcePropertyChanged we would remove this second row if the modified state of
+ // the insert row changes from sal_True to sal_False. But if our current cell is the only modified element (means the
+ // data source isn't modified) and we're reset this DataSourcePropertyChanged would never be called, so we
+ // would never delete the obsolet "second insert row". Thus in this special case this method here
+ // is the only possibility to determine the redundance of the row (resetCurrentRow is called when the
+ // "first insert row" is about to be cleaned, so of course the "second insert row" is redundant now)
+ Reference< XPropertySet > xDataSource = getDataSource()->getPropertySet();
+ if (xDataSource.is() && !::comphelper::getBOOL(xDataSource->getPropertyValue(FM_PROP_ISMODIFIED)))
+ {
+ // are we on a new row currently ?
+ if (m_xCurrentRow->IsNew())
+ {
+ if (m_nCurrentPos == GetRowCount() - 2)
+ {
+ RowRemoved(GetRowCount() - 1, 1, sal_True);
+ m_aBar.InvalidateAll(m_nCurrentPos);
+ }
+ }
+ }
+
+ // update the rows
+ m_xDataRow->SetState(m_pDataCursor, sal_False);
+ if (&m_xPaintRow == &m_xCurrentRow)
+ m_xPaintRow = m_xCurrentRow = m_xDataRow;
+ else
+ m_xCurrentRow = m_xDataRow;
+ }
+
+ RowModified(GetCurRow()); // will update the current controller if affected
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::RowModified( long nRow, sal_uInt16 /*nColId*/ )
+{
+ if (nRow == m_nCurrentPos && IsEditing())
+ {
+ CellControllerRef aTmpRef = Controller();
+ aTmpRef->ClearModified();
+ InitController(aTmpRef, m_nCurrentPos, GetCurColumnId());
+ }
+ DbGridControl_Base::RowModified(nRow);
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::IsModified() const
+{
+ return !IsFilterMode() && IsValid(m_xCurrentRow) && (m_xCurrentRow->IsModified() || DbGridControl_Base::IsModified());
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::IsCurrentAppending() const
+{
+ return m_xCurrentRow.Is() && m_xCurrentRow->IsNew();
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::IsInsertionRow(long nRow) const
+{
+ return (m_nOptions & OPT_INSERT) && m_nTotalCount >= 0 && (nRow == GetRowCount() - 1);
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::SaveModified()
+{
+ TRACE_RANGE("DbGridControl::SaveModified");
+ DBG_ASSERT(IsValid(m_xCurrentRow), "GridControl:: Invalid row");
+ if (!IsValid(m_xCurrentRow))
+ return sal_True;
+
+ // Uebernimmt die Dateneingabe fuer das Feld
+ // Hat es aenderungen im aktuellen Eingabefeld gegeben ?
+ if (!DbGridControl_Base::IsModified())
+ return sal_True;
+
+ DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(GetCurColumnId()));
+ sal_Bool bOK = pColumn->Commit();
+ DBG_ASSERT( Controller().Is(), "DbGridControl::SaveModified: was modified, by have no controller?!" );
+ if ( !Controller().Is() )
+ // this might happen if the callbacks implicitly triggered by Commit
+ // fiddled with the form or the control ...
+ // (Note that this here is a workaround, at most. We need a general concept how
+ // to treat this, you can imagine an arbitrary number of scenarios where a callback
+ // triggers something which leaves us in an expected state.)
+ // #i67147# / 2006-07-17 / frank.schoenheit@sun.com
+ return bOK;
+
+ if (bOK)
+ {
+ Controller()->ClearModified();
+
+ if ( IsValid(m_xCurrentRow) )
+ {
+ m_xCurrentRow->SetState(m_pDataCursor, sal_False);
+ TRACE_RANGE_MESSAGE1("explicit SetState, new state : %s", ROWSTATUS(m_xCurrentRow));
+ InvalidateStatusCell( m_nCurrentPos );
+ }
+#ifdef DBG_UTIL
+ else
+ {
+ TRACE_RANGE_MESSAGE1("no SetState, new state : %s", ROWSTATUS(m_xCurrentRow));
+ }
+#endif
+ }
+ else
+ {
+ // reset the modified flag ....
+ Controller()->SetModified();
+ }
+
+ return bOK;
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::SaveRow()
+{
+ TRACE_RANGE("DbGridControl::SaveRow");
+ // gueltige Zeile
+ if (!IsValid(m_xCurrentRow) || !IsModified())
+ return sal_True;
+ // Wert des Controllers noch nicht gespeichert
+ else if (Controller().Is() && Controller()->IsModified())
+ {
+ if (!SaveModified())
+ return sal_False;
+ }
+ m_bUpdating = sal_True;
+
+ BeginCursorAction();
+ sal_Bool bAppending = m_xCurrentRow->IsNew();
+ sal_Bool bSuccess = sal_False;
+ try
+ {
+ Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
+ if (bAppending)
+ xUpdateCursor->insertRow();
+ else
+ xUpdateCursor->updateRow();
+ bSuccess = sal_True;
+ }
+ catch(SQLException& e)
+ {
+ (void)e; // make compiler happy
+ EndCursorAction();
+ m_bUpdating = sal_False;
+ return sal_False;
+ }
+
+ try
+ {
+ if (bSuccess)
+ {
+ // if we are appending we still sit on the insert row
+ // we don't move just clear the flags not to move on the current row
+ m_xCurrentRow->SetState(m_pDataCursor, sal_False);
+ TRACE_RANGE_MESSAGE1("explicit SetState after a successfull update, new state : %s", ROWSTATUS(m_xCurrentRow));
+ m_xCurrentRow->SetNew(sal_False);
+
+ // adjust the seekcursor if it is on the same position as the datacursor
+ if (m_nSeekPos == m_nCurrentPos || bAppending)
+ {
+ // get the bookmark to refetch the data
+ // in insert mode we take the new bookmark of the data cursor
+ Any aBookmark = bAppending ? m_pDataCursor->getBookmark() : m_pSeekCursor->getBookmark();
+ m_pSeekCursor->moveToBookmark(aBookmark);
+ // get the data
+ m_xSeekRow->SetState(m_pSeekCursor, sal_True);
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ }
+ }
+ // and repaint the row
+ RowModified(m_nCurrentPos);
+ }
+ catch(Exception&)
+ {
+ }
+
+ m_bUpdating = sal_False;
+ EndCursorAction();
+
+ // The old code returned (nRecords != 0) here.
+ // Me thinks this is wrong : If something goes wrong while update the record, an exception will be thrown,
+ // which results in a "return sal_False" (see above). If no exception is thrown, everything is fine. If nRecords
+ // is zero, this simply means all fields had their original values.
+ // FS - 06.12.99 - 70502
+ return sal_True;
+}
+
+//------------------------------------------------------------------------------
+long DbGridControl::PreNotify(NotifyEvent& rEvt)
+{
+ // keine Events der Navbar behandeln
+ if (m_aBar.IsWindowOrChild(rEvt.GetWindow()))
+ return BrowseBox::PreNotify(rEvt);
+
+ switch (rEvt.GetType())
+ {
+ case EVENT_KEYINPUT:
+ {
+ const KeyEvent* pKeyEvent = rEvt.GetKeyEvent();
+
+ sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
+ sal_Bool bShift = pKeyEvent->GetKeyCode().IsShift();
+ sal_Bool bCtrl = pKeyEvent->GetKeyCode().IsMod1();
+ sal_Bool bAlt = pKeyEvent->GetKeyCode().IsMod2();
+ if ( ( KEY_TAB == nCode ) && bCtrl && !bAlt )
+ {
+ // Ctrl-Tab is used to step out of the control, without traveling to the
+ // remaining cells first
+ // -> build a new key event without the Ctrl-key, and let the very base class handle it
+ KeyCode aNewCode( KEY_TAB, bShift, sal_False, sal_False, sal_False );
+ KeyEvent aNewEvent( pKeyEvent->GetCharCode(), aNewCode );
+
+ // call the Control - our direct base class will interpret this in a way we do not want (and do
+ // a cell traveling)
+ Control::KeyInput( aNewEvent );
+ return 1;
+ }
+
+ if ( !bShift && !bCtrl && ( KEY_ESCAPE == nCode ) )
+ {
+ if (IsModified())
+ {
+ Undo();
+ return 1;
+ }
+ }
+ else if ( ( KEY_DELETE == nCode ) && !bShift && !bCtrl ) // delete rows
+ {
+ if ((m_nOptions & OPT_DELETE) && GetSelectRowCount())
+ {
+ // delete asynchron
+ if (m_nDeleteEvent)
+ Application::RemoveUserEvent(m_nDeleteEvent);
+ m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete));
+ return 1;
+ }
+ }
+ } // kein break!
+ default:
+ return DbGridControl_Base::PreNotify(rEvt);
+ }
+}
+
+//------------------------------------------------------------------------------
+sal_Bool DbGridControl::IsTabAllowed(sal_Bool bRight) const
+{
+ if (bRight)
+ // Tab nur wenn nicht auf der letzten Zelle
+ return GetCurRow() < (GetRowCount() - 1) || !m_bRecordCountFinal ||
+ GetViewColumnPos(GetCurColumnId()) < (GetViewColCount() - 1);
+ else
+ {
+ // Tab nur wenn nicht auf der ersten Zelle
+ return GetCurRow() > 0 || (GetCurColumnId() && GetViewColumnPos(GetCurColumnId()) > 0);
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::KeyInput( const KeyEvent& rEvt )
+{
+ if (rEvt.GetKeyCode().GetFunction() == KEYFUNC_COPY)
+ {
+ long nRow = GetCurRow();
+ sal_uInt16 nColId = GetCurColumnId();
+ if (nRow >= 0 && nRow < GetRowCount() && nColId < ColCount())
+ {
+ DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColId));
+ OStringTransfer::CopyString( GetCurrentRowCellText( pColumn,m_xPaintRow ), this );
+ return;
+ }
+ }
+ DbGridControl_Base::KeyInput(rEvt);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::HideColumn(sal_uInt16 nId)
+{
+ DeactivateCell();
+
+ // determine the col for the focus to set to after removal
+ sal_uInt16 nPos = GetViewColumnPos(nId);
+ sal_uInt16 nNewColId = nPos == (ColCount()-1)
+ ? GetColumnIdFromViewPos(nPos-1) // last col is to be removed -> take the previous
+ : GetColumnIdFromViewPos(nPos+1); // take the next
+
+ long lCurrentWidth = GetColumnWidth(nId);
+ DbGridControl_Base::RemoveColumn(nId);
+ // don't use my own RemoveColumn, this would remove it from m_aColumns, too
+
+ // update my model
+ DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nId));
+ DBG_ASSERT(pColumn, "DbGridControl::HideColumn : somebody did hide a nonexistent column !");
+ if (pColumn)
+ {
+ pColumn->m_bHidden = sal_True;
+ pColumn->m_nLastVisibleWidth = CalcReverseZoom(lCurrentWidth);
+ }
+
+ // and reset the focus
+ if ( nId == GetCurColumnId() )
+ GoToColumnId( nNewColId );
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::ShowColumn(sal_uInt16 nId)
+{
+ sal_uInt16 nPos = GetModelColumnPos(nId);
+ DBG_ASSERT(nPos != (sal_uInt16)-1, "DbGridControl::ShowColumn : invalid argument !");
+ if (nPos == (sal_uInt16)-1)
+ return;
+
+ DbGridColumn* pColumn = m_aColumns.GetObject(nPos);
+ if (!pColumn->IsHidden())
+ {
+ DBG_ASSERT(GetViewColumnPos(nId) != (sal_uInt16)-1, "DbGridControl::ShowColumn : inconsistent internal state !");
+ // if the column isn't marked as hidden, it should be visible, shouldn't it ?
+ return;
+ }
+ DBG_ASSERT(GetViewColumnPos(nId) == (sal_uInt16)-1, "DbGridControl::ShowColumn : inconsistent internal state !");
+ // the opposite situation ...
+
+ // to determine the new view position we need an adjacent non-hidden column
+ sal_uInt16 nNextNonHidden = (sal_uInt16)-1;
+ // first search the cols to the right
+ for (sal_uInt16 i = nPos + 1; i<m_aColumns.Count(); ++i)
+ {
+ DbGridColumn* pCurCol = m_aColumns.GetObject(i);
+ if (!pCurCol->IsHidden())
+ {
+ nNextNonHidden = i;
+ break;
+ }
+ }
+ if ((nNextNonHidden == (sal_uInt16)-1) && (nPos > 0))
+ {
+ // then to the left
+ for (sal_uInt16 i = nPos; i>0; --i)
+ {
+ DbGridColumn* pCurCol = m_aColumns.GetObject(i-1);
+ if (!pCurCol->IsHidden())
+ {
+ nNextNonHidden = i-1;
+ break;
+ }
+ }
+ }
+ sal_uInt16 nNewViewPos = (nNextNonHidden == (sal_uInt16)-1)
+ ? 1 // there is no visible column -> insert behinde the handle col
+ : GetViewColumnPos(m_aColumns.GetObject(nNextNonHidden)->GetId()) + 1;
+ // the first non-handle col has "view pos" 0, but the pos arg for InsertDataColumn expects
+ // a position 1 for the first non-handle col -> +1
+ DBG_ASSERT(nNewViewPos != (sal_uInt16)-1, "DbGridControl::ShowColumn : inconsistent internal state !");
+ // we found a col marked as visible but got no view pos for it ...
+
+ if ((nNextNonHidden<nPos) && (nNextNonHidden != (sal_uInt16)-1))
+ // nNextNonHidden is a column to the left, so we want to insert the new col _right_ beside it's pos
+ ++nNewViewPos;
+
+ DeactivateCell();
+
+ ::rtl::OUString aName;
+ pColumn->getModel()->getPropertyValue(FM_PROP_LABEL) >>= aName;
+ InsertDataColumn(nId, aName, CalcZoom(pColumn->m_nLastVisibleWidth), HIB_CENTER | HIB_VCENTER | HIB_CLICKABLE, nNewViewPos);
+ pColumn->m_bHidden = sal_False;
+
+ ActivateCell();
+ Invalidate();
+}
+
+//------------------------------------------------------------------------------
+sal_uInt16 DbGridControl::GetColumnIdFromModelPos( sal_uInt16 nPos ) const
+{
+ if (nPos >= m_aColumns.Count())
+ {
+ DBG_ERROR("DbGridControl::GetColumnIdFromModelPos : invalid argument !");
+ return (sal_uInt16)-1;
+ }
+
+ DbGridColumn* pCol = m_aColumns.GetObject(nPos);
+#if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
+ // in der Debug-Version rechnen wir die ModelPos in eine ViewPos um und vergleichen das mit dem Wert,
+ // den wir zurueckliefern werden (nId an der entsprechenden Col in m_aColumns)
+
+ if (!pCol->IsHidden())
+ { // macht nur Sinn, wenn die Spalte sichtbar ist
+ sal_uInt16 nViewPos = nPos;
+ for (sal_uInt16 i=0; i<m_aColumns.Count() && i<nPos; ++i)
+ if (m_aColumns.GetObject(i)->IsHidden())
+ --nViewPos;
+
+ DBG_ASSERT(pCol && GetColumnIdFromViewPos(nViewPos) == pCol->GetId(),
+ "DbGridControl::GetColumnIdFromModelPos : this isn't consistent .... did I misunderstand something ?");
+ }
+#endif
+ return pCol->GetId();
+}
+
+//------------------------------------------------------------------------------
+sal_uInt16 DbGridControl::GetModelColumnPos( sal_uInt16 nId ) const
+{
+ for (sal_uInt16 i=0; i<m_aColumns.Count(); ++i)
+ if (m_aColumns.GetObject(i)->GetId() == nId)
+ return i;
+
+ return GRID_COLUMN_NOT_FOUND;
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::implAdjustInSolarThread(BOOL _bRows)
+{
+ TRACE_RANGE("DbGridControl::implAdjustInSolarThread");
+ ::osl::MutexGuard aGuard(m_aAdjustSafety);
+ if (::vos::OThread::getCurrentIdentifier() != Application::GetMainThreadIdentifier())
+ {
+ m_nAsynAdjustEvent = PostUserEvent(LINK(this, DbGridControl, OnAsyncAdjust), reinterpret_cast< void* >( _bRows ));
+ m_bPendingAdjustRows = _bRows;
+#ifdef DBG_UTIL
+ if (_bRows)
+ TRACE_RANGE_MESSAGE("posting an AdjustRows")
+ else
+ TRACE_RANGE_MESSAGE("posting an AdjustDataSource")
+#endif
+ }
+ else
+ {
+#ifdef DBG_UTIL
+ if (_bRows)
+ TRACE_RANGE_MESSAGE("doing an AdjustRows")
+ else
+ TRACE_RANGE_MESSAGE("doing an AdjustDataSource")
+#endif
+ // always adjust the rows before adjusting the data source
+ // If this is not necessary (because the row count did not change), nothing is done
+ // The problem is that we can't rely on the order of which the calls come in: If the cursor was moved
+ // to a position behind row count know 'til now, the cursorMoved notification may come before the
+ // RowCountChanged notification
+ // 94093 - 02.11.2001 - frank.schoenheit@sun.com
+ AdjustRows();
+
+ if ( !_bRows )
+ AdjustDataSource();
+ }
+}
+
+//------------------------------------------------------------------------------
+IMPL_LINK(DbGridControl, OnAsyncAdjust, void*, pAdjustWhat)
+{
+ m_nAsynAdjustEvent = 0;
+
+ AdjustRows();
+ // see implAdjustInSolarThread for a comment why we do this every time
+
+ if ( !pAdjustWhat )
+ AdjustDataSource();
+
+ return 0L;
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::BeginCursorAction()
+{
+ if (m_pFieldListeners)
+ {
+ ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
+ ConstColumnFieldValueListenersIterator aIter = pListeners->begin();
+ while (aIter != pListeners->end())
+ {
+ GridFieldValueListener* pCurrent = (*aIter).second;
+ if (pCurrent)
+ pCurrent->suspend();
+ ++aIter;
+ }
+ }
+
+ if (m_pDataSourcePropListener)
+ m_pDataSourcePropListener->suspend();
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::EndCursorAction()
+{
+ if (m_pFieldListeners)
+ {
+ ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
+ ConstColumnFieldValueListenersIterator aIter = pListeners->begin();
+ while (aIter != pListeners->end())
+ {
+ GridFieldValueListener* pCurrent = (*aIter).second;
+ if (pCurrent)
+ pCurrent->resume();
+ ++aIter;
+ }
+ }
+
+ if (m_pDataSourcePropListener)
+ m_pDataSourcePropListener->resume();
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::ConnectToFields()
+{
+ ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
+ DBG_ASSERT(!pListeners || pListeners->size() == 0, "DbGridControl::ConnectToFields : please call DisconnectFromFields first !");
+
+ if (!pListeners)
+ {
+ pListeners = new ColumnFieldValueListeners;
+ m_pFieldListeners = pListeners;
+ }
+
+ for (sal_Int32 i=0; i<(sal_Int32)m_aColumns.Count(); ++i)
+ {
+ DbGridColumn* pCurrent = m_aColumns.GetObject(i);
+ sal_uInt16 nViewPos = pCurrent ? GetViewColumnPos(pCurrent->GetId()) : (sal_uInt16)-1;
+ if ((sal_uInt16)-1 == nViewPos)
+ continue;
+
+ Reference< XPropertySet > xField = pCurrent->GetField();
+ if (!xField.is())
+ continue;
+
+ // column is visible and bound here
+ GridFieldValueListener*& rpListener = (*pListeners)[pCurrent->GetId()];
+ DBG_ASSERT(!rpListener, "DbGridControl::ConnectToFields : already a listener for this column ?!");
+ rpListener = new GridFieldValueListener(*this, xField, pCurrent->GetId());
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::DisconnectFromFields()
+{
+ if (!m_pFieldListeners)
+ return;
+
+ ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
+ while (pListeners->size())
+ {
+#ifdef DBG_UTIL
+ sal_Int32 nOldSize = pListeners->size();
+#endif
+ pListeners->begin()->second->dispose();
+ DBG_ASSERT(nOldSize > (sal_Int32)pListeners->size(), "DbGridControl::DisconnectFromFields : dispose on a listener should result in a removal from my list !");
+ }
+
+ delete pListeners;
+ m_pFieldListeners = NULL;
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::FieldValueChanged(sal_uInt16 _nId, const PropertyChangeEvent& /*_evt*/)
+{
+ osl::MutexGuard aPreventDestruction(m_aDestructionSafety);
+ // needed as this may run in a thread other than the main one
+ if (GetRowStatus(GetCurRow()) != DbGridControl_Base::MODIFIED)
+ // all other cases are handled elsewhere
+ return;
+
+ DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(_nId));
+ if (pColumn)
+ {
+ sal_Bool bAcquiredPaintSafety = sal_False;
+ while (!m_bWantDestruction && !bAcquiredPaintSafety)
+ bAcquiredPaintSafety = Application::GetSolarMutex().tryToAcquire();
+
+ if (m_bWantDestruction)
+ { // at this moment, within another thread, our destructor tries to destroy the listener which called this method
+ // => don't do anything
+ // 73365 - 23.02.00 - FS
+ if (bAcquiredPaintSafety)
+ // though the above while-loop suggests that (m_bWantDestruction && bAcquiredPaintSafety) is impossible,
+ // it isnt't, as m_bWantDestruction isn't protected with any mutex
+ Application::GetSolarMutex().release();
+ return;
+ }
+ // here we got the solar mutex, transfer it to a guard for safety reasons
+ ::vos::OGuard aPaintSafety(Application::GetSolarMutex());
+ Application::GetSolarMutex().release();
+
+ // and finally do the update ...
+ pColumn->UpdateFromField(m_xCurrentRow, m_xFormatter);
+ RowModified(GetCurRow(), _nId);
+ }
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::FieldListenerDisposing(sal_uInt16 _nId)
+{
+ ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
+ if (!pListeners)
+ {
+ DBG_ERROR("DbGridControl::FieldListenerDisposing : invalid call (have no listener array) !");
+ return;
+ }
+
+ ColumnFieldValueListenersIterator aPos = pListeners->find(_nId);
+ if (aPos == pListeners->end())
+ {
+ DBG_ERROR("DbGridControl::FieldListenerDisposing : invalid call (did not find the listener) !");
+ return;
+ }
+
+ delete aPos->second;
+
+ pListeners->erase(aPos);
+}
+
+//------------------------------------------------------------------------------
+void DbGridControl::disposing(sal_uInt16 _nId, const EventObject& /*_rEvt*/)
+{
+ if (_nId == 0)
+ { // the seek cursor is beeing disposed
+ ::osl::MutexGuard aGuard(m_aAdjustSafety);
+ setDataSource(NULL,0); // our clone was disposed so we set our datasource to null to avoid later acces to it
+ if (m_nAsynAdjustEvent)
+ {
+ RemoveUserEvent(m_nAsynAdjustEvent);
+ m_nAsynAdjustEvent = 0;
+ }
+ }
+}
+// -----------------------------------------------------------------------------
+sal_Int32 DbGridControl::GetAccessibleControlCount() const
+{
+ return DbGridControl_Base::GetAccessibleControlCount() + 1; // the navigation control
+}
+// -----------------------------------------------------------------------------
+Reference<XAccessible > DbGridControl::CreateAccessibleControl( sal_Int32 _nIndex )
+{
+ Reference<XAccessible > xRet;
+ if ( _nIndex == DbGridControl_Base::GetAccessibleControlCount() )
+ {
+ xRet = m_aBar.GetAccessible();
+ }
+ else
+ xRet = DbGridControl_Base::CreateAccessibleControl( _nIndex );
+ return xRet;
+}
+// -----------------------------------------------------------------------------
+Reference< XAccessible > DbGridControl::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
+{
+ USHORT nColumnId = GetColumnId( _nColumnPos );
+ DbGridColumn* pColumn = m_aColumns.GetObject(GetModelColumnPos(nColumnId));
+ if ( pColumn )
+ {
+ Reference< ::com::sun::star::awt::XControl> xInt(pColumn->GetCell());
+ Reference< ::com::sun::star::awt::XCheckBox> xBox(xInt,UNO_QUERY);
+ if ( xBox.is() )
+ {
+ TriState eValue = STATE_NOCHECK;
+ switch( xBox->getState() )
+ {
+ case 0:
+ eValue = STATE_NOCHECK;
+ break;
+ case 1:
+ eValue = STATE_CHECK;
+ break;
+ case 2:
+ eValue = STATE_DONTKNOW;
+ break;
+ }
+ return DbGridControl_Base::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,eValue,TRUE );
+ }
+ }
+ return DbGridControl_Base::CreateAccessibleCell( _nRow, _nColumnPos );
+}
+// -----------------------------------------------------------------------------
+
+