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