/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: gridctrl.cxx,v $ * * $Revision: 1.75 $ * * last change: $Author: hr $ $Date: 2006-06-19 15:50:48 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library 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 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ************************************************************************/ #ifndef _SVX_FMHELP_HRC #include "fmhelp.hrc" #endif #ifndef _SVX_GRIDCTRL_HXX #include "gridctrl.hxx" #endif #ifndef _SVX_GRIDCELL_HXX #include "gridcell.hxx" #endif #ifndef SVX_DBTOOLSCLIENT_HXX #include "dbtoolsclient.hxx" #endif #ifndef _SVX_FMTOOLS_HXX #include "fmtools.hxx" #endif #ifndef _SVTOOLS_STRINGTRANSFER_HXX_ #include #endif #ifndef _SVX_FMPROP_HRC #include "fmprop.hrc" #endif #ifndef _SVTOOLS_STRINGTRANSFER_HXX_ #include #endif #ifndef _COM_SUN_STAR_SDBC_RESULTSETCONCURRENCY_HPP_ #include #endif #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLE_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDB_XRESULTSETACCESS_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_XRESULTSETUPDATE_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBCX_PRIVILEGE_HPP_ #include #endif #ifndef _COM_SUN_STAR_CONTAINER_XCHILD_HPP_ #include #endif #ifndef _COM_SUN_STAR_UTIL_XNUMBERFORMATTER_HPP_ #include #endif #ifndef _COM_SUN_STAR_UTIL_XNUMBERFORMATSSUPPLIER_HPP_ #include #endif #ifndef _COM_SUN_STAR_UTIL_XCLONEABLE_HPP_ #include #endif #ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_ #include #endif #ifndef _COM_SUN_STAR_BEANS_PROPERTYCHANGEEVENT_HPP_ #include #endif #ifndef _COMPHELPER_EXTRACT_HXX_ #include #endif #ifndef _TOOLS_RESID_HXX //autogen #include #endif #ifndef _SV_SOUND_HXX //autogen #include #endif #ifndef _SV_MENU_HXX //autogen #include #endif #ifndef _SVX_FMRESIDS_HRC #include "fmresids.hrc" #endif #ifndef _SVX_SVXIDS_HRC #include "svxids.hrc" #endif #ifndef _SHL_HXX #include #endif #ifndef _SVX_DIALMGR_HXX #include "dialmgr.hxx" #endif #ifndef _SVX_FMSERVS_HXX #include "fmservs.hxx" #endif #ifndef SVX_FORM_SDBDATACOLUMN_HXX #include "sdbdatacolumn.hxx" #endif #define CURSORPOSITION_UNKNOWN -2 #define HANDLE_ID 0 String INVALIDTEXT = String::CreateFromAscii("###"); String OBJECTTEXT = String::CreateFromAscii(""); #ifndef _COMPHELPER_STLTYPES_HXX_ #include #endif #ifndef _COMPHELPER_PROPERTY_HXX_ #include #endif #ifndef _TRACE_HXX_ #include "trace.hxx" #endif #include 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 GridFieldValueListener; DECLARE_STL_MAP(sal_uInt16, GridFieldValueListener*, ::std::less, 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_Int32 nRecord = GetValue(); if (nRecord < GetMin() || nRecord > GetMax()) return; else ((NavigationBar*)GetParent())->PositionDataSource(nRecord); } else if (rEvt.GetKeyCode() == KEY_TAB) GetParent()->GetParent()->GrabFocus(); else NumericField::KeyInput(rEvt); } //------------------------------------------------------------------------------ void DbGridControl::NavigationBar::AbsolutePos::LoseFocus() { NumericField::LoseFocus(); sal_Int32 nRecord = GetValue(); if (nRecord < GetMin() || nRecord > GetMax()) return; else { ((NavigationBar*)GetParent())->PositionDataSource(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_uInt16)(nTextWidth + aBorder.Width()); m_aAbsolute.SetPosPixel( Point(nX,nY)); m_aAbsolute.SetSizePixel( Size(3*nH,aRect.GetSize().Height()) ); // Heuristik XXXXXXX nX += (sal_uInt16)((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_uInt16)(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_uInt16)(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 = 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); { vos::OGuard aPaintSafety(Application::GetSolarMutex()); // we want to update only the window, not our parent, so lock the latter // (In fact, if we are in DbGridControl::RecalcRows, perhaps as a result of an setDataSource or // a VisibleRowsChanged, the grid will be frozen and a SeekRow triggered implicitly by the update // of pWnd will fail.) // (the SetUpdateMode call goes to the data window : it's sufficient to prevent SeekRow's, but it // avoids the Invalidate which would be triggered by BrowseBox::SetUpdateMode (which lead to massive // flicker when scrolling)) // FS - 06.10.99 // don't use SetUpdateMode in those situations as all necessary paints get lost DG // so update only if necessary (DG) if (pParent->IsPaintEnabled()) { pWnd->Update(); pWnd->Flush(); } } 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); if (STATE_CHANGE_ZOOM == nType) { Fraction aZoom = GetZoom(); Window* pWindows[] = { &m_aRecordText, &m_aAbsolute, &m_aRecordOf, &m_aRecordCount, &m_aFirstBtn, &m_aPrevBtn, &m_aNextBtn, &m_aLastBtn, &m_aNewBtn }; // not all of these controls need to know the new zoom, but to be sure ... Font aFont( IsControlFont() ? GetControlFont() : GetPointFont()); for (size_t i=0; i < sizeof(pWindows)/sizeof(pWindows[0]); ++i) { pWindows[i]->SetZoom(aZoom); pWindows[i]->SetZoomedPointFont(aFont); } // rearrange the controls m_nDefaultWidth = ArrangeControls(); } } //------------------------------------------------------------------------------ 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&) { OSL_ENSURE(0,"SQLException catched while getting the bookmark"); 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_pSelectionListener(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_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(); ImplInitSettings(sal_True,sal_True,sal_True); } //------------------------------------------------------------------------------ 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; } delete m_pDataCursor; delete m_pSeekCursor; DBG_DTOR(DbGridControl,NULL); } //------------------------------------------------------------------------------ void DbGridControl::StateChanged( StateChangedType nType ) { DbGridControl_Base::StateChanged( nType ); switch (nType) { case STATE_CHANGE_ZOOM: { ImplInitSettings( sal_True, sal_False, sal_False ); // forward the zoom factor to the navigation bar if (m_bNavigationBar) m_aBar.SetZoom(GetZoom()); // 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: ImplInitSettings( sal_True, sal_False, sal_False ); Invalidate(); break; case STATE_CHANGE_CONTROLFOREGROUND: ImplInitSettings( sal_False, sal_True, sal_False ); Invalidate(); break; case STATE_CHANGE_CONTROLBACKGROUND: ImplInitSettings( sal_False, sal_False, sal_True ); Invalidate(); break; } } //------------------------------------------------------------------------------ void DbGridControl::DataChanged( const DataChangedEvent& rDCEvt ) { DbGridControl_Base::DataChanged( rDCEvt ); if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS ) && (rDCEvt.GetFlags() & SETTINGS_STYLE) ) { ImplInitSettings( sal_True, sal_True, sal_True ); 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_pSelectionListener) m_pSelectionListener->selectionChanged(); } //------------------------------------------------------------------------------ void DbGridControl::ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground ) { for (sal_uInt32 i = 0; i < m_aColumns.Count(); i++) { DbGridColumn* pCol = m_aColumns.GetObject(i); if (pCol) pCol->ImplInitSettings(&GetDataWindow(), bFont, bForeground, bBackground); } if (bBackground) { 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; 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, GrantCellControlAccess /*_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; } // 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 Updatemöglichkeiten 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& ) { OSL_ENSURE( sal_False, "DbGridControl::setDataSource: caught an exception while checking the privileges!" ); } 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)); // 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()) m_nSeekPos = m_pSeekCursor->getRow() - 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