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