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