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  if ( IsControlFont() )
1112  m_aBar->SetControlFont( GetControlFont() );
1113  else
1114  m_aBar->SetControlFont();
1115 
1116  m_aBar->SetZoom( GetZoom() );
1117  }
1118  }
1119 
1120  if ( _eInitWhat & InitWindowFacet::Background )
1121  {
1122  if (IsControlBackground())
1123  {
1124  GetDataWindow().SetBackground(GetControlBackground());
1125  GetDataWindow().SetControlBackground(GetControlBackground());
1126  GetDataWindow().SetFillColor(GetControlBackground());
1127  }
1128  else
1129  {
1131  GetDataWindow().SetFillColor(GetFillColor());
1132  }
1133  }
1134 }
1135 
1136 void DbGridControl::RemoveRows(bool bNewCursor)
1137 {
1138  // Did the data cursor change?
1139  if (!bNewCursor)
1140  {
1141  m_pSeekCursor.reset();
1143  m_nCurrentPos = m_nSeekPos = -1;
1145 
1146  RowRemoved(0, GetRowCount(), false);
1147  m_nTotalCount = -1;
1148  }
1149  else
1150  {
1151  RemoveRows();
1152  }
1153 }
1154 
1156 {
1157  // we're going to remove all columns and all row, so deactivate the current cell
1158  if (IsEditing())
1159  DeactivateCell();
1160 
1161  // de-initialize all columns
1162  // if there are columns, free all controllers
1163  for (auto const & pColumn : m_aColumns)
1164  pColumn->Clear();
1165 
1166  m_pSeekCursor.reset();
1167  m_pDataCursor.reset();
1168 
1172 
1173  // reset number of sentences to zero in the browser
1174  EditBrowseBox::RemoveRows();
1175  m_aBar->InvalidateAll(m_nCurrentPos, true);
1176 }
1177 
1178 void DbGridControl::ArrangeControls(sal_uInt16& nX, sal_uInt16 nY)
1179 {
1180  // positioning of the controls
1181  if (m_bNavigationBar)
1182  {
1184  m_aBar->SetPosSizePixel(Point(0, nY + 1), Size(aRect.GetSize().Width(), aRect.GetSize().Height() - 1));
1185  nX = m_aBar->ArrangeControls();
1186  }
1187 }
1188 
1190 {
1191  if (m_bHandle == bEnable)
1192  return;
1193 
1194  // HandleColumn is only hidden because there are a lot of problems while painting otherwise
1196  m_bHandle = bEnable;
1198 }
1199 
1200 namespace
1201 {
1202  bool adjustModeForScrollbars( BrowserMode& _rMode, bool _bNavigationBar, bool _bHideScrollbars )
1203  {
1204  BrowserMode nOldMode = _rMode;
1205 
1206  if ( !_bNavigationBar )
1207  {
1208  _rMode &= ~BrowserMode::AUTO_HSCROLL;
1209  }
1210 
1211  if ( _bHideScrollbars )
1212  {
1213  _rMode |= BrowserMode::NO_HSCROLL | BrowserMode::NO_VSCROLL;
1214  _rMode &= ~BrowserMode( BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL );
1215  }
1216  else
1217  {
1218  _rMode |= BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL;
1219  _rMode &= ~BrowserMode( BrowserMode::NO_HSCROLL | BrowserMode::NO_VSCROLL );
1220  }
1221 
1222  // note: if we have a navigation bar, we always have an AUTO_HSCROLL. In particular,
1223  // _bHideScrollbars is ignored then
1224  if ( _bNavigationBar )
1225  {
1226  _rMode |= BrowserMode::AUTO_HSCROLL;
1227  _rMode &= ~BrowserMode::NO_HSCROLL;
1228  }
1229 
1230  return nOldMode != _rMode;
1231  }
1232 }
1233 
1235 {
1236  if (m_bNavigationBar == bEnable)
1237  return;
1238 
1239  m_bNavigationBar = bEnable;
1240 
1241  if (bEnable)
1242  {
1243  m_aBar->Show();
1244  m_aBar->Enable();
1245  m_aBar->InvalidateAll(m_nCurrentPos, true);
1246 
1247  if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1248  SetMode( m_nMode );
1249 
1250  // get size of the reserved ControlArea
1251  Point aPoint = GetControlArea().TopLeft();
1252  sal_uInt16 nX = static_cast<sal_uInt16>(aPoint.X());
1253 
1254  ArrangeControls(nX, static_cast<sal_uInt16>(aPoint.Y()));
1255  ReserveControlArea(nX);
1256  }
1257  else
1258  {
1259  m_aBar->Hide();
1260  m_aBar->Disable();
1261 
1262  if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1263  SetMode( m_nMode );
1264 
1266  }
1267 }
1268 
1270 {
1272  "DbGridControl::SetOptions : please do not call when editing a record (things are much easier this way ;) !");
1273 
1274  // for the next setDataSource (which is triggered by a refresh, for instance)
1275  m_nOptionMask = nOpt;
1276 
1277  // normalize the new options
1278  Reference< XPropertySet > xDataSourceSet = m_pDataCursor->getPropertySet();
1279  if (xDataSourceSet.is())
1280  {
1281  // check what kind of options are available
1282  sal_Int32 nPrivileges = 0;
1283  xDataSourceSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
1284  if ((nPrivileges & Privilege::INSERT) == 0)
1285  nOpt &= ~DbGridControlOptions::Insert;
1286  if ((nPrivileges & Privilege::UPDATE) == 0)
1287  nOpt &= ~DbGridControlOptions::Update;
1288  if ((nPrivileges & Privilege::DELETE) == 0)
1289  nOpt &= ~DbGridControlOptions::Delete;
1290  }
1291  else
1293 
1294  // need to do something after that ?
1295  if (nOpt == m_nOptions)
1296  return m_nOptions;
1297 
1298  // the 'update' option only affects our BrowserMode (with or w/o focus rect)
1299  BrowserMode nNewMode = m_nMode;
1300  if (!(m_nMode & BrowserMode::CURSOR_WO_FOCUS))
1301  {
1302  if (nOpt & DbGridControlOptions::Update)
1303  nNewMode |= BrowserMode::HIDECURSOR;
1304  else
1305  nNewMode &= ~BrowserMode::HIDECURSOR;
1306  }
1307  else
1308  nNewMode &= ~BrowserMode::HIDECURSOR;
1309  // should not be necessary if EnablePermanentCursor is used to change the cursor behaviour, but to be sure ...
1310 
1311  if (nNewMode != m_nMode)
1312  {
1313  SetMode(nNewMode);
1314  m_nMode = nNewMode;
1315  }
1316 
1317  // _after_ setting the mode because this results in an ActivateCell
1318  DeactivateCell();
1319 
1320  bool bInsertChanged = (nOpt & DbGridControlOptions::Insert) != (m_nOptions & DbGridControlOptions::Insert);
1321  m_nOptions = nOpt;
1322  // we need to set this before the code below because it indirectly uses m_nOptions
1323 
1324  // the 'insert' option affects our empty row
1325  if (bInsertChanged)
1326  {
1327  if (m_nOptions & DbGridControlOptions::Insert)
1328  { // the insert option is to be set
1329  m_xEmptyRow = new DbGridRow();
1331  }
1332  else
1333  { // the insert option is to be reset
1334  m_xEmptyRow = nullptr;
1335  if ((GetCurRow() == GetRowCount() - 1) && (GetCurRow() > 0))
1338  }
1339  }
1340 
1341  // the 'delete' options has no immediate consequences
1342 
1343  ActivateCell();
1344  Invalidate();
1345  return m_nOptions;
1346 }
1347 
1349 {
1350  if ( m_bHideScrollbars )
1351  return;
1352 
1353  m_bHideScrollbars = true;
1354 
1355  if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1356  SetMode( m_nMode );
1357 }
1358 
1360 {
1361  if (IsPermanentCursorEnabled() == bEnable)
1362  return;
1363 
1364  if (bEnable)
1365  {
1366  m_nMode &= ~BrowserMode::HIDECURSOR; // without this BrowserMode::CURSOR_WO_FOCUS won't have any affect
1367  m_nMode |= BrowserMode::CURSOR_WO_FOCUS;
1368  }
1369  else
1370  {
1372  m_nMode |= BrowserMode::HIDECURSOR; // no cursor at all
1373  else
1374  m_nMode &= ~BrowserMode::HIDECURSOR; // at least the "non-permanent" cursor
1375 
1376  m_nMode &= ~BrowserMode::CURSOR_WO_FOCUS;
1377  }
1378  SetMode(m_nMode);
1379 
1380  bool bWasEditing = IsEditing();
1381  DeactivateCell();
1382  if (bWasEditing)
1383  ActivateCell();
1384 }
1385 
1387 {
1388  return (m_nMode & BrowserMode::CURSOR_WO_FOCUS) && !(m_nMode & BrowserMode::HIDECURSOR);
1389 }
1390 
1391 void DbGridControl::refreshController(sal_uInt16 _nColId, GrantControlAccess /*_aAccess*/)
1392 {
1393  if ((GetCurColumnId() == _nColId) && IsEditing())
1394  { // the controller which is currently active needs to be refreshed
1395  DeactivateCell();
1396  ActivateCell();
1397  }
1398 }
1399 
1400 void DbGridControl::setDataSource(const Reference< XRowSet >& _xCursor, DbGridControlOptions nOpts)
1401 {
1402  if (!_xCursor.is() && !m_pDataCursor)
1403  return;
1404 
1406  {
1407  m_pDataSourcePropMultiplexer->dispose();
1408  m_pDataSourcePropMultiplexer.clear(); // this should delete the multiplexer
1410  m_pDataSourcePropListener = nullptr;
1411  }
1412  m_xRowSetListener.clear();
1413 
1414  // is the new cursor valid ?
1415  // the cursor is only valid if it contains some columns
1416  // if there is no cursor or the cursor is not valid we have to clean up and leave
1417  if (!_xCursor.is() || !Reference< XColumnsSupplier > (_xCursor, UNO_QUERY_THROW)->getColumns()->hasElements())
1418  {
1419  RemoveRows();
1420  return;
1421  }
1422 
1423  // did the data cursor change?
1424  sal_uInt16 nCurPos = GetColumnPos(GetCurColumnId());
1425 
1426  SetUpdateMode(false);
1427  RemoveRows();
1429 
1430  m_pCursorDisposeListener.reset();
1431 
1432  {
1433  ::osl::MutexGuard aGuard(m_aAdjustSafety);
1434  if (m_nAsynAdjustEvent)
1435  {
1436  // the adjust was thought to work with the old cursor which we don't have anymore
1437  RemoveUserEvent(m_nAsynAdjustEvent);
1438  m_nAsynAdjustEvent = nullptr;
1439  }
1440  }
1441 
1442  // get a new formatter and data cursor
1443  m_xFormatter = nullptr;
1444  Reference< css::util::XNumberFormatsSupplier > xSupplier = getNumberFormats(getConnection(_xCursor), true);
1445  if (xSupplier.is())
1446  {
1447  m_xFormatter = css::util::NumberFormatter::create(m_xContext);
1448  m_xFormatter->attachNumberFormatsSupplier(xSupplier);
1449 
1450  // retrieve the datebase of the Numberformatter
1451  try
1452  {
1453  xSupplier->getNumberFormatSettings()->getPropertyValue("NullDate") >>= m_aNullDate;
1454  }
1455  catch(Exception&)
1456  {
1457  }
1458  }
1459 
1460  m_pDataCursor.reset(new CursorWrapper(_xCursor));
1461 
1462  // now create a cursor for painting rows
1463  // we need that cursor only if we are not in insert only mode
1464  Reference< XResultSet > xClone;
1465  Reference< XResultSetAccess > xAccess( _xCursor, UNO_QUERY );
1466  try
1467  {
1468  xClone = xAccess.is() ? xAccess->createResultSet() : Reference< XResultSet > ();
1469  }
1470  catch(Exception&)
1471  {
1472  }
1473  if (xClone.is())
1474  m_pSeekCursor.reset(new CursorWrapper(xClone));
1475 
1476  // property listening on the data source
1477  // (Normally one class would be sufficient : the multiplexer which could forward the property change to us.
1478  // But for that we would have been derived from ::comphelper::OPropertyChangeListener, which isn't exported.
1479  // So we introduce a second class, which is a ::comphelper::OPropertyChangeListener (in the implementation file we know this class)
1480  // and forwards the property changes to our special method "DataSourcePropertyChanged".)
1481  if (m_pDataCursor)
1482  {
1484  m_pDataSourcePropMultiplexer = new ::comphelper::OPropertyChangeMultiplexer(m_pDataSourcePropListener, m_pDataCursor->getPropertySet() );
1487  }
1488 
1489  BrowserMode nOldMode = m_nMode;
1490  if (m_pSeekCursor)
1491  {
1492  try
1493  {
1494  Reference< XPropertySet > xSet(_xCursor, UNO_QUERY);
1495  if (xSet.is())
1496  {
1497  // check what kind of options are available
1498  sal_Int32 nConcurrency = ResultSetConcurrency::READ_ONLY;
1499  xSet->getPropertyValue(FM_PROP_RESULTSET_CONCURRENCY) >>= nConcurrency;
1500 
1501  if ( ResultSetConcurrency::UPDATABLE == nConcurrency )
1502  {
1503  sal_Int32 nPrivileges = 0;
1504  xSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
1505 
1506  // Insert Option should be set if insert only otherwise you won't see any rows
1507  // and no insertion is possible
1509  && ((nPrivileges & Privilege::INSERT) == Privilege::INSERT) && (nOpts & DbGridControlOptions::Insert))
1512  && ((nPrivileges & Privilege::UPDATE) == Privilege::UPDATE) && (nOpts & DbGridControlOptions::Update))
1515  && ((nPrivileges & Privilege::DELETE) == Privilege::DELETE) && (nOpts & DbGridControlOptions::Delete))
1517  }
1518  }
1519  }
1520  catch( const Exception& )
1521  {
1522  DBG_UNHANDLED_EXCEPTION("svx");
1523  }
1524 
1525  bool bPermanentCursor = IsPermanentCursorEnabled();
1527 
1528  if ( bPermanentCursor )
1529  {
1530  m_nMode |= BrowserMode::CURSOR_WO_FOCUS;
1531  m_nMode &= ~BrowserMode::HIDECURSOR;
1532  }
1533  else
1534  {
1535  // updates are allowed -> no focus rectangle
1537  m_nMode |= BrowserMode::HIDECURSOR;
1538  }
1539 
1540  m_nMode |= BrowserMode::MULTISELECTION;
1541 
1542  adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars );
1543 
1544  Reference< XColumnsSupplier > xSupplyColumns(_xCursor, UNO_QUERY);
1545  if (xSupplyColumns.is())
1546  InitColumnsByFields(Reference< XIndexAccess > (xSupplyColumns->getColumns(), UNO_QUERY));
1547 
1548  ConnectToFields();
1549  }
1550 
1551  sal_uInt32 nRecordCount(0);
1552 
1553  if (m_pSeekCursor)
1554  {
1555  Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
1556  xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
1557  m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
1558 
1560  Reference< XRowsChangeBroadcaster> xChangeBroad(xSet,UNO_QUERY);
1561  if ( xChangeBroad.is( ) )
1562  xChangeBroad->addRowsChangeListener(m_xRowSetListener);
1563 
1564 
1565  // insert the currently known rows
1566  // and one row if we are able to insert rows
1568  {
1569  // insert the empty row for insertion
1570  m_xEmptyRow = new DbGridRow();
1571  ++nRecordCount;
1572  }
1573  if (nRecordCount)
1574  {
1575  m_xPaintRow = m_xSeekRow = new DbGridRow(m_pSeekCursor.get(), true);
1576  m_xDataRow = new DbGridRow(m_pDataCursor.get(), false);
1577  RowInserted(0, nRecordCount, false);
1578 
1579  if (m_xSeekRow->IsValid())
1580  try
1581  {
1582  m_nSeekPos = m_pSeekCursor->getRow() - 1;
1583  }
1584  catch( const Exception& )
1585  {
1586  DBG_UNHANDLED_EXCEPTION("svx");
1587  m_nSeekPos = -1;
1588  }
1589  }
1590  else
1591  {
1592  // no rows so we don't need a seekcursor
1593  m_pSeekCursor.reset();
1594  }
1595  }
1596 
1597  // go to the old column
1598  if (nCurPos == BROWSER_INVALIDID || nCurPos >= ColCount())
1599  nCurPos = 0;
1600 
1601  // Column zero is a valid choice and guaranteed to exist,
1602  // but invisible to the user; if we have at least one
1603  // user-visible column, go to that one.
1604  if (nCurPos == 0 && ColCount() > 1)
1605  nCurPos = 1;
1606 
1607  // there are rows so go to the selected current column
1608  if (nRecordCount)
1609  GoToRowColumnId(0, GetColumnId(nCurPos));
1610  // else stop the editing if necessary
1611  else if (IsEditing())
1612  DeactivateCell();
1613 
1614  // now reset the mode
1615  if (m_nMode != nOldMode)
1616  SetMode(m_nMode);
1617 
1618  // RecalcRows was already called while resizing
1619  if (!IsResizing() && GetRowCount())
1620  RecalcRows(GetTopRow(), GetVisibleRows(), true);
1621 
1622  m_aBar->InvalidateAll(m_nCurrentPos, true);
1623  SetUpdateMode(true);
1624 
1625  // start listening on the seek cursor
1626  if (m_pSeekCursor)
1627  m_pCursorDisposeListener.reset(new DisposeListenerGridBridge(*this, Reference< XComponent > (Reference< XInterface >(*m_pSeekCursor), UNO_QUERY)));
1628 }
1629 
1631 {
1632  if ( IsEditing() )
1633  DeactivateCell();
1634 
1635  m_aColumns.clear();
1636 
1637  EditBrowseBox::RemoveColumns();
1638 }
1639 
1640 std::unique_ptr<DbGridColumn> DbGridControl::CreateColumn(sal_uInt16 nId) const
1641 {
1642  return std::unique_ptr<DbGridColumn>(new DbGridColumn(nId, *const_cast<DbGridControl*>(this)));
1643 }
1644 
1645 sal_uInt16 DbGridControl::AppendColumn(const OUString& rName, sal_uInt16 nWidth, sal_uInt16 nModelPos, sal_uInt16 nId)
1646 {
1647  DBG_ASSERT(nId == BROWSER_INVALIDID, "DbGridControl::AppendColumn : I want to set the ID myself ...");
1648  sal_uInt16 nRealPos = nModelPos;
1649  if (nModelPos != HEADERBAR_APPEND)
1650  {
1651  // calc the view pos. we can't use our converting functions because the new column
1652  // has no VCL-representation, yet.
1653  sal_Int16 nViewPos = nModelPos;
1654  while (nModelPos--)
1655  {
1656  if ( m_aColumns[ nModelPos ]->IsHidden() )
1657  --nViewPos;
1658  }
1659  // restore nModelPos, we need it later
1660  nModelPos = nRealPos;
1661  // the position the base class gets is the view pos + 1 (because of the handle column)
1662  nRealPos = nViewPos + 1;
1663  }
1664 
1665  // calculate the new id
1666  for (nId=1; (GetModelColumnPos(nId) != GRID_COLUMN_NOT_FOUND) && size_t(nId) <= m_aColumns.size(); ++nId)
1667  ;
1668  DBG_ASSERT(GetViewColumnPos(nId) == GRID_COLUMN_NOT_FOUND, "DbGridControl::AppendColumn : inconsistent internal state !");
1669  // my column's models say "there is no column with id nId", but the view (the base class) says "there is a column ..."
1670 
1671  EditBrowseBox::AppendColumn(rName, nWidth, nRealPos, nId);
1672  if (nModelPos == HEADERBAR_APPEND)
1673  m_aColumns.push_back( CreateColumn(nId) );
1674  else
1675  m_aColumns.insert( m_aColumns.begin() + nModelPos, CreateColumn(nId) );
1676 
1677  return nId;
1678 }
1679 
1680 void DbGridControl::RemoveColumn(sal_uInt16 nId)
1681 {
1682  EditBrowseBox::RemoveColumn(nId);
1683 
1684  const sal_uInt16 nIndex = GetModelColumnPos(nId);
1685  if(nIndex != GRID_COLUMN_NOT_FOUND)
1686  {
1687  m_aColumns.erase( m_aColumns.begin()+nIndex );
1688  }
1689 }
1690 
1691 void DbGridControl::ColumnMoved(sal_uInt16 nId)
1692 {
1693  EditBrowseBox::ColumnMoved(nId);
1694 
1695  // remove the col from the model
1696  sal_uInt16 nOldModelPos = GetModelColumnPos(nId);
1697 #ifdef DBG_UTIL
1698  DbGridColumn* pCol = m_aColumns[ nOldModelPos ].get();
1699  DBG_ASSERT(!pCol->IsHidden(), "DbGridControl::ColumnMoved : moved a hidden col ? how this ?");
1700 #endif
1701 
1702  // for the new model pos we can't use GetModelColumnPos because we are altering the model at the moment
1703  // so the method won't work (in fact it would return the old model pos)
1704 
1705  // the new view pos is calculated easily
1706  sal_uInt16 nNewViewPos = GetViewColumnPos(nId);
1707 
1708  // from that we can compute the new model pos
1709  size_t nNewModelPos;
1710  for (nNewModelPos = 0; nNewModelPos < m_aColumns.size(); ++nNewModelPos)
1711  {
1712  if (!m_aColumns[ nNewModelPos ]->IsHidden())
1713  {
1714  if (!nNewViewPos)
1715  break;
1716  else
1717  --nNewViewPos;
1718  }
1719  }
1720  DBG_ASSERT( nNewModelPos < m_aColumns.size(), "DbGridControl::ColumnMoved : could not find the new model position !");
1721 
1722  // this will work. of course the model isn't fully consistent with our view right now, but let's
1723  // look at the situation : a column has been moved with in the VIEW from pos m to n, say m<n (in the
1724  // other case we can use analogue arguments).
1725  // All cols k with m<k<=n have been shifted left on pos, the former col m now has pos n.
1726  // In the model this affects a range of cols x to y, where x<=m and y<=n. And the number of hidden cols
1727  // within this range is constant, so we may calculate the view pos from the model pos in the above way.
1728 
1729  // for instance, let's look at a grid with six columns where the third one is hidden. this will
1730  // initially look like this :
1731 
1732  // +---+---+---+---+---+---+
1733  // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1734  // +---+---+---+---+---+---+
1735  // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1736  // +---+---+---+---+---+---+
1737  // view pos | 0 | 1 | - | 2 | 3 | 4 |
1738  // +---+---+---+---+---+---+
1739 
1740  // if we move the column at (view) pos 1 to (view) pos 3 we have :
1741 
1742  // +---+---+---+---+---+---+
1743  // model pos | 0 | 3 |*2*| 4 | 1 | 5 | // not reflecting the changes, yet
1744  // +---+---+---+---+---+---+
1745  // ID | 1 | 4 | 3 | 5 | 2 | 6 | // already reflecting the changes
1746  // +---+---+---+---+---+---+
1747  // view pos | 0 | 1 | - | 2 | 3 | 4 |
1748  // +---+---+---+---+---+---+
1749 
1750  // or, sorted by the out-of-date model positions :
1751 
1752  // +---+---+---+---+---+---+
1753  // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1754  // +---+---+---+---+---+---+
1755  // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1756  // +---+---+---+---+---+---+
1757  // view pos | 0 | 3 | - | 1 | 2 | 4 |
1758  // +---+---+---+---+---+---+
1759 
1760  // We know the new view pos (3) of the moved column because our base class tells us. So we look at our
1761  // model for the 4th (the pos is zero-based) visible column, it is at (model) position 4. And this is
1762  // exactly the pos where we have to re-insert our column's model, so it looks ike this :
1763 
1764  // +---+---+---+---+---+---+
1765  // model pos | 0 |*1*| 2 | 3 | 4 | 5 |
1766  // +---+---+---+---+---+---+
1767  // ID | 1 | 3 | 4 | 5 | 2 | 6 |
1768  // +---+---+---+---+---+---+
1769  // view pos | 0 | - | 1 | 2 | 3 | 4 |
1770  // +---+---+---+---+---+---+
1771 
1772  // Now, all is consistent again.
1773  // (except of the hidden column : The cycling of the cols occurred on the model, not on the view. maybe
1774  // the user expected the latter but there really is no good argument against our method ;) ...)
1775 
1776  // And no, this large explanation isn't just because I wanted to play a board game or something like
1777  // that. It's because it took me a while to see it myself, and the whole theme (hidden cols, model col
1778  // positions, view col positions) is really painful (at least for me) so the above pictures helped me a lot ;)
1779 
1780  auto temp = std::move(m_aColumns[ nOldModelPos ]);
1781  m_aColumns.erase( m_aColumns.begin() + nOldModelPos );
1782  m_aColumns.insert( m_aColumns.begin() + nNewModelPos, std::move(temp) );
1783 }
1784 
1785 bool DbGridControl::SeekRow(long nRow)
1786 {
1787  // in filter mode or in insert only mode we don't have any cursor!
1788  if ( !SeekCursor( nRow ) )
1789  return false;
1790 
1791  if ( IsFilterMode() )
1792  {
1793  DBG_ASSERT( IsFilterRow( nRow ), "DbGridControl::SeekRow(): No filter row, wrong mode" );
1795  }
1796  else
1797  {
1798  // on the current position we have to take the current row for display as we want
1799  // to have the most recent values for display
1800  if ( ( nRow == m_nCurrentPos ) && getDisplaySynchron() )
1802  // seek to the empty insert row
1803  else if ( IsInsertionRow( nRow ) )
1805  else
1806  {
1807  m_xSeekRow->SetState( m_pSeekCursor.get(), true );
1809  }
1810  }
1811 
1812  EditBrowseBox::SeekRow(nRow);
1813 
1814  return m_nSeekPos >= 0;
1815 }
1816 
1817 // Is called whenever the visible amount of data changes
1818 void DbGridControl::VisibleRowsChanged( long nNewTopRow, sal_uInt16 nLinesOnScreen )
1819 {
1820  RecalcRows(nNewTopRow, nLinesOnScreen, false);
1821 }
1822 
1823 void DbGridControl::RecalcRows(long nNewTopRow, sal_uInt16 nLinesOnScreen, bool bUpdateCursor)
1824 {
1825  // If no cursor -> no rows in the browser.
1826  if (!m_pSeekCursor)
1827  {
1828  DBG_ASSERT(GetRowCount() == 0,"DbGridControl: without cursor no rows are allowed to be there");
1829  return;
1830  }
1831 
1832  // ignore any implicitly made updates
1833  bool bDisablePaint = !bUpdateCursor && IsPaintEnabled();
1834  if (bDisablePaint)
1835  EnablePaint(false);
1836 
1837  // adjust cache to the visible area
1838  Reference< XPropertySet > xSet = m_pSeekCursor->getPropertySet();
1839  sal_Int32 nCacheSize = 0;
1840  xSet->getPropertyValue(FM_PROP_FETCHSIZE) >>= nCacheSize;
1841  bool bCacheAligned = false;
1842  // no further cursor movements after initializing (m_nSeekPos < 0) because it is already
1843  // positioned on the first sentence
1844  long nDelta = nNewTopRow - GetTopRow();
1845  // limit for relative positioning
1846  long nLimit = nCacheSize ? nCacheSize / 2 : 0;
1847 
1848  // more lines on screen than in cache
1849  if (nLimit < nLinesOnScreen)
1850  {
1851  Any aCacheSize;
1852  aCacheSize <<= sal_Int32(nLinesOnScreen*2);
1853  xSet->setPropertyValue(FM_PROP_FETCHSIZE, aCacheSize);
1854  // here we need to update the cursor for sure
1855  bUpdateCursor = true;
1856  bCacheAligned = true;
1857  nLimit = nLinesOnScreen;
1858  }
1859 
1860  // In the following, all positionings are done as it is
1861  // ensured that there are enough lines in the data cache
1862 
1863  // window goes downwards with less than two windows difference or
1864  // the cache was updated and no rowcount yet
1865  if (nDelta < nLimit && (nDelta > 0
1866  || (bCacheAligned && m_nTotalCount < 0)) )
1867  SeekCursor(nNewTopRow + nLinesOnScreen - 1);
1868  else if (nDelta < 0 && std::abs(nDelta) < nLimit)
1869  SeekCursor(nNewTopRow);
1870  else if (nDelta != 0 || bUpdateCursor)
1871  SeekCursor(nNewTopRow, true);
1872 
1873  AdjustRows();
1874 
1875  // ignore any updates implicit made
1876  EnablePaint(true);
1877 }
1878 
1879 void DbGridControl::RowInserted(long nRow, long nNumRows, bool bDoPaint)
1880 {
1881  if (nNumRows)
1882  {
1884  {
1885  // if we have an insert row we have to reduce to count by 1
1886  // as the total count reflects only the existing rows in database
1887  m_nTotalCount = GetRowCount() + nNumRows;
1888  if (m_xEmptyRow.is())
1889  --m_nTotalCount;
1890  }
1891  else if (m_nTotalCount >= 0)
1892  m_nTotalCount += nNumRows;
1893 
1894  EditBrowseBox::RowInserted(nRow, nNumRows, bDoPaint);
1896  }
1897 }
1898 
1899 void DbGridControl::RowRemoved(long nRow, long nNumRows, bool bDoPaint)
1900 {
1901  if (nNumRows)
1902  {
1904  {
1905  m_nTotalCount = GetRowCount() - nNumRows;
1906  // if we have an insert row reduce by 1
1907  if (m_xEmptyRow.is())
1908  --m_nTotalCount;
1909  }
1910  else if (m_nTotalCount >= 0)
1911  m_nTotalCount -= nNumRows;
1912 
1913  EditBrowseBox::RowRemoved(nRow, nNumRows, bDoPaint);
1915  }
1916 }
1917 
1919 {
1920  if (!m_pSeekCursor)
1921  return;
1922 
1923  Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
1924 
1925  // refresh RecordCount
1926  sal_Int32 nRecordCount = 0;
1927  xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
1928  if (!m_bRecordCountFinal)
1929  m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
1930 
1931  // Did the number of rows change?
1932  // Here we need to consider that there might be an additional row for adding new data sets
1933 
1934  // add additional AppendRow for insertion
1936  ++nRecordCount;
1937 
1938  // If there is currently an insertion, so do not consider this added row in RecordCount or Appendrow
1940  m_xCurrentRow->IsNew())
1941  ++nRecordCount;
1942  // ensured with !m_bUpdating: otherwise the edited data set (that SaveRow added and why this
1943  // method was called) would be called twice (if m_bUpdating == sal_True): once in RecordCount
1944  // and a second time here (60787 - FS)
1945 
1946  if (nRecordCount != GetRowCount())
1947  {
1948  long nDelta = GetRowCount() - static_cast<long>(nRecordCount);
1949  if (nDelta > 0) // too many
1950  {
1951  RowRemoved(GetRowCount() - nDelta, nDelta, false);
1952  // some rows are gone, thus, repaint starting at the current position
1953  Invalidate();
1954 
1955  sal_Int32 nNewPos = AlignSeekCursor();
1956  if (m_bSynchDisplay)
1957  EditBrowseBox::GoToRow(nNewPos);
1958 
1959  SetCurrent(nNewPos);
1960  // there are rows so go to the selected current column
1961  if (nRecordCount)
1963  if (!IsResizing() && GetRowCount())
1964  RecalcRows(GetTopRow(), GetVisibleRows(), true);
1965  m_aBar->InvalidateAll(m_nCurrentPos, true);
1966  }
1967  else // too few
1968  RowInserted(GetRowCount(), -nDelta);
1969  }
1970 
1972  {
1973  if (m_nOptions & DbGridControlOptions::Insert)
1974  m_nTotalCount = GetRowCount() - 1;
1975  else
1977  }
1979 }
1980 
1982 {
1983  if (IsFilterRow(nRow))
1984  return EditBrowseBox::FILTER;
1985  else if (m_nCurrentPos >= 0 && nRow == m_nCurrentPos)
1986  {
1987  // new row
1988  if (!IsValid(m_xCurrentRow))
1989  return EditBrowseBox::DELETED;
1990  else if (IsModified())
1991  return EditBrowseBox::MODIFIED;
1992  else if (m_xCurrentRow->IsNew())
1993  return EditBrowseBox::CURRENTNEW;
1994  else
1995  return EditBrowseBox::CURRENT;
1996  }
1997  else if (IsInsertionRow(nRow))
1998  return EditBrowseBox::NEW;
1999  else if (!IsValid(m_xSeekRow))
2000  return EditBrowseBox::DELETED;
2001  else
2002  return EditBrowseBox::CLEAN;
2003 }
2004 
2005 void DbGridControl::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId) const
2006 {
2007  if (!IsValid(m_xPaintRow))
2008  return;
2009 
2010  size_t Location = GetModelColumnPos(nColumnId);
2011  DbGridColumn* pColumn = (Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2012  if (pColumn)
2013  {
2014  tools::Rectangle aArea(rRect);
2015  if ((GetMode() & BrowserMode::CURSOR_WO_FOCUS) == BrowserMode::CURSOR_WO_FOCUS)
2016  {
2017  aArea.AdjustTop(1 );
2018  aArea.AdjustBottom( -1 );
2019  }
2020  pColumn->Paint(rDev, aArea, m_xPaintRow.get(), getNumberFormatter());
2021  }
2022 }
2023 
2024 bool DbGridControl::CursorMoving(long nNewRow, sal_uInt16 nNewCol)
2025 {
2026 
2027  DeactivateCell( false );
2028 
2029  if ( m_pDataCursor
2030  && ( m_nCurrentPos != nNewRow )
2031  && !SetCurrent( nNewRow )
2032  )
2033  {
2034  ActivateCell();
2035  return false;
2036  }
2037 
2038  return EditBrowseBox::CursorMoving( nNewRow, nNewCol );
2039 }
2040 
2041 bool DbGridControl::SetCurrent(long nNewRow)
2042 {
2043  // Each movement of the datacursor must start with BeginCursorAction and end with
2044  // EndCursorAction to block all notifications during the movement
2046 
2047  try
2048  {
2049  // compare positions
2050  if (SeekCursor(nNewRow))
2051  {
2052  if (IsFilterRow(nNewRow)) // special mode for filtering
2053  {
2055  m_nCurrentPos = nNewRow;
2056  }
2057  else
2058  {
2059  bool bNewRowInserted = false;
2060  // Should we go to the insertrow ?
2061  if (IsInsertionRow(nNewRow))
2062  {
2063  // to we need to move the cursor to the insert row?
2064  // we need to insert the if the current row isn't the insert row or if the
2065  // cursor triggered the move by itself and we need a reinitialization of the row
2066  Reference< XPropertySet > xCursorProps = m_pDataCursor->getPropertySet();
2067  if ( !::comphelper::getBOOL(xCursorProps->getPropertyValue(FM_PROP_ISNEW)) )
2068  {
2069  Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
2070  xUpdateCursor->moveToInsertRow();
2071  }
2072  bNewRowInserted = true;
2073  }
2074  else
2075  {
2076 
2077  if ( !m_pSeekCursor->isBeforeFirst() && !m_pSeekCursor->isAfterLast() )
2078  {
2079  Any aBookmark = m_pSeekCursor->getBookmark();
2080  if (!m_xCurrentRow.is() || m_xCurrentRow->IsNew() || !CompareBookmark(aBookmark, m_pDataCursor->getBookmark()))
2081  {
2082  // adjust the cursor to the new desired row
2083  if (!m_pDataCursor->moveToBookmark(aBookmark))
2084  {
2085  EndCursorAction();
2086  return false;
2087  }
2088  }
2089  }
2090  }
2091  m_xDataRow->SetState(m_pDataCursor.get(), false);
2093 
2094  long nPaintPos = -1;
2095  // do we have to repaint the last regular row in case of setting defaults or autovalues
2096  if (m_nCurrentPos >= 0 && m_nCurrentPos >= (GetRowCount() - 2))
2097  nPaintPos = m_nCurrentPos;
2098 
2099  m_nCurrentPos = nNewRow;
2100 
2101  // repaint the new row to display all defaults
2102  if (bNewRowInserted)
2104  if (nPaintPos >= 0)
2105  RowModified(nPaintPos);
2106  }
2107  }
2108  else
2109  {
2110  OSL_FAIL("DbGridControl::SetCurrent : SeekRow failed !");
2111  EndCursorAction();
2112  return false;
2113  }
2114  }
2115  catch ( const Exception& )
2116  {
2117  DBG_UNHANDLED_EXCEPTION("svx");
2118  EndCursorAction();
2119  return false;
2120  }
2121 
2122  EndCursorAction();
2123  return true;
2124 }
2125 
2127 {
2128 
2129  // cursor movement due to deletion or insertion of rows
2131  {
2132  DeactivateCell();
2133  SetCurrent(GetCurRow());
2134  }
2135 
2136  EditBrowseBox::CursorMoved();
2137  m_aBar->InvalidateAll(m_nCurrentPos);
2138 
2139  // select the new column when they moved
2140  if ( IsDesignMode() && GetSelectedColumnCount() > 0 && GetCurColumnId() )
2141  {
2143  }
2144 
2145  if ( m_nLastColId != GetCurColumnId() )
2146  onColumnChange();
2148 
2149  if ( m_nLastRowId != GetCurRow() )
2150  onRowChange();
2151  m_nLastRowId = GetCurRow();
2152 }
2153 
2155 {
2156  // not interested in
2157 }
2158 
2160 {
2161  if ( m_pGridListener )
2163 }
2164 
2166 {
2167  if (bSync != m_bSynchDisplay)
2168  {
2169  m_bSynchDisplay = bSync;
2170  if (m_bSynchDisplay)
2171  AdjustDataSource();
2172  }
2173 }
2174 
2176 {
2177  SAL_INFO("svx.fmcomp", "DbGridControl::AdjustDataSource");
2178  SolarMutexGuard aGuard;
2179  // If the current row is recalculated at the moment, do not adjust
2180 
2181  if (bFull)
2182  m_xCurrentRow = nullptr;
2183  // if we are on the same row only repaint
2184  // but this is only possible for rows which are not inserted, in that case the comparison result
2185  // may not be correct
2186  else
2187  if ( m_xCurrentRow.is()
2188  && !m_xCurrentRow->IsNew()
2189  && !m_pDataCursor->isBeforeFirst()
2190  && !m_pDataCursor->isAfterLast()
2191  && !m_pDataCursor->rowDeleted()
2192  )
2193  {
2194  bool bEqualBookmarks = CompareBookmark( m_xCurrentRow->GetBookmark(), m_pDataCursor->getBookmark() );
2195 
2196  bool bDataCursorIsOnNew = false;
2197  m_pDataCursor->getPropertySet()->getPropertyValue( FM_PROP_ISNEW ) >>= bDataCursorIsOnNew;
2198 
2199  if ( bEqualBookmarks && !bDataCursorIsOnNew )
2200  {
2201  // position of my data cursor is the same as the position our current row points tpo
2202  // sync the status, repaint, done
2203  DBG_ASSERT(m_xDataRow == m_xCurrentRow, "Errors in the data row");
2204  SAL_INFO("svx.fmcomp", "same position, new state: " << ROWSTATUS(m_xCurrentRow));
2206  return;
2207  }
2208  }
2209 
2210  // away from the data cursor's row
2211  if (m_xPaintRow == m_xCurrentRow)
2213 
2214  // not up-to-date row, thus, adjust completely
2215  if (!m_xCurrentRow.is())
2216  AdjustRows();
2217 
2218  sal_Int32 nNewPos = AlignSeekCursor();
2219  if (nNewPos < 0)// could not find any position
2220  return;
2221 
2222  if (nNewPos != m_nCurrentPos)
2223  {
2224  if (m_bSynchDisplay)
2225  EditBrowseBox::GoToRow(nNewPos);
2226 
2227  if (!m_xCurrentRow.is())
2228  // Happens e.g. when deleting the n last datasets (n>1) while the cursor was positioned
2229  // on the last one. In this case, AdjustRows deletes two rows from BrowseBox, by what
2230  // CurrentRow is corrected to point two rows down, so that GoToRow will point into
2231  // emptiness (since we are - purportedly - at the correct position)
2232  SetCurrent(nNewPos);
2233  }
2234  else
2235  {
2236  SetCurrent(nNewPos);
2237  RowModified(nNewPos);
2238  }
2239 
2240  // if the data cursor was moved from outside, this section is voided
2241  SetNoSelection();
2242  m_aBar->InvalidateAll(m_nCurrentPos, m_xCurrentRow.is());
2243 }
2244 
2246 {
2247  // position SeekCursor onto the data cursor, no data transmission
2248 
2249  if (!m_pSeekCursor)
2250  return -1;
2251 
2252  Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
2253 
2254  // now align the seek cursor and the data cursor
2255  if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW)))
2256  m_nSeekPos = GetRowCount() - 1;
2257  else
2258  {
2259  try
2260  {
2261  if ( m_pDataCursor->isBeforeFirst() )
2262  {
2263  // this is somewhat strange, but can nevertheless happen
2264  SAL_INFO( "svx.fmcomp", "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (before first)!" );
2265  m_pSeekCursor->first();
2266  m_pSeekCursor->previous();
2267  m_nSeekPos = -1;
2268  }
2269  else if ( m_pDataCursor->isAfterLast() )
2270  {
2271  SAL_INFO( "svx.fmcomp", "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (after last)!" );
2272  m_pSeekCursor->last();
2273  m_pSeekCursor->next();
2274  m_nSeekPos = -1;
2275  }
2276  else
2277  {
2278  m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
2279  if (!CompareBookmark(m_pDataCursor->getBookmark(), m_pSeekCursor->getBookmark()))
2280  // unfortunately, moveToBookmark might lead to a re-positioning of the seek
2281  // cursor (if the complex moveToBookmark with all its events fires an update
2282  // somewhere) -> retry
2283  m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
2284  // Now there is still the chance of a failure but it is less likely.
2285  // The alternative would be a loop until everything is fine - no good solution...
2286  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2287  }
2288  }
2289  catch(Exception&)
2290  {
2291  }
2292  }
2293  return m_nSeekPos;
2294 }
2295 
2296 bool DbGridControl::SeekCursor(long nRow, bool bAbsolute)
2297 {
2298  // position SeekCursor onto the data cursor, no data transmission
2299 
2300  // additions for the filtermode
2301  if (IsFilterRow(nRow))
2302  {
2303  m_nSeekPos = 0;
2304  return true;
2305  }
2306 
2307  if (!m_pSeekCursor)
2308  return false;
2309 
2310  // is this an insertion?
2312  nRow >= m_nCurrentPos)
2313  {
2314  // if so, scrolling down must be prevented as this is already the last data set!
2315  if (nRow == m_nCurrentPos)
2316  {
2317  // no adjustment necessary
2318  m_nSeekPos = nRow;
2319  }
2320  else if (IsInsertionRow(nRow)) // blank row for data insertion
2321  m_nSeekPos = nRow;
2322  }
2323  else if (IsInsertionRow(nRow)) // blank row for data insertion
2324  m_nSeekPos = nRow;
2325  else if ((-1 == nRow) && (GetRowCount() == ((m_nOptions & DbGridControlOptions::Insert) ? 1 : 0)) && m_pSeekCursor->isAfterLast())
2326  m_nSeekPos = nRow;
2327  else
2328  {
2329  bool bSuccess = false;
2330  long nSteps = 0;
2331  try
2332  {
2333  if ( m_pSeekCursor->rowDeleted() )
2334  {
2335  // somebody deleted the current row of the seek cursor. Move it away from this row.
2336  m_pSeekCursor->next();
2337  if ( m_pSeekCursor->isAfterLast() || m_pSeekCursor->isBeforeFirst() )
2338  bAbsolute = true;
2339  }
2340 
2341  if ( !bAbsolute )
2342  {
2343  DBG_ASSERT( !m_pSeekCursor->isAfterLast() && !m_pSeekCursor->isBeforeFirst(),
2344  "DbGridControl::SeekCursor: how did the seek cursor get to this position?!" );
2345  nSteps = nRow - (m_pSeekCursor->getRow() - 1);
2346  bAbsolute = std::abs(nSteps) > 100;
2347  }
2348 
2349  if ( bAbsolute )
2350  {
2351  bSuccess = m_pSeekCursor->absolute(nRow + 1);
2352  if (bSuccess)
2353  m_nSeekPos = nRow;
2354  }
2355  else
2356  {
2357  if (nSteps > 0) // position onto the last needed data set
2358  {
2359  if (m_pSeekCursor->isAfterLast())
2360  bSuccess = false;
2361  else if (m_pSeekCursor->isBeforeFirst())
2362  bSuccess = m_pSeekCursor->absolute(nSteps);
2363  else
2364  bSuccess = m_pSeekCursor->relative(nSteps);
2365  }
2366  else if (nSteps < 0)
2367  {
2368  if (m_pSeekCursor->isBeforeFirst())
2369  bSuccess = false;
2370  else if (m_pSeekCursor->isAfterLast())
2371  bSuccess = m_pSeekCursor->absolute(nSteps);
2372  else
2373  bSuccess = m_pSeekCursor->relative(nSteps);
2374  }
2375  else
2376  {
2377  m_nSeekPos = nRow;
2378  return true;
2379  }
2380  }
2381  }
2382  catch(Exception&)
2383  {
2384  OSL_FAIL("DbGridControl::SeekCursor : failed ...");
2385  }
2386 
2387  try
2388  {
2389  if (!bSuccess)
2390  {
2391  if (bAbsolute || nSteps > 0)
2392  {
2393  if (m_pSeekCursor->isLast())
2394  bSuccess = true;
2395  else
2396  bSuccess = m_pSeekCursor->last();
2397  }
2398  else
2399  {
2400  if (m_pSeekCursor->isFirst())
2401  bSuccess = true;
2402  else
2403  bSuccess = m_pSeekCursor->first();
2404  }
2405  }
2406 
2407  if (bSuccess)
2408  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2409  else
2410  m_nSeekPos = -1;
2411  }
2412  catch(Exception&)
2413  {
2414  DBG_UNHANDLED_EXCEPTION("svx");
2415  OSL_FAIL("DbGridControl::SeekCursor : failed ...");
2416  m_nSeekPos = -1; // no further data set available
2417  }
2418  }
2419  return m_nSeekPos == nRow;
2420 }
2421 
2423 {
2424  if (m_pSeekCursor && (GetCurRow() != 0))
2425  MoveToPosition(0);
2426 }
2427 
2429 {
2430  if (!m_pSeekCursor)
2431  return;
2432 
2433  if (m_nTotalCount < 0) // no RecordCount, yet
2434  {
2435  try
2436  {
2437  bool bRes = m_pSeekCursor->last();
2438 
2439  if (bRes)
2440  {
2441  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2442  AdjustRows();
2443  }
2444  }
2445  catch(Exception&)
2446  {
2447  }
2448  }
2449 
2450  // position onto the last data set not on a blank row
2452  {
2453  if ((GetRowCount() - 1) > 0)
2454  MoveToPosition(GetRowCount() - 2);
2455  }
2456  else if (GetRowCount())
2457  MoveToPosition(GetRowCount() - 1);
2458 }
2459 
2461 {
2462  long nNewRow = std::max(GetCurRow() - 1, 0L);
2463  if (GetCurRow() != nNewRow)
2464  MoveToPosition(nNewRow);
2465 }
2466 
2468 {
2469  if (!m_pSeekCursor)
2470  return;
2471 
2472  if (m_nTotalCount > 0)
2473  {
2474  // move the data cursor to the right position
2475  long nNewRow = std::min(GetRowCount() - 1, GetCurRow() + 1);
2476  if (GetCurRow() != nNewRow)
2477  MoveToPosition(nNewRow);
2478  }
2479  else
2480  {
2481  bool bOk = false;
2482  try
2483  {
2484  // try to move to next row
2485  // when not possible our paint cursor is already on the last row
2486  // then we must be sure that the data cursor is on the position
2487  // we call ourself again
2488  bOk = m_pSeekCursor->next();
2489  if (bOk)
2490  {
2491  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2492  MoveToPosition(GetCurRow() + 1);
2493  }
2494  }
2495  catch(SQLException &)
2496  {
2497  DBG_UNHANDLED_EXCEPTION("svx");
2498  }
2499 
2500  if(!bOk)
2501  {
2502  AdjustRows();
2503  if (m_nTotalCount > 0) // only to avoid infinite recursion
2504  MoveToNext();
2505  }
2506  }
2507 }
2508 
2509 void DbGridControl::MoveToPosition(sal_uInt32 nPos)
2510 {
2511  if (!m_pSeekCursor)
2512  return;
2513 
2514  if (m_nTotalCount < 0 && static_cast<long>(nPos) >= GetRowCount())
2515  {
2516  try
2517  {
2518  if (!m_pSeekCursor->absolute(nPos + 1))
2519  {
2520  AdjustRows();
2521  return;
2522  }
2523  else
2524  {
2525  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2526  AdjustRows();
2527  }
2528  }
2529  catch(Exception&)
2530  {
2531  return;
2532  }
2533  }
2534  EditBrowseBox::GoToRow(nPos);
2535  m_aBar->InvalidateAll(m_nCurrentPos);
2536 }
2537 
2539 {
2541  return;
2542 
2543  if (m_nTotalCount < 0) // no RecordCount, yet
2544  {
2545  try
2546  {
2547  bool bRes = m_pSeekCursor->last();
2548 
2549  if (bRes)
2550  {
2551  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2552  AdjustRows();
2553  }
2554  }
2555  catch(Exception&)
2556  {
2557  return;
2558  }
2559  }
2560 
2561  long nNewRow = m_nTotalCount + 1;
2562  if (nNewRow > 0 && GetCurRow() != nNewRow)
2563  MoveToPosition(nNewRow - 1);
2564 }
2565 
2567 {
2568  if (IsDesignMode() != bMode)
2569  {
2570  // adjust Enable/Disable for design mode so that the headerbar remains configurable
2571  if (bMode)
2572  {
2573  if (!IsEnabled())
2574  {
2575  Enable();
2576  GetDataWindow().Disable();
2577  }
2578  }
2579  else
2580  {
2581  // disable completely
2582  if (!GetDataWindow().IsEnabled())
2583  Disable();
2584  }
2585 
2586  m_bDesignMode = bMode;
2588  SetMouseTransparent(bMode);
2589 
2590  m_aBar->InvalidateAll(m_nCurrentPos, true);
2591  }
2592 }
2593 
2595 {
2596  if (IsFilterMode() != bMode)
2597  {
2598  m_bFilterMode = bMode;
2599 
2600  if (bMode)
2601  {
2602  SetUpdateMode(false);
2603 
2604  // there is no cursor anymore
2605  if (IsEditing())
2606  DeactivateCell();
2607  RemoveRows(false);
2608 
2609  m_xEmptyRow = new DbGridRow();
2610 
2611  // setting the new filter controls
2612  for (auto const & pCurCol : m_aColumns)
2613  {
2614  if (!pCurCol->IsHidden())
2615  pCurCol->UpdateControl();
2616  }
2617 
2618  // one row for filtering
2619  RowInserted(0);
2620  SetUpdateMode(true);
2621  }
2622  else
2623  setDataSource(Reference< XRowSet > ());
2624  }
2625 }
2626 
2627 OUString DbGridControl::GetCellText(long _nRow, sal_uInt16 _nColId) const
2628 {
2629  size_t Location = GetModelColumnPos( _nColId );
2630  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2631  OUString sRet;
2632  if ( const_cast<DbGridControl*>(this)->SeekRow(_nRow) )
2633  sRet = GetCurrentRowCellText(pColumn, m_xPaintRow);
2634  return sRet;
2635 }
2636 
2637 OUString DbGridControl::GetCurrentRowCellText(DbGridColumn const * pColumn,const DbGridRowRef& _rRow) const
2638 {
2639  // text output for a single row
2640  OUString aText;
2641  if ( pColumn && IsValid(_rRow) )
2642  aText = pColumn->GetCellText(_rRow.get(), m_xFormatter);
2643  return aText;
2644 }
2645 
2646 sal_uInt32 DbGridControl::GetTotalCellWidth(long nRow, sal_uInt16 nColId)
2647 {
2648  if (SeekRow(nRow))
2649  {
2650  size_t Location = GetModelColumnPos( nColId );
2651  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2653  }
2654  else
2655  return 30; // FIXME magic number for default cell width
2656 }
2657 
2658 void DbGridControl::PreExecuteRowContextMenu(sal_uInt16 /*nRow*/, PopupMenu& rMenu)
2659 {
2661  // if only a blank row is selected then do not delete
2662  bDelete = bDelete && !((m_nOptions & DbGridControlOptions::Insert) && GetSelectRowCount() == 1 && IsRowSelected(GetRowCount() - 1));
2663 
2664  rMenu.EnableItem(rMenu.GetItemId("delete"), bDelete);
2665  rMenu.EnableItem(rMenu.GetItemId("save"), IsModified());
2666 
2667  // the undo is more difficult
2668  bool bCanUndo = IsModified();
2669  int nState = -1;
2672  bCanUndo &= ( 0 != nState );
2673 
2674  rMenu.EnableItem(rMenu.GetItemId("undo"), bCanUndo);
2675 }
2676 
2677 void DbGridControl::PostExecuteRowContextMenu(sal_uInt16 /*nRow*/, const PopupMenu& rMenu, sal_uInt16 nExecutionResult)
2678 {
2679  if (nExecutionResult == rMenu.GetItemId("delete"))
2680  {
2681  // delete asynchronously
2682  if (m_nDeleteEvent)
2684  m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete), nullptr, true);
2685  }
2686  else if (nExecutionResult == rMenu.GetItemId("undo"))
2687  Undo();
2688  else if (nExecutionResult == rMenu.GetItemId("save"))
2689  SaveRow();
2690 }
2691 
2692 void DbGridControl::DataSourcePropertyChanged(const PropertyChangeEvent& evt)
2693 {
2694  SAL_INFO("svx.fmcomp", "DbGridControl::DataSourcePropertyChanged");
2695  SolarMutexGuard aGuard;
2696  // prop "IsModified" changed ?
2697  // during update don't care about the modified state
2698  if (!IsUpdating() && evt.PropertyName == FM_PROP_ISMODIFIED )
2699  {
2700  Reference< XPropertySet > xSource(evt.Source, UNO_QUERY);
2701  DBG_ASSERT( xSource.is(), "DbGridControl::DataSourcePropertyChanged: invalid event source!" );
2702  bool bIsNew = false;
2703  if (xSource.is())
2704  bIsNew = ::comphelper::getBOOL(xSource->getPropertyValue(FM_PROP_ISNEW));
2705 
2706  if (bIsNew && m_xCurrentRow.is())
2707  {
2708  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 !");
2709  sal_Int32 nRecordCount = 0;
2710  xSource->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
2711  if (::comphelper::getBOOL(evt.NewValue))
2712  { // modified state changed from sal_False to sal_True and we're on an insert row
2713  // -> we've to add a new grid row
2714  if ((nRecordCount == GetRowCount() - 1) && m_xCurrentRow->IsNew())
2715  {
2718  m_aBar->InvalidateAll(m_nCurrentPos);
2719  }
2720  }
2721  else
2722  { // modified state changed from sal_True to sal_False and we're on an insert row
2723  // we have two "new row"s at the moment : the one we're editing currently (where the current
2724  // column is the only dirty element) and a "new new" row which is completely clean. As the first
2725  // one is about to be cleaned, too, the second one is obsolete now.
2726  if (m_xCurrentRow->IsNew() && nRecordCount == (GetRowCount() - 2))
2727  {
2728  RowRemoved(GetRowCount() - 1);
2730  m_aBar->InvalidateAll(m_nCurrentPos);
2731  }
2732  }
2733  }
2734  if (m_xCurrentRow.is())
2735  {
2737  m_xCurrentRow->SetNew( bIsNew );
2739  SAL_INFO("svx.fmcomp", "modified flag changed, new state: " << ROWSTATUS(m_xCurrentRow));
2740  }
2741  }
2742 }
2743 
2744 void DbGridControl::StartDrag( sal_Int8 /*nAction*/, const Point& rPosPixel )
2745 {
2746  if (!m_pSeekCursor || IsResizing())
2747  return;
2748 
2749  sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rPosPixel.X()));
2750  long nRow = GetRowAtYPosPixel(rPosPixel.Y());
2751  if (nColId != HandleColumnId && nRow >= 0)
2752  {
2755 
2756  size_t Location = GetModelColumnPos( nColId );
2757  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2758  rtl::Reference<OStringTransferable> pTransferable = new OStringTransferable(GetCurrentRowCellText(pColumn,m_xPaintRow));
2759  pTransferable->StartDrag(this, DND_ACTION_COPY);
2760  }
2761 }
2762 
2763 bool DbGridControl::canCopyCellText(sal_Int32 _nRow, sal_uInt16 _nColId)
2764 {
2765  return (_nRow >= 0)
2766  && (_nRow < GetRowCount())
2767  && (_nColId != HandleColumnId)
2768  && (GetModelColumnPos(_nColId) != GRID_COLUMN_NOT_FOUND);
2769 }
2770 
2771 void DbGridControl::copyCellText(sal_Int32 _nRow, sal_uInt16 _nColId)
2772 {
2773  DBG_ASSERT(canCopyCellText(_nRow, _nColId), "DbGridControl::copyCellText: invalid call!");
2774  DbGridColumn* pColumn = m_aColumns[ GetModelColumnPos(_nColId) ].get();
2775  SeekRow(_nRow);
2776  OStringTransfer::CopyString( GetCurrentRowCellText( pColumn,m_xPaintRow ), this );
2777 }
2778 
2779 void DbGridControl::executeRowContextMenu( long _nRow, const Point& _rPreferredPos )
2780 {
2781  VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "svx/ui/rowsmenu.ui", "");
2782  VclPtr<PopupMenu> aContextMenu(aBuilder.get_menu("menu"));
2783 
2784  PreExecuteRowContextMenu( static_cast<sal_uInt16>(_nRow), *aContextMenu );
2785  aContextMenu->RemoveDisabledEntries( true, true );
2786  PostExecuteRowContextMenu( static_cast<sal_uInt16>(_nRow), *aContextMenu, aContextMenu->Execute( this, _rPreferredPos ) );
2787 }
2788 
2790 {
2791  switch (rEvt.GetCommand())
2792  {
2793  case CommandEventId::ContextMenu:
2794  {
2795  if ( !m_pSeekCursor )
2796  {
2797  EditBrowseBox::Command(rEvt);
2798  return;
2799  }
2800 
2801  if ( !rEvt.IsMouseEvent() )
2802  { // context menu requested by keyboard
2803  if ( GetSelectRowCount() )
2804  {
2805  long nRow = FirstSelectedRow( );
2806 
2807  ::tools::Rectangle aRowRect( GetRowRectPixel( nRow ) );
2808  executeRowContextMenu( nRow, aRowRect.LeftCenter() );
2809 
2810  // handled
2811  return;
2812  }
2813  }
2814 
2815  sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X()));
2816  long nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y());
2817 
2818  if (nColId == HandleColumnId)
2819  {
2820  executeRowContextMenu( nRow, rEvt.GetMousePosPixel() );
2821  }
2822  else if (canCopyCellText(nRow, nColId))
2823  {
2824  VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "svx/ui/cellmenu.ui", "");
2825  VclPtr<PopupMenu> aContextMenu(aBuilder.get_menu("menu"));
2826  if (aContextMenu->Execute(this, rEvt.GetMousePosPixel()))
2827  copyCellText(nRow, nColId);
2828  }
2829  else
2830  {
2831  EditBrowseBox::Command(rEvt);
2832  return;
2833  }
2834 
2835  [[fallthrough]];
2836  }
2837  default:
2838  EditBrowseBox::Command(rEvt);
2839  }
2840 }
2841 
2842 IMPL_LINK_NOARG(DbGridControl, OnDelete, void*, void)
2843 {
2844  m_nDeleteEvent = nullptr;
2845  DeleteSelectedRows();
2846 }
2847 
2849 {
2850  DBG_ASSERT(GetSelection(), "no selection!!!");
2851 
2852  if (!m_pSeekCursor)
2853  return;
2854 }
2855 
2856 CellController* DbGridControl::GetController(long /*nRow*/, sal_uInt16 nColumnId)
2857 {
2858  if (!IsValid(m_xCurrentRow) || !IsEnabled())
2859  return nullptr;
2860 
2861  size_t Location = GetModelColumnPos(nColumnId);
2862  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2863  if (!pColumn)
2864  return nullptr;
2865 
2866  CellController* pReturn = nullptr;
2867  if (IsFilterMode())
2868  pReturn = pColumn->GetController().get();
2869  else
2870  {
2872  {
2873  if (!::comphelper::getBOOL(pColumn->getModel()->getPropertyValue(FM_PROP_ENABLED)))
2874  return nullptr;
2875  }
2876 
2877  bool bInsert = (m_xCurrentRow->IsNew() && (m_nOptions & DbGridControlOptions::Insert));
2878  bool bUpdate = (!m_xCurrentRow->IsNew() && (m_nOptions & DbGridControlOptions::Update));
2879 
2880  if ((bInsert && !pColumn->IsAutoValue()) || bUpdate)
2881  {
2882  pReturn = pColumn->GetController().get();
2883  }
2884  }
2885  return pReturn;
2886 }
2887 
2889 {
2890  SAL_INFO("svx.fmcomp", "DbGridControl::CellModified");
2891 
2892  {
2893  ::osl::MutexGuard aGuard(m_aAdjustSafety);
2894  if (m_nAsynAdjustEvent)
2895  {
2896  SAL_INFO("svx.fmcomp", "forcing a synchron call to " << (m_bPendingAdjustRows ? "AdjustRows" : "AdustDataSource"));
2897  RemoveUserEvent(m_nAsynAdjustEvent);
2898  m_nAsynAdjustEvent = nullptr;
2899 
2900  // force the call : this should be no problem as we're probably running in the solar thread here
2901  // (cell modified is triggered by user actions)
2903  AdjustRows();
2904  else
2905  AdjustDataSource();
2906  }
2907  }
2908 
2910  {
2911  // enable edit mode
2912  // a data set should be inserted
2913  if (m_xCurrentRow->IsNew())
2914  {
2916  SAL_INFO("svx.fmcomp", "current row is new, new state: MODIFIED");
2917  // if no row was added yet, do it now
2918  if (m_nCurrentPos == GetRowCount() - 1)
2919  {
2920  // increment RowCount
2923  m_aBar->InvalidateAll(m_nCurrentPos);
2924  }
2925  }
2927  {
2928  m_xCurrentRow->SetState(m_pDataCursor.get(), false);
2929  SAL_INFO("svx.fmcomp", "current row is not new, after SetState, new state: " << ROWSTATUS(m_xCurrentRow));
2931  SAL_INFO("svx.fmcomp", "current row is not new, new state: MODIFIED");
2933  }
2934  }
2935 }
2936 
2937 void DbGridControl::Dispatch(sal_uInt16 nId)
2938 {
2939  if (nId == BROWSER_CURSORENDOFFILE)
2940  {
2942  AppendNew();
2943  else
2944  MoveToLast();
2945  }
2946  else
2947  EditBrowseBox::Dispatch(nId);
2948 }
2949 
2951 {
2952  if (IsFilterMode() || !IsValid(m_xCurrentRow) || !IsModified())
2953  return;
2954 
2955  // check if we have somebody doin' the UNDO for us
2956  int nState = -1;
2959  if (nState>0)
2960  { // yes, we have, and the slot is enabled
2961  DBG_ASSERT(m_aMasterSlotExecutor.IsSet(), "DbGridControl::Undo : a state, but no execute link ?");
2963  if (lResult)
2964  // handled
2965  return;
2966  }
2967  else if (nState == 0)
2968  // yes, we have, and the slot is disabled
2969  return;
2970 
2972 
2973  bool bAppending = m_xCurrentRow->IsNew();
2974  bool bDirty = m_xCurrentRow->IsModified();
2975 
2976  try
2977  {
2978  // cancel editing
2979  Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
2980  // no effects if we're not updating currently
2981  if (bAppending)
2982  // just refresh the row
2983  xUpdateCursor->moveToInsertRow();
2984  else
2985  xUpdateCursor->cancelRowUpdates();
2986 
2987  }
2988  catch(Exception&)
2989  {
2990  DBG_UNHANDLED_EXCEPTION("svx");
2991  }
2992 
2993  EndCursorAction();
2994 
2995  m_xDataRow->SetState(m_pDataCursor.get(), false);
2996  if (m_xPaintRow == m_xCurrentRow)
2998  else
3000 
3001  if (bAppending && (EditBrowseBox::IsModified() || bDirty))
3002  // remove the row
3003  if (m_nCurrentPos == GetRowCount() - 2)
3004  { // maybe we already removed it (in resetCurrentRow, called if the above moveToInsertRow
3005  // caused our data source form to be reset - which should be the usual case...)
3006  RowRemoved(GetRowCount() - 1);
3007  m_aBar->InvalidateAll(m_nCurrentPos);
3008  }
3009 
3011 }
3012 
3014 {
3015  if (IsModified())
3016  {
3017  // scenario : we're on the insert row, the row is dirty, and thus there exists a "second" insert row (which
3018  // is clean). Normally in DataSourcePropertyChanged we would remove this second row if the modified state of
3019  // the insert row changes from sal_True to sal_False. But if our current cell is the only modified element (means the
3020  // data source isn't modified) and we're reset this DataSourcePropertyChanged would never be called, so we
3021  // would never delete the obsolete "second insert row". Thus in this special case this method here
3022  // is the only possibility to determine the redundance of the row (resetCurrentRow is called when the
3023  // "first insert row" is about to be cleaned, so of course the "second insert row" is redundant now)
3024  Reference< XPropertySet > xDataSource = getDataSource()->getPropertySet();
3025  if (xDataSource.is() && !::comphelper::getBOOL(xDataSource->getPropertyValue(FM_PROP_ISMODIFIED)))
3026  {
3027  // are we on a new row currently ?
3028  if (m_xCurrentRow->IsNew())
3029  {
3030  if (m_nCurrentPos == GetRowCount() - 2)
3031  {
3032  RowRemoved(GetRowCount() - 1);
3033  m_aBar->InvalidateAll(m_nCurrentPos);
3034  }
3035  }
3036  }
3037 
3038  // update the rows
3039  m_xDataRow->SetState(m_pDataCursor.get(), false);
3040  if (m_xPaintRow == m_xCurrentRow)
3042  else
3044  }
3045 
3046  RowModified(GetCurRow()); // will update the current controller if affected
3047 }
3048 
3050 {
3051  if (nRow == m_nCurrentPos && IsEditing())
3052  {
3053  CellControllerRef aTmpRef = Controller();
3054  aTmpRef->ClearModified();
3056  }
3057  EditBrowseBox::RowModified(nRow);
3058 }
3059 
3061 {
3062  return !IsFilterMode() && IsValid(m_xCurrentRow) && (m_xCurrentRow->IsModified() || EditBrowseBox::IsModified());
3063 }
3064 
3066 {
3067  return m_xCurrentRow.is() && m_xCurrentRow->IsNew();
3068 }
3069 
3070 bool DbGridControl::IsInsertionRow(long nRow) const
3071 {
3072  return (m_nOptions & DbGridControlOptions::Insert) && m_nTotalCount >= 0 && (nRow == GetRowCount() - 1);
3073 }
3074 
3076 {
3077  SAL_INFO("svx.fmcomp", "DbGridControl::SaveModified");
3078  DBG_ASSERT(IsValid(m_xCurrentRow), "GridControl:: Invalid row");
3079  if (!IsValid(m_xCurrentRow))
3080  return true;
3081 
3082  // accept input for this field
3083  // Where there changes at the current input field?
3084  if (!EditBrowseBox::IsModified())
3085  return true;
3086 
3088  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3089  bool bOK = pColumn && pColumn->Commit();
3090  DBG_ASSERT( Controller().is(), "DbGridControl::SaveModified: was modified, by have no controller?!" );
3091  if ( !Controller().is() )
3092  // this might happen if the callbacks implicitly triggered by Commit
3093  // fiddled with the form or the control ...
3094  // (Note that this here is a workaround, at most. We need a general concept how
3095  // to treat this, you can imagine an arbitrary number of scenarios where a callback
3096  // triggers something which leaves us in an expected state.)
3097  // #i67147# / 2006-07-17 / frank.schoenheit@sun.com
3098  return bOK;
3099 
3100  if (bOK)
3101  {
3102  Controller()->ClearModified();
3103 
3104  if ( IsValid(m_xCurrentRow) )
3105  {
3106  m_xCurrentRow->SetState(m_pDataCursor.get(), false);
3107  SAL_INFO("svx.fmcomp", "explicit SetState, new state: " << ROWSTATUS(m_xCurrentRow));
3109  }
3110  else
3111  {
3112  SAL_INFO("svx.fmcomp", "no SetState, new state: " << ROWSTATUS(m_xCurrentRow));
3113  }
3114  }
3115  else
3116  {
3117  // reset the modified flag...
3118  Controller()->SetModified();
3119  }
3120 
3121  return bOK;
3122 }
3123 
3125 {
3126  SAL_INFO("svx.fmcomp", "DbGridControl::SaveRow");
3127  // valid row
3128  if (!IsValid(m_xCurrentRow) || !IsModified())
3129  return true;
3130  // value of the controller was not saved, yet
3131  else if (Controller().is() && Controller()->IsModified())
3132  {
3133  if (!SaveModified())
3134  return false;
3135  }
3136  m_bUpdating = true;
3137 
3139  bool bAppending = m_xCurrentRow->IsNew();
3140  bool bSuccess = false;
3141  try
3142  {
3143  Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
3144  if (bAppending)
3145  xUpdateCursor->insertRow();
3146  else
3147  xUpdateCursor->updateRow();
3148  bSuccess = true;
3149  }
3150  catch(SQLException&)
3151  {
3152  EndCursorAction();
3153  m_bUpdating = false;
3154  return false;
3155  }
3156 
3157  try
3158  {
3159  if (bSuccess)
3160  {
3161  // if we are appending we still sit on the insert row
3162  // we don't move just clear the flags not to move on the current row
3163  m_xCurrentRow->SetState(m_pDataCursor.get(), false);
3164  SAL_INFO("svx.fmcomp", "explicit SetState after a successful update, new state: " << ROWSTATUS(m_xCurrentRow));
3165  m_xCurrentRow->SetNew(false);
3166 
3167  // adjust the seekcursor if it is on the same position as the datacursor
3168  if (m_nSeekPos == m_nCurrentPos || bAppending)
3169  {
3170  // get the bookmark to refetch the data
3171  // in insert mode we take the new bookmark of the data cursor
3172  Any aBookmark = bAppending ? m_pDataCursor->getBookmark() : m_pSeekCursor->getBookmark();
3173  m_pSeekCursor->moveToBookmark(aBookmark);
3174  // get the data
3175  m_xSeekRow->SetState(m_pSeekCursor.get(), true);
3176  m_nSeekPos = m_pSeekCursor->getRow() - 1;
3177  }
3178  }
3179  // and repaint the row
3181  }
3182  catch(Exception&)
3183  {
3184  }
3185 
3186  m_bUpdating = false;
3187  EndCursorAction();
3188 
3189  // The old code returned (nRecords != 0) here.
3190  // Me thinks this is wrong : If something goes wrong while update the record, an exception will be thrown,
3191  // which results in a "return sal_False" (see above). If no exception is thrown, everything is fine. If nRecords
3192  // is zero, this simply means all fields had their original values.
3193  // FS - 06.12.99 - 70502
3194  return true;
3195 }
3196 
3198 {
3199  // do not handle events of the Navbar
3200  if (m_aBar->IsWindowOrChild(rEvt.GetWindow()))
3201  return BrowseBox::PreNotify(rEvt);
3202 
3203  switch (rEvt.GetType())
3204  {
3205  case MouseNotifyEvent::KEYINPUT:
3206  {
3207  const KeyEvent* pKeyEvent = rEvt.GetKeyEvent();
3208 
3209  sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
3210  bool bShift = pKeyEvent->GetKeyCode().IsShift();
3211  bool bCtrl = pKeyEvent->GetKeyCode().IsMod1();
3212  bool bAlt = pKeyEvent->GetKeyCode().IsMod2();
3213  if ( ( KEY_TAB == nCode ) && bCtrl && !bAlt )
3214  {
3215  // Ctrl-Tab is used to step out of the control, without traveling to the
3216  // remaining cells first
3217  // -> build a new key event without the Ctrl-key, and let the very base class handle it
3218  vcl::KeyCode aNewCode( KEY_TAB, bShift, false, false, false );
3219  KeyEvent aNewEvent( pKeyEvent->GetCharCode(), aNewCode );
3220 
3221  // call the Control - our direct base class will interpret this in a way we do not want (and do
3222  // a cell traveling)
3223  Control::KeyInput( aNewEvent );
3224  return true;
3225  }
3226 
3227  if ( !bShift && !bCtrl && ( KEY_ESCAPE == nCode ) )
3228  {
3229  if (IsModified())
3230  {
3231  Undo();
3232  return true;
3233  }
3234  }
3235  else if ( ( KEY_DELETE == nCode ) && !bShift && !bCtrl ) // delete rows
3236  {
3238  {
3239  // delete asynchronously
3240  if (m_nDeleteEvent)
3242  m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete), nullptr, true);
3243  return true;
3244  }
3245  }
3246 
3247  [[fallthrough]];
3248  }
3249  default:
3250  return EditBrowseBox::PreNotify(rEvt);
3251  }
3252 }
3253 
3254 bool DbGridControl::IsTabAllowed(bool bRight) const
3255 {
3256  if (bRight)
3257  // Tab only if not on the _last_ row
3258  return GetCurRow() < (GetRowCount() - 1) || !m_bRecordCountFinal ||
3260  else
3261  {
3262  // Tab only if not on the _first_ row
3263  return GetCurRow() > 0 || (GetCurColumnId() && GetViewColumnPos(GetCurColumnId()) > 0);
3264  }
3265 }
3266 
3268 {
3269  if (rEvt.GetKeyCode().GetFunction() == KeyFuncType::COPY)
3270  {
3271  long nRow = GetCurRow();
3272  sal_uInt16 nColId = GetCurColumnId();
3273  if (nRow >= 0 && nRow < GetRowCount() && nColId < ColCount())
3274  {
3275  size_t Location = GetModelColumnPos( nColId );
3276  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3277  OStringTransfer::CopyString( GetCurrentRowCellText( pColumn, m_xCurrentRow ), this );
3278  return;
3279  }
3280  }
3281  EditBrowseBox::KeyInput(rEvt);
3282 }
3283 
3284 void DbGridControl::HideColumn(sal_uInt16 nId)
3285 {
3286  DeactivateCell();
3287 
3288  // determine the col for the focus to set to after removal
3289  sal_uInt16 nPos = GetViewColumnPos(nId);
3290  sal_uInt16 nNewColId = nPos == (ColCount()-1)
3291  ? GetColumnIdFromViewPos(nPos-1) // last col is to be removed -> take the previous
3292  : GetColumnIdFromViewPos(nPos+1); // take the next
3293 
3294  long lCurrentWidth = GetColumnWidth(nId);
3295  EditBrowseBox::RemoveColumn(nId);
3296  // don't use my own RemoveColumn, this would remove it from m_aColumns, too
3297 
3298  // update my model
3299  size_t Location = GetModelColumnPos( nId );
3300  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3301  DBG_ASSERT(pColumn, "DbGridControl::HideColumn : somebody did hide a nonexistent column !");
3302  if (pColumn)
3303  {
3304  pColumn->m_bHidden = true;
3305  pColumn->m_nLastVisibleWidth = CalcReverseZoom(lCurrentWidth);
3306  }
3307 
3308  // and reset the focus
3309  if ( nId == GetCurColumnId() )
3310  GoToColumnId( nNewColId );
3311 }
3312 
3313 void DbGridControl::ShowColumn(sal_uInt16 nId)
3314 {
3315  sal_uInt16 nPos = GetModelColumnPos(nId);
3316  DBG_ASSERT(nPos != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : invalid argument !");
3317  if (nPos == GRID_COLUMN_NOT_FOUND)
3318  return;
3319 
3320  DbGridColumn* pColumn = m_aColumns[ nPos ].get();
3321  if (!pColumn->IsHidden())
3322  {
3323  DBG_ASSERT(GetViewColumnPos(nId) != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3324  // if the column isn't marked as hidden, it should be visible, shouldn't it ?
3325  return;
3326  }
3327  DBG_ASSERT(GetViewColumnPos(nId) == GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3328  // the opposite situation ...
3329 
3330  // to determine the new view position we need an adjacent non-hidden column
3331  sal_uInt16 nNextNonHidden = BROWSER_INVALIDID;
3332  // first search the cols to the right
3333  for ( size_t i = nPos + 1; i < m_aColumns.size(); ++i )
3334  {
3335  DbGridColumn* pCurCol = m_aColumns[ i ].get();
3336  if (!pCurCol->IsHidden())
3337  {
3338  nNextNonHidden = i;
3339  break;
3340  }
3341  }
3342  if ((nNextNonHidden == BROWSER_INVALIDID) && (nPos > 0))
3343  {
3344  // then to the left
3345  for ( size_t i = nPos; i > 0; --i )
3346  {
3347  DbGridColumn* pCurCol = m_aColumns[ i-1 ].get();
3348  if (!pCurCol->IsHidden())
3349  {
3350  nNextNonHidden = i-1;
3351  break;
3352  }
3353  }
3354  }
3355  sal_uInt16 nNewViewPos = (nNextNonHidden == BROWSER_INVALIDID)
3356  ? 1 // there is no visible column -> insert behind the handle col
3357  : GetViewColumnPos( m_aColumns[ nNextNonHidden ]->GetId() ) + 1;
3358  // the first non-handle col has "view pos" 0, but the pos arg for InsertDataColumn expects
3359  // a position 1 for the first non-handle col -> +1
3360  DBG_ASSERT(nNewViewPos != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3361  // we found a col marked as visible but got no view pos for it ...
3362 
3363  if ((nNextNonHidden<nPos) && (nNextNonHidden != BROWSER_INVALIDID))
3364  // nNextNonHidden is a column to the left, so we want to insert the new col _right_ beside it's pos
3365  ++nNewViewPos;
3366 
3367  DeactivateCell();
3368 
3369  OUString aName;
3370  pColumn->getModel()->getPropertyValue(FM_PROP_LABEL) >>= aName;
3371  InsertDataColumn(nId, aName, CalcZoom(pColumn->m_nLastVisibleWidth), HeaderBarItemBits::CENTER | HeaderBarItemBits::CLICKABLE, nNewViewPos);
3372  pColumn->m_bHidden = false;
3373 
3374  ActivateCell();
3375  Invalidate();
3376 }
3377 
3378 sal_uInt16 DbGridControl::GetColumnIdFromModelPos( sal_uInt16 nPos ) const
3379 {
3380  if (nPos >= m_aColumns.size())
3381  {
3382  OSL_FAIL("DbGridControl::GetColumnIdFromModelPos : invalid argument !");
3383  return GRID_COLUMN_NOT_FOUND;
3384  }
3385 
3386  DbGridColumn* pCol = m_aColumns[ nPos ].get();
3387 #if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
3388  // in the debug version, we convert the ModelPos into a ViewPos and compare this with the
3389  // value we will return (nId at the corresponding Col in m_aColumns)
3390 
3391  if (!pCol->IsHidden())
3392  { // makes sense only if the column is visible
3393  sal_uInt16 nViewPos = nPos;
3394  for ( size_t i = 0; i < m_aColumns.size() && i < nPos; ++i)
3395  if ( m_aColumns[ i ]->IsHidden())
3396  --nViewPos;
3397 
3398  DBG_ASSERT(pCol && GetColumnIdFromViewPos(nViewPos) == pCol->GetId(),
3399  "DbGridControl::GetColumnIdFromModelPos : this isn't consistent... did I misunderstand something ?");
3400  }
3401 #endif
3402  return pCol->GetId();
3403 }
3404 
3405 sal_uInt16 DbGridControl::GetModelColumnPos( sal_uInt16 nId ) const
3406 {
3407  for ( size_t i = 0; i < m_aColumns.size(); ++i )
3408  if ( m_aColumns[ i ]->GetId() == nId )
3409  return i;
3410 
3411  return GRID_COLUMN_NOT_FOUND;
3412 }
3413 
3415 {
3416  SAL_INFO("svx.fmcomp", "DbGridControl::implAdjustInSolarThread");
3417  ::osl::MutexGuard aGuard(m_aAdjustSafety);
3419  {
3420  m_nAsynAdjustEvent = PostUserEvent(LINK(this, DbGridControl, OnAsyncAdjust), reinterpret_cast< void* >( _bRows ), true);
3421  m_bPendingAdjustRows = _bRows;
3422  if (_bRows)
3423  SAL_INFO("svx.fmcomp", "posting an AdjustRows");
3424  else
3425  SAL_INFO("svx.fmcomp", "posting an AdjustDataSource");
3426  }
3427  else
3428  {
3429  if (_bRows)
3430  SAL_INFO("svx.fmcomp", "doing an AdjustRows");
3431  else
3432  SAL_INFO("svx.fmcomp", "doing an AdjustDataSource");
3433  // always adjust the rows before adjusting the data source
3434  // If this is not necessary (because the row count did not change), nothing is done
3435  // The problem is that we can't rely on the order of which the calls come in: If the cursor was moved
3436  // to a position behind row count know 'til now, the cursorMoved notification may come before the
3437  // RowCountChanged notification
3438  // 94093 - 02.11.2001 - frank.schoenheit@sun.com
3439  AdjustRows();
3440 
3441  if ( !_bRows )
3442  AdjustDataSource();
3443  }
3444 }
3445 
3446 IMPL_LINK(DbGridControl, OnAsyncAdjust, void*, pAdjustWhat, void)
3447 {
3448  m_nAsynAdjustEvent = nullptr;
3449 
3450  AdjustRows();
3451  // see implAdjustInSolarThread for a comment why we do this every time
3452 
3453  if ( !pAdjustWhat )
3454  AdjustDataSource();
3455 }
3456 
3458 {
3459  if (m_pFieldListeners)
3460  {
3462  for (const auto& rListener : *pListeners)
3463  {
3464  GridFieldValueListener* pCurrent = rListener.second;
3465  if (pCurrent)
3466  pCurrent->suspend();
3467  }
3468  }
3469 
3472 }
3473 
3475 {
3476  if (m_pFieldListeners)
3477  {
3479  for (const auto& rListener : *pListeners)
3480  {
3481  GridFieldValueListener* pCurrent = rListener.second;
3482  if (pCurrent)
3483  pCurrent->resume();
3484  }
3485  }
3486 
3489 }
3490 
3492 {
3494  DBG_ASSERT(!pListeners || pListeners->empty(), "DbGridControl::ConnectToFields : please call DisconnectFromFields first !");
3495 
3496  if (!pListeners)
3497  {
3498  pListeners = new ColumnFieldValueListeners;
3499  m_pFieldListeners = pListeners;
3500  }
3501 
3502  for (auto const & pCurrent : m_aColumns)
3503  {
3504  sal_uInt16 nViewPos = pCurrent ? GetViewColumnPos(pCurrent->GetId()) : GRID_COLUMN_NOT_FOUND;
3505  if (GRID_COLUMN_NOT_FOUND == nViewPos)
3506  continue;
3507 
3508  Reference< XPropertySet > xField = pCurrent->GetField();
3509  if (!xField.is())
3510  continue;
3511 
3512  // column is visible and bound here
3513  GridFieldValueListener*& rpListener = (*pListeners)[pCurrent->GetId()];
3514  DBG_ASSERT(!rpListener, "DbGridControl::ConnectToFields : already a listener for this column ?!");
3515  rpListener = new GridFieldValueListener(*this, xField, pCurrent->GetId());
3516  }
3517 }
3518 
3520 {
3521  if (!m_pFieldListeners)
3522  return;
3523 
3525  while (!pListeners->empty())
3526  {
3527  sal_Int32 nOldSize = pListeners->size();
3528  pListeners->begin()->second->dispose();
3529  DBG_ASSERT(nOldSize > static_cast<sal_Int32>(pListeners->size()), "DbGridControl::DisconnectFromFields : dispose on a listener should result in a removal from my list !");
3530  }
3531 
3532  delete pListeners;
3533  m_pFieldListeners = nullptr;
3534 }
3535 
3537 {
3538  osl::MutexGuard aPreventDestruction(m_aDestructionSafety);
3539  // needed as this may run in a thread other than the main one
3540  if (GetRowStatus(GetCurRow()) != EditBrowseBox::MODIFIED)
3541  // all other cases are handled elsewhere
3542  return;
3543 
3544  size_t Location = GetModelColumnPos( _nId );
3545  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3546  if (pColumn)
3547  {
3548  std::unique_ptr<vcl::SolarMutexTryAndBuyGuard> pGuard;
3549  while (!m_bWantDestruction && (!pGuard || !pGuard->isAcquired()))
3550  pGuard.reset(new vcl::SolarMutexTryAndBuyGuard);
3551 
3552  if (m_bWantDestruction)
3553  { // at this moment, within another thread, our destructor tries to destroy the listener which called this method
3554  // => don't do anything
3555  // 73365 - 23.02.00 - FS
3556  return;
3557  }
3558 
3559  // and finally do the update ...
3562  }
3563 }
3564 
3566 {
3568  if (!pListeners)
3569  {
3570  OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (have no listener array) !");
3571  return;
3572  }
3573 
3574  ColumnFieldValueListeners::const_iterator aPos = pListeners->find(_nId);
3575  if (aPos == pListeners->end())
3576  {
3577  OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (did not find the listener) !");
3578  return;
3579  }
3580 
3581  delete aPos->second;
3582 
3583  pListeners->erase(aPos);
3584 }
3585 
3586 void DbGridControl::disposing(sal_uInt16 _nId)
3587 {
3588  if (_nId == 0)
3589  { // the seek cursor is being disposed
3590  ::osl::MutexGuard aGuard(m_aAdjustSafety);
3591  setDataSource(nullptr, DbGridControlOptions::Readonly); // our clone was disposed so we set our datasource to null to avoid later access to it
3592  if (m_nAsynAdjustEvent)
3593  {
3594  RemoveUserEvent(m_nAsynAdjustEvent);
3595  m_nAsynAdjustEvent = nullptr;
3596  }
3597  }
3598 }
3599 
3601 {
3602  return EditBrowseBox::GetAccessibleControlCount() + 1; // the navigation control
3603 }
3604 
3605 Reference<XAccessible > DbGridControl::CreateAccessibleControl( sal_Int32 _nIndex )
3606 {
3607  Reference<XAccessible > xRet;
3608  if ( _nIndex == EditBrowseBox::GetAccessibleControlCount() )
3609  {
3610  xRet = m_aBar->GetAccessible();
3611  }
3612  else
3613  xRet = EditBrowseBox::CreateAccessibleControl( _nIndex );
3614  return xRet;
3615 }
3616 
3617 Reference< XAccessible > DbGridControl::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
3618 {
3619  sal_uInt16 nColumnId = GetColumnId( _nColumnPos );
3620  size_t Location = GetModelColumnPos(nColumnId);
3621  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3622  if ( pColumn )
3623  {
3624  Reference< css::awt::XControl> xInt(pColumn->GetCell());
3625  Reference< css::awt::XCheckBox> xBox(xInt,UNO_QUERY);
3626  if ( xBox.is() )
3627  {
3628  TriState eValue = TRISTATE_FALSE;
3629  switch( xBox->getState() )
3630  {
3631  case 0:
3632  eValue = TRISTATE_FALSE;
3633  break;
3634  case 1:
3635  eValue = TRISTATE_TRUE;
3636  break;
3637  case 2:
3638  eValue = TRISTATE_INDET;
3639  break;
3640  }
3641  return EditBrowseBox::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,eValue );
3642  }
3643  }
3644  return EditBrowseBox::CreateAccessibleCell( _nRow, _nColumnPos );
3645 }
3646 
3647 /* 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:1640
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:3075
virtual ::svt::CellController * GetController(long nRow, sal_uInt16 nCol) override
Definition: gridctrl.cxx:2856
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:1400
DbGridControl & m_rParent
Definition: gridctrl.cxx:135
osl::Mutex m_aDestructionSafety
Definition: gridctrl.hxx:272
virtual bool SeekRow(long nRow) override
Definition: gridctrl.cxx:1785
sal_Int32 nIndex
virtual ~NavigationBar() override
Definition: gridctrl.cxx:398
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:2422
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:1645
long AdjustX(long nHorzMove)
virtual bool IsTabAllowed(bool bForward) const override
Definition: gridctrl.cxx:3254
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:2509
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:1359
#define FM_PROP_ISMODIFIED
Definition: fmprop.hxx:114
virtual bool CursorMoving(long nNewRow, sal_uInt16 nNewCol) override
Definition: gridctrl.cxx:2024
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:2005
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:2428
#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:2460
virtual void CursorMoved() override
Definition: gridctrl.cxx:2126
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:2744
virtual bool PreNotify(NotifyEvent &rEvt) override
Definition: gridctrl.cxx:3197
virtual sal_uInt32 GetTotalCellWidth(long nRow, sal_uInt16 nColId) override
Definition: gridctrl.cxx:2646
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:2594
bool GoToRowColumnId(long nRow, sal_uInt16 nColId)
void FieldListenerDisposing(sal_uInt16 _nId)
Definition: gridctrl.cxx:3565
void SetStrictFormat(bool bStrict)
TRISTATE_TRUE
virtual void ArrangeControls(sal_uInt16 &nX, sal_uInt16 nY) override
Definition: gridctrl.cxx:1178
sal_uInt16 GetModelColumnPos(sal_uInt16 nId) const
Definition: gridctrl.cxx:3405
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:3586
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:3600
virtual void Command(const CommandEvent &rEvt) override
Definition: gridctrl.cxx:2789
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:3457
virtual void DeleteSelectedRows()
Definition: gridctrl.cxx:2848
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:2637
void SetSymbol(SymbolType eSymbol)
virtual void ColumnMoved(sal_uInt16 nId) override
Definition: gridctrl.cxx:1691
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:3065
long GetRowAtYPosPixel(long nY, bool bRelToBrowser=true) const
void DataSourcePropertyChanged(const css::beans::PropertyChangeEvent &evt)
Definition: gridctrl.cxx:2692
virtual void VisibleRowsChanged(long nNewTopRow, sal_uInt16 nNumRows) override
Definition: gridctrl.cxx:1818
AllSettingsFlags GetFlags() const
void EnableNavigationBar(bool bEnable)
Definition: gridctrl.cxx:1234
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:2566
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:2538
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:3617
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:1879
void DrawLine(const Point &rStartPt, const Point &rEndPt)
sal_uInt16 nCode
bool IsPermanentCursorEnabled() const
Definition: gridctrl.cxx:1386
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:2159
void DisconnectFromFields()
Definition: gridctrl.cxx:3519
static void RemoveUserEvent(ImplSVEvent *nUserEvent)
void SetNew(bool _bNew)
Definition: gridctrl.hxx:85
bool Commit()
Definition: gridcell.cxx:278
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:2763
virtual void columnChanged()=0
sal_Int32 AlignSeekCursor()
Definition: gridctrl.cxx:2245
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:1918
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
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:2175
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:3313
std::unique_ptr< CursorWrapper > m_pSeekCursor
Definition: gridctrl.hxx:263
void SetFillColor()
CommandEventId GetCommand() const
virtual bool SaveRow() override
Definition: gridctrl.cxx:3124
css::uno::Reference< css::sdb::XRowsChangeListener > m_xRowSetListener
Definition: gridctrl.hxx:249
virtual void CellModified() override
Definition: gridctrl.cxx:2888
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:3474
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:2041
void RemoveColumn(sal_uInt16 nId)
Definition: gridctrl.cxx:1680
virtual void dispose() override
void FieldValueChanged(sal_uInt16 _nId)
Definition: gridctrl.cxx:3536
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:3378
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:1981
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:1391
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:2658
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
constexpr sal_uInt16 KEY_RETURN
virtual bool IsModified() const override
Definition: gridctrl.cxx:3060
void MoveToNext()
Definition: gridctrl.cxx:2467
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:3414
void ReleaseMouse()
virtual void KeyInput(const KeyEvent &rKEvt)
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:3049
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:268
#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:3070
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:2154
virtual ~DisposeListenerGridBridge() override
Definition: gridctrl.cxx:220
void SetFirst(sal_Int64 nNewFirst)
VclPtr< FixedText > m_aRecordText
Definition: gridctrl.hxx:187
constexpr sal_uInt16 KEY_ESCAPE
virtual void Dispatch(sal_uInt16 nId) override
Definition: gridctrl.cxx:2937
void RemoveColumns()
Definition: gridctrl.cxx:1630
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:1189
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:458
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:2165
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:3605
friend class FmXGridSourcePropListener
Definition: gridctrl.hxx:165
IMPL_LINK_NOARG(DbGridControl, OnDelete, void *, void)
Definition: gridctrl.cxx:2842
PopupMenu * get_menu(const OString &sID)
osl::Mutex m_aAdjustSafety
Definition: gridctrl.hxx:273
void ConnectToFields()
Definition: gridctrl.cxx:3491
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:2771
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:2627
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:2677
sal_Int32 m_nCurrentPos
virtual void HideColumn(sal_uInt16 nId)
hide a column
Definition: gridctrl.cxx:3284
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:3267
DbGridControlOptions SetOptions(DbGridControlOptions nOpt)
Definition: gridctrl.cxx:1269
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:1348
constexpr sal_uInt16 KEY_DELETE
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:1899
InitWindowFacet
Definition: gridctrl.hxx:116
Reference< XComponentContext > m_xContext
void resetCurrentRow()
Definition: gridctrl.cxx:3013
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:1823
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
constexpr sal_uInt16 KEY_TAB
void executeRowContextMenu(long _nRow, const Point &_rPreferredPos)
Definition: gridctrl.cxx:2779
bool SeekCursor(long nRow, bool bAbsolute=false)
Definition: gridctrl.cxx:2296
#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:1155
#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