LibreOffice Module svx (master)  1
gridctrl.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/macros.h>
21 #include <sal/log.hxx>
22 #include <helpids.h>
23 #include <svx/gridctrl.hxx>
24 #include <gridcell.hxx>
25 #include <svx/fmtools.hxx>
27 #include <connectivity/dbtools.hxx>
29 
30 #include <fmprop.hxx>
31 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
32 #include <com/sun/star/accessibility/XAccessible.hpp>
33 #include <com/sun/star/sdb/XResultSetAccess.hpp>
34 #include <com/sun/star/sdb/RowChangeAction.hpp>
35 #include <com/sun/star/sdb/XRowsChangeBroadcaster.hpp>
36 #include <com/sun/star/sdbc/SQLException.hpp>
37 #include <com/sun/star/sdbc/XResultSetUpdate.hpp>
38 #include <com/sun/star/sdbcx/Privilege.hpp>
39 #include <com/sun/star/container/XChild.hpp>
40 #include <com/sun/star/util/NumberFormatter.hpp>
41 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
42 #include <com/sun/star/util/XCloneable.hpp>
43 #include <com/sun/star/beans/XPropertySet.hpp>
44 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
45 #include <com/sun/star/container/XIndexAccess.hpp>
46 #include <tools/diagnose_ex.h>
47 #include <tools/debug.hxx>
48 #include <tools/fract.hxx>
49 #include <vcl/builder.hxx>
50 #include <vcl/menu.hxx>
51 #include <vcl/settings.hxx>
52 #include <vcl/commandevent.hxx>
53 #include <vcl/svapp.hxx>
54 
55 #include <svx/strings.hrc>
56 
57 #include <svx/svxids.hrc>
58 #include <svx/dialmgr.hxx>
59 #include <fmservs.hxx>
60 #include <sdbdatacolumn.hxx>
61 
62 #include <comphelper/property.hxx>
63 #include <comphelper/types.hxx>
64 #include <cppuhelper/implbase.hxx>
65 
66 #include <algorithm>
67 #include <cstdlib>
68 #include <map>
69 #include <memory>
70 
71 using namespace ::dbtools;
72 using namespace ::dbtools::DBTypeConversion;
73 using namespace ::svxform;
74 using namespace ::svt;
75 using namespace ::com::sun::star::beans;
76 using namespace ::com::sun::star::lang;
77 using namespace ::com::sun::star::uno;
78 using namespace ::com::sun::star::sdbc;
79 using namespace ::com::sun::star::sdbcx;
80 using namespace ::com::sun::star::sdb;
81 using namespace ::com::sun::star::datatransfer;
82 using namespace ::com::sun::star::container;
83 using namespace com::sun::star::accessibility;
84 
85 #define ROWSTATUS(row) (!row.is() ? "NULL" : row->GetStatus() == GridRowStatus::Clean ? "CLEAN" : row->GetStatus() == GridRowStatus::Modified ? "MODIFIED" : row->GetStatus() == GridRowStatus::Deleted ? "DELETED" : "INVALID")
86 
87 static constexpr auto DEFAULT_BROWSE_MODE =
88  BrowserMode::COLUMNSELECTION
89  | BrowserMode::MULTISELECTION
90  | BrowserMode::KEEPHIGHLIGHT
91  | BrowserMode::TRACKING_TIPS
92  | BrowserMode::HLINES
93  | BrowserMode::VLINES
94  | BrowserMode::HEADERBAR_NEW;
95 
96 class RowSetEventListener : public ::cppu::WeakImplHelper<XRowsChangeListener>
97 {
99 public:
100  explicit RowSetEventListener(DbGridControl* i_pControl) : m_pControl(i_pControl)
101  {
102  }
103 
104 private:
105  // XEventListener
106  virtual void SAL_CALL disposing(const css::lang::EventObject& /*i_aEvt*/) override
107  {
108  }
109  virtual void SAL_CALL rowsChanged(const css::sdb::RowsChangeEvent& i_aEvt) override
110  {
111  if ( i_aEvt.Action == RowChangeAction::UPDATE )
112  {
114  CursorWrapper* pSeek = m_pControl->GetSeekCursor(aAccess);
115  const DbGridRowRef& rSeekRow = m_pControl->GetSeekRow(aAccess);
116  for(const Any& rBookmark : i_aEvt.Bookmarks)
117  {
118  pSeek->moveToBookmark(rBookmark);
119  // get the data
120  rSeekRow->SetState(pSeek, true);
121  sal_Int32 nSeekPos = pSeek->getRow() - 1;
122  m_pControl->SetSeekPos(nSeekPos,aAccess);
123  m_pControl->RowModified(nSeekPos);
124  }
125  }
126  }
127 };
128 
130 typedef std::map<sal_uInt16, GridFieldValueListener*> ColumnFieldValueListeners;
131 
133 {
134  osl::Mutex m_aMutex;
137  sal_uInt16 const m_nId;
138  sal_Int16 m_nSuspended;
139  bool m_bDisposed : 1;
140 
141 public:
142  GridFieldValueListener(DbGridControl& _rParent, const Reference< XPropertySet >& xField, sal_uInt16 _nId);
143  virtual ~GridFieldValueListener() override;
144 
145  virtual void _propertyChanged(const PropertyChangeEvent& evt) override;
146 
147  void suspend() { ++m_nSuspended; }
148  void resume() { --m_nSuspended; }
149 
150  void dispose();
151 };
152 
153 GridFieldValueListener::GridFieldValueListener(DbGridControl& _rParent, const Reference< XPropertySet >& _rField, sal_uInt16 _nId)
154  :OPropertyChangeListener(m_aMutex)
155  ,m_rParent(_rParent)
156  ,m_nId(_nId)
157  ,m_nSuspended(0)
158  ,m_bDisposed(false)
159 {
160  if (_rField.is())
161  {
162  m_pRealListener = new ::comphelper::OPropertyChangeMultiplexer(this, _rField);
163  m_pRealListener->addProperty(FM_PROP_VALUE);
164  }
165 }
166 
168 {
169  dispose();
170 }
171 
172 void GridFieldValueListener::_propertyChanged(const PropertyChangeEvent& /*_evt*/)
173 {
174  DBG_ASSERT(m_nSuspended>=0, "GridFieldValueListener::_propertyChanged : resume > suspend !");
175  if (m_nSuspended <= 0)
177 }
178 
180 {
181  if (m_bDisposed)
182  {
183  DBG_ASSERT(m_pRealListener.get() == nullptr, "GridFieldValueListener::dispose : inconsistent !");
184  return;
185  }
186 
187  if (m_pRealListener.is())
188  {
189  m_pRealListener->dispose();
190  m_pRealListener.clear();
191  }
192 
193  m_bDisposed = true;
195 }
196 
198 {
201 
202 public:
203  DisposeListenerGridBridge( DbGridControl& _rParent, const Reference< XComponent >& _rxObject);
204  virtual ~DisposeListenerGridBridge() override;
205 
206  virtual void disposing(sal_Int16 _nId) override { m_rParent.disposing(_nId); }
207 };
208 
209 DisposeListenerGridBridge::DisposeListenerGridBridge(DbGridControl& _rParent, const Reference< XComponent >& _rxObject)
211  ,m_rParent(_rParent)
212 {
213 
214  if (_rxObject.is())
215  {
216  m_xRealListener = new FmXDisposeMultiplexer(this, _rxObject);
217  }
218 }
219 
221 {
222  if (m_xRealListener.is())
223  {
224  m_xRealListener->dispose();
225  }
226 }
227 
229  {
240  };
241 
242 bool CompareBookmark(const Any& aLeft, const Any& aRight)
243 {
244  return aLeft == aRight;
245 }
246 
248 {
250 
251  // a DbGridControl has no mutex, so we use our own as the base class expects one
252  osl::Mutex m_aMutex;
253  sal_Int16 m_nSuspended;
254 
255 public:
256  explicit FmXGridSourcePropListener(DbGridControl* _pParent);
257 
258  void suspend() { ++m_nSuspended; }
259  void resume() { --m_nSuspended; }
260 
261  virtual void _propertyChanged(const PropertyChangeEvent& evt) override;
262 };
263 
265  :OPropertyChangeListener(m_aMutex)
266  ,m_pParent(_pParent)
267  ,m_nSuspended(0)
268 {
269  DBG_ASSERT(m_pParent, "FmXGridSourcePropListener::FmXGridSourcePropListener : invalid parent !");
270 }
271 
272 void FmXGridSourcePropListener::_propertyChanged(const PropertyChangeEvent& evt)
273 {
274  DBG_ASSERT(m_nSuspended>=0, "FmXGridSourcePropListener::_propertyChanged : resume > suspend !");
275  if (m_nSuspended <= 0)
277 }
278 
280  :NumericField(pParent, nStyle)
281 {
282  SetMin(1);
283  SetFirst(1);
284  SetSpinSize(1);
285 
286  SetDecimalDigits(0);
287  SetStrictFormat(true);
288 }
289 
291 {
292  if (rEvt.GetKeyCode() == KEY_RETURN && !GetText().isEmpty())
293  {
294  sal_Int64 nRecord = GetValue();
295  if (nRecord < GetMin() || nRecord > GetMax())
296  return;
297  else
298  static_cast<NavigationBar*>(GetParent())->PositionDataSource(static_cast<sal_Int32>(nRecord));
299  }
300  else if (rEvt.GetKeyCode() == KEY_TAB)
301  GetParent()->GetParent()->GrabFocus();
302  else
304 }
305 
307 {
309  sal_Int64 nRecord = GetValue();
310  if (nRecord < GetMin() || nRecord > GetMax())
311  return;
312  else
313  {
314  static_cast<NavigationBar*>(GetParent())->PositionDataSource(static_cast<sal_Int32>(nRecord));
316  }
317 }
318 
320 {
321  if (m_bPositioning)
322  return;
323  // the MoveToPosition may cause a LoseFocus which would lead to a second MoveToPosition,
324  // so protect against this recursion
325  m_bPositioning = true;
326  static_cast<DbGridControl*>(GetParent())->MoveToPosition(nRecord - 1);
327  m_bPositioning = false;
328 }
329 
331  :Control(pParent, 0)
341  ,m_nCurrentPos(-1)
342  ,m_bPositioning(false)
343 {
344  m_aFirstBtn->SetSymbol(SymbolType::FIRST);
345  m_aPrevBtn->SetSymbol(SymbolType::PREV);
346  m_aNextBtn->SetSymbol(SymbolType::NEXT);
347  m_aLastBtn->SetSymbol(SymbolType::LAST);
348  m_aNewBtn->SetModeImage(static_cast<DbGridControl*>(pParent)->GetImage(EditBrowseBox::NEW));
349 
357 
358  // set handlers for buttons
364 
365  m_aRecordText->SetText(SvxResId(RID_STR_REC_TEXT));
366  m_aRecordOf->SetText(SvxResId(RID_STR_REC_FROM_TEXT));
367  m_aRecordCount->SetText(OUString('?'));
368 
369  m_aFirstBtn->Disable();
370  m_aPrevBtn->Disable();
371  m_aNextBtn->Disable();
372  m_aLastBtn->Disable();
373  m_aNewBtn->Disable();
375  m_aRecordOf->Disable();
377  m_aAbsolute->Disable();
378 
379  AllSettings aSettings = m_aNextBtn->GetSettings();
380  MouseSettings aMouseSettings = aSettings.GetMouseSettings();
381  aMouseSettings.SetButtonRepeat(aMouseSettings.GetButtonRepeat() / 4);
382  aSettings.SetMouseSettings(aMouseSettings);
383  m_aNextBtn->SetSettings(aSettings, true);
384  m_aPrevBtn->SetSettings(aSettings, true);
385 
386  m_aFirstBtn->Show();
387  m_aPrevBtn->Show();
388  m_aNextBtn->Show();
389  m_aLastBtn->Show();
390  m_aNewBtn->Show();
391  m_aRecordText->Show();
392  m_aRecordOf->Show();
393  m_aRecordCount->Show();
394  m_aAbsolute->Show();
395 }
396 
397 
399 {
400  disposeOnce();
401 }
402 
404 {
405  m_aRecordText.disposeAndClear();
406  m_aAbsolute.disposeAndClear();
407  m_aRecordOf.disposeAndClear();
408  m_aRecordCount.disposeAndClear();
409  m_aFirstBtn.disposeAndClear();
410  m_aPrevBtn.disposeAndClear();
411  m_aNextBtn.disposeAndClear();
412  m_aLastBtn.disposeAndClear();
413  m_aNewBtn.disposeAndClear();
415 }
416 
417 namespace
418 {
419  void SetPosAndSize(Button& _rButton,Point& _rPos,const Size& _rSize)
420  {
421  _rButton.SetPosPixel( _rPos );
422  _rButton.SetSizePixel( _rSize );
423  _rPos.AdjustX(static_cast<sal_uInt16>(_rSize.Width()) );
424  }
425 }
426 
428 {
429  // positioning of the controls
430  // calculate base size
431  tools::Rectangle aRect(static_cast<DbGridControl*>(GetParent())->GetControlArea());
432  long nH = aRect.GetSize().Height();
433  long nW = GetParent()->GetOutputSizePixel().Width();
434  Size aBorder = LogicToPixel(Size(2, 2), MapMode(MapUnit::MapAppFont));
435  aBorder = Size(CalcZoom(aBorder.Width()), CalcZoom(aBorder.Height()));
436  sal_uInt16 nX = 1;
437  sal_uInt16 nY = 0;
438 
439  {
440  vcl::Font aApplFont(GetSettings().GetStyleSettings().GetToolFont());
441  m_aAbsolute->SetControlFont( aApplFont );
442  aApplFont.SetTransparent( true );
443  m_aRecordText->SetControlFont( aApplFont );
444  m_aRecordOf->SetControlFont( aApplFont );
445  m_aRecordCount->SetControlFont( aApplFont );
446  }
447 
448  // set size and position of the control
449  OUString aText = m_aRecordText->GetText();
450  long nTextWidth = m_aRecordText->GetTextWidth(aText);
451  m_aRecordText->SetPosPixel(Point(nX,nY));
452  m_aRecordText->SetSizePixel(Size(nTextWidth,nH));
453  nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
454 
455  // count an extra hairspace (U+200A) left and right
456  const OUString sevenDigits(m_aAbsolute->CreateFieldText(6000000));
457  const OUString hairSpace(u'\x200A');
458  OUString textPattern = hairSpace + sevenDigits + hairSpace;
459  nTextWidth = m_aAbsolute->GetTextWidth(textPattern);
460  m_aAbsolute->SetPosPixel(Point(nX,nY));
461  m_aAbsolute->SetSizePixel(Size(nTextWidth, nH));
462  nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
463 
464  aText = m_aRecordOf->GetText();
465  nTextWidth = m_aRecordOf->GetTextWidth(aText);
466  m_aRecordOf->SetPosPixel(Point(nX,nY));
467  m_aRecordOf->SetSizePixel(Size(nTextWidth,nH));
468  nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
469 
470  textPattern = sevenDigits + " * (" + sevenDigits + ")";
471  nTextWidth = m_aRecordCount->GetTextWidth(textPattern);
472  m_aRecordCount->SetPosPixel(Point(nX,nY));
473  m_aRecordCount->SetSizePixel(Size(nTextWidth,nH));
474  nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
475 
476  Point aButtonPos(nX,nY);
477  const Size aButtonSize(nH,nH);
478  SetPosAndSize(*m_aFirstBtn.get(), aButtonPos, aButtonSize);
479  SetPosAndSize(*m_aPrevBtn.get(), aButtonPos, aButtonSize);
480  SetPosAndSize(*m_aNextBtn.get(), aButtonPos, aButtonSize);
481  SetPosAndSize(*m_aLastBtn.get(), aButtonPos, aButtonSize);
482  SetPosAndSize(*m_aNewBtn.get(), aButtonPos, aButtonSize);
483 
484  nX = sal::static_int_cast< sal_uInt16 >(aButtonPos.X() + 1);
485 
486  nW = std::max(nW - GetSettings().GetStyleSettings().GetScrollBarSize(), 0L);
487 
488  if (nX > nW)
489  {
490  aButtonPos.setX( nW-nH );
491  m_aNewBtn->SetPosPixel(aButtonPos);
492  aButtonPos.AdjustX( -nH );
493  m_aLastBtn->SetPosPixel(aButtonPos);
494  aButtonPos.AdjustX( -nH );
495  m_aNextBtn->SetPosPixel(aButtonPos);
496  aButtonPos.AdjustX( -nH );
497  m_aPrevBtn->SetPosPixel(aButtonPos);
498  aButtonPos.AdjustX( -nH );
499  m_aFirstBtn->SetPosPixel(aButtonPos);
500 
501  auto nDiff = nX - nW;
502 
503  Size aSize = m_aAbsolute->GetSizePixel();
504  aSize.AdjustWidth( -(nDiff/3.0) );
505  m_aAbsolute->SetSizePixel(aSize);
506 
507  aSize = m_aRecordCount->GetSizePixel();
508  aSize.AdjustWidth( -(nDiff/3.0*2) );
509  m_aRecordCount->SetSizePixel(aSize);
510 
511  Point aPos = m_aRecordOf->GetPosPixel();
512  aPos.AdjustX( -(nDiff/3.0) );
513  m_aRecordOf->SetPosPixel(aPos);
514 
515  aPos = m_aRecordCount->GetPosPixel();
516  aPos.AdjustX( -(nDiff/3.0) );
517  m_aRecordCount->SetPosPixel(aPos);
518 
519  vcl::Window* pWindows[] =
520  {
521  m_aRecordText.get(),
522  m_aAbsolute.get(),
523  m_aRecordOf.get(),
524  m_aRecordCount.get(),
525  m_aFirstBtn.get(),
526  m_aPrevBtn.get(),
527  m_aNextBtn.get(),
528  m_aLastBtn.get(),
529  m_aNewBtn.get()
530  };
531 
532  for (vcl::Window* pWindow : pWindows)
533  {
534  if (pWindow->GetPosPixel().X() < 0)
535  pWindow->SetSizePixel(Size(0, nH));
536  aSize = pWindow->GetSizePixel();
537  auto nExcess = (pWindow->GetPosPixel().X() + aSize.Width()) - nW;
538  if (nExcess > 0)
539  {
540  aSize.AdjustWidth( -nExcess );
541  pWindow->SetSizePixel(aSize);
542  }
543  }
544 
545  nX = nW;
546  }
547 
548  return nX;
549 }
550 
551 IMPL_LINK(DbGridControl::NavigationBar, OnClick, Button *, pButton, void )
552 {
553  DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
554 
555  if (pParent->m_aMasterSlotExecutor.IsSet())
556  {
557  bool lResult = false;
558  if (pButton == m_aFirstBtn.get())
560  else if( pButton == m_aPrevBtn.get() )
562  else if( pButton == m_aNextBtn.get() )
564  else if( pButton == m_aLastBtn.get() )
566  else if( pButton == m_aNewBtn.get() )
568 
569  if (lResult)
570  // the link already handled it
571  return;
572  }
573 
574  if (pButton == m_aFirstBtn.get())
575  pParent->MoveToFirst();
576  else if( pButton == m_aPrevBtn.get() )
577  pParent->MoveToPrev();
578  else if( pButton == m_aNextBtn.get() )
579  pParent->MoveToNext();
580  else if( pButton == m_aLastBtn.get() )
581  pParent->MoveToLast();
582  else if( pButton == m_aNewBtn.get() )
583  pParent->AppendNew();
584 }
585 
586 void DbGridControl::NavigationBar::InvalidateAll(sal_Int32 nCurrentPos, bool bAll)
587 {
588  if (m_nCurrentPos != nCurrentPos || nCurrentPos < 0 || bAll)
589  {
590  DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
591 
592  sal_Int32 nAdjustedRowCount = pParent->GetRowCount() - ((pParent->GetOptions() & DbGridControlOptions::Insert) ? 2 : 1);
593 
594  // check if everything needs to be invalidated
595  bAll = bAll || m_nCurrentPos <= 0;
596  bAll = bAll || nCurrentPos <= 0;
597  bAll = bAll || m_nCurrentPos >= nAdjustedRowCount;
598  bAll = bAll || nCurrentPos >= nAdjustedRowCount;
599 
600  if ( bAll )
601  {
602  m_nCurrentPos = nCurrentPos;
603  int i = 0;
605  SetState(ControlMap[i++]);
606  }
607  else // is in the center
608  {
609  m_nCurrentPos = nCurrentPos;
612  }
613  }
614 }
615 
617 {
618  DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
619 
620  if (!pParent->IsOpen() || pParent->IsDesignMode() || !pParent->IsEnabled()
621  || pParent->IsFilterMode() )
622  return false;
623  else
624  {
625  // check if we have a master state provider
626  if (pParent->m_aMasterStateProvider.IsSet())
627  {
628  long nState = pParent->m_aMasterStateProvider.Call( nWhich );
629  if (nState>=0)
630  return (nState>0);
631  }
632 
633  bool bAvailable = true;
634 
635  switch (nWhich)
636  {
639  bAvailable = m_nCurrentPos > 0;
640  break;
642  if(pParent->m_bRecordCountFinal)
643  {
644  bAvailable = m_nCurrentPos < pParent->GetRowCount() - 1;
645  if (!bAvailable && pParent->GetOptions() & DbGridControlOptions::Insert)
646  bAvailable = (m_nCurrentPos == pParent->GetRowCount() - 2) && pParent->IsModified();
647  }
648  break;
650  if(pParent->m_bRecordCountFinal)
651  {
652  if (pParent->GetOptions() & DbGridControlOptions::Insert)
653  bAvailable = pParent->IsCurrentAppending() ? pParent->GetRowCount() > 1 :
654  m_nCurrentPos != pParent->GetRowCount() - 2;
655  else
656  bAvailable = m_nCurrentPos != pParent->GetRowCount() - 1;
657  }
658  break;
660  bAvailable = (pParent->GetOptions() & DbGridControlOptions::Insert) && pParent->GetRowCount() && m_nCurrentPos < pParent->GetRowCount() - 1;
661  break;
663  bAvailable = pParent->GetRowCount() > 0;
664  break;
665  default: break;
666  }
667  return bAvailable;
668  }
669 }
670 
672 {
673  bool bAvailable = GetState(nWhich);
674  DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
675  vcl::Window* pWnd = nullptr;
676  switch (nWhich)
677  {
679  pWnd = m_aFirstBtn.get();
680  break;
682  pWnd = m_aPrevBtn.get();
683  break;
685  pWnd = m_aNextBtn.get();
686  break;
688  pWnd = m_aLastBtn.get();
689  break;
691  pWnd = m_aNewBtn.get();
692  break;
694  pWnd = m_aAbsolute.get();
695  if (bAvailable)
696  {
697  if (pParent->m_nTotalCount >= 0)
698  {
699  if (pParent->IsCurrentAppending())
700  m_aAbsolute->SetMax(pParent->m_nTotalCount + 1);
701  else
702  m_aAbsolute->SetMax(pParent->m_nTotalCount);
703  }
704  else
705  m_aAbsolute->SetMax(LONG_MAX);
706 
707  m_aAbsolute->SetValue(m_nCurrentPos + 1);
708  }
709  else
710  m_aAbsolute->SetText(OUString());
711  break;
713  pWnd = m_aRecordText.get();
714  break;
716  pWnd = m_aRecordOf.get();
717  break;
719  {
720  pWnd = m_aRecordCount.get();
721  OUString aText;
722  if (bAvailable)
723  {
724  if (pParent->GetOptions() & DbGridControlOptions::Insert)
725  {
726  if (pParent->IsCurrentAppending() && !pParent->IsModified())
727  aText = m_aAbsolute->CreateFieldText(pParent->GetRowCount());
728  else
729  aText = m_aAbsolute->CreateFieldText(pParent->GetRowCount() - 1);
730  }
731  else
732  aText = m_aAbsolute->CreateFieldText(pParent->GetRowCount());
733  if(!pParent->m_bRecordCountFinal)
734  aText += " *";
735  }
736  else
737  aText.clear();
738 
739  // add the number of selected rows, if applicable
740  if (pParent->GetSelectRowCount())
741  {
742  OUString aExtendedInfo = aText + " (" +
743  m_aAbsolute->CreateFieldText(pParent->GetSelectRowCount()) + ")";
744  pWnd->SetText(aExtendedInfo);
745  }
746  else
747  pWnd->SetText(aText);
748 
749  pParent->SetRealRowCount(aText);
750  } break;
751  default: break;
752  }
753  DBG_ASSERT(pWnd, "no window");
754  if (pWnd && (pWnd->IsEnabled() != bAvailable))
755  // this "pWnd->IsEnabled() != bAvailable" is a little hack : Window::Enable always generates a user
756  // event (ImplGenerateMouseMove) even if nothing happened. This may lead to some unwanted effects, so we
757  // do this check.
758  // For further explanation see Bug 69900.
759  pWnd->Enable(bAvailable);
760 }
761 
763 {
764  Control::Resize();
765  ArrangeControls();
766 }
767 
769 {
770  Control::Paint(rRenderContext, rRect);
771  Point aAbsolutePos = m_aAbsolute->GetPosPixel();
772  Size aAbsoluteSize = m_aAbsolute->GetSizePixel();
773 
774  rRenderContext.DrawLine(Point(aAbsolutePos.X() - 1, 0 ),
775  Point(aAbsolutePos.X() - 1, aAbsolutePos.Y() + aAbsoluteSize.Height()));
776 
777  rRenderContext.DrawLine(Point(aAbsolutePos.X() + aAbsoluteSize.Width() + 1, 0 ),
778  Point(aAbsolutePos.X() + aAbsoluteSize.Width() + 1, aAbsolutePos.Y() + aAbsoluteSize.Height()));
779 }
780 
782 {
783  Control::StateChanged(nType);
784 
785  vcl::Window* pWindows[] =
786  {
787  m_aRecordText.get(),
788  m_aAbsolute.get(),
789  m_aRecordOf.get(),
790  m_aRecordCount.get(),
791  m_aFirstBtn.get(),
792  m_aPrevBtn.get(),
793  m_aNextBtn.get(),
794  m_aLastBtn.get(),
795  m_aNewBtn.get()
796  };
797 
798  switch ( nType )
799  {
800  case StateChangedType::Mirroring:
801  {
802  bool bIsRTLEnabled = IsRTLEnabled();
803  for (vcl::Window* pWindow : pWindows)
804  pWindow->EnableRTL( bIsRTLEnabled );
805  }
806  break;
807 
808  case StateChangedType::Zoom:
809  {
810  Fraction aZoom = GetZoom();
811 
812  // not all of these controls need to know the new zoom, but to be sure ...
813  vcl::Font aFont(GetSettings().GetStyleSettings().GetToolFont());
814  if (IsControlFont())
815  aFont.Merge(GetControlFont());
816 
817  for (vcl::Window* pWindow : pWindows)
818  {
819  pWindow->SetZoom(aZoom);
820  pWindow->SetZoomedPointFont(*pWindow, aFont);
821  }
822 
823  SetZoomedPointFont(*this, aFont);
824 
825  // rearrange the controls
826  ArrangeControls();
827  }
828  break;
829  default:;
830  }
831 }
832 
833 DbGridRow::DbGridRow():m_eStatus(GridRowStatus::Clean), m_bIsNew(true)
834 {}
835 
836 DbGridRow::DbGridRow(CursorWrapper* pCur, bool bPaintCursor)
837  :m_bIsNew(false)
838 {
839 
840  if (pCur && pCur->Is())
841  {
842  Reference< XIndexAccess > xColumns(pCur->getColumns(), UNO_QUERY);
843  for (sal_Int32 i = 0; i < xColumns->getCount(); ++i)
844  {
845  Reference< XPropertySet > xColSet(
846  xColumns->getByIndex(i), css::uno::UNO_QUERY);
847  m_aVariants.emplace_back( new DataColumn(xColSet) );
848  }
849 
850  if (pCur->rowDeleted())
852  else
853  {
854  if (bPaintCursor)
856  else
857  {
858  const Reference< XPropertySet >& xSet = pCur->getPropertySet();
859  if (xSet.is())
860  {
861  m_bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
862  if (!m_bIsNew && (pCur->isAfterLast() || pCur->isBeforeFirst()))
864  else if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED)))
866  else
868  }
869  else
871  }
872  }
873  if (!m_bIsNew && IsValid())
874  m_aBookmark = pCur->getBookmark();
875  else
876  m_aBookmark = Any();
877  }
878  else
880 }
881 
883 {
884 }
885 
886 void DbGridRow::SetState(CursorWrapper* pCur, bool bPaintCursor)
887 {
888  if (pCur && pCur->Is())
889  {
890  if (pCur->rowDeleted())
891  {
893  m_bIsNew = false;
894  }
895  else
896  {
898  if (!bPaintCursor)
899  {
900  const Reference< XPropertySet >& xSet = pCur->getPropertySet();
901  DBG_ASSERT(xSet.is(), "DbGridRow::SetState : invalid cursor !");
902 
903  if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED)))
905  m_bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
906  }
907  else
908  m_bIsNew = false;
909  }
910 
911  try
912  {
913  if (!m_bIsNew && IsValid())
914  m_aBookmark = pCur->getBookmark();
915  else
916  m_aBookmark = Any();
917  }
918  catch(SQLException&)
919  {
921  m_aBookmark = Any();
923  m_bIsNew = false;
924  }
925  }
926  else
927  {
928  m_aBookmark = Any();
930  m_bIsNew = false;
931  }
932 }
933 
935  Reference< XComponentContext > const & _rxContext,
936  vcl::Window* pParent,
937  WinBits nBits)
938  :EditBrowseBox(pParent, EditBrowseBoxFlags::NONE, nBits, DEFAULT_BROWSE_MODE )
939  ,m_xContext(_rxContext)
940  ,m_aBar(VclPtr<DbGridControl::NavigationBar>::Create(this))
941  ,m_nAsynAdjustEvent(nullptr)
942  ,m_pDataSourcePropListener(nullptr)
943  ,m_pFieldListeners(nullptr)
944  ,m_pGridListener(nullptr)
945  ,m_nSeekPos(-1)
946  ,m_nTotalCount(-1)
947  ,m_aNullDate(::dbtools::DBTypeConversion::getStandardDate())
948  ,m_nMode(DEFAULT_BROWSE_MODE)
949  ,m_nCurrentPos(-1)
950  ,m_nDeleteEvent(nullptr)
951  ,m_nOptions(DbGridControlOptions::Readonly)
953  ,m_nLastColId(sal_uInt16(-1))
954  ,m_nLastRowId(-1)
955  ,m_bDesignMode(false)
956  ,m_bRecordCountFinal(false)
957  ,m_bNavigationBar(true)
958  ,m_bSynchDisplay(true)
959  ,m_bHandle(true)
960  ,m_bFilterMode(false)
961  ,m_bWantDestruction(false)
962  ,m_bPendingAdjustRows(false)
963  ,m_bHideScrollbars( false )
964  ,m_bUpdating(false)
965 {
966 
967  OUString sName(SvxResId(RID_STR_NAVIGATIONBAR));
968  m_aBar->SetAccessibleName(sName);
969  m_aBar->Show();
971 }
972 
974 {
975  // BrowseBox has problems when painting without a handleColumn (hide it here)
976  if (HasHandle())
978  else
980 }
981 
983 {
984  VclPtr<BrowserHeader> pNewHeader = CreateHeaderBar(this);
985  pHeader->SetMouseTransparent(false);
986 
987  SetHeaderBar(pNewHeader);
988  SetMode(m_nMode);
989  SetCursorColor(Color(0xFF, 0, 0));
990 
992 }
993 
995 {
996  disposeOnce();
997 }
998 
1000 {
1001  if (!IsDisposed())
1002  {
1003  RemoveColumns();
1004 
1005  m_bWantDestruction = true;
1006  osl::MutexGuard aGuard(m_aDestructionSafety);
1007  if (m_pFieldListeners)
1009  m_pCursorDisposeListener.reset();
1010  }
1011 
1012  if (m_nDeleteEvent)
1014 
1016  {
1017  m_pDataSourcePropMultiplexer->dispose();
1018  m_pDataSourcePropMultiplexer.clear(); // this should delete the multiplexer
1020  m_pDataSourcePropListener = nullptr;
1021  }
1022  m_xRowSetListener.clear();
1023 
1024  m_pDataCursor.reset();
1025  m_pSeekCursor.reset();
1026 
1027  m_aBar.disposeAndClear();
1028 
1029  EditBrowseBox::dispose();
1030 }
1031 
1033 {
1034  EditBrowseBox::StateChanged( nType );
1035 
1036  switch (nType)
1037  {
1038  case StateChangedType::Mirroring:
1040  Invalidate();
1041  break;
1042 
1043  case StateChangedType::Zoom:
1044  {
1046 
1047  // and give it a chance to rearrange
1048  Point aPoint = GetControlArea().TopLeft();
1049  sal_uInt16 nX = static_cast<sal_uInt16>(aPoint.X());
1050  ArrangeControls(nX, static_cast<sal_uInt16>(aPoint.Y()));
1051  ReserveControlArea(nX);
1052  }
1053  break;
1054  case StateChangedType::ControlFont:
1056  Invalidate();
1057  break;
1058  case StateChangedType::ControlForeground:
1060  Invalidate();
1061  break;
1062  case StateChangedType::ControlBackground:
1064  Invalidate();
1065  break;
1066  default:;
1067  }
1068 }
1069 
1071 {
1072  EditBrowseBox::DataChanged( rDCEvt );
1073  if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS ) &&
1074  (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
1075  {
1077  Invalidate();
1078  }
1079 }
1080 
1082 {
1083  EditBrowseBox::Select();
1084 
1085  // as the selected rows may have changed, update the according display in our navigation bar
1087 
1088  if (m_pGridListener)
1090 }
1091 
1093 {
1094  for (auto const & pCol : m_aColumns)
1095  {
1096  pCol->ImplInitWindow( GetDataWindow(), _eInitWhat );
1097  }
1098 
1099  if ( _eInitWhat & InitWindowFacet::WritingMode )
1100  {
1101  if ( m_bNavigationBar )
1102  {
1103  m_aBar->EnableRTL( IsRTLEnabled() );
1104  }
1105  }
1106 
1107  if ( _eInitWhat & InitWindowFacet::Font )
1108  {
1109  if ( m_bNavigationBar )
1110  {
1111  vcl::Font aFont = m_aBar->GetSettings().GetStyleSettings().GetToolFont();
1112  if ( IsControlFont() )
1113  m_aBar->SetControlFont( GetControlFont() );
1114  else
1115  m_aBar->SetControlFont();
1116 
1117  m_aBar->SetZoom( GetZoom() );
1118  }
1119  }
1120 
1121  if ( _eInitWhat & InitWindowFacet::Background )
1122  {
1123  if (IsControlBackground())
1124  {
1125  GetDataWindow().SetBackground(GetControlBackground());
1126  GetDataWindow().SetControlBackground(GetControlBackground());
1127  GetDataWindow().SetFillColor(GetControlBackground());
1128  }
1129  else
1130  {
1132  GetDataWindow().SetFillColor(GetFillColor());
1133  }
1134  }
1135 }
1136 
1137 void DbGridControl::RemoveRows(bool bNewCursor)
1138 {
1139  // Did the data cursor change?
1140  if (!bNewCursor)
1141  {
1142  m_pSeekCursor.reset();
1144  m_nCurrentPos = m_nSeekPos = -1;
1146 
1147  RowRemoved(0, GetRowCount(), false);
1148  m_nTotalCount = -1;
1149  }
1150  else
1151  {
1152  RemoveRows();
1153  }
1154 }
1155 
1157 {
1158  // we're going to remove all columns and all row, so deactivate the current cell
1159  if (IsEditing())
1160  DeactivateCell();
1161 
1162  // de-initialize all columns
1163  // if there are columns, free all controllers
1164  for (auto const & pColumn : m_aColumns)
1165  pColumn->Clear();
1166 
1167  m_pSeekCursor.reset();
1168  m_pDataCursor.reset();
1169 
1173 
1174  // reset number of sentences to zero in the browser
1175  EditBrowseBox::RemoveRows();
1176  m_aBar->InvalidateAll(m_nCurrentPos, true);
1177 }
1178 
1179 void DbGridControl::ArrangeControls(sal_uInt16& nX, sal_uInt16 nY)
1180 {
1181  // positioning of the controls
1182  if (m_bNavigationBar)
1183  {
1185  m_aBar->SetPosSizePixel(Point(0, nY + 1), Size(aRect.GetSize().Width(), aRect.GetSize().Height() - 1));
1186  nX = m_aBar->ArrangeControls();
1187  }
1188 }
1189 
1191 {
1192  if (m_bHandle == bEnable)
1193  return;
1194 
1195  // HandleColumn is only hidden because there are a lot of problems while painting otherwise
1197  m_bHandle = bEnable;
1199 }
1200 
1201 namespace
1202 {
1203  bool adjustModeForScrollbars( BrowserMode& _rMode, bool _bNavigationBar, bool _bHideScrollbars )
1204  {
1205  BrowserMode nOldMode = _rMode;
1206 
1207  if ( !_bNavigationBar )
1208  {
1209  _rMode &= ~BrowserMode::AUTO_HSCROLL;
1210  }
1211 
1212  if ( _bHideScrollbars )
1213  {
1214  _rMode |= BrowserMode::NO_HSCROLL | BrowserMode::NO_VSCROLL;
1215  _rMode &= ~BrowserMode( BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL );
1216  }
1217  else
1218  {
1219  _rMode |= BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL;
1220  _rMode &= ~BrowserMode( BrowserMode::NO_HSCROLL | BrowserMode::NO_VSCROLL );
1221  }
1222 
1223  // note: if we have a navigation bar, we always have an AUTO_HSCROLL. In particular,
1224  // _bHideScrollbars is ignored then
1225  if ( _bNavigationBar )
1226  {
1227  _rMode |= BrowserMode::AUTO_HSCROLL;
1228  _rMode &= ~BrowserMode::NO_HSCROLL;
1229  }
1230 
1231  return nOldMode != _rMode;
1232  }
1233 }
1234 
1236 {
1237  if (m_bNavigationBar == bEnable)
1238  return;
1239 
1240  m_bNavigationBar = bEnable;
1241 
1242  if (bEnable)
1243  {
1244  m_aBar->Show();
1245  m_aBar->Enable();
1246  m_aBar->InvalidateAll(m_nCurrentPos, true);
1247 
1248  if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1249  SetMode( m_nMode );
1250 
1251  // get size of the reserved ControlArea
1252  Point aPoint = GetControlArea().TopLeft();
1253  sal_uInt16 nX = static_cast<sal_uInt16>(aPoint.X());
1254 
1255  ArrangeControls(nX, static_cast<sal_uInt16>(aPoint.Y()));
1256  ReserveControlArea(nX);
1257  }
1258  else
1259  {
1260  m_aBar->Hide();
1261  m_aBar->Disable();
1262 
1263  if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1264  SetMode( m_nMode );
1265 
1267  }
1268 }
1269 
1271 {
1273  "DbGridControl::SetOptions : please do not call when editing a record (things are much easier this way ;) !");
1274 
1275  // for the next setDataSource (which is triggered by a refresh, for instance)
1276  m_nOptionMask = nOpt;
1277 
1278  // normalize the new options
1279  Reference< XPropertySet > xDataSourceSet = m_pDataCursor->getPropertySet();
1280  if (xDataSourceSet.is())
1281  {
1282  // check what kind of options are available
1283  sal_Int32 nPrivileges = 0;
1284  xDataSourceSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
1285  if ((nPrivileges & Privilege::INSERT) == 0)
1286  nOpt &= ~DbGridControlOptions::Insert;
1287  if ((nPrivileges & Privilege::UPDATE) == 0)
1288  nOpt &= ~DbGridControlOptions::Update;
1289  if ((nPrivileges & Privilege::DELETE) == 0)
1290  nOpt &= ~DbGridControlOptions::Delete;
1291  }
1292  else
1294 
1295  // need to do something after that ?
1296  if (nOpt == m_nOptions)
1297  return m_nOptions;
1298 
1299  // the 'update' option only affects our BrowserMode (with or w/o focus rect)
1300  BrowserMode nNewMode = m_nMode;
1301  if (!(m_nMode & BrowserMode::CURSOR_WO_FOCUS))
1302  {
1303  if (nOpt & DbGridControlOptions::Update)
1304  nNewMode |= BrowserMode::HIDECURSOR;
1305  else
1306  nNewMode &= ~BrowserMode::HIDECURSOR;
1307  }
1308  else
1309  nNewMode &= ~BrowserMode::HIDECURSOR;
1310  // should not be necessary if EnablePermanentCursor is used to change the cursor behaviour, but to be sure ...
1311 
1312  if (nNewMode != m_nMode)
1313  {
1314  SetMode(nNewMode);
1315  m_nMode = nNewMode;
1316  }
1317 
1318  // _after_ setting the mode because this results in an ActivateCell
1319  DeactivateCell();
1320 
1321  bool bInsertChanged = (nOpt & DbGridControlOptions::Insert) != (m_nOptions & DbGridControlOptions::Insert);
1322  m_nOptions = nOpt;
1323  // we need to set this before the code below because it indirectly uses m_nOptions
1324 
1325  // the 'insert' option affects our empty row
1326  if (bInsertChanged)
1327  {
1328  if (m_nOptions & DbGridControlOptions::Insert)
1329  { // the insert option is to be set
1330  m_xEmptyRow = new DbGridRow();
1332  }
1333  else
1334  { // the insert option is to be reset
1335  m_xEmptyRow = nullptr;
1336  if ((GetCurRow() == GetRowCount() - 1) && (GetCurRow() > 0))
1339  }
1340  }
1341 
1342  // the 'delete' options has no immediate consequences
1343 
1344  ActivateCell();
1345  Invalidate();
1346  return m_nOptions;
1347 }
1348 
1350 {
1351  if ( m_bHideScrollbars )
1352  return;
1353 
1354  m_bHideScrollbars = true;
1355 
1356  if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1357  SetMode( m_nMode );
1358 }
1359 
1361 {
1362  if (IsPermanentCursorEnabled() == bEnable)
1363  return;
1364 
1365  if (bEnable)
1366  {
1367  m_nMode &= ~BrowserMode::HIDECURSOR; // without this BrowserMode::CURSOR_WO_FOCUS won't have any affect
1368  m_nMode |= BrowserMode::CURSOR_WO_FOCUS;
1369  }
1370  else
1371  {
1373  m_nMode |= BrowserMode::HIDECURSOR; // no cursor at all
1374  else
1375  m_nMode &= ~BrowserMode::HIDECURSOR; // at least the "non-permanent" cursor
1376 
1377  m_nMode &= ~BrowserMode::CURSOR_WO_FOCUS;
1378  }
1379  SetMode(m_nMode);
1380 
1381  bool bWasEditing = IsEditing();
1382  DeactivateCell();
1383  if (bWasEditing)
1384  ActivateCell();
1385 }
1386 
1388 {
1389  return (m_nMode & BrowserMode::CURSOR_WO_FOCUS) && !(m_nMode & BrowserMode::HIDECURSOR);
1390 }
1391 
1392 void DbGridControl::refreshController(sal_uInt16 _nColId, GrantControlAccess /*_aAccess*/)
1393 {
1394  if ((GetCurColumnId() == _nColId) && IsEditing())
1395  { // the controller which is currently active needs to be refreshed
1396  DeactivateCell();
1397  ActivateCell();
1398  }
1399 }
1400 
1401 void DbGridControl::setDataSource(const Reference< XRowSet >& _xCursor, DbGridControlOptions nOpts)
1402 {
1403  if (!_xCursor.is() && !m_pDataCursor)
1404  return;
1405 
1407  {
1408  m_pDataSourcePropMultiplexer->dispose();
1409  m_pDataSourcePropMultiplexer.clear(); // this should delete the multiplexer
1411  m_pDataSourcePropListener = nullptr;
1412  }
1413  m_xRowSetListener.clear();
1414 
1415  // is the new cursor valid ?
1416  // the cursor is only valid if it contains some columns
1417  // if there is no cursor or the cursor is not valid we have to clean up and leave
1418  if (!_xCursor.is() || !Reference< XColumnsSupplier > (_xCursor, UNO_QUERY_THROW)->getColumns()->hasElements())
1419  {
1420  RemoveRows();
1421  return;
1422  }
1423 
1424  // did the data cursor change?
1425  sal_uInt16 nCurPos = GetColumnPos(GetCurColumnId());
1426 
1427  SetUpdateMode(false);
1428  RemoveRows();
1430 
1431  m_pCursorDisposeListener.reset();
1432 
1433  {
1434  ::osl::MutexGuard aGuard(m_aAdjustSafety);
1435  if (m_nAsynAdjustEvent)
1436  {
1437  // the adjust was thought to work with the old cursor which we don't have anymore
1438  RemoveUserEvent(m_nAsynAdjustEvent);
1439  m_nAsynAdjustEvent = nullptr;
1440  }
1441  }
1442 
1443  // get a new formatter and data cursor
1444  m_xFormatter = nullptr;
1445  Reference< css::util::XNumberFormatsSupplier > xSupplier = getNumberFormats(getConnection(_xCursor), true);
1446  if (xSupplier.is())
1447  {
1448  m_xFormatter = css::util::NumberFormatter::create(m_xContext);
1449  m_xFormatter->attachNumberFormatsSupplier(xSupplier);
1450 
1451  // retrieve the datebase of the Numberformatter
1452  try
1453  {
1454  xSupplier->getNumberFormatSettings()->getPropertyValue("NullDate") >>= m_aNullDate;
1455  }
1456  catch(Exception&)
1457  {
1458  }
1459  }
1460 
1461  m_pDataCursor.reset(new CursorWrapper(_xCursor));
1462 
1463  // now create a cursor for painting rows
1464  // we need that cursor only if we are not in insert only mode
1465  Reference< XResultSet > xClone;
1466  Reference< XResultSetAccess > xAccess( _xCursor, UNO_QUERY );
1467  try
1468  {
1469  xClone = xAccess.is() ? xAccess->createResultSet() : Reference< XResultSet > ();
1470  }
1471  catch(Exception&)
1472  {
1473  }
1474  if (xClone.is())
1475  m_pSeekCursor.reset(new CursorWrapper(xClone));
1476 
1477  // property listening on the data source
1478  // (Normally one class would be sufficient : the multiplexer which could forward the property change to us.
1479  // But for that we would have been derived from ::comphelper::OPropertyChangeListener, which isn't exported.
1480  // So we introduce a second class, which is a ::comphelper::OPropertyChangeListener (in the implementation file we know this class)
1481  // and forwards the property changes to our special method "DataSourcePropertyChanged".)
1482  if (m_pDataCursor)
1483  {
1485  m_pDataSourcePropMultiplexer = new ::comphelper::OPropertyChangeMultiplexer(m_pDataSourcePropListener, m_pDataCursor->getPropertySet() );
1488  }
1489 
1490  BrowserMode nOldMode = m_nMode;
1491  if (m_pSeekCursor)
1492  {
1493  try
1494  {
1495  Reference< XPropertySet > xSet(_xCursor, UNO_QUERY);
1496  if (xSet.is())
1497  {
1498  // check what kind of options are available
1499  sal_Int32 nConcurrency = ResultSetConcurrency::READ_ONLY;
1500  xSet->getPropertyValue(FM_PROP_RESULTSET_CONCURRENCY) >>= nConcurrency;
1501 
1502  if ( ResultSetConcurrency::UPDATABLE == nConcurrency )
1503  {
1504  sal_Int32 nPrivileges = 0;
1505  xSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
1506 
1507  // Insert Option should be set if insert only otherwise you won't see any rows
1508  // and no insertion is possible
1510  && ((nPrivileges & Privilege::INSERT) == Privilege::INSERT) && (nOpts & DbGridControlOptions::Insert))
1513  && ((nPrivileges & Privilege::UPDATE) == Privilege::UPDATE) && (nOpts & DbGridControlOptions::Update))
1516  && ((nPrivileges & Privilege::DELETE) == Privilege::DELETE) && (nOpts & DbGridControlOptions::Delete))
1518  }
1519  }
1520  }
1521  catch( const Exception& )
1522  {
1523  DBG_UNHANDLED_EXCEPTION("svx");
1524  }
1525 
1526  bool bPermanentCursor = IsPermanentCursorEnabled();
1528 
1529  if ( bPermanentCursor )
1530  {
1531  m_nMode |= BrowserMode::CURSOR_WO_FOCUS;
1532  m_nMode &= ~BrowserMode::HIDECURSOR;
1533  }
1534  else
1535  {
1536  // updates are allowed -> no focus rectangle
1538  m_nMode |= BrowserMode::HIDECURSOR;
1539  }
1540 
1541  m_nMode |= BrowserMode::MULTISELECTION;
1542 
1543  adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars );
1544 
1545  Reference< XColumnsSupplier > xSupplyColumns(_xCursor, UNO_QUERY);
1546  if (xSupplyColumns.is())
1547  InitColumnsByFields(Reference< XIndexAccess > (xSupplyColumns->getColumns(), UNO_QUERY));
1548 
1549  ConnectToFields();
1550  }
1551 
1552  sal_uInt32 nRecordCount(0);
1553 
1554  if (m_pSeekCursor)
1555  {
1556  Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
1557  xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
1558  m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
1559 
1561  Reference< XRowsChangeBroadcaster> xChangeBroad(xSet,UNO_QUERY);
1562  if ( xChangeBroad.is( ) )
1563  xChangeBroad->addRowsChangeListener(m_xRowSetListener);
1564 
1565 
1566  // insert the currently known rows
1567  // and one row if we are able to insert rows
1569  {
1570  // insert the empty row for insertion
1571  m_xEmptyRow = new DbGridRow();
1572  ++nRecordCount;
1573  }
1574  if (nRecordCount)
1575  {
1576  m_xPaintRow = m_xSeekRow = new DbGridRow(m_pSeekCursor.get(), true);
1577  m_xDataRow = new DbGridRow(m_pDataCursor.get(), false);
1578  RowInserted(0, nRecordCount, false);
1579 
1580  if (m_xSeekRow->IsValid())
1581  try
1582  {
1583  m_nSeekPos = m_pSeekCursor->getRow() - 1;
1584  }
1585  catch( const Exception& )
1586  {
1587  DBG_UNHANDLED_EXCEPTION("svx");
1588  m_nSeekPos = -1;
1589  }
1590  }
1591  else
1592  {
1593  // no rows so we don't need a seekcursor
1594  m_pSeekCursor.reset();
1595  }
1596  }
1597 
1598  // go to the old column
1599  if (nCurPos == BROWSER_INVALIDID || nCurPos >= ColCount())
1600  nCurPos = 0;
1601 
1602  // Column zero is a valid choice and guaranteed to exist,
1603  // but invisible to the user; if we have at least one
1604  // user-visible column, go to that one.
1605  if (nCurPos == 0 && ColCount() > 1)
1606  nCurPos = 1;
1607 
1608  // there are rows so go to the selected current column
1609  if (nRecordCount)
1610  GoToRowColumnId(0, GetColumnId(nCurPos));
1611  // else stop the editing if necessary
1612  else if (IsEditing())
1613  DeactivateCell();
1614 
1615  // now reset the mode
1616  if (m_nMode != nOldMode)
1617  SetMode(m_nMode);
1618 
1619  // RecalcRows was already called while resizing
1620  if (!IsResizing() && GetRowCount())
1621  RecalcRows(GetTopRow(), GetVisibleRows(), true);
1622 
1623  m_aBar->InvalidateAll(m_nCurrentPos, true);
1624  SetUpdateMode(true);
1625 
1626  // start listening on the seek cursor
1627  if (m_pSeekCursor)
1628  m_pCursorDisposeListener.reset(new DisposeListenerGridBridge(*this, Reference< XComponent > (Reference< XInterface >(*m_pSeekCursor), UNO_QUERY)));
1629 }
1630 
1632 {
1633  if ( IsEditing() )
1634  DeactivateCell();
1635 
1636  m_aColumns.clear();
1637 
1638  EditBrowseBox::RemoveColumns();
1639 }
1640 
1641 std::unique_ptr<DbGridColumn> DbGridControl::CreateColumn(sal_uInt16 nId) const
1642 {
1643  return std::unique_ptr<DbGridColumn>(new DbGridColumn(nId, *const_cast<DbGridControl*>(this)));
1644 }
1645 
1646 sal_uInt16 DbGridControl::AppendColumn(const OUString& rName, sal_uInt16 nWidth, sal_uInt16 nModelPos, sal_uInt16 nId)
1647 {
1648  DBG_ASSERT(nId == BROWSER_INVALIDID, "DbGridControl::AppendColumn : I want to set the ID myself ...");
1649  sal_uInt16 nRealPos = nModelPos;
1650  if (nModelPos != HEADERBAR_APPEND)
1651  {
1652  // calc the view pos. we can't use our converting functions because the new column
1653  // has no VCL-representation, yet.
1654  sal_Int16 nViewPos = nModelPos;
1655  while (nModelPos--)
1656  {
1657  if ( m_aColumns[ nModelPos ]->IsHidden() )
1658  --nViewPos;
1659  }
1660  // restore nModelPos, we need it later
1661  nModelPos = nRealPos;
1662  // the position the base class gets is the view pos + 1 (because of the handle column)
1663  nRealPos = nViewPos + 1;
1664  }
1665 
1666  // calculate the new id
1667  for (nId=1; (GetModelColumnPos(nId) != GRID_COLUMN_NOT_FOUND) && size_t(nId) <= m_aColumns.size(); ++nId)
1668  ;
1669  DBG_ASSERT(GetViewColumnPos(nId) == GRID_COLUMN_NOT_FOUND, "DbGridControl::AppendColumn : inconsistent internal state !");
1670  // my column's models say "there is no column with id nId", but the view (the base class) says "there is a column ..."
1671 
1672  EditBrowseBox::AppendColumn(rName, nWidth, nRealPos, nId);
1673  if (nModelPos == HEADERBAR_APPEND)
1674  m_aColumns.push_back( CreateColumn(nId) );
1675  else
1676  m_aColumns.insert( m_aColumns.begin() + nModelPos, CreateColumn(nId) );
1677 
1678  return nId;
1679 }
1680 
1681 void DbGridControl::RemoveColumn(sal_uInt16 nId)
1682 {
1683  EditBrowseBox::RemoveColumn(nId);
1684 
1685  const sal_uInt16 nIndex = GetModelColumnPos(nId);
1686  if(nIndex != GRID_COLUMN_NOT_FOUND)
1687  {
1688  m_aColumns.erase( m_aColumns.begin()+nIndex );
1689  }
1690 }
1691 
1692 void DbGridControl::ColumnMoved(sal_uInt16 nId)
1693 {
1694  EditBrowseBox::ColumnMoved(nId);
1695 
1696  // remove the col from the model
1697  sal_uInt16 nOldModelPos = GetModelColumnPos(nId);
1698 #ifdef DBG_UTIL
1699  DbGridColumn* pCol = m_aColumns[ nOldModelPos ].get();
1700  DBG_ASSERT(!pCol->IsHidden(), "DbGridControl::ColumnMoved : moved a hidden col ? how this ?");
1701 #endif
1702 
1703  // for the new model pos we can't use GetModelColumnPos because we are altering the model at the moment
1704  // so the method won't work (in fact it would return the old model pos)
1705 
1706  // the new view pos is calculated easily
1707  sal_uInt16 nNewViewPos = GetViewColumnPos(nId);
1708 
1709  // from that we can compute the new model pos
1710  size_t nNewModelPos;
1711  for (nNewModelPos = 0; nNewModelPos < m_aColumns.size(); ++nNewModelPos)
1712  {
1713  if (!m_aColumns[ nNewModelPos ]->IsHidden())
1714  {
1715  if (!nNewViewPos)
1716  break;
1717  else
1718  --nNewViewPos;
1719  }
1720  }
1721  DBG_ASSERT( nNewModelPos < m_aColumns.size(), "DbGridControl::ColumnMoved : could not find the new model position !");
1722 
1723  // this will work. of course the model isn't fully consistent with our view right now, but let's
1724  // look at the situation : a column has been moved with in the VIEW from pos m to n, say m<n (in the
1725  // other case we can use analogue arguments).
1726  // All cols k with m<k<=n have been shifted left on pos, the former col m now has pos n.
1727  // In the model this affects a range of cols x to y, where x<=m and y<=n. And the number of hidden cols
1728  // within this range is constant, so we may calculate the view pos from the model pos in the above way.
1729 
1730  // for instance, let's look at a grid with six columns where the third one is hidden. this will
1731  // initially look like this :
1732 
1733  // +---+---+---+---+---+---+
1734  // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1735  // +---+---+---+---+---+---+
1736  // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1737  // +---+---+---+---+---+---+
1738  // view pos | 0 | 1 | - | 2 | 3 | 4 |
1739  // +---+---+---+---+---+---+
1740 
1741  // if we move the column at (view) pos 1 to (view) pos 3 we have :
1742 
1743  // +---+---+---+---+---+---+
1744  // model pos | 0 | 3 |*2*| 4 | 1 | 5 | // not reflecting the changes, yet
1745  // +---+---+---+---+---+---+
1746  // ID | 1 | 4 | 3 | 5 | 2 | 6 | // already reflecting the changes
1747  // +---+---+---+---+---+---+
1748  // view pos | 0 | 1 | - | 2 | 3 | 4 |
1749  // +---+---+---+---+---+---+
1750 
1751  // or, sorted by the out-of-date model positions :
1752 
1753  // +---+---+---+---+---+---+
1754  // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1755  // +---+---+---+---+---+---+
1756  // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1757  // +---+---+---+---+---+---+
1758  // view pos | 0 | 3 | - | 1 | 2 | 4 |
1759  // +---+---+---+---+---+---+
1760 
1761  // We know the new view pos (3) of the moved column because our base class tells us. So we look at our
1762  // model for the 4th (the pos is zero-based) visible column, it is at (model) position 4. And this is
1763  // exactly the pos where we have to re-insert our column's model, so it looks ike this :
1764 
1765  // +---+---+---+---+---+---+
1766  // model pos | 0 |*1*| 2 | 3 | 4 | 5 |
1767  // +---+---+---+---+---+---+
1768  // ID | 1 | 3 | 4 | 5 | 2 | 6 |
1769  // +---+---+---+---+---+---+
1770  // view pos | 0 | - | 1 | 2 | 3 | 4 |
1771  // +---+---+---+---+---+---+
1772 
1773  // Now, all is consistent again.
1774  // (except of the hidden column : The cycling of the cols occurred on the model, not on the view. maybe
1775  // the user expected the latter but there really is no good argument against our method ;) ...)
1776 
1777  // And no, this large explanation isn't just because I wanted to play a board game or something like
1778  // that. It's because it took me a while to see it myself, and the whole theme (hidden cols, model col
1779  // positions, view col positions) is really painful (at least for me) so the above pictures helped me a lot ;)
1780 
1781  auto temp = std::move(m_aColumns[ nOldModelPos ]);
1782  m_aColumns.erase( m_aColumns.begin() + nOldModelPos );
1783  m_aColumns.insert( m_aColumns.begin() + nNewModelPos, std::move(temp) );
1784 }
1785 
1786 bool DbGridControl::SeekRow(long nRow)
1787 {
1788  // in filter mode or in insert only mode we don't have any cursor!
1789  if ( !SeekCursor( nRow ) )
1790  return false;
1791 
1792  if ( IsFilterMode() )
1793  {
1794  DBG_ASSERT( IsFilterRow( nRow ), "DbGridControl::SeekRow(): No filter row, wrong mode" );
1796  }
1797  else
1798  {
1799  // on the current position we have to take the current row for display as we want
1800  // to have the most recent values for display
1801  if ( ( nRow == m_nCurrentPos ) && getDisplaySynchron() )
1803  // seek to the empty insert row
1804  else if ( IsInsertionRow( nRow ) )
1806  else
1807  {
1808  m_xSeekRow->SetState( m_pSeekCursor.get(), true );
1810  }
1811  }
1812 
1813  EditBrowseBox::SeekRow(nRow);
1814 
1815  return m_nSeekPos >= 0;
1816 }
1817 
1818 // Is called whenever the visible amount of data changes
1819 void DbGridControl::VisibleRowsChanged( long nNewTopRow, sal_uInt16 nLinesOnScreen )
1820 {
1821  RecalcRows(nNewTopRow, nLinesOnScreen, false);
1822 }
1823 
1824 void DbGridControl::RecalcRows(long nNewTopRow, sal_uInt16 nLinesOnScreen, bool bUpdateCursor)
1825 {
1826  // If no cursor -> no rows in the browser.
1827  if (!m_pSeekCursor)
1828  {
1829  DBG_ASSERT(GetRowCount() == 0,"DbGridControl: without cursor no rows are allowed to be there");
1830  return;
1831  }
1832 
1833  // ignore any implicitly made updates
1834  bool bDisablePaint = !bUpdateCursor && IsPaintEnabled();
1835  if (bDisablePaint)
1836  EnablePaint(false);
1837 
1838  // adjust cache to the visible area
1839  Reference< XPropertySet > xSet = m_pSeekCursor->getPropertySet();
1840  sal_Int32 nCacheSize = 0;
1841  xSet->getPropertyValue(FM_PROP_FETCHSIZE) >>= nCacheSize;
1842  bool bCacheAligned = false;
1843  // no further cursor movements after initializing (m_nSeekPos < 0) because it is already
1844  // positioned on the first sentence
1845  long nDelta = nNewTopRow - GetTopRow();
1846  // limit for relative positioning
1847  long nLimit = nCacheSize ? nCacheSize / 2 : 0;
1848 
1849  // more lines on screen than in cache
1850  if (nLimit < nLinesOnScreen)
1851  {
1852  Any aCacheSize;
1853  aCacheSize <<= sal_Int32(nLinesOnScreen*2);
1854  xSet->setPropertyValue(FM_PROP_FETCHSIZE, aCacheSize);
1855  // here we need to update the cursor for sure
1856  bUpdateCursor = true;
1857  bCacheAligned = true;
1858  nLimit = nLinesOnScreen;
1859  }
1860 
1861  // In the following, all positionings are done as it is
1862  // ensured that there are enough lines in the data cache
1863 
1864  // window goes downwards with less than two windows difference or
1865  // the cache was updated and no rowcount yet
1866  if (nDelta < nLimit && (nDelta > 0
1867  || (bCacheAligned && m_nTotalCount < 0)) )
1868  SeekCursor(nNewTopRow + nLinesOnScreen - 1);
1869  else if (nDelta < 0 && std::abs(nDelta) < nLimit)
1870  SeekCursor(nNewTopRow);
1871  else if (nDelta != 0 || bUpdateCursor)
1872  SeekCursor(nNewTopRow, true);
1873 
1874  AdjustRows();
1875 
1876  // ignore any updates implicit made
1877  EnablePaint(true);
1878 }
1879 
1880 void DbGridControl::RowInserted(long nRow, long nNumRows, bool bDoPaint)
1881 {
1882  if (nNumRows)
1883  {
1885  {
1886  // if we have an insert row we have to reduce to count by 1
1887  // as the total count reflects only the existing rows in database
1888  m_nTotalCount = GetRowCount() + nNumRows;
1889  if (m_xEmptyRow.is())
1890  --m_nTotalCount;
1891  }
1892  else if (m_nTotalCount >= 0)
1893  m_nTotalCount += nNumRows;
1894 
1895  EditBrowseBox::RowInserted(nRow, nNumRows, bDoPaint);
1897  }
1898 }
1899 
1900 void DbGridControl::RowRemoved(long nRow, long nNumRows, bool bDoPaint)
1901 {
1902  if (nNumRows)
1903  {
1905  {
1906  m_nTotalCount = GetRowCount() - nNumRows;
1907  // if we have an insert row reduce by 1
1908  if (m_xEmptyRow.is())
1909  --m_nTotalCount;
1910  }
1911  else if (m_nTotalCount >= 0)
1912  m_nTotalCount -= nNumRows;
1913 
1914  EditBrowseBox::RowRemoved(nRow, nNumRows, bDoPaint);
1916  }
1917 }
1918 
1920 {
1921  if (!m_pSeekCursor)
1922  return;
1923 
1924  Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
1925 
1926  // refresh RecordCount
1927  sal_Int32 nRecordCount = 0;
1928  xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
1929  if (!m_bRecordCountFinal)
1930  m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
1931 
1932  // Did the number of rows change?
1933  // Here we need to consider that there might be an additional row for adding new data sets
1934 
1935  // add additional AppendRow for insertion
1937  ++nRecordCount;
1938 
1939  // If there is currently an insertion, so do not consider this added row in RecordCount or Appendrow
1941  m_xCurrentRow->IsNew())
1942  ++nRecordCount;
1943  // ensured with !m_bUpdating: otherwise the edited data set (that SaveRow added and why this
1944  // method was called) would be called twice (if m_bUpdating == sal_True): once in RecordCount
1945  // and a second time here (60787 - FS)
1946 
1947  if (nRecordCount != GetRowCount())
1948  {
1949  long nDelta = GetRowCount() - static_cast<long>(nRecordCount);
1950  if (nDelta > 0) // too many
1951  {
1952  RowRemoved(GetRowCount() - nDelta, nDelta, false);
1953  // some rows are gone, thus, repaint starting at the current position
1954  Invalidate();
1955 
1956  sal_Int32 nNewPos = AlignSeekCursor();
1957  if (m_bSynchDisplay)
1958  EditBrowseBox::GoToRow(nNewPos);
1959 
1960  SetCurrent(nNewPos);
1961  // there are rows so go to the selected current column
1962  if (nRecordCount)
1964  if (!IsResizing() && GetRowCount())
1965  RecalcRows(GetTopRow(), GetVisibleRows(), true);
1966  m_aBar->InvalidateAll(m_nCurrentPos, true);
1967  }
1968  else // too few
1969  RowInserted(GetRowCount(), -nDelta);
1970  }
1971 
1973  {
1974  if (m_nOptions & DbGridControlOptions::Insert)
1975  m_nTotalCount = GetRowCount() - 1;
1976  else
1978  }
1980 }
1981 
1983 {
1984  if (IsFilterRow(nRow))
1985  return EditBrowseBox::FILTER;
1986  else if (m_nCurrentPos >= 0 && nRow == m_nCurrentPos)
1987  {
1988  // new row
1989  if (!IsValid(m_xCurrentRow))
1990  return EditBrowseBox::DELETED;
1991  else if (IsModified())
1992  return EditBrowseBox::MODIFIED;
1993  else if (m_xCurrentRow->IsNew())
1994  return EditBrowseBox::CURRENTNEW;
1995  else
1996  return EditBrowseBox::CURRENT;
1997  }
1998  else if (IsInsertionRow(nRow))
1999  return EditBrowseBox::NEW;
2000  else if (!IsValid(m_xSeekRow))
2001  return EditBrowseBox::DELETED;
2002  else
2003  return EditBrowseBox::CLEAN;
2004 }
2005 
2006 void DbGridControl::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId) const
2007 {
2008  if (!IsValid(m_xPaintRow))
2009  return;
2010 
2011  size_t Location = GetModelColumnPos(nColumnId);
2012  DbGridColumn* pColumn = (Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2013  if (pColumn)
2014  {
2015  tools::Rectangle aArea(rRect);
2016  if ((GetMode() & BrowserMode::CURSOR_WO_FOCUS) == BrowserMode::CURSOR_WO_FOCUS)
2017  {
2018  aArea.AdjustTop(1 );
2019  aArea.AdjustBottom( -1 );
2020  }
2021  pColumn->Paint(rDev, aArea, m_xPaintRow.get(), getNumberFormatter());
2022  }
2023 }
2024 
2025 bool DbGridControl::CursorMoving(long nNewRow, sal_uInt16 nNewCol)
2026 {
2027 
2028  DeactivateCell( false );
2029 
2030  if ( m_pDataCursor
2031  && ( m_nCurrentPos != nNewRow )
2032  && !SetCurrent( nNewRow )
2033  )
2034  {
2035  ActivateCell();
2036  return false;
2037  }
2038 
2039  return EditBrowseBox::CursorMoving( nNewRow, nNewCol );
2040 }
2041 
2042 bool DbGridControl::SetCurrent(long nNewRow)
2043 {
2044  // Each movement of the datacursor must start with BeginCursorAction and end with
2045  // EndCursorAction to block all notifications during the movement
2047 
2048  try
2049  {
2050  // compare positions
2051  if (SeekCursor(nNewRow))
2052  {
2053  if (IsFilterRow(nNewRow)) // special mode for filtering
2054  {
2056  m_nCurrentPos = nNewRow;
2057  }
2058  else
2059  {
2060  bool bNewRowInserted = false;
2061  // Should we go to the insertrow ?
2062  if (IsInsertionRow(nNewRow))
2063  {
2064  // to we need to move the cursor to the insert row?
2065  // we need to insert the if the current row isn't the insert row or if the
2066  // cursor triggered the move by itself and we need a reinitialization of the row
2067  Reference< XPropertySet > xCursorProps = m_pDataCursor->getPropertySet();
2068  if ( !::comphelper::getBOOL(xCursorProps->getPropertyValue(FM_PROP_ISNEW)) )
2069  {
2070  Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
2071  xUpdateCursor->moveToInsertRow();
2072  }
2073  bNewRowInserted = true;
2074  }
2075  else
2076  {
2077 
2078  if ( !m_pSeekCursor->isBeforeFirst() && !m_pSeekCursor->isAfterLast() )
2079  {
2080  Any aBookmark = m_pSeekCursor->getBookmark();
2081  if (!m_xCurrentRow.is() || m_xCurrentRow->IsNew() || !CompareBookmark(aBookmark, m_pDataCursor->getBookmark()))
2082  {
2083  // adjust the cursor to the new desired row
2084  if (!m_pDataCursor->moveToBookmark(aBookmark))
2085  {
2086  EndCursorAction();
2087  return false;
2088  }
2089  }
2090  }
2091  }
2092  m_xDataRow->SetState(m_pDataCursor.get(), false);
2094 
2095  long nPaintPos = -1;
2096  // do we have to repaint the last regular row in case of setting defaults or autovalues
2097  if (m_nCurrentPos >= 0 && m_nCurrentPos >= (GetRowCount() - 2))
2098  nPaintPos = m_nCurrentPos;
2099 
2100  m_nCurrentPos = nNewRow;
2101 
2102  // repaint the new row to display all defaults
2103  if (bNewRowInserted)
2105  if (nPaintPos >= 0)
2106  RowModified(nPaintPos);
2107  }
2108  }
2109  else
2110  {
2111  OSL_FAIL("DbGridControl::SetCurrent : SeekRow failed !");
2112  EndCursorAction();
2113  return false;
2114  }
2115  }
2116  catch ( const Exception& )
2117  {
2118  DBG_UNHANDLED_EXCEPTION("svx");
2119  EndCursorAction();
2120  return false;
2121  }
2122 
2123  EndCursorAction();
2124  return true;
2125 }
2126 
2128 {
2129 
2130  // cursor movement due to deletion or insertion of rows
2132  {
2133  DeactivateCell();
2134  SetCurrent(GetCurRow());
2135  }
2136 
2137  EditBrowseBox::CursorMoved();
2138  m_aBar->InvalidateAll(m_nCurrentPos);
2139 
2140  // select the new column when they moved
2141  if ( IsDesignMode() && GetSelectedColumnCount() > 0 && GetCurColumnId() )
2142  {
2144  }
2145 
2146  if ( m_nLastColId != GetCurColumnId() )
2147  onColumnChange();
2149 
2150  if ( m_nLastRowId != GetCurRow() )
2151  onRowChange();
2152  m_nLastRowId = GetCurRow();
2153 }
2154 
2156 {
2157  // not interested in
2158 }
2159 
2161 {
2162  if ( m_pGridListener )
2164 }
2165 
2167 {
2168  if (bSync != m_bSynchDisplay)
2169  {
2170  m_bSynchDisplay = bSync;
2171  if (m_bSynchDisplay)
2172  AdjustDataSource();
2173  }
2174 }
2175 
2177 {
2178  SAL_INFO("svx.fmcomp", "DbGridControl::AdjustDataSource");
2179  SolarMutexGuard aGuard;
2180  // If the current row is recalculated at the moment, do not adjust
2181 
2182  if (bFull)
2183  m_xCurrentRow = nullptr;
2184  // if we are on the same row only repaint
2185  // but this is only possible for rows which are not inserted, in that case the comparison result
2186  // may not be correct
2187  else
2188  if ( m_xCurrentRow.is()
2189  && !m_xCurrentRow->IsNew()
2190  && !m_pDataCursor->isBeforeFirst()
2191  && !m_pDataCursor->isAfterLast()
2192  && !m_pDataCursor->rowDeleted()
2193  )
2194  {
2195  bool bEqualBookmarks = CompareBookmark( m_xCurrentRow->GetBookmark(), m_pDataCursor->getBookmark() );
2196 
2197  bool bDataCursorIsOnNew = false;
2198  m_pDataCursor->getPropertySet()->getPropertyValue( FM_PROP_ISNEW ) >>= bDataCursorIsOnNew;
2199 
2200  if ( bEqualBookmarks && !bDataCursorIsOnNew )
2201  {
2202  // position of my data cursor is the same as the position our current row points tpo
2203  // sync the status, repaint, done
2204  DBG_ASSERT(m_xDataRow == m_xCurrentRow, "Errors in the data row");
2205  SAL_INFO("svx.fmcomp", "same position, new state: " << ROWSTATUS(m_xCurrentRow));
2207  return;
2208  }
2209  }
2210 
2211  // away from the data cursor's row
2212  if (m_xPaintRow == m_xCurrentRow)
2214 
2215  // not up-to-date row, thus, adjust completely
2216  if (!m_xCurrentRow.is())
2217  AdjustRows();
2218 
2219  sal_Int32 nNewPos = AlignSeekCursor();
2220  if (nNewPos < 0)// could not find any position
2221  return;
2222 
2223  if (nNewPos != m_nCurrentPos)
2224  {
2225  if (m_bSynchDisplay)
2226  EditBrowseBox::GoToRow(nNewPos);
2227 
2228  if (!m_xCurrentRow.is())
2229  // Happens e.g. when deleting the n last datasets (n>1) while the cursor was positioned
2230  // on the last one. In this case, AdjustRows deletes two rows from BrowseBox, by what
2231  // CurrentRow is corrected to point two rows down, so that GoToRow will point into
2232  // emptiness (since we are - purportedly - at the correct position)
2233  SetCurrent(nNewPos);
2234  }
2235  else
2236  {
2237  SetCurrent(nNewPos);
2238  RowModified(nNewPos);
2239  }
2240 
2241  // if the data cursor was moved from outside, this section is voided
2242  SetNoSelection();
2243  m_aBar->InvalidateAll(m_nCurrentPos, m_xCurrentRow.is());
2244 }
2245 
2247 {
2248  // position SeekCursor onto the data cursor, no data transmission
2249 
2250  if (!m_pSeekCursor)
2251  return -1;
2252 
2253  Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
2254 
2255  // now align the seek cursor and the data cursor
2256  if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW)))
2257  m_nSeekPos = GetRowCount() - 1;
2258  else
2259  {
2260  try
2261  {
2262  if ( m_pDataCursor->isBeforeFirst() )
2263  {
2264  // this is somewhat strange, but can nevertheless happen
2265  SAL_INFO( "svx.fmcomp", "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (before first)!" );
2266  m_pSeekCursor->first();
2267  m_pSeekCursor->previous();
2268  m_nSeekPos = -1;
2269  }
2270  else if ( m_pDataCursor->isAfterLast() )
2271  {
2272  SAL_INFO( "svx.fmcomp", "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (after last)!" );
2273  m_pSeekCursor->last();
2274  m_pSeekCursor->next();
2275  m_nSeekPos = -1;
2276  }
2277  else
2278  {
2279  m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
2280  if (!CompareBookmark(m_pDataCursor->getBookmark(), m_pSeekCursor->getBookmark()))
2281  // unfortunately, moveToBookmark might lead to a re-positioning of the seek
2282  // cursor (if the complex moveToBookmark with all its events fires an update
2283  // somewhere) -> retry
2284  m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
2285  // Now there is still the chance of a failure but it is less likely.
2286  // The alternative would be a loop until everything is fine - no good solution...
2287  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2288  }
2289  }
2290  catch(Exception&)
2291  {
2292  }
2293  }
2294  return m_nSeekPos;
2295 }
2296 
2297 bool DbGridControl::SeekCursor(long nRow, bool bAbsolute)
2298 {
2299  // position SeekCursor onto the data cursor, no data transmission
2300 
2301  // additions for the filtermode
2302  if (IsFilterRow(nRow))
2303  {
2304  m_nSeekPos = 0;
2305  return true;
2306  }
2307 
2308  if (!m_pSeekCursor)
2309  return false;
2310 
2311  // is this an insertion?
2313  nRow >= m_nCurrentPos)
2314  {
2315  // if so, scrolling down must be prevented as this is already the last data set!
2316  if (nRow == m_nCurrentPos)
2317  {
2318  // no adjustment necessary
2319  m_nSeekPos = nRow;
2320  }
2321  else if (IsInsertionRow(nRow)) // blank row for data insertion
2322  m_nSeekPos = nRow;
2323  }
2324  else if (IsInsertionRow(nRow)) // blank row for data insertion
2325  m_nSeekPos = nRow;
2326  else if ((-1 == nRow) && (GetRowCount() == ((m_nOptions & DbGridControlOptions::Insert) ? 1 : 0)) && m_pSeekCursor->isAfterLast())
2327  m_nSeekPos = nRow;
2328  else
2329  {
2330  bool bSuccess = false;
2331  long nSteps = 0;
2332  try
2333  {
2334  if ( m_pSeekCursor->rowDeleted() )
2335  {
2336  // somebody deleted the current row of the seek cursor. Move it away from this row.
2337  m_pSeekCursor->next();
2338  if ( m_pSeekCursor->isAfterLast() || m_pSeekCursor->isBeforeFirst() )
2339  bAbsolute = true;
2340  }
2341 
2342  if ( !bAbsolute )
2343  {
2344  DBG_ASSERT( !m_pSeekCursor->isAfterLast() && !m_pSeekCursor->isBeforeFirst(),
2345  "DbGridControl::SeekCursor: how did the seek cursor get to this position?!" );
2346  nSteps = nRow - (m_pSeekCursor->getRow() - 1);
2347  bAbsolute = std::abs(nSteps) > 100;
2348  }
2349 
2350  if ( bAbsolute )
2351  {
2352  bSuccess = m_pSeekCursor->absolute(nRow + 1);
2353  if (bSuccess)
2354  m_nSeekPos = nRow;
2355  }
2356  else
2357  {
2358  if (nSteps > 0) // position onto the last needed data set
2359  {
2360  if (m_pSeekCursor->isAfterLast())
2361  bSuccess = false;
2362  else if (m_pSeekCursor->isBeforeFirst())
2363  bSuccess = m_pSeekCursor->absolute(nSteps);
2364  else
2365  bSuccess = m_pSeekCursor->relative(nSteps);
2366  }
2367  else if (nSteps < 0)
2368  {
2369  if (m_pSeekCursor->isBeforeFirst())
2370  bSuccess = false;
2371  else if (m_pSeekCursor->isAfterLast())
2372  bSuccess = m_pSeekCursor->absolute(nSteps);
2373  else
2374  bSuccess = m_pSeekCursor->relative(nSteps);
2375  }
2376  else
2377  {
2378  m_nSeekPos = nRow;
2379  return true;
2380  }
2381  }
2382  }
2383  catch(Exception&)
2384  {
2385  OSL_FAIL("DbGridControl::SeekCursor : failed ...");
2386  }
2387 
2388  try
2389  {
2390  if (!bSuccess)
2391  {
2392  if (bAbsolute || nSteps > 0)
2393  {
2394  if (m_pSeekCursor->isLast())
2395  bSuccess = true;
2396  else
2397  bSuccess = m_pSeekCursor->last();
2398  }
2399  else
2400  {
2401  if (m_pSeekCursor->isFirst())
2402  bSuccess = true;
2403  else
2404  bSuccess = m_pSeekCursor->first();
2405  }
2406  }
2407 
2408  if (bSuccess)
2409  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2410  else
2411  m_nSeekPos = -1;
2412  }
2413  catch(Exception&)
2414  {
2415  DBG_UNHANDLED_EXCEPTION("svx");
2416  OSL_FAIL("DbGridControl::SeekCursor : failed ...");
2417  m_nSeekPos = -1; // no further data set available
2418  }
2419  }
2420  return m_nSeekPos == nRow;
2421 }
2422 
2424 {
2425  if (m_pSeekCursor && (GetCurRow() != 0))
2426  MoveToPosition(0);
2427 }
2428 
2430 {
2431  if (!m_pSeekCursor)
2432  return;
2433 
2434  if (m_nTotalCount < 0) // no RecordCount, yet
2435  {
2436  try
2437  {
2438  bool bRes = m_pSeekCursor->last();
2439 
2440  if (bRes)
2441  {
2442  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2443  AdjustRows();
2444  }
2445  }
2446  catch(Exception&)
2447  {
2448  }
2449  }
2450 
2451  // position onto the last data set not on a blank row
2453  {
2454  if ((GetRowCount() - 1) > 0)
2455  MoveToPosition(GetRowCount() - 2);
2456  }
2457  else if (GetRowCount())
2458  MoveToPosition(GetRowCount() - 1);
2459 }
2460 
2462 {
2463  long nNewRow = std::max(GetCurRow() - 1, 0L);
2464  if (GetCurRow() != nNewRow)
2465  MoveToPosition(nNewRow);
2466 }
2467 
2469 {
2470  if (!m_pSeekCursor)
2471  return;
2472 
2473  if (m_nTotalCount > 0)
2474  {
2475  // move the data cursor to the right position
2476  long nNewRow = std::min(GetRowCount() - 1, GetCurRow() + 1);
2477  if (GetCurRow() != nNewRow)
2478  MoveToPosition(nNewRow);
2479  }
2480  else
2481  {
2482  bool bOk = false;
2483  try
2484  {
2485  // try to move to next row
2486  // when not possible our paint cursor is already on the last row
2487  // then we must be sure that the data cursor is on the position
2488  // we call ourself again
2489  bOk = m_pSeekCursor->next();
2490  if (bOk)
2491  {
2492  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2493  MoveToPosition(GetCurRow() + 1);
2494  }
2495  }
2496  catch(SQLException &)
2497  {
2498  DBG_UNHANDLED_EXCEPTION("svx");
2499  }
2500 
2501  if(!bOk)
2502  {
2503  AdjustRows();
2504  if (m_nTotalCount > 0) // only to avoid infinite recursion
2505  MoveToNext();
2506  }
2507  }
2508 }
2509 
2510 void DbGridControl::MoveToPosition(sal_uInt32 nPos)
2511 {
2512  if (!m_pSeekCursor)
2513  return;
2514 
2515  if (m_nTotalCount < 0 && static_cast<long>(nPos) >= GetRowCount())
2516  {
2517  try
2518  {
2519  if (!m_pSeekCursor->absolute(nPos + 1))
2520  {
2521  AdjustRows();
2522  return;
2523  }
2524  else
2525  {
2526  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2527  AdjustRows();
2528  }
2529  }
2530  catch(Exception&)
2531  {
2532  return;
2533  }
2534  }
2535  EditBrowseBox::GoToRow(nPos);
2536  m_aBar->InvalidateAll(m_nCurrentPos);
2537 }
2538 
2540 {
2542  return;
2543 
2544  if (m_nTotalCount < 0) // no RecordCount, yet
2545  {
2546  try
2547  {
2548  bool bRes = m_pSeekCursor->last();
2549 
2550  if (bRes)
2551  {
2552  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2553  AdjustRows();
2554  }
2555  }
2556  catch(Exception&)
2557  {
2558  return;
2559  }
2560  }
2561 
2562  long nNewRow = m_nTotalCount + 1;
2563  if (nNewRow > 0 && GetCurRow() != nNewRow)
2564  MoveToPosition(nNewRow - 1);
2565 }
2566 
2568 {
2569  if (IsDesignMode() != bMode)
2570  {
2571  // adjust Enable/Disable for design mode so that the headerbar remains configurable
2572  if (bMode)
2573  {
2574  if (!IsEnabled())
2575  {
2576  Enable();
2577  GetDataWindow().Disable();
2578  }
2579  }
2580  else
2581  {
2582  // disable completely
2583  if (!GetDataWindow().IsEnabled())
2584  Disable();
2585  }
2586 
2587  m_bDesignMode = bMode;
2589  SetMouseTransparent(bMode);
2590 
2591  m_aBar->InvalidateAll(m_nCurrentPos, true);
2592  }
2593 }
2594 
2596 {
2597  if (IsFilterMode() != bMode)
2598  {
2599  m_bFilterMode = bMode;
2600 
2601  if (bMode)
2602  {
2603  SetUpdateMode(false);
2604 
2605  // there is no cursor anymore
2606  if (IsEditing())
2607  DeactivateCell();
2608  RemoveRows(false);
2609 
2610  m_xEmptyRow = new DbGridRow();
2611 
2612  // setting the new filter controls
2613  for (auto const & pCurCol : m_aColumns)
2614  {
2615  if (!pCurCol->IsHidden())
2616  pCurCol->UpdateControl();
2617  }
2618 
2619  // one row for filtering
2620  RowInserted(0);
2621  SetUpdateMode(true);
2622  }
2623  else
2624  setDataSource(Reference< XRowSet > ());
2625  }
2626 }
2627 
2628 OUString DbGridControl::GetCellText(long _nRow, sal_uInt16 _nColId) const
2629 {
2630  size_t Location = GetModelColumnPos( _nColId );
2631  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2632  OUString sRet;
2633  if ( const_cast<DbGridControl*>(this)->SeekRow(_nRow) )
2634  sRet = GetCurrentRowCellText(pColumn, m_xPaintRow);
2635  return sRet;
2636 }
2637 
2638 OUString DbGridControl::GetCurrentRowCellText(DbGridColumn const * pColumn,const DbGridRowRef& _rRow) const
2639 {
2640  // text output for a single row
2641  OUString aText;
2642  if ( pColumn && IsValid(_rRow) )
2643  aText = pColumn->GetCellText(_rRow.get(), m_xFormatter);
2644  return aText;
2645 }
2646 
2647 sal_uInt32 DbGridControl::GetTotalCellWidth(long nRow, sal_uInt16 nColId)
2648 {
2649  if (SeekRow(nRow))
2650  {
2651  size_t Location = GetModelColumnPos( nColId );
2652  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2654  }
2655  else
2656  return 30; // FIXME magic number for default cell width
2657 }
2658 
2659 void DbGridControl::PreExecuteRowContextMenu(sal_uInt16 /*nRow*/, PopupMenu& rMenu)
2660 {
2662  // if only a blank row is selected then do not delete
2663  bDelete = bDelete && !((m_nOptions & DbGridControlOptions::Insert) && GetSelectRowCount() == 1 && IsRowSelected(GetRowCount() - 1));
2664 
2665  rMenu.EnableItem(rMenu.GetItemId("delete"), bDelete);
2666  rMenu.EnableItem(rMenu.GetItemId("save"), IsModified());
2667 
2668  // the undo is more difficult
2669  bool bCanUndo = IsModified();
2670  int nState = -1;
2673  bCanUndo &= ( 0 != nState );
2674 
2675  rMenu.EnableItem(rMenu.GetItemId("undo"), bCanUndo);
2676 }
2677 
2678 void DbGridControl::PostExecuteRowContextMenu(sal_uInt16 /*nRow*/, const PopupMenu& rMenu, sal_uInt16 nExecutionResult)
2679 {
2680  if (nExecutionResult == rMenu.GetItemId("delete"))
2681  {
2682  // delete asynchronously
2683  if (m_nDeleteEvent)
2685  m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete), nullptr, true);
2686  }
2687  else if (nExecutionResult == rMenu.GetItemId("undo"))
2688  Undo();
2689  else if (nExecutionResult == rMenu.GetItemId("save"))
2690  SaveRow();
2691 }
2692 
2693 void DbGridControl::DataSourcePropertyChanged(const PropertyChangeEvent& evt)
2694 {
2695  SAL_INFO("svx.fmcomp", "DbGridControl::DataSourcePropertyChanged");
2696  SolarMutexGuard aGuard;
2697  // prop "IsModified" changed ?
2698  // during update don't care about the modified state
2699  if (!IsUpdating() && evt.PropertyName == FM_PROP_ISMODIFIED )
2700  {
2701  Reference< XPropertySet > xSource(evt.Source, UNO_QUERY);
2702  DBG_ASSERT( xSource.is(), "DbGridControl::DataSourcePropertyChanged: invalid event source!" );
2703  bool bIsNew = false;
2704  if (xSource.is())
2705  bIsNew = ::comphelper::getBOOL(xSource->getPropertyValue(FM_PROP_ISNEW));
2706 
2707  if (bIsNew && m_xCurrentRow.is())
2708  {
2709  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 !");
2710  sal_Int32 nRecordCount = 0;
2711  xSource->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
2712  if (::comphelper::getBOOL(evt.NewValue))
2713  { // modified state changed from sal_False to sal_True and we're on an insert row
2714  // -> we've to add a new grid row
2715  if ((nRecordCount == GetRowCount() - 1) && m_xCurrentRow->IsNew())
2716  {
2719  m_aBar->InvalidateAll(m_nCurrentPos);
2720  }
2721  }
2722  else
2723  { // modified state changed from sal_True to sal_False and we're on an insert row
2724  // we have two "new row"s at the moment : the one we're editing currently (where the current
2725  // column is the only dirty element) and a "new new" row which is completely clean. As the first
2726  // one is about to be cleaned, too, the second one is obsolete now.
2727  if (m_xCurrentRow->IsNew() && nRecordCount == (GetRowCount() - 2))
2728  {
2729  RowRemoved(GetRowCount() - 1);
2731  m_aBar->InvalidateAll(m_nCurrentPos);
2732  }
2733  }
2734  }
2735  if (m_xCurrentRow.is())
2736  {
2738  m_xCurrentRow->SetNew( bIsNew );
2740  SAL_INFO("svx.fmcomp", "modified flag changed, new state: " << ROWSTATUS(m_xCurrentRow));
2741  }
2742  }
2743 }
2744 
2745 void DbGridControl::StartDrag( sal_Int8 /*nAction*/, const Point& rPosPixel )
2746 {
2747  if (!m_pSeekCursor || IsResizing())
2748  return;
2749 
2750  sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rPosPixel.X()));
2751  long nRow = GetRowAtYPosPixel(rPosPixel.Y());
2752  if (nColId != HandleColumnId && nRow >= 0)
2753  {
2756 
2757  size_t Location = GetModelColumnPos( nColId );
2758  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2759  rtl::Reference<OStringTransferable> pTransferable = new OStringTransferable(GetCurrentRowCellText(pColumn,m_xPaintRow));
2760  pTransferable->StartDrag(this, DND_ACTION_COPY);
2761  }
2762 }
2763 
2764 bool DbGridControl::canCopyCellText(sal_Int32 _nRow, sal_uInt16 _nColId)
2765 {
2766  return (_nRow >= 0)
2767  && (_nRow < GetRowCount())
2768  && (_nColId != HandleColumnId)
2769  && (GetModelColumnPos(_nColId) != GRID_COLUMN_NOT_FOUND);
2770 }
2771 
2772 void DbGridControl::copyCellText(sal_Int32 _nRow, sal_uInt16 _nColId)
2773 {
2774  DBG_ASSERT(canCopyCellText(_nRow, _nColId), "DbGridControl::copyCellText: invalid call!");
2775  DbGridColumn* pColumn = m_aColumns[ GetModelColumnPos(_nColId) ].get();
2776  SeekRow(_nRow);
2777  OStringTransfer::CopyString( GetCurrentRowCellText( pColumn,m_xPaintRow ), this );
2778 }
2779 
2780 void DbGridControl::executeRowContextMenu( long _nRow, const Point& _rPreferredPos )
2781 {
2782  VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "svx/ui/rowsmenu.ui", "");
2783  VclPtr<PopupMenu> aContextMenu(aBuilder.get_menu("menu"));
2784 
2785  PreExecuteRowContextMenu( static_cast<sal_uInt16>(_nRow), *aContextMenu );
2786  aContextMenu->RemoveDisabledEntries( true, true );
2787  PostExecuteRowContextMenu( static_cast<sal_uInt16>(_nRow), *aContextMenu, aContextMenu->Execute( this, _rPreferredPos ) );
2788 }
2789 
2791 {
2792  switch (rEvt.GetCommand())
2793  {
2794  case CommandEventId::ContextMenu:
2795  {
2796  if ( !m_pSeekCursor )
2797  {
2798  EditBrowseBox::Command(rEvt);
2799  return;
2800  }
2801 
2802  if ( !rEvt.IsMouseEvent() )
2803  { // context menu requested by keyboard
2804  if ( GetSelectRowCount() )
2805  {
2806  long nRow = FirstSelectedRow( );
2807 
2808  ::tools::Rectangle aRowRect( GetRowRectPixel( nRow ) );
2809  executeRowContextMenu( nRow, aRowRect.LeftCenter() );
2810 
2811  // handled
2812  return;
2813  }
2814  }
2815 
2816  sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X()));
2817  long nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y());
2818 
2819  if (nColId == HandleColumnId)
2820  {
2821  executeRowContextMenu( nRow, rEvt.GetMousePosPixel() );
2822  }
2823  else if (canCopyCellText(nRow, nColId))
2824  {
2825  VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "svx/ui/cellmenu.ui", "");
2826  VclPtr<PopupMenu> aContextMenu(aBuilder.get_menu("menu"));
2827  if (aContextMenu->Execute(this, rEvt.GetMousePosPixel()))
2828  copyCellText(nRow, nColId);
2829  }
2830  else
2831  {
2832  EditBrowseBox::Command(rEvt);
2833  return;
2834  }
2835 
2836  [[fallthrough]];
2837  }
2838  default:
2839  EditBrowseBox::Command(rEvt);
2840  }
2841 }
2842 
2843 IMPL_LINK_NOARG(DbGridControl, OnDelete, void*, void)
2844 {
2845  m_nDeleteEvent = nullptr;
2846  DeleteSelectedRows();
2847 }
2848 
2850 {
2851  DBG_ASSERT(GetSelection(), "no selection!!!");
2852 
2853  if (!m_pSeekCursor)
2854  return;
2855 }
2856 
2857 CellController* DbGridControl::GetController(long /*nRow*/, sal_uInt16 nColumnId)
2858 {
2859  if (!IsValid(m_xCurrentRow) || !IsEnabled())
2860  return nullptr;
2861 
2862  size_t Location = GetModelColumnPos(nColumnId);
2863  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2864  if (!pColumn)
2865  return nullptr;
2866 
2867  CellController* pReturn = nullptr;
2868  if (IsFilterMode())
2869  pReturn = pColumn->GetController().get();
2870  else
2871  {
2873  {
2874  if (!::comphelper::getBOOL(pColumn->getModel()->getPropertyValue(FM_PROP_ENABLED)))
2875  return nullptr;
2876  }
2877 
2878  bool bInsert = (m_xCurrentRow->IsNew() && (m_nOptions & DbGridControlOptions::Insert));
2879  bool bUpdate = (!m_xCurrentRow->IsNew() && (m_nOptions & DbGridControlOptions::Update));
2880 
2881  if ((bInsert && !pColumn->IsAutoValue()) || bUpdate)
2882  {
2883  pReturn = pColumn->GetController().get();
2884  }
2885  }
2886  return pReturn;
2887 }
2888 
2890 {
2891  SAL_INFO("svx.fmcomp", "DbGridControl::CellModified");
2892 
2893  {
2894  ::osl::MutexGuard aGuard(m_aAdjustSafety);
2895  if (m_nAsynAdjustEvent)
2896  {
2897  SAL_INFO("svx.fmcomp", "forcing a synchron call to " << (m_bPendingAdjustRows ? "AdjustRows" : "AdustDataSource"));
2898  RemoveUserEvent(m_nAsynAdjustEvent);
2899  m_nAsynAdjustEvent = nullptr;
2900 
2901  // force the call : this should be no problem as we're probably running in the solar thread here
2902  // (cell modified is triggered by user actions)
2904  AdjustRows();
2905  else
2906  AdjustDataSource();
2907  }
2908  }
2909 
2911  {
2912  // enable edit mode
2913  // a data set should be inserted
2914  if (m_xCurrentRow->IsNew())
2915  {
2917  SAL_INFO("svx.fmcomp", "current row is new, new state: MODIFIED");
2918  // if no row was added yet, do it now
2919  if (m_nCurrentPos == GetRowCount() - 1)
2920  {
2921  // increment RowCount
2924  m_aBar->InvalidateAll(m_nCurrentPos);
2925  }
2926  }
2928  {
2929  m_xCurrentRow->SetState(m_pDataCursor.get(), false);
2930  SAL_INFO("svx.fmcomp", "current row is not new, after SetState, new state: " << ROWSTATUS(m_xCurrentRow));
2932  SAL_INFO("svx.fmcomp", "current row is not new, new state: MODIFIED");
2934  }
2935  }
2936 }
2937 
2938 void DbGridControl::Dispatch(sal_uInt16 nId)
2939 {
2940  if (nId == BROWSER_CURSORENDOFFILE)
2941  {
2943  AppendNew();
2944  else
2945  MoveToLast();
2946  }
2947  else
2948  EditBrowseBox::Dispatch(nId);
2949 }
2950 
2952 {
2953  if (IsFilterMode() || !IsValid(m_xCurrentRow) || !IsModified())
2954  return;
2955 
2956  // check if we have somebody doin' the UNDO for us
2957  int nState = -1;
2960  if (nState>0)
2961  { // yes, we have, and the slot is enabled
2962  DBG_ASSERT(m_aMasterSlotExecutor.IsSet(), "DbGridControl::Undo : a state, but no execute link ?");
2964  if (lResult)
2965  // handled
2966  return;
2967  }
2968  else if (nState == 0)
2969  // yes, we have, and the slot is disabled
2970  return;
2971 
2973 
2974  bool bAppending = m_xCurrentRow->IsNew();
2975  bool bDirty = m_xCurrentRow->IsModified();
2976 
2977  try
2978  {
2979  // cancel editing
2980  Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
2981  // no effects if we're not updating currently
2982  if (bAppending)
2983  // just refresh the row
2984  xUpdateCursor->moveToInsertRow();
2985  else
2986  xUpdateCursor->cancelRowUpdates();
2987 
2988  }
2989  catch(Exception&)
2990  {
2991  DBG_UNHANDLED_EXCEPTION("svx");
2992  }
2993 
2994  EndCursorAction();
2995 
2996  m_xDataRow->SetState(m_pDataCursor.get(), false);
2997  if (m_xPaintRow == m_xCurrentRow)
2999  else
3001 
3002  if (bAppending && (EditBrowseBox::IsModified() || bDirty))
3003  // remove the row
3004  if (m_nCurrentPos == GetRowCount() - 2)
3005  { // maybe we already removed it (in resetCurrentRow, called if the above moveToInsertRow
3006  // caused our data source form to be reset - which should be the usual case...)
3007  RowRemoved(GetRowCount() - 1);
3008  m_aBar->InvalidateAll(m_nCurrentPos);
3009  }
3010 
3012 }
3013 
3015 {
3016  if (IsModified())
3017  {
3018  // scenario : we're on the insert row, the row is dirty, and thus there exists a "second" insert row (which
3019  // is clean). Normally in DataSourcePropertyChanged we would remove this second row if the modified state of
3020  // the insert row changes from sal_True to sal_False. But if our current cell is the only modified element (means the
3021  // data source isn't modified) and we're reset this DataSourcePropertyChanged would never be called, so we
3022  // would never delete the obsolete "second insert row". Thus in this special case this method here
3023  // is the only possibility to determine the redundance of the row (resetCurrentRow is called when the
3024  // "first insert row" is about to be cleaned, so of course the "second insert row" is redundant now)
3025  Reference< XPropertySet > xDataSource = getDataSource()->getPropertySet();
3026  if (xDataSource.is() && !::comphelper::getBOOL(xDataSource->getPropertyValue(FM_PROP_ISMODIFIED)))
3027  {
3028  // are we on a new row currently ?
3029  if (m_xCurrentRow->IsNew())
3030  {
3031  if (m_nCurrentPos == GetRowCount() - 2)
3032  {
3033  RowRemoved(GetRowCount() - 1);
3034  m_aBar->InvalidateAll(m_nCurrentPos);
3035  }
3036  }
3037  }
3038 
3039  // update the rows
3040  m_xDataRow->SetState(m_pDataCursor.get(), false);
3041  if (m_xPaintRow == m_xCurrentRow)
3043  else
3045  }
3046 
3047  RowModified(GetCurRow()); // will update the current controller if affected
3048 }
3049 
3051 {
3052  if (nRow == m_nCurrentPos && IsEditing())
3053  {
3054  CellControllerRef aTmpRef = Controller();
3055  aTmpRef->ClearModified();
3057  }
3058  EditBrowseBox::RowModified(nRow);
3059 }
3060 
3062 {
3063  return !IsFilterMode() && IsValid(m_xCurrentRow) && (m_xCurrentRow->IsModified() || EditBrowseBox::IsModified());
3064 }
3065 
3067 {
3068  return m_xCurrentRow.is() && m_xCurrentRow->IsNew();
3069 }
3070 
3071 bool DbGridControl::IsInsertionRow(long nRow) const
3072 {
3073  return (m_nOptions & DbGridControlOptions::Insert) && m_nTotalCount >= 0 && (nRow == GetRowCount() - 1);
3074 }
3075 
3077 {
3078  SAL_INFO("svx.fmcomp", "DbGridControl::SaveModified");
3079  DBG_ASSERT(IsValid(m_xCurrentRow), "GridControl:: Invalid row");
3080  if (!IsValid(m_xCurrentRow))
3081  return true;
3082 
3083  // accept input for this field
3084  // Where there changes at the current input field?
3085  if (!EditBrowseBox::IsModified())
3086  return true;
3087 
3089  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3090  bool bOK = pColumn && pColumn->Commit();
3091  DBG_ASSERT( Controller().is(), "DbGridControl::SaveModified: was modified, by have no controller?!" );
3092  if ( !Controller().is() )
3093  // this might happen if the callbacks implicitly triggered by Commit
3094  // fiddled with the form or the control ...
3095  // (Note that this here is a workaround, at most. We need a general concept how
3096  // to treat this, you can imagine an arbitrary number of scenarios where a callback
3097  // triggers something which leaves us in an expected state.)
3098  // #i67147# / 2006-07-17 / frank.schoenheit@sun.com
3099  return bOK;
3100 
3101  if (bOK)
3102  {
3103  Controller()->ClearModified();
3104 
3105  if ( IsValid(m_xCurrentRow) )
3106  {
3107  m_xCurrentRow->SetState(m_pDataCursor.get(), false);
3108  SAL_INFO("svx.fmcomp", "explicit SetState, new state: " << ROWSTATUS(m_xCurrentRow));
3110  }
3111  else
3112  {
3113  SAL_INFO("svx.fmcomp", "no SetState, new state: " << ROWSTATUS(m_xCurrentRow));
3114  }
3115  }
3116  else
3117  {
3118  // reset the modified flag...
3119  Controller()->SetModified();
3120  }
3121 
3122  return bOK;
3123 }
3124 
3126 {
3127  SAL_INFO("svx.fmcomp", "DbGridControl::SaveRow");
3128  // valid row
3129  if (!IsValid(m_xCurrentRow) || !IsModified())
3130  return true;
3131  // value of the controller was not saved, yet
3132  else if (Controller().is() && Controller()->IsModified())
3133  {
3134  if (!SaveModified())
3135  return false;
3136  }
3137  m_bUpdating = true;
3138 
3140  bool bAppending = m_xCurrentRow->IsNew();
3141  bool bSuccess = false;
3142  try
3143  {
3144  Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
3145  if (bAppending)
3146  xUpdateCursor->insertRow();
3147  else
3148  xUpdateCursor->updateRow();
3149  bSuccess = true;
3150  }
3151  catch(SQLException&)
3152  {
3153  EndCursorAction();
3154  m_bUpdating = false;
3155  return false;
3156  }
3157 
3158  try
3159  {
3160  if (bSuccess)
3161  {
3162  // if we are appending we still sit on the insert row
3163  // we don't move just clear the flags not to move on the current row
3164  m_xCurrentRow->SetState(m_pDataCursor.get(), false);
3165  SAL_INFO("svx.fmcomp", "explicit SetState after a successful update, new state: " << ROWSTATUS(m_xCurrentRow));
3166  m_xCurrentRow->SetNew(false);
3167 
3168  // adjust the seekcursor if it is on the same position as the datacursor
3169  if (m_nSeekPos == m_nCurrentPos || bAppending)
3170  {
3171  // get the bookmark to refetch the data
3172  // in insert mode we take the new bookmark of the data cursor
3173  Any aBookmark = bAppending ? m_pDataCursor->getBookmark() : m_pSeekCursor->getBookmark();
3174  m_pSeekCursor->moveToBookmark(aBookmark);
3175  // get the data
3176  m_xSeekRow->SetState(m_pSeekCursor.get(), true);
3177  m_nSeekPos = m_pSeekCursor->getRow() - 1;
3178  }
3179  }
3180  // and repaint the row
3182  }
3183  catch(Exception&)
3184  {
3185  }
3186 
3187  m_bUpdating = false;
3188  EndCursorAction();
3189 
3190  // The old code returned (nRecords != 0) here.
3191  // Me thinks this is wrong : If something goes wrong while update the record, an exception will be thrown,
3192  // which results in a "return sal_False" (see above). If no exception is thrown, everything is fine. If nRecords
3193  // is zero, this simply means all fields had their original values.
3194  // FS - 06.12.99 - 70502
3195  return true;
3196 }
3197 
3199 {
3200  // do not handle events of the Navbar
3201  if (m_aBar->IsWindowOrChild(rEvt.GetWindow()))
3202  return BrowseBox::PreNotify(rEvt);
3203 
3204  switch (rEvt.GetType())
3205  {
3206  case MouseNotifyEvent::KEYINPUT:
3207  {
3208  const KeyEvent* pKeyEvent = rEvt.GetKeyEvent();
3209 
3210  sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
3211  bool bShift = pKeyEvent->GetKeyCode().IsShift();
3212  bool bCtrl = pKeyEvent->GetKeyCode().IsMod1();
3213  bool bAlt = pKeyEvent->GetKeyCode().IsMod2();
3214  if ( ( KEY_TAB == nCode ) && bCtrl && !bAlt )
3215  {
3216  // Ctrl-Tab is used to step out of the control, without traveling to the
3217  // remaining cells first
3218  // -> build a new key event without the Ctrl-key, and let the very base class handle it
3219  vcl::KeyCode aNewCode( KEY_TAB, bShift, false, false, false );
3220  KeyEvent aNewEvent( pKeyEvent->GetCharCode(), aNewCode );
3221 
3222  // call the Control - our direct base class will interpret this in a way we do not want (and do
3223  // a cell traveling)
3224  Control::KeyInput( aNewEvent );
3225  return true;
3226  }
3227 
3228  if ( !bShift && !bCtrl && ( KEY_ESCAPE == nCode ) )
3229  {
3230  if (IsModified())
3231  {
3232  Undo();
3233  return true;
3234  }
3235  }
3236  else if ( ( KEY_DELETE == nCode ) && !bShift && !bCtrl ) // delete rows
3237  {
3239  {
3240  // delete asynchronously
3241  if (m_nDeleteEvent)
3243  m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete), nullptr, true);
3244  return true;
3245  }
3246  }
3247 
3248  [[fallthrough]];
3249  }
3250  default:
3251  return EditBrowseBox::PreNotify(rEvt);
3252  }
3253 }
3254 
3255 bool DbGridControl::IsTabAllowed(bool bRight) const
3256 {
3257  if (bRight)
3258  // Tab only if not on the _last_ row
3259  return GetCurRow() < (GetRowCount() - 1) || !m_bRecordCountFinal ||
3261  else
3262  {
3263  // Tab only if not on the _first_ row
3264  return GetCurRow() > 0 || (GetCurColumnId() && GetViewColumnPos(GetCurColumnId()) > 0);
3265  }
3266 }
3267 
3269 {
3270  if (rEvt.GetKeyCode().GetFunction() == KeyFuncType::COPY)
3271  {
3272  long nRow = GetCurRow();
3273  sal_uInt16 nColId = GetCurColumnId();
3274  if (nRow >= 0 && nRow < GetRowCount() && nColId < ColCount())
3275  {
3276  size_t Location = GetModelColumnPos( nColId );
3277  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3278  OStringTransfer::CopyString( GetCurrentRowCellText( pColumn, m_xCurrentRow ), this );
3279  return;
3280  }
3281  }
3282  EditBrowseBox::KeyInput(rEvt);
3283 }
3284 
3285 void DbGridControl::HideColumn(sal_uInt16 nId)
3286 {
3287  DeactivateCell();
3288 
3289  // determine the col for the focus to set to after removal
3290  sal_uInt16 nPos = GetViewColumnPos(nId);
3291  sal_uInt16 nNewColId = nPos == (ColCount()-1)
3292  ? GetColumnIdFromViewPos(nPos-1) // last col is to be removed -> take the previous
3293  : GetColumnIdFromViewPos(nPos+1); // take the next
3294 
3295  long lCurrentWidth = GetColumnWidth(nId);
3296  EditBrowseBox::RemoveColumn(nId);
3297  // don't use my own RemoveColumn, this would remove it from m_aColumns, too
3298 
3299  // update my model
3300  size_t Location = GetModelColumnPos( nId );
3301  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3302  DBG_ASSERT(pColumn, "DbGridControl::HideColumn : somebody did hide a nonexistent column !");
3303  if (pColumn)
3304  {
3305  pColumn->m_bHidden = true;
3306  pColumn->m_nLastVisibleWidth = CalcReverseZoom(lCurrentWidth);
3307  }
3308 
3309  // and reset the focus
3310  if ( nId == GetCurColumnId() )
3311  GoToColumnId( nNewColId );
3312 }
3313 
3314 void DbGridControl::ShowColumn(sal_uInt16 nId)
3315 {
3316  sal_uInt16 nPos = GetModelColumnPos(nId);
3317  DBG_ASSERT(nPos != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : invalid argument !");
3318  if (nPos == GRID_COLUMN_NOT_FOUND)
3319  return;
3320 
3321  DbGridColumn* pColumn = m_aColumns[ nPos ].get();
3322  if (!pColumn->IsHidden())
3323  {
3324  DBG_ASSERT(GetViewColumnPos(nId) != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3325  // if the column isn't marked as hidden, it should be visible, shouldn't it ?
3326  return;
3327  }
3328  DBG_ASSERT(GetViewColumnPos(nId) == GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3329  // the opposite situation ...
3330 
3331  // to determine the new view position we need an adjacent non-hidden column
3332  sal_uInt16 nNextNonHidden = BROWSER_INVALIDID;
3333  // first search the cols to the right
3334  for ( size_t i = nPos + 1; i < m_aColumns.size(); ++i )
3335  {
3336  DbGridColumn* pCurCol = m_aColumns[ i ].get();
3337  if (!pCurCol->IsHidden())
3338  {
3339  nNextNonHidden = i;
3340  break;
3341  }
3342  }
3343  if ((nNextNonHidden == BROWSER_INVALIDID) && (nPos > 0))
3344  {
3345  // then to the left
3346  for ( size_t i = nPos; i > 0; --i )
3347  {
3348  DbGridColumn* pCurCol = m_aColumns[ i-1 ].get();
3349  if (!pCurCol->IsHidden())
3350  {
3351  nNextNonHidden = i-1;
3352  break;
3353  }
3354  }
3355  }
3356  sal_uInt16 nNewViewPos = (nNextNonHidden == BROWSER_INVALIDID)
3357  ? 1 // there is no visible column -> insert behind the handle col
3358  : GetViewColumnPos( m_aColumns[ nNextNonHidden ]->GetId() ) + 1;
3359  // the first non-handle col has "view pos" 0, but the pos arg for InsertDataColumn expects
3360  // a position 1 for the first non-handle col -> +1
3361  DBG_ASSERT(nNewViewPos != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3362  // we found a col marked as visible but got no view pos for it ...
3363 
3364  if ((nNextNonHidden<nPos) && (nNextNonHidden != BROWSER_INVALIDID))
3365  // nNextNonHidden is a column to the left, so we want to insert the new col _right_ beside it's pos
3366  ++nNewViewPos;
3367 
3368  DeactivateCell();
3369 
3370  OUString aName;
3371  pColumn->getModel()->getPropertyValue(FM_PROP_LABEL) >>= aName;
3372  InsertDataColumn(nId, aName, CalcZoom(pColumn->m_nLastVisibleWidth), HeaderBarItemBits::CENTER | HeaderBarItemBits::CLICKABLE, nNewViewPos);
3373  pColumn->m_bHidden = false;
3374 
3375  ActivateCell();
3376  Invalidate();
3377 }
3378 
3379 sal_uInt16 DbGridControl::GetColumnIdFromModelPos( sal_uInt16 nPos ) const
3380 {
3381  if (nPos >= m_aColumns.size())
3382  {
3383  OSL_FAIL("DbGridControl::GetColumnIdFromModelPos : invalid argument !");
3384  return GRID_COLUMN_NOT_FOUND;
3385  }
3386 
3387  DbGridColumn* pCol = m_aColumns[ nPos ].get();
3388 #if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
3389  // in the debug version, we convert the ModelPos into a ViewPos and compare this with the
3390  // value we will return (nId at the corresponding Col in m_aColumns)
3391 
3392  if (!pCol->IsHidden())
3393  { // makes sense only if the column is visible
3394  sal_uInt16 nViewPos = nPos;
3395  for ( size_t i = 0; i < m_aColumns.size() && i < nPos; ++i)
3396  if ( m_aColumns[ i ]->IsHidden())
3397  --nViewPos;
3398 
3399  DBG_ASSERT(pCol && GetColumnIdFromViewPos(nViewPos) == pCol->GetId(),
3400  "DbGridControl::GetColumnIdFromModelPos : this isn't consistent... did I misunderstand something ?");
3401  }
3402 #endif
3403  return pCol->GetId();
3404 }
3405 
3406 sal_uInt16 DbGridControl::GetModelColumnPos( sal_uInt16 nId ) const
3407 {
3408  for ( size_t i = 0; i < m_aColumns.size(); ++i )
3409  if ( m_aColumns[ i ]->GetId() == nId )
3410  return i;
3411 
3412  return GRID_COLUMN_NOT_FOUND;
3413 }
3414 
3416 {
3417  SAL_INFO("svx.fmcomp", "DbGridControl::implAdjustInSolarThread");
3418  ::osl::MutexGuard aGuard(m_aAdjustSafety);
3420  {
3421  m_nAsynAdjustEvent = PostUserEvent(LINK(this, DbGridControl, OnAsyncAdjust), reinterpret_cast< void* >( _bRows ), true);
3422  m_bPendingAdjustRows = _bRows;
3423  if (_bRows)
3424  SAL_INFO("svx.fmcomp", "posting an AdjustRows");
3425  else
3426  SAL_INFO("svx.fmcomp", "posting an AdjustDataSource");
3427  }
3428  else
3429  {
3430  if (_bRows)
3431  SAL_INFO("svx.fmcomp", "doing an AdjustRows");
3432  else
3433  SAL_INFO("svx.fmcomp", "doing an AdjustDataSource");
3434  // always adjust the rows before adjusting the data source
3435  // If this is not necessary (because the row count did not change), nothing is done
3436  // The problem is that we can't rely on the order of which the calls come in: If the cursor was moved
3437  // to a position behind row count know 'til now, the cursorMoved notification may come before the
3438  // RowCountChanged notification
3439  // 94093 - 02.11.2001 - frank.schoenheit@sun.com
3440  AdjustRows();
3441 
3442  if ( !_bRows )
3443  AdjustDataSource();
3444  }
3445 }
3446 
3447 IMPL_LINK(DbGridControl, OnAsyncAdjust, void*, pAdjustWhat, void)
3448 {
3449  m_nAsynAdjustEvent = nullptr;
3450 
3451  AdjustRows();
3452  // see implAdjustInSolarThread for a comment why we do this every time
3453 
3454  if ( !pAdjustWhat )
3455  AdjustDataSource();
3456 }
3457 
3459 {
3460  if (m_pFieldListeners)
3461  {
3463  for (const auto& rListener : *pListeners)
3464  {
3465  GridFieldValueListener* pCurrent = rListener.second;
3466  if (pCurrent)
3467  pCurrent->suspend();
3468  }
3469  }
3470 
3473 }
3474 
3476 {
3477  if (m_pFieldListeners)
3478  {
3480  for (const auto& rListener : *pListeners)
3481  {
3482  GridFieldValueListener* pCurrent = rListener.second;
3483  if (pCurrent)
3484  pCurrent->resume();
3485  }
3486  }
3487 
3490 }
3491 
3493 {
3495  DBG_ASSERT(!pListeners || pListeners->empty(), "DbGridControl::ConnectToFields : please call DisconnectFromFields first !");
3496 
3497  if (!pListeners)
3498  {
3499  pListeners = new ColumnFieldValueListeners;
3500  m_pFieldListeners = pListeners;
3501  }
3502 
3503  for (auto const & pCurrent : m_aColumns)
3504  {
3505  sal_uInt16 nViewPos = pCurrent ? GetViewColumnPos(pCurrent->GetId()) : GRID_COLUMN_NOT_FOUND;
3506  if (GRID_COLUMN_NOT_FOUND == nViewPos)
3507  continue;
3508 
3509  Reference< XPropertySet > xField = pCurrent->GetField();
3510  if (!xField.is())
3511  continue;
3512 
3513  // column is visible and bound here
3514  GridFieldValueListener*& rpListener = (*pListeners)[pCurrent->GetId()];
3515  DBG_ASSERT(!rpListener, "DbGridControl::ConnectToFields : already a listener for this column ?!");
3516  rpListener = new GridFieldValueListener(*this, xField, pCurrent->GetId());
3517  }
3518 }
3519 
3521 {
3522  if (!m_pFieldListeners)
3523  return;
3524 
3526  while (!pListeners->empty())
3527  {
3528  sal_Int32 nOldSize = pListeners->size();
3529  pListeners->begin()->second->dispose();
3530  DBG_ASSERT(nOldSize > static_cast<sal_Int32>(pListeners->size()), "DbGridControl::DisconnectFromFields : dispose on a listener should result in a removal from my list !");
3531  }
3532 
3533  delete pListeners;
3534  m_pFieldListeners = nullptr;
3535 }
3536 
3538 {
3539  osl::MutexGuard aPreventDestruction(m_aDestructionSafety);
3540  // needed as this may run in a thread other than the main one
3541  if (GetRowStatus(GetCurRow()) != EditBrowseBox::MODIFIED)
3542  // all other cases are handled elsewhere
3543  return;
3544 
3545  size_t Location = GetModelColumnPos( _nId );
3546  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3547  if (pColumn)
3548  {
3549  std::unique_ptr<vcl::SolarMutexTryAndBuyGuard> pGuard;
3550  while (!m_bWantDestruction && (!pGuard || !pGuard->isAcquired()))
3551  pGuard.reset(new vcl::SolarMutexTryAndBuyGuard);
3552 
3553  if (m_bWantDestruction)
3554  { // at this moment, within another thread, our destructor tries to destroy the listener which called this method
3555  // => don't do anything
3556  // 73365 - 23.02.00 - FS
3557  return;
3558  }
3559 
3560  // and finally do the update ...
3563  }
3564 }
3565 
3567 {
3569  if (!pListeners)
3570  {
3571  OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (have no listener array) !");
3572  return;
3573  }
3574 
3575  ColumnFieldValueListeners::const_iterator aPos = pListeners->find(_nId);
3576  if (aPos == pListeners->end())
3577  {
3578  OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (did not find the listener) !");
3579  return;
3580  }
3581 
3582  delete aPos->second;
3583 
3584  pListeners->erase(aPos);
3585 }
3586 
3587 void DbGridControl::disposing(sal_uInt16 _nId)
3588 {
3589  if (_nId == 0)
3590  { // the seek cursor is being disposed
3591  ::osl::MutexGuard aGuard(m_aAdjustSafety);
3592  setDataSource(nullptr, DbGridControlOptions::Readonly); // our clone was disposed so we set our datasource to null to avoid later access to it
3593  if (m_nAsynAdjustEvent)
3594  {
3595  RemoveUserEvent(m_nAsynAdjustEvent);
3596  m_nAsynAdjustEvent = nullptr;
3597  }
3598  }
3599 }
3600 
3602 {
3603  return EditBrowseBox::GetAccessibleControlCount() + 1; // the navigation control
3604 }
3605 
3606 Reference<XAccessible > DbGridControl::CreateAccessibleControl( sal_Int32 _nIndex )
3607 {
3608  Reference<XAccessible > xRet;
3609  if ( _nIndex == EditBrowseBox::GetAccessibleControlCount() )
3610  {
3611  xRet = m_aBar->GetAccessible();
3612  }
3613  else
3614  xRet = EditBrowseBox::CreateAccessibleControl( _nIndex );
3615  return xRet;
3616 }
3617 
3618 Reference< XAccessible > DbGridControl::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
3619 {
3620  sal_uInt16 nColumnId = GetColumnId( _nColumnPos );
3621  size_t Location = GetModelColumnPos(nColumnId);
3622  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3623  if ( pColumn )
3624  {
3625  Reference< css::awt::XControl> xInt(pColumn->GetCell());
3626  Reference< css::awt::XCheckBox> xBox(xInt,UNO_QUERY);
3627  if ( xBox.is() )
3628  {
3629  TriState eValue = TRISTATE_FALSE;
3630  switch( xBox->getState() )
3631  {
3632  case 0:
3633  eValue = TRISTATE_FALSE;
3634  break;
3635  case 1:
3636  eValue = TRISTATE_TRUE;
3637  break;
3638  case 2:
3639  eValue = TRISTATE_INDET;
3640  break;
3641  }
3642  return EditBrowseBox::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,eValue );
3643  }
3644  }
3645  return EditBrowseBox::CreateAccessibleCell( _nRow, _nColumnPos );
3646 }
3647 
3648 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void InsertHandleColumn(sal_uLong nWidth)
virtual void SetText(const OUString &rStr)
std::unique_ptr< DbGridColumn > CreateColumn(sal_uInt16 nId) const
Definition: gridctrl.cxx:1641
Point TopLeft() const
long Width() const
bool is() const
const css::uno::Reference< css::beans::XPropertySet > & getModel() const
Definition: gridcell.hxx:122
virtual bool SaveModified() override
Definition: gridctrl.cxx:3076
virtual ::svt::CellController * GetController(long nRow, sal_uInt16 nCol) override
Definition: gridctrl.cxx:2857
friend class GridFieldValueListener
Definition: gridctrl.hxx:166
#define GRID_COLUMN_NOT_FOUND
Definition: gridctrl.hxx:111
DbGridControl & m_rParent
Definition: gridctrl.cxx:199
NavigationBar(vcl::Window *pParent)
Definition: gridctrl.cxx:330
void SetMode(BrowserMode nMode)
void setDataSource(const css::uno::Reference< css::sdbc::XRowSet > &rCursor, DbGridControlOptions nOpts=DbGridControlOptions::Insert|DbGridControlOptions::Update|DbGridControlOptions::Delete)
Definition: gridctrl.cxx:1401
DbGridControl & m_rParent
Definition: gridctrl.cxx:135
osl::Mutex m_aDestructionSafety
Definition: gridctrl.hxx:272
virtual bool SeekRow(long nRow) override
Definition: gridctrl.cxx:1786
sal_Int32 nIndex
virtual ~NavigationBar() override
Definition: gridctrl.cxx:398
#define KEY_DELETE
GridRowStatus GetStatus() const
Definition: gridctrl.hxx:84
VclPtr< NavigationBar > m_aBar
Definition: gridctrl.hxx:233
DbGridControlNavigationBarState
Definition: gridctrl.hxx:146
static bool IsMainThread()
VclPtr< ImageButton > m_aLastBtn
Definition: gridctrl.hxx:195
void MoveToFirst()
Definition: gridctrl.cxx:2423
osl::Mutex m_aMutex
EditBrowseBoxFlags
bool m_bDisposed
long AdjustWidth(long n)
#define DND_ACTION_COPY
void SetClickHdl(const Link< Button *, void > &rLink)
static const sal_uInt16 HandleColumnId
virtual sal_uInt16 AppendColumn(const OUString &rName, sal_uInt16 nWidth, sal_uInt16 nPos=HEADERBAR_APPEND, sal_uInt16 nId=sal_uInt16(-1)) override
Definition: gridctrl.cxx:1646
long AdjustX(long nHorzMove)
virtual bool IsTabAllowed(bool bForward) const override
Definition: gridctrl.cxx:3255
#define KEY_TAB
std::string GetValue
virtual void _propertyChanged(const PropertyChangeEvent &evt) override
Definition: gridctrl.cxx:272
void SetModeImage(const Image &rImage)
virtual sal_Int32 GetSelectedColumnCount() const override
FmXGridSourcePropListener * m_pDataSourcePropListener
Definition: gridctrl.hxx:247
bool IsModified() const
Definition: gridctrl.hxx:91
sal_Int32 getRow() const
Definition: fmtools.hxx:114
long Height() const
DbGridControlOptions m_nOptionMask
Definition: gridctrl.hxx:283
void MoveToPosition(sal_uInt32 nPos)
Definition: gridctrl.cxx:2510
signed char sal_Int8
long FirstSelectedRow()
#define FM_PROP_VALUE
Definition: fmprop.hxx:35
#define FM_PROP_RESULTSET_CONCURRENCY
Definition: fmprop.hxx:119
bool m_bDesignMode
Definition: gridctrl.hxx:289
void Create(SwFormatVertOrient &rItem, SvStream &rStrm, sal_uInt16 nVersionAbusedAsSize)
const css::uno::Any & GetBookmark() const
Definition: gridctrl.hxx:88
bool IsNew() const
Definition: gridctrl.hxx:86
void EnablePermanentCursor(bool bEnable)
Definition: gridctrl.cxx:1360
#define FM_PROP_ISMODIFIED
Definition: fmprop.hxx:114
virtual bool CursorMoving(long nNewRow, sal_uInt16 nNewCol) override
Definition: gridctrl.cxx:2025
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: gridctrl.cxx:1070
VclPtr< FixedText > m_aRecordOf
Definition: gridctrl.hxx:189
virtual void PaintCell(OutputDevice &rDev, const tools::Rectangle &rRect, sal_uInt16 nColId) const override
Definition: gridctrl.cxx:2006
bool getBOOL(const Any &_rAny)
virtual void StateChanged(StateChangedType nType) override
Definition: gridctrl.cxx:781
virtual void StateChanged(StateChangedType nStateChange) override
bool IsOpen() const
Definition: gridctrl.hxx:425
#define FM_PROP_LABEL
Definition: fmprop.hxx:40
void MoveToLast()
Definition: gridctrl.cxx:2429
#define FM_PROP_ROWCOUNTFINAL
Definition: fmprop.hxx:33
virtual void SetSizePixel(const Size &rNewSize)
#define FM_PROP_ISNEW
Definition: fmprop.hxx:115
const DbGridRowRef & GetSeekRow(GrantControlAccess) const
Definition: gridctrl.hxx:523
void SetRealRowCount(const OUString &rRealRowCount)
vcl::Window & GetDataWindow() const
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
void SetUpdateMode(bool bUpdate)
virtual void DeactivateCell(bool bUpdate=true)
sal_uInt16 GetCode() const
DbGridControlOptions
Definition: gridctrl.hxx:132
void MoveToPrev()
Definition: gridctrl.cxx:2461
virtual void CursorMoved() override
Definition: gridctrl.cxx:2127
const css::uno::Reference< css::beans::XPropertySet > & getPropertySet() const
Definition: fmtools.hxx:95
css::uno::Reference< css::container::XNameAccess > getColumns() const
Definition: fmtools.hxx:123
DataChangedEventType GetType() const
const KeyEvent * GetKeyEvent() const
sal_Int32 m_nLastVisibleWidth
Definition: gridcell.hxx:83
sal_uInt16 GetColumnPos(sal_uInt16 nColumnId) const
virtual void StartDrag(sal_Int8 nAction, const Point &rPosPixel) override
Definition: gridctrl.cxx:2745
virtual bool PreNotify(NotifyEvent &rEvt) override
Definition: gridctrl.cxx:3198
virtual sal_uInt32 GetTotalCellWidth(long nRow, sal_uInt16 nColId) override
Definition: gridctrl.cxx:2647
virtual void SetSettings(const AllSettings &rSettings) override
void SetHelpId(const OString &)
bool IsEditing() const
Image GetImage(RowStatus) const
Reference< XNumberFormatsSupplier > getNumberFormats(const Reference< XConnection > &_rxConn, bool _bAlloweDefault, const Reference< XComponentContext > &_rxContext)
void SetFilterMode(bool bMode)
Definition: gridctrl.cxx:2595
bool GoToRowColumnId(long nRow, sal_uInt16 nColId)
void FieldListenerDisposing(sal_uInt16 _nId)
Definition: gridctrl.cxx:3566
void SetStrictFormat(bool bStrict)
TRISTATE_TRUE
virtual void ArrangeControls(sal_uInt16 &nX, sal_uInt16 nY) override
Definition: gridctrl.cxx:1179
sal_uInt16 GetModelColumnPos(sal_uInt16 nId) const
Definition: gridctrl.cxx:3406
bool IsAutoValue() const
Definition: gridcell.hxx:128
#define FM_PROP_PRIVILEGES
Definition: fmprop.hxx:116
rtl::Reference< FmXDisposeMultiplexer > m_xRealListener
Definition: gridctrl.cxx:200
bool IsDesignMode() const
Definition: gridctrl.hxx:424
#define HID_GRID_TRAVEL_LAST
Definition: helpids.h:53
long AdjustBottom(long nVertMoveDelta)
void disposing(sal_uInt16 _nId)
Definition: gridctrl.cxx:3587
bool IsFilterMode() const
Definition: gridctrl.hxx:428
void SetSpinSize(sal_Int64 nNewSize)
void SetMin(sal_Int64 nNewMin)
NONE
virtual sal_Int32 GetAccessibleControlCount() const override
Definition: gridctrl.cxx:3601
virtual void Command(const CommandEvent &rEvt) override
Definition: gridctrl.cxx:2790
StateChangedType
WinBits const WB_NOPOINTERFOCUS
virtual void StateChanged(StateChangedType nType) override
Definition: gridctrl.cxx:1032
BrowserMode m_nMode
Definition: gridctrl.hxx:278
sal_Int64 WinBits
tools::Rectangle GetControlArea() const
vcl::Window * GetWindow() const
#define ROWSTATUS(row)
Definition: gridctrl.cxx:85
void SetBackground()
sal_Int32 m_nSeekPos
Definition: gridctrl.hxx:269
virtual void BeginCursorAction()
Definition: gridctrl.cxx:3458
virtual void DeleteSelectedRows()
Definition: gridctrl.cxx:2849
std::map< sal_uInt16, GridFieldValueListener * > ColumnFieldValueListeners
Definition: gridctrl.cxx:129
virtual VclPtr< BrowserHeader > CreateHeaderBar(BrowseBox *pParent) override
void Enable(bool bEnable=true, bool bChild=true)
sal_uInt16 m_nLastColId
Definition: gridctrl.hxx:286
OUString GetCurrentRowCellText(DbGridColumn const *pCol, const DbGridRowRef &_rRow) const
Definition: gridctrl.cxx:2638
void SetSymbol(SymbolType eSymbol)
virtual void ColumnMoved(sal_uInt16 nId) override
Definition: gridctrl.cxx:1692
OUString SvxResId(const char *pId)
Definition: dialmgr.cxx:28
bool m_bUpdating
Definition: gridctrl.hxx:301
bool IsUpdating() const
Definition: gridctrl.hxx:462
DbGridControl(css::uno::Reference< css::uno::XComponentContext > const &_rxContext, vcl::Window *pParent, WinBits nBits)
Definition: gridctrl.cxx:934
#define BROWSER_CURSORENDOFFILE
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
Definition: gridctrl.cxx:768
sal_uLong GetButtonRepeat() const
BrowserMode GetMode() const
CursorWrapper * getDataSource() const
Definition: gridctrl.hxx:401
bool rowDeleted()
Definition: fmtools.hxx:120
bool IsMouseEvent() const
bool IsCurrentAppending() const
Definition: gridctrl.cxx:3066
long GetRowAtYPosPixel(long nY, bool bRelToBrowser=true) const
void DataSourcePropertyChanged(const css::beans::PropertyChangeEvent &evt)
Definition: gridctrl.cxx:2693
virtual void VisibleRowsChanged(long nNewTopRow, sal_uInt16 nNumRows) override
Definition: gridctrl.cxx:1819
AllSettingsFlags GetFlags() const
void EnableNavigationBar(bool bEnable)
Definition: gridctrl.cxx:1235
sal_uInt16 GetViewColCount() const
Definition: gridctrl.hxx:417
const css::uno::Reference< css::util::XNumberFormatter > & getNumberFormatter() const
Definition: gridctrl.hxx:393
virtual void SetDesignMode(bool bMode)
Definition: gridctrl.cxx:2567
css::uno::Reference< css::util::XNumberFormatter > m_xFormatter
Definition: gridctrl.hxx:229
std::vector< std::unique_ptr< DbGridColumn > > m_aColumns
Definition: gridctrl.hxx:232
virtual void SetNoSelection() override
css::uno::Any m_aBookmark
Definition: gridctrl.hxx:66
virtual OUString GetText() const
void AppendNew()
Definition: gridctrl.cxx:2539
virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessibleCell(sal_Int32 nRow, sal_uInt16 nColumnId) override
Creates the accessible object of a data table cell.
Definition: gridctrl.cxx:3618
void InvalidateAll(sal_Int32 nCurrentPos, bool bAll=false)
Definition: gridctrl.cxx:586
Point LeftCenter() const
void RowInserted(long nRow, long nNumRows=1, bool bDoPaint=true)
Definition: gridctrl.cxx:1880
void DrawLine(const Point &rStartPt, const Point &rEndPt)
sal_uInt16 nCode
bool IsPermanentCursorEnabled() const
Definition: gridctrl.cxx:1387
TRISTATE_INDET
long GetSelectRowCount() const
bool moveToBookmark(const css::uno::Any &bookmark)
Definition: fmtools.hxx:104
virtual void KeyInput(const KeyEvent &rEvt) override
Definition: gridctrl.cxx:290
sal_uInt16 GetColumnIdFromViewPos(sal_uInt16 nPos) const
Definition: gridctrl.hxx:420
::cppu::OWeakObject & m_rParent
AbsolutePos(vcl::Window *pParent, WinBits nStyle)
Definition: gridctrl.cxx:279
VclPtr< BrowserHeader > pHeader
OOO_DLLPUBLIC_DBTOOLS css::util::Date const & getStandardDate()
virtual void Select() override
Definition: gridctrl.cxx:1081
bool GoToColumnId(sal_uInt16 nColId)
virtual void onColumnChange()
called when the current column changed
Definition: gridctrl.cxx:2160
void DisconnectFromFields()
Definition: gridctrl.cxx:3520
static void RemoveUserEvent(ImplSVEvent *nUserEvent)
void SetNew(bool _bNew)
Definition: gridctrl.hxx:85
bool Commit()
Definition: gridcell.cxx:279
void InsertDataColumn(sal_uInt16 nItemId, const OUString &rText, long nSize, HeaderBarItemBits nBits=HeaderBarItemBits::STDSTYLE, sal_uInt16 nPos=HEADERBAR_APPEND)
#define DBG_UNHANDLED_EXCEPTION(...)
sal_Int32 m_nCurrentPos
Definition: gridctrl.hxx:279
T * get() const
sal_uInt32 const m_nId
virtual void dispose() override
Definition: gridctrl.cxx:999
bool m_bPendingAdjustRows
Definition: gridctrl.hxx:297
virtual long GetRowCount() const override
rtl::Reference<::comphelper::OPropertyChangeMultiplexer > m_pDataSourcePropMultiplexer
Definition: gridctrl.hxx:246
#define DBG_ASSERT(sCon, aError)
bool CompareBookmark(const Any &aLeft, const Any &aRight)
Definition: gridctrl.cxx:242
sal_uInt16 GetVisibleRows() const
#define HID_GRID_TRAVEL_PREV
Definition: helpids.h:51
bool m_bRecordCountFinal
Definition: gridctrl.hxx:290
virtual bool IsRowSelected(long nRow) const override
virtual void InitController(CellControllerRef &rController, long nRow, sal_uInt16 nCol)
bool canCopyCellText(sal_Int32 _nRow, sal_uInt16 _nColId)
returns if the text of the given cell can be copied into the clipboard
Definition: gridctrl.cxx:2764
virtual void columnChanged()=0
sal_Int32 AlignSeekCursor()
Definition: gridctrl.cxx:2246
OUString sName
bool getDisplaySynchron() const
Definition: gridctrl.hxx:470
DbGridControlOptions m_nOptions
Definition: gridctrl.hxx:281
bool m_bNavigationBar
Definition: gridctrl.hxx:291
void SetControlBackground()
virtual void SetText(const OUString &rStr) override
void AdjustRows()
Definition: gridctrl.cxx:1919
void SetMouseSettings(const MouseSettings &rSet)
virtual ~DbGridRow() override
Definition: gridctrl.cxx:882
long GetCurRow() const
int i
bool isAfterLast() const
Definition: fmtools.hxx:108
WinBits const WB_VCENTER
#define KEY_ESCAPE
sal_uInt16 GetItemId(sal_uInt16 nPos) const
TRISTATE_FALSE
void Create(SvxOrientationItem &rItem, SvStream &rStrm, sal_uInt16)
Definition: legacyitem.cxx:34
void AdjustDataSource(bool bFull=false)
Definition: gridctrl.cxx:2176
virtual ~GridFieldValueListener() override
Definition: gridctrl.cxx:167
void PositionDataSource(sal_Int32 nRecord)
Definition: gridctrl.cxx:319
DbGridControlOptions GetOptions() const
Definition: gridctrl.hxx:434
virtual void ShowColumn(sal_uInt16 nId)
show a column
Definition: gridctrl.cxx:3314
std::unique_ptr< CursorWrapper > m_pSeekCursor
Definition: gridctrl.hxx:263
void SetFillColor()
CommandEventId GetCommand() const
virtual bool SaveRow() override
Definition: gridctrl.cxx:3125
css::uno::Reference< css::sdb::XRowsChangeListener > m_xRowSetListener
Definition: gridctrl.hxx:249
virtual void CellModified() override
Definition: gridctrl.cxx:2889
float u
#define HID_GRID_TRAVEL_ABSOLUTE
Definition: helpids.h:55
bool HasHandle() const
Definition: gridctrl.hxx:405
CursorWrapper * GetSeekCursor(GrantControlAccess) const
Definition: gridctrl.hxx:522
ImplSVEvent * m_nAsynAdjustEvent
Definition: gridctrl.hxx:241
virtual void EndCursorAction()
Definition: gridctrl.cxx:3475
WinBits const WB_RECTSTYLE
void Merge(const Font &rFont)
css::uno::Reference< css::uno::XComponentContext > m_xContext
Definition: gridctrl.hxx:230
virtual void _propertyChanged(const PropertyChangeEvent &evt) override
Definition: gridctrl.cxx:172
bool ReserveControlArea(sal_uInt16 nWidth=USHRT_MAX)
MouseNotifyEvent GetType() const
long CalcReverseZoom(long nVal)
bool IsMouseCaptured() const
bool SetCurrent(long nNewRow)
Definition: gridctrl.cxx:2042
void RemoveColumn(sal_uInt16 nId)
Definition: gridctrl.cxx:1681
virtual void dispose() override
void FieldValueChanged(sal_uInt16 _nId)
Definition: gridctrl.cxx:3537
static const DbGridControlNavigationBarState ControlMap[]
Definition: gridctrl.cxx:228
BrowserMode
Link< DbGridControlNavigationBarState, int > m_aMasterStateProvider
Definition: gridctrl.hxx:226
const AllSettings & GetSettings() const
#define FM_PROP_ROWCOUNT
Definition: fmprop.hxx:32
sal_uInt16 GetColumnIdFromModelPos(sal_uInt16 nPos) const
Definition: gridctrl.cxx:3379
static OUString getUIRootDir()
::std::vector< std::unique_ptr<::svxform::DataColumn > > m_aVariants
Definition: gridctrl.hxx:68
virtual void SAL_CALL disposing(const css::lang::EventObject &) override
Definition: gridctrl.cxx:106
VclPtr< ImageButton > m_aNextBtn
Definition: gridctrl.hxx:194
DbGridRowRef m_xPaintRow
Definition: gridctrl.hxx:268
virtual void Resize() override
Definition: gridctrl.cxx:762
FmGridListener * m_pGridListener
Definition: gridctrl.hxx:259
void SetCursorColor(const Color &_rCol)
sal_Int32 m_nTotalCount
Definition: gridctrl.hxx:270
void InvalidateState(DbGridControlNavigationBarState nWhich)
Definition: gridctrl.hxx:208
virtual RowStatus GetRowStatus(long nRow) const override
Definition: gridctrl.cxx:1982
DbGridRowRef m_xDataRow
Definition: gridctrl.hxx:234
void refreshController(sal_uInt16 _nColId, GrantControlAccess _aAccess)
called when a controller needs to be re-initialized
Definition: gridctrl.cxx:1392
KeyFuncType GetFunction() const
void GrabFocus()
VclPtr< FixedText > m_aRecordCount
Definition: gridctrl.hxx:190
virtual void KeyInput(const KeyEvent &rKEvt) override
vcl::Window * GetParent() const
long X() const
sal_uInt16 GetColumnId(sal_uInt16 nPos) const
IMPL_LINK(DbGridControl::NavigationBar, OnClick, Button *, pButton, void)
Definition: gridctrl.cxx:551
Size GetSize() const
long m_nLastRowId
Definition: gridctrl.hxx:287
const long LONG_MAX
virtual void PreExecuteRowContextMenu(sal_uInt16 nRow, PopupMenu &rMenu)
This is called before executing a context menu for a row.
Definition: gridctrl.cxx:2659
WinBits const WB_REPEAT
void Disable(bool bChild=true)
void EnableItem(sal_uInt16 nItemId, bool bEnable=true)
css::util::Date m_aNullDate
Definition: gridctrl.hxx:276
virtual bool IsModified() const override
Definition: gridctrl.cxx:3061
void MoveToNext()
Definition: gridctrl.cxx:2468
const Point & GetMousePosPixel() const
#define HEADERBAR_APPEND
VclPtr< DbGridControl > m_pParent
Definition: gridctrl.cxx:249
bool m_bWantDestruction
Definition: gridctrl.hxx:296
void implAdjustInSolarThread(bool _bRows)
Definition: gridctrl.cxx:3415
void ReleaseMouse()
virtual void KeyInput(const KeyEvent &rKEvt)
#define KEY_RETURN
void SetSeekPos(sal_Int32 nPos, GrantControlAccess)
Definition: gridctrl.hxx:524
VclPtr< DbGridControl > m_pControl
Definition: gridctrl.cxx:98
void RowModified(long nRow)
Definition: gridctrl.cxx:3050
const vcl::KeyCode & GetKeyCode() const
FmXGridSourcePropListener(DbGridControl *_pParent)
Definition: gridctrl.cxx:264
bool IsShift() const
void UpdateFromField(const DbGridRow *pRow, const css::uno::Reference< css::util::XNumberFormatter > &xFormatter)
Definition: gridcell.cxx:269
#define HID_GRID_NUMBEROFRECORDS
Definition: helpids.h:56
bool m_bSynchDisplay
Definition: gridctrl.hxx:293
DbGridRowRef m_xEmptyRow
Definition: gridctrl.hxx:236
virtual void Resize() override
VclPtr< ImageButton > m_aPrevBtn
Definition: gridctrl.hxx:193
bool IsInsertionRow(long nRow) const
Definition: gridctrl.cxx:3071
void SetMouseTransparent(bool bTransparent)
bool IsResizing() const
virtual void dispose() override
Definition: gridctrl.cxx:403
DbGridRowRef m_xCurrentRow
Definition: gridctrl.hxx:267
void SetState(CursorWrapper *pCur, bool bPaintCursor)
Definition: gridctrl.cxx:886
void ImplInitWindow(const InitWindowFacet _eInitWhat)
Definition: gridctrl.cxx:1092
virtual void onRowChange()
called when the current row changed
Definition: gridctrl.cxx:2155
virtual ~DisposeListenerGridBridge() override
Definition: gridctrl.cxx:220
void SetFirst(sal_Int64 nNewFirst)
VclPtr< FixedText > m_aRecordText
Definition: gridctrl.hxx:187
virtual void Dispatch(sal_uInt16 nId) override
Definition: gridctrl.cxx:2938
void RemoveColumns()
Definition: gridctrl.cxx:1631
VclPtr< AbsolutePos > m_aAbsolute
Definition: gridctrl.hxx:188
void SetTransparent(bool bTransparent)
virtual void disposing(sal_Int16 _nId) override
Definition: gridctrl.cxx:206
OUString GetCellText(const DbGridRow *pRow, const css::uno::Reference< css::util::XNumberFormatter > &xFormatter) const
const CellControllerRef & Controller() const
virtual void Init() override
Definition: gridctrl.cxx:982
#define SAL_INFO(area, stream)
OUString aName
void EnableHandle(bool bEnable)
Definition: gridctrl.cxx:1190
sal_Unicode GetCharCode() const
void InsertHandleColumn()
Definition: gridctrl.cxx:973
void Paint(OutputDevice &rDev, const tools::Rectangle &rRect, const DbGridRow *pRow, const css::uno::Reference< css::util::XNumberFormatter > &xFormatter)
Definition: gridcell.cxx:459
bool IsMod1() const
#define FM_PROP_FETCHSIZE
Definition: fmprop.hxx:34
sal_uInt16 GetViewColumnPos(sal_uInt16 nId) const
Definition: gridctrl.hxx:409
void setDisplaySynchron(bool bSync)
Definition: gridctrl.cxx:2166
void * m_pFieldListeners
Definition: gridctrl.hxx:251
#define HID_GRID_TRAVEL_FIRST
Definition: helpids.h:50
long AdjustTop(long nVertMoveDelta)
std::unique_ptr< CursorWrapper > m_pDataCursor
Definition: gridctrl.hxx:262
bool Is() const
Definition: fmtools.hxx:87
const MouseSettings & GetMouseSettings() const
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect)
bool GetState(DbGridControlNavigationBarState nWhich) const
Definition: gridctrl.cxx:616
void SetDecimalDigits(sal_uInt16 nDigits)
virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessibleControl(sal_Int32 _nIndex) override
Creates the accessible object of an additional control.
Definition: gridctrl.cxx:3606
friend class FmXGridSourcePropListener
Definition: gridctrl.hxx:165
IMPL_LINK_NOARG(DbGridControl, OnDelete, void *, void)
Definition: gridctrl.cxx:2843
PopupMenu * get_menu(const OString &sID)
osl::Mutex m_aAdjustSafety
Definition: gridctrl.hxx:273
void ConnectToFields()
Definition: gridctrl.cxx:3492
void SetStatus(GridRowStatus _eStat)
Definition: gridctrl.hxx:83
VclPtr< ImageButton > m_aFirstBtn
Definition: gridctrl.hxx:192
static bool IsValid(const DbGridRowRef &_xRow)
Definition: gridctrl.hxx:561
long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
bool m_bHidden
Definition: gridcell.hxx:95
virtual ~DbGridControl() override
Definition: gridctrl.cxx:994
void InvalidateStatusCell(long nRow)
sal_uInt16 const m_nId
Definition: gridctrl.cxx:137
friend class FmXDisposeMultiplexer
Definition: fmtools.hxx:132
Reference< XConnection > getConnection(const Reference< XRowSet > &_rxRowSet)
RowSetEventListener(DbGridControl *i_pControl)
Definition: gridctrl.cxx:100
void copyCellText(sal_Int32 _nRow, sal_uInt16 _nColId)
copies the text of the given cell into the clipboard
Definition: gridctrl.cxx:2772
static constexpr auto DEFAULT_BROWSE_MODE
Definition: gridctrl.cxx:87
void SetState(DbGridControlNavigationBarState nWhich)
Definition: gridctrl.cxx:671
rtl::Reference<::comphelper::OPropertyChangeMultiplexer > m_pRealListener
Definition: gridctrl.cxx:136
virtual OUString GetCellText(long _nRow, sal_uInt16 _nColId) const override
GetCellText returns the text at the given position.
Definition: gridctrl.cxx:2628
virtual void PostExecuteRowContextMenu(sal_uInt16 nRow, const PopupMenu &rMenu, sal_uInt16 nExecutionResult)
After executing the context menu for a row this method is called.
Definition: gridctrl.cxx:2678
sal_Int32 m_nCurrentPos
virtual void HideColumn(sal_uInt16 nId)
hide a column
Definition: gridctrl.cxx:3285
ImplSVEvent * m_nDeleteEvent
Definition: gridctrl.hxx:280
bool hasProperty(const OUString &_rName, const Reference< XPropertySet > &_rxSet)
#define HID_GRID_TRAVEL_NEXT
Definition: helpids.h:52
tools::Rectangle GetRowRectPixel(long nRow) const
WinBits const WB_CENTER
virtual void KeyInput(const KeyEvent &rEvt) override
Definition: gridctrl.cxx:3268
DbGridControlOptions SetOptions(DbGridControlOptions nOpt)
Definition: gridctrl.cxx:1270
DisposeListenerGridBridge(DbGridControl &_rParent, const Reference< XComponent > &_rxObject)
Definition: gridctrl.cxx:209
bool IsEnabled() const
bool m_bFilterMode
Definition: gridctrl.hxx:295
class FmSearchEngine - Impl class for FmSearchDialog
sal_uLong GetDefaultColumnWidth(const OUString &_rText) const
bool isBeforeFirst() const
Definition: fmtools.hxx:107
bool IsHidden() const
Definition: gridcell.hxx:132
void ForceHideScrollbars()
forces both scrollbars to be hidden
Definition: gridctrl.cxx:1349
virtual void LoseFocus() override
virtual void selectionChanged()=0
GridRowStatus
Definition: gridctrl.hxx:52
void RowRemoved(long nRow, long nNumRows=1, bool bDoPaint=true)
Definition: gridctrl.cxx:1900
InitWindowFacet
Definition: gridctrl.hxx:116
Reference< XComponentContext > m_xContext
void resetCurrentRow()
Definition: gridctrl.cxx:3014
void dispose()
bool m_bIsNew
Definition: gridctrl.hxx:70
virtual void InitColumnsByFields(const css::uno::Reference< css::container::XIndexAccess > &xFields)=0
void RecalcRows(long nNewTopRow, sal_uInt16 nLinesOnScreen, bool bUpdateCursor)
Definition: gridctrl.cxx:1824
void SetButtonRepeat(sal_uLong nRepeat)
TriState
bool IsFilterRow(long nRow) const
Definition: gridctrl.hxx:429
css::uno::Any getBookmark()
Definition: fmtools.hxx:100
sal_uInt16 GetColumnAtXPosPixel(long nX) const
void SetHeaderBar(BrowserHeader *)
GridRowStatus m_eStatus
Definition: gridctrl.hxx:69
#define BROWSER_INVALIDID
sal_uInt16 GetId() const
Definition: gridcell.hxx:126
GridFieldValueListener(DbGridControl &_rParent, const Reference< XPropertySet > &xField, sal_uInt16 _nId)
Definition: gridctrl.cxx:153
sal_Int32 nState
const ::svt::CellControllerRef & GetController() const
Definition: gridcell.hxx:134
virtual void SetPosPixel(const Point &rNewPos)
bool IsValid() const
Definition: gridctrl.hxx:90
sal_uLong GetColumnWidth(sal_uInt16 nColumnId) const
void SelectColumnId(sal_uInt16 nColId)
sal_uInt16 GetCurColumnId() const
VclPtr< ImageButton > m_aNewBtn
Definition: gridctrl.hxx:196
Link< DbGridControlNavigationBarState, bool > m_aMasterSlotExecutor
Definition: gridctrl.hxx:227
DbGridRowRef m_xSeekRow
Definition: gridctrl.hxx:236
friend class DisposeListenerGridBridge
Definition: gridctrl.hxx:167
long Y() const
const MultiSelection * GetSelection() const
sal_uInt16 nPos
sal_uInt16 ColCount() const
long GetTopRow() const
void executeRowContextMenu(long _nRow, const Point &_rPreferredPos)
Definition: gridctrl.cxx:2780
bool SeekCursor(long nRow, bool bAbsolute=false)
Definition: gridctrl.cxx:2297
#define HID_GRID_TRAVEL_NEW
Definition: helpids.h:54
std::unique_ptr< DisposeListenerGridBridge > m_pCursorDisposeListener
Definition: gridctrl.hxx:254
virtual void RemoveRows() override
Definition: gridctrl.cxx:1156
#define FM_PROP_ENABLED
Definition: fmprop.hxx:44
bool IsMod2() const
void Show(bool bVisible=true, ShowFlags nFlags=ShowFlags::NONE)
bool m_bHideScrollbars
Definition: gridctrl.hxx:298
virtual void SAL_CALL rowsChanged(const css::sdb::RowsChangeEvent &i_aEvt) override
Definition: gridctrl.cxx:109
FmXGridCell * GetCell() const
Definition: gridcell.hxx:137