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