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/builder.hxx>
47 #include <vcl/menu.hxx>
48 #include <vcl/settings.hxx>
49 #include <vcl/commandevent.hxx>
50 #include <vcl/svapp.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 
2411 void DbGridControl::PreExecuteRowContextMenu(sal_uInt16 /*nRow*/, PopupMenu& rMenu)
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.EnableItem(rMenu.GetItemId("delete"), bDelete);
2418  rMenu.EnableItem(rMenu.GetItemId("save"), IsModified());
2419 
2420  // the undo is more difficult
2421  bool bCanUndo = IsModified();
2422  int nState = -1;
2425  bCanUndo &= ( 0 != nState );
2426 
2427  rMenu.EnableItem(rMenu.GetItemId("undo"), bCanUndo);
2428 }
2429 
2430 void DbGridControl::PostExecuteRowContextMenu(sal_uInt16 /*nRow*/, const PopupMenu& rMenu, sal_uInt16 nExecutionResult)
2431 {
2432  if (nExecutionResult == rMenu.GetItemId("delete"))
2433  {
2434  // delete asynchronously
2435  if (m_nDeleteEvent)
2437  m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete), nullptr, true);
2438  }
2439  else if (nExecutionResult == rMenu.GetItemId("undo"))
2440  Undo();
2441  else if (nExecutionResult == rMenu.GetItemId("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( sal_Int32 _nRow, const Point& _rPreferredPos )
2533 {
2534  VclBuilder aBuilder(nullptr, AllSettings::GetUIRootDir(), "svx/ui/rowsmenu.ui", "");
2535  VclPtr<PopupMenu> aContextMenu(aBuilder.get_menu("menu"));
2536 
2537  PreExecuteRowContextMenu( static_cast<sal_uInt16>(_nRow), *aContextMenu );
2538  aContextMenu->RemoveDisabledEntries( true, true );
2539  PostExecuteRowContextMenu( static_cast<sal_uInt16>(_nRow), *aContextMenu, aContextMenu->Execute( this, _rPreferredPos ) );
2540 }
2541 
2543 {
2544  switch (rEvt.GetCommand())
2545  {
2546  case CommandEventId::ContextMenu:
2547  {
2548  if ( !m_pSeekCursor )
2549  {
2550  EditBrowseBox::Command(rEvt);
2551  return;
2552  }
2553 
2554  if ( !rEvt.IsMouseEvent() )
2555  { // context menu requested by keyboard
2556  if ( GetSelectRowCount() )
2557  {
2558  tools::Long nRow = FirstSelectedRow( );
2559 
2560  ::tools::Rectangle aRowRect( GetRowRectPixel( nRow ) );
2561  executeRowContextMenu( nRow, aRowRect.LeftCenter() );
2562 
2563  // handled
2564  return;
2565  }
2566  }
2567 
2568  sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X()));
2569  tools::Long nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y());
2570 
2571  if (nColId == HandleColumnId)
2572  {
2573  executeRowContextMenu( nRow, rEvt.GetMousePosPixel() );
2574  }
2575  else if (canCopyCellText(nRow, nColId))
2576  {
2577  ::tools::Rectangle aRect(rEvt.GetMousePosPixel(), Size(1, 1));
2578  weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
2579  std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "svx/ui/cellmenu.ui"));
2580  std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
2581  if (!xContextMenu->popup_at_rect(pPopupParent, aRect).isEmpty())
2582  copyCellText(nRow, nColId);
2583  }
2584  else
2585  {
2586  EditBrowseBox::Command(rEvt);
2587  return;
2588  }
2589 
2590  [[fallthrough]];
2591  }
2592  default:
2593  EditBrowseBox::Command(rEvt);
2594  }
2595 }
2596 
2597 IMPL_LINK_NOARG(DbGridControl, OnDelete, void*, void)
2598 {
2599  m_nDeleteEvent = nullptr;
2600  DeleteSelectedRows();
2601 }
2602 
2604 {
2605  DBG_ASSERT(GetSelection(), "no selection!!!");
2606 
2607  if (!m_pSeekCursor)
2608  return;
2609 }
2610 
2611 CellController* DbGridControl::GetController(sal_Int32 /*nRow*/, sal_uInt16 nColumnId)
2612 {
2613  if (!IsValid(m_xCurrentRow) || !IsEnabled())
2614  return nullptr;
2615 
2616  size_t Location = GetModelColumnPos(nColumnId);
2617  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2618  if (!pColumn)
2619  return nullptr;
2620 
2621  CellController* pReturn = nullptr;
2622  if (IsFilterMode())
2623  pReturn = pColumn->GetController().get();
2624  else
2625  {
2627  {
2628  if (!::comphelper::getBOOL(pColumn->getModel()->getPropertyValue(FM_PROP_ENABLED)))
2629  return nullptr;
2630  }
2631 
2632  bool bInsert = (m_xCurrentRow->IsNew() && (m_nOptions & DbGridControlOptions::Insert));
2633  bool bUpdate = (!m_xCurrentRow->IsNew() && (m_nOptions & DbGridControlOptions::Update));
2634 
2635  if ((bInsert && !pColumn->IsAutoValue()) || bUpdate)
2636  {
2637  pReturn = pColumn->GetController().get();
2638  }
2639  }
2640  return pReturn;
2641 }
2642 
2644 {
2645  SAL_INFO("svx.fmcomp", "DbGridControl::CellModified");
2646 
2647  {
2648  ::osl::MutexGuard aGuard(m_aAdjustSafety);
2649  if (m_nAsynAdjustEvent)
2650  {
2651  SAL_INFO("svx.fmcomp", "forcing a synchron call to " << (m_bPendingAdjustRows ? "AdjustRows" : "AdustDataSource"));
2652  RemoveUserEvent(m_nAsynAdjustEvent);
2653  m_nAsynAdjustEvent = nullptr;
2654 
2655  // force the call : this should be no problem as we're probably running in the solar thread here
2656  // (cell modified is triggered by user actions)
2658  AdjustRows();
2659  else
2660  AdjustDataSource();
2661  }
2662  }
2663 
2665  return;
2666 
2667  // enable edit mode
2668  // a data set should be inserted
2669  if (m_xCurrentRow->IsNew())
2670  {
2672  SAL_INFO("svx.fmcomp", "current row is new, new state: MODIFIED");
2673  // if no row was added yet, do it now
2674  if (m_nCurrentPos == GetRowCount() - 1)
2675  {
2676  // increment RowCount
2680  }
2681  }
2683  {
2684  m_xCurrentRow->SetState(m_pDataCursor.get(), false);
2685  SAL_INFO("svx.fmcomp", "current row is not new, after SetState, new state: " << ROWSTATUS(m_xCurrentRow));
2687  SAL_INFO("svx.fmcomp", "current row is not new, new state: MODIFIED");
2689  }
2690 }
2691 
2692 void DbGridControl::Dispatch(sal_uInt16 nId)
2693 {
2694  if (nId == BROWSER_CURSORENDOFFILE)
2695  {
2697  AppendNew();
2698  else
2699  MoveToLast();
2700  }
2701  else
2702  EditBrowseBox::Dispatch(nId);
2703 }
2704 
2706 {
2707  if (IsFilterMode() || !IsValid(m_xCurrentRow) || !IsModified())
2708  return;
2709 
2710  // check if we have somebody doin' the UNDO for us
2711  int nState = -1;
2714  if (nState>0)
2715  { // yes, we have, and the slot is enabled
2716  DBG_ASSERT(m_aMasterSlotExecutor.IsSet(), "DbGridControl::Undo : a state, but no execute link ?");
2718  if (lResult)
2719  // handled
2720  return;
2721  }
2722  else if (nState == 0)
2723  // yes, we have, and the slot is disabled
2724  return;
2725 
2727 
2728  bool bAppending = m_xCurrentRow->IsNew();
2729  bool bDirty = m_xCurrentRow->IsModified();
2730 
2731  try
2732  {
2733  // cancel editing
2734  Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
2735  // no effects if we're not updating currently
2736  if (bAppending)
2737  // just refresh the row
2738  xUpdateCursor->moveToInsertRow();
2739  else
2740  xUpdateCursor->cancelRowUpdates();
2741 
2742  }
2743  catch(Exception&)
2744  {
2745  DBG_UNHANDLED_EXCEPTION("svx");
2746  }
2747 
2748  EndCursorAction();
2749 
2750  m_xDataRow->SetState(m_pDataCursor.get(), false);
2751  if (m_xPaintRow == m_xCurrentRow)
2753  else
2755 
2756  if (bAppending && (EditBrowseBox::IsModified() || bDirty))
2757  // remove the row
2758  if (m_nCurrentPos == GetRowCount() - 2)
2759  { // maybe we already removed it (in resetCurrentRow, called if the above moveToInsertRow
2760  // caused our data source form to be reset - which should be the usual case...)
2761  RowRemoved(GetRowCount() - 1);
2763  }
2764 
2766 }
2767 
2769 {
2770  if (IsModified())
2771  {
2772  // scenario : we're on the insert row, the row is dirty, and thus there exists a "second" insert row (which
2773  // is clean). Normally in DataSourcePropertyChanged we would remove this second row if the modified state of
2774  // the insert row changes from sal_True to sal_False. But if our current cell is the only modified element (means the
2775  // data source isn't modified) and we're reset this DataSourcePropertyChanged would never be called, so we
2776  // would never delete the obsolete "second insert row". Thus in this special case this method here
2777  // is the only possibility to determine the redundance of the row (resetCurrentRow is called when the
2778  // "first insert row" is about to be cleaned, so of course the "second insert row" is redundant now)
2780  if (xDataSource.is() && !::comphelper::getBOOL(xDataSource->getPropertyValue(FM_PROP_ISMODIFIED)))
2781  {
2782  // are we on a new row currently ?
2783  if (m_xCurrentRow->IsNew())
2784  {
2785  if (m_nCurrentPos == GetRowCount() - 2)
2786  {
2787  RowRemoved(GetRowCount() - 1);
2789  }
2790  }
2791  }
2792 
2793  // update the rows
2794  m_xDataRow->SetState(m_pDataCursor.get(), false);
2795  if (m_xPaintRow == m_xCurrentRow)
2797  else
2799  }
2800 
2801  RowModified(GetCurRow()); // will update the current controller if affected
2802 }
2803 
2804 void DbGridControl::RowModified( sal_Int32 nRow )
2805 {
2806  if (nRow == m_nCurrentPos && IsEditing())
2807  {
2808  CellControllerRef aTmpRef = Controller();
2809  aTmpRef->SaveValue();
2811  }
2812  EditBrowseBox::RowModified(nRow);
2813 }
2814 
2816 {
2817  return !IsFilterMode() && IsValid(m_xCurrentRow) && (m_xCurrentRow->IsModified() || EditBrowseBox::IsModified());
2818 }
2819 
2821 {
2822  return m_xCurrentRow.is() && m_xCurrentRow->IsNew();
2823 }
2824 
2825 bool DbGridControl::IsInsertionRow(sal_Int32 nRow) const
2826 {
2827  return (m_nOptions & DbGridControlOptions::Insert) && m_nTotalCount >= 0 && (nRow == GetRowCount() - 1);
2828 }
2829 
2831 {
2832  SAL_INFO("svx.fmcomp", "DbGridControl::SaveModified");
2833  DBG_ASSERT(IsValid(m_xCurrentRow), "GridControl:: Invalid row");
2834  if (!IsValid(m_xCurrentRow))
2835  return true;
2836 
2837  // accept input for this field
2838  // Where there changes at the current input field?
2839  if (!EditBrowseBox::IsModified())
2840  return true;
2841 
2843  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
2844  bool bOK = pColumn && pColumn->Commit();
2845  DBG_ASSERT( Controller().is(), "DbGridControl::SaveModified: was modified, by have no controller?!" );
2846  if ( !Controller().is() )
2847  // this might happen if the callbacks implicitly triggered by Commit
2848  // fiddled with the form or the control ...
2849  // (Note that this here is a workaround, at most. We need a general concept how
2850  // to treat this, you can imagine an arbitrary number of scenarios where a callback
2851  // triggers something which leaves us in an expected state.)
2852  // #i67147# / 2006-07-17 / frank.schoenheit@sun.com
2853  return bOK;
2854 
2855  if (bOK)
2856  {
2857  Controller()->SaveValue();
2858 
2859  if ( IsValid(m_xCurrentRow) )
2860  {
2861  m_xCurrentRow->SetState(m_pDataCursor.get(), false);
2862  SAL_INFO("svx.fmcomp", "explicit SetState, new state: " << ROWSTATUS(m_xCurrentRow));
2864  }
2865  else
2866  {
2867  SAL_INFO("svx.fmcomp", "no SetState, new state: " << ROWSTATUS(m_xCurrentRow));
2868  }
2869  }
2870 
2871  return bOK;
2872 }
2873 
2875 {
2876  SAL_INFO("svx.fmcomp", "DbGridControl::SaveRow");
2877  // valid row
2878  if (!IsValid(m_xCurrentRow) || !IsModified())
2879  return true;
2880  // value of the controller was not saved, yet
2881  else if (Controller().is() && Controller()->IsValueChangedFromSaved())
2882  {
2883  if (!SaveModified())
2884  return false;
2885  }
2886  m_bUpdating = true;
2887 
2889  bool bAppending = m_xCurrentRow->IsNew();
2890  bool bSuccess = false;
2891  try
2892  {
2893  Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
2894  if (bAppending)
2895  xUpdateCursor->insertRow();
2896  else
2897  xUpdateCursor->updateRow();
2898  bSuccess = true;
2899  }
2900  catch(SQLException&)
2901  {
2902  EndCursorAction();
2903  m_bUpdating = false;
2904  return false;
2905  }
2906 
2907  try
2908  {
2909  if (bSuccess)
2910  {
2911  // if we are appending we still sit on the insert row
2912  // we don't move just clear the flags not to move on the current row
2913  m_xCurrentRow->SetState(m_pDataCursor.get(), false);
2914  SAL_INFO("svx.fmcomp", "explicit SetState after a successful update, new state: " << ROWSTATUS(m_xCurrentRow));
2915  m_xCurrentRow->SetNew(false);
2916 
2917  // adjust the seekcursor if it is on the same position as the datacursor
2918  if (m_nSeekPos == m_nCurrentPos || bAppending)
2919  {
2920  // get the bookmark to refetch the data
2921  // in insert mode we take the new bookmark of the data cursor
2922  Any aBookmark = bAppending ? m_pDataCursor->getBookmark() : m_pSeekCursor->getBookmark();
2923  m_pSeekCursor->moveToBookmark(aBookmark);
2924  // get the data
2925  m_xSeekRow->SetState(m_pSeekCursor.get(), true);
2926  m_nSeekPos = m_pSeekCursor->getRow() - 1;
2927  }
2928  }
2929  // and repaint the row
2931  }
2932  catch(Exception&)
2933  {
2934  }
2935 
2936  m_bUpdating = false;
2937  EndCursorAction();
2938 
2939  // The old code returned (nRecords != 0) here.
2940  // Me thinks this is wrong : If something goes wrong while update the record, an exception will be thrown,
2941  // which results in a "return sal_False" (see above). If no exception is thrown, everything is fine. If nRecords
2942  // is zero, this simply means all fields had their original values.
2943  // FS - 06.12.99 - 70502
2944  return true;
2945 }
2946 
2948 {
2949  // do not handle events of the Navbar
2950  if (m_aBar->IsWindowOrChild(rEvt.GetWindow()))
2951  return BrowseBox::PreNotify(rEvt);
2952 
2953  switch (rEvt.GetType())
2954  {
2955  case MouseNotifyEvent::KEYINPUT:
2956  {
2957  const KeyEvent* pKeyEvent = rEvt.GetKeyEvent();
2958 
2959  sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
2960  bool bShift = pKeyEvent->GetKeyCode().IsShift();
2961  bool bCtrl = pKeyEvent->GetKeyCode().IsMod1();
2962  bool bAlt = pKeyEvent->GetKeyCode().IsMod2();
2963  if ( ( KEY_TAB == nCode ) && bCtrl && !bAlt )
2964  {
2965  // Ctrl-Tab is used to step out of the control, without traveling to the
2966  // remaining cells first
2967  // -> build a new key event without the Ctrl-key, and let the very base class handle it
2968  vcl::KeyCode aNewCode( KEY_TAB, bShift, false, false, false );
2969  KeyEvent aNewEvent( pKeyEvent->GetCharCode(), aNewCode );
2970 
2971  // call the Control - our direct base class will interpret this in a way we do not want (and do
2972  // a cell traveling)
2973  Control::KeyInput( aNewEvent );
2974  return true;
2975  }
2976 
2977  if ( !bShift && !bCtrl && ( KEY_ESCAPE == nCode ) )
2978  {
2979  if (IsModified())
2980  {
2981  Undo();
2982  return true;
2983  }
2984  }
2985  else if ( ( KEY_DELETE == nCode ) && !bShift && !bCtrl ) // delete rows
2986  {
2988  {
2989  // delete asynchronously
2990  if (m_nDeleteEvent)
2992  m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete), nullptr, true);
2993  return true;
2994  }
2995  }
2996 
2997  [[fallthrough]];
2998  }
2999  default:
3000  return EditBrowseBox::PreNotify(rEvt);
3001  }
3002 }
3003 
3004 bool DbGridControl::IsTabAllowed(bool bRight) const
3005 {
3006  if (bRight)
3007  // Tab only if not on the _last_ row
3008  return GetCurRow() < (GetRowCount() - 1) || !m_bRecordCountFinal ||
3010  else
3011  {
3012  // Tab only if not on the _first_ row
3013  return GetCurRow() > 0 || (GetCurColumnId() && GetViewColumnPos(GetCurColumnId()) > 0);
3014  }
3015 }
3016 
3018 {
3019  if (rEvt.GetKeyCode().GetFunction() == KeyFuncType::COPY)
3020  {
3021  tools::Long nRow = GetCurRow();
3022  sal_uInt16 nColId = GetCurColumnId();
3023  if (nRow >= 0 && nRow < GetRowCount() && nColId < ColCount())
3024  {
3025  size_t Location = GetModelColumnPos( nColId );
3026  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3027  OStringTransfer::CopyString( GetCurrentRowCellText( pColumn, m_xCurrentRow ), this );
3028  return;
3029  }
3030  }
3031  EditBrowseBox::KeyInput(rEvt);
3032 }
3033 
3034 void DbGridControl::HideColumn(sal_uInt16 nId)
3035 {
3036  DeactivateCell();
3037 
3038  // determine the col for the focus to set to after removal
3039  sal_uInt16 nPos = GetViewColumnPos(nId);
3040  sal_uInt16 nNewColId = nPos == (ColCount()-1)
3041  ? GetColumnIdFromViewPos(nPos-1) // last col is to be removed -> take the previous
3042  : GetColumnIdFromViewPos(nPos+1); // take the next
3043 
3044  tools::Long lCurrentWidth = GetColumnWidth(nId);
3045  EditBrowseBox::RemoveColumn(nId);
3046  // don't use my own RemoveColumn, this would remove it from m_aColumns, too
3047 
3048  // update my model
3049  size_t Location = GetModelColumnPos( nId );
3050  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3051  DBG_ASSERT(pColumn, "DbGridControl::HideColumn : somebody did hide a nonexistent column !");
3052  if (pColumn)
3053  {
3054  pColumn->m_bHidden = true;
3055  pColumn->m_nLastVisibleWidth = CalcReverseZoom(lCurrentWidth);
3056  }
3057 
3058  // and reset the focus
3059  if ( nId == GetCurColumnId() )
3060  GoToColumnId( nNewColId );
3061 }
3062 
3063 void DbGridControl::ShowColumn(sal_uInt16 nId)
3064 {
3065  sal_uInt16 nPos = GetModelColumnPos(nId);
3066  DBG_ASSERT(nPos != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : invalid argument !");
3067  if (nPos == GRID_COLUMN_NOT_FOUND)
3068  return;
3069 
3070  DbGridColumn* pColumn = m_aColumns[ nPos ].get();
3071  if (!pColumn->IsHidden())
3072  {
3073  DBG_ASSERT(GetViewColumnPos(nId) != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3074  // if the column isn't marked as hidden, it should be visible, shouldn't it ?
3075  return;
3076  }
3077  DBG_ASSERT(GetViewColumnPos(nId) == GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3078  // the opposite situation ...
3079 
3080  // to determine the new view position we need an adjacent non-hidden column
3081  sal_uInt16 nNextNonHidden = BROWSER_INVALIDID;
3082  // first search the cols to the right
3083  for ( size_t i = nPos + 1; i < m_aColumns.size(); ++i )
3084  {
3085  DbGridColumn* pCurCol = m_aColumns[ i ].get();
3086  if (!pCurCol->IsHidden())
3087  {
3088  nNextNonHidden = i;
3089  break;
3090  }
3091  }
3092  if ((nNextNonHidden == BROWSER_INVALIDID) && (nPos > 0))
3093  {
3094  // then to the left
3095  for ( size_t i = nPos; i > 0; --i )
3096  {
3097  DbGridColumn* pCurCol = m_aColumns[ i-1 ].get();
3098  if (!pCurCol->IsHidden())
3099  {
3100  nNextNonHidden = i-1;
3101  break;
3102  }
3103  }
3104  }
3105  sal_uInt16 nNewViewPos = (nNextNonHidden == BROWSER_INVALIDID)
3106  ? 1 // there is no visible column -> insert behind the handle col
3107  : GetViewColumnPos( m_aColumns[ nNextNonHidden ]->GetId() ) + 1;
3108  // the first non-handle col has "view pos" 0, but the pos arg for InsertDataColumn expects
3109  // a position 1 for the first non-handle col -> +1
3110  DBG_ASSERT(nNewViewPos != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3111  // we found a col marked as visible but got no view pos for it ...
3112 
3113  if ((nNextNonHidden<nPos) && (nNextNonHidden != BROWSER_INVALIDID))
3114  // nNextNonHidden is a column to the left, so we want to insert the new col _right_ beside it's pos
3115  ++nNewViewPos;
3116 
3117  DeactivateCell();
3118 
3119  OUString aName;
3120  pColumn->getModel()->getPropertyValue(FM_PROP_LABEL) >>= aName;
3121  InsertDataColumn(nId, aName, CalcZoom(pColumn->m_nLastVisibleWidth), HeaderBarItemBits::CENTER | HeaderBarItemBits::CLICKABLE, nNewViewPos);
3122  pColumn->m_bHidden = false;
3123 
3124  ActivateCell();
3125  Invalidate();
3126 }
3127 
3128 sal_uInt16 DbGridControl::GetColumnIdFromModelPos( sal_uInt16 nPos ) const
3129 {
3130  if (nPos >= m_aColumns.size())
3131  {
3132  OSL_FAIL("DbGridControl::GetColumnIdFromModelPos : invalid argument !");
3133  return GRID_COLUMN_NOT_FOUND;
3134  }
3135 
3136  DbGridColumn* pCol = m_aColumns[ nPos ].get();
3137 #if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
3138  // in the debug version, we convert the ModelPos into a ViewPos and compare this with the
3139  // value we will return (nId at the corresponding Col in m_aColumns)
3140 
3141  if (!pCol->IsHidden())
3142  { // makes sense only if the column is visible
3143  sal_uInt16 nViewPos = nPos;
3144  for ( size_t i = 0; i < m_aColumns.size() && i < nPos; ++i)
3145  if ( m_aColumns[ i ]->IsHidden())
3146  --nViewPos;
3147 
3148  DBG_ASSERT(pCol && GetColumnIdFromViewPos(nViewPos) == pCol->GetId(),
3149  "DbGridControl::GetColumnIdFromModelPos : this isn't consistent... did I misunderstand something ?");
3150  }
3151 #endif
3152  return pCol->GetId();
3153 }
3154 
3155 sal_uInt16 DbGridControl::GetModelColumnPos( sal_uInt16 nId ) const
3156 {
3157  for ( size_t i = 0; i < m_aColumns.size(); ++i )
3158  if ( m_aColumns[ i ]->GetId() == nId )
3159  return i;
3160 
3161  return GRID_COLUMN_NOT_FOUND;
3162 }
3163 
3165 {
3166  SAL_INFO("svx.fmcomp", "DbGridControl::implAdjustInSolarThread");
3167  ::osl::MutexGuard aGuard(m_aAdjustSafety);
3169  {
3170  m_nAsynAdjustEvent = PostUserEvent(LINK(this, DbGridControl, OnAsyncAdjust), reinterpret_cast< void* >( _bRows ), true);
3171  m_bPendingAdjustRows = _bRows;
3172  if (_bRows)
3173  SAL_INFO("svx.fmcomp", "posting an AdjustRows");
3174  else
3175  SAL_INFO("svx.fmcomp", "posting an AdjustDataSource");
3176  }
3177  else
3178  {
3179  if (_bRows)
3180  SAL_INFO("svx.fmcomp", "doing an AdjustRows");
3181  else
3182  SAL_INFO("svx.fmcomp", "doing an AdjustDataSource");
3183  // always adjust the rows before adjusting the data source
3184  // If this is not necessary (because the row count did not change), nothing is done
3185  // The problem is that we can't rely on the order of which the calls come in: If the cursor was moved
3186  // to a position behind row count know 'til now, the cursorMoved notification may come before the
3187  // RowCountChanged notification
3188  // 94093 - 02.11.2001 - frank.schoenheit@sun.com
3189  AdjustRows();
3190 
3191  if ( !_bRows )
3192  AdjustDataSource();
3193  }
3194 }
3195 
3196 IMPL_LINK(DbGridControl, OnAsyncAdjust, void*, pAdjustWhat, void)
3197 {
3198  m_nAsynAdjustEvent = nullptr;
3199 
3200  AdjustRows();
3201  // see implAdjustInSolarThread for a comment why we do this every time
3202 
3203  if ( !pAdjustWhat )
3204  AdjustDataSource();
3205 }
3206 
3208 {
3209  if (m_pFieldListeners)
3210  {
3212  for (const auto& rListener : *pListeners)
3213  {
3214  GridFieldValueListener* pCurrent = rListener.second;
3215  if (pCurrent)
3216  pCurrent->suspend();
3217  }
3218  }
3219 
3222 }
3223 
3225 {
3226  if (m_pFieldListeners)
3227  {
3229  for (const auto& rListener : *pListeners)
3230  {
3231  GridFieldValueListener* pCurrent = rListener.second;
3232  if (pCurrent)
3233  pCurrent->resume();
3234  }
3235  }
3236 
3239 }
3240 
3242 {
3244  DBG_ASSERT(!pListeners || pListeners->empty(), "DbGridControl::ConnectToFields : please call DisconnectFromFields first !");
3245 
3246  if (!pListeners)
3247  {
3248  pListeners = new ColumnFieldValueListeners;
3249  m_pFieldListeners = pListeners;
3250  }
3251 
3252  for (auto const & pCurrent : m_aColumns)
3253  {
3254  sal_uInt16 nViewPos = pCurrent ? GetViewColumnPos(pCurrent->GetId()) : GRID_COLUMN_NOT_FOUND;
3255  if (GRID_COLUMN_NOT_FOUND == nViewPos)
3256  continue;
3257 
3258  Reference< XPropertySet > xField = pCurrent->GetField();
3259  if (!xField.is())
3260  continue;
3261 
3262  // column is visible and bound here
3263  GridFieldValueListener*& rpListener = (*pListeners)[pCurrent->GetId()];
3264  DBG_ASSERT(!rpListener, "DbGridControl::ConnectToFields : already a listener for this column ?!");
3265  rpListener = new GridFieldValueListener(*this, xField, pCurrent->GetId());
3266  }
3267 }
3268 
3270 {
3271  if (!m_pFieldListeners)
3272  return;
3273 
3275  while (!pListeners->empty())
3276  {
3277  sal_Int32 nOldSize = pListeners->size();
3278  pListeners->begin()->second->dispose();
3279  DBG_ASSERT(nOldSize > static_cast<sal_Int32>(pListeners->size()), "DbGridControl::DisconnectFromFields : dispose on a listener should result in a removal from my list !");
3280  }
3281 
3282  delete pListeners;
3283  m_pFieldListeners = nullptr;
3284 }
3285 
3287 {
3288  osl::MutexGuard aPreventDestruction(m_aDestructionSafety);
3289  // needed as this may run in a thread other than the main one
3290  if (GetRowStatus(GetCurRow()) != EditBrowseBox::MODIFIED)
3291  // all other cases are handled elsewhere
3292  return;
3293 
3294  size_t Location = GetModelColumnPos( _nId );
3295  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3296  if (!pColumn)
3297  return;
3298 
3299  std::unique_ptr<vcl::SolarMutexTryAndBuyGuard> pGuard;
3300  while (!m_bWantDestruction && (!pGuard || !pGuard->isAcquired()))
3301  pGuard.reset(new vcl::SolarMutexTryAndBuyGuard);
3302 
3303  if (m_bWantDestruction)
3304  { // at this moment, within another thread, our destructor tries to destroy the listener which called this method
3305  // => don't do anything
3306  // 73365 - 23.02.00 - FS
3307  return;
3308  }
3309 
3310  // and finally do the update ...
3313 }
3314 
3316 {
3318  if (!pListeners)
3319  {
3320  OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (have no listener array) !");
3321  return;
3322  }
3323 
3324  ColumnFieldValueListeners::const_iterator aPos = pListeners->find(_nId);
3325  if (aPos == pListeners->end())
3326  {
3327  OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (did not find the listener) !");
3328  return;
3329  }
3330 
3331  delete aPos->second;
3332 
3333  pListeners->erase(aPos);
3334 }
3335 
3336 void DbGridControl::disposing(sal_uInt16 _nId)
3337 {
3338  if (_nId == 0)
3339  { // the seek cursor is being disposed
3340  ::osl::MutexGuard aGuard(m_aAdjustSafety);
3341  setDataSource(nullptr, DbGridControlOptions::Readonly); // our clone was disposed so we set our datasource to null to avoid later access to it
3342  if (m_nAsynAdjustEvent)
3343  {
3344  RemoveUserEvent(m_nAsynAdjustEvent);
3345  m_nAsynAdjustEvent = nullptr;
3346  }
3347  }
3348 }
3349 
3351 {
3352  return EditBrowseBox::GetAccessibleControlCount() + 1; // the navigation control
3353 }
3354 
3355 Reference<XAccessible > DbGridControl::CreateAccessibleControl( sal_Int32 _nIndex )
3356 {
3357  Reference<XAccessible > xRet;
3358  if ( _nIndex == EditBrowseBox::GetAccessibleControlCount() )
3359  {
3360  xRet = m_aBar->GetAccessible();
3361  }
3362  else
3363  xRet = EditBrowseBox::CreateAccessibleControl( _nIndex );
3364  return xRet;
3365 }
3366 
3367 Reference< XAccessible > DbGridControl::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
3368 {
3369  sal_uInt16 nColumnId = GetColumnId( _nColumnPos );
3370  size_t Location = GetModelColumnPos(nColumnId);
3371  DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
3372  if ( pColumn )
3373  {
3374  Reference< css::awt::XControl> xInt(pColumn->GetCell());
3375  Reference< css::awt::XCheckBox> xBox(xInt,UNO_QUERY);
3376  if ( xBox.is() )
3377  {
3378  TriState eValue = TRISTATE_FALSE;
3379  switch( xBox->getState() )
3380  {
3381  case 0:
3382  eValue = TRISTATE_FALSE;
3383  break;
3384  case 1:
3385  eValue = TRISTATE_TRUE;
3386  break;
3387  case 2:
3388  eValue = TRISTATE_INDET;
3389  break;
3390  }
3391  return EditBrowseBox::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,eValue );
3392  }
3393  }
3394  return EditBrowseBox::CreateAccessibleCell( _nRow, _nColumnPos );
3395 }
3396 
3397 /* 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:2830
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:3004
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:115
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:96
css::uno::Reference< css::container::XNameAccess > getColumns() const
Definition: fmtools.hxx:124
DataChangedEventType GetType() const
const KeyEvent * GetKeyEvent() const
sal_Int32 m_nLastVisibleWidth
Definition: gridcell.hxx:83
sal_uInt16 GetColumnPos(sal_uInt16 nColumnId) const
virtual ::svt::CellController * GetController(sal_Int32 nRow, sal_uInt16 nCol) override
Definition: gridctrl.cxx:2611
virtual void StartDrag(sal_Int8 nAction, const Point &rPosPixel) override
Definition: gridctrl.cxx:2497
virtual bool PreNotify(NotifyEvent &rEvt) override
Definition: gridctrl.cxx:2947
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:3315
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:3155
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:3336
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:3350
virtual void Command(const CommandEvent &rEvt) override
Definition: gridctrl.cxx:2542
StateChangedType
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:3207
virtual void DeleteSelectedRows()
Definition: gridctrl.cxx:2603
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)
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:121
bool IsMouseEvent() const
bool IsCurrentAppending() const
Definition: gridctrl.cxx:2820
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:3367
virtual sal_Int32 GetRowCount() const override
Point LeftCenter() const
sal_Int32 GetCurRow() const
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
sal_uInt16 nCode
bool IsPermanentCursorEnabled() const
Definition: gridctrl.cxx:1139
TRISTATE_INDET
bool moveToBookmark(const css::uno::Any &bookmark)
Definition: fmtools.hxx:105
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:3269
static void RemoveUserEvent(ImplSVEvent *nUserEvent)
bool IsInsertionRow(sal_Int32 nRow) const
Definition: gridctrl.cxx:2825
void InvalidateStatusCell(sal_Int32 nRow)
static OUString GetUIRootDir()
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 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:109
sal_uInt16 GetItemId(sal_uInt16 nPos) const
TRISTATE_FALSE
PopupMenu * get_menu(std::string_view sID)
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:3063
sal_uInt16 ArrangeControls()
Definition: gridctrl.cxx:373
std::unique_ptr< CursorWrapper > m_pSeekCursor
Definition: gridctrl.hxx:267
tools::Long Width() const
CommandEventId GetCommand() const
virtual bool SaveRow() override
Definition: gridctrl.cxx:2874
css::uno::Reference< css::sdb::XRowsChangeListener > m_xRowSetListener
Definition: gridctrl.hxx:253
virtual void CellModified() override
Definition: gridctrl.cxx:2643
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:3224
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:3286
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:3128
::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
void executeRowContextMenu(sal_Int32 _nRow, const Point &_rPreferredPos)
Definition: gridctrl.cxx:2532
Size GetSize() const
virtual sal_uInt32 GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) override
Definition: gridctrl.cxx:2399
virtual void PreExecuteRowContextMenu(sal_uInt16 nRow, PopupMenu &rMenu)
This is called before executing a context menu for a row.
Definition: gridctrl.cxx:2411
void Disable(bool bChild=true)
void EnableItem(sal_uInt16 nItemId, bool bEnable=true)
css::util::Date m_aNullDate
Definition: gridctrl.hxx:280
virtual bool IsModified() const override
Definition: gridctrl.cxx:2815
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:3164
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
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:2692
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
tools::Long Height() const
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:88
virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessibleControl(sal_Int32 _nIndex) override
Creates the accessible object of an additional control.
Definition: gridctrl.cxx:3355
friend class FmXGridSourcePropListener
Definition: gridctrl.hxx:221
IMPL_LINK_NOARG(DbGridControl, OnDelete, void *, void)
Definition: gridctrl.cxx:2597
osl::Mutex m_aAdjustSafety
Definition: gridctrl.hxx:277
void ConnectToFields()
Definition: gridctrl.cxx:3241
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:133
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)
virtual void PostExecuteRowContextMenu(sal_uInt16 nRow, const PopupMenu &rMenu, sal_uInt16 nExecutionResult)
After executing the context menu for a row this method is called.
Definition: gridctrl.cxx:2430
sal_Int32 m_nCurrentPos
virtual void HideColumn(sal_uInt16 nId)
hide a column
Definition: gridctrl.cxx:3034
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:3017
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
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:2804
bool isBeforeFirst() const
Definition: fmtools.hxx:108
bool IsHidden() const
Definition: gridcell.hxx:132
void ForceHideScrollbars()
forces both scrollbars to be hidden
Definition: gridctrl.cxx: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:2768
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:101
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