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