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