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>
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
58#include <comphelper/types.hxx>
60
61#include <algorithm>
62#include <cstdlib>
63#include <map>
64#include <memory>
65
66using namespace ::dbtools;
67using namespace ::dbtools::DBTypeConversion;
68using namespace ::svxform;
69using namespace ::svt;
70using namespace ::com::sun::star::beans;
71using namespace ::com::sun::star::lang;
72using namespace ::com::sun::star::uno;
73using namespace ::com::sun::star::sdbc;
74using namespace ::com::sun::star::sdbcx;
75using namespace ::com::sun::star::sdb;
76using namespace ::com::sun::star::datatransfer;
77using namespace ::com::sun::star::container;
78using 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
82constexpr 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
91class RowSetEventListener : public ::cppu::WeakImplHelper<XRowsChangeListener>
92{
94public:
95 explicit RowSetEventListener(DbGridControl* i_pControl) : m_pControl(i_pControl)
96 {
97 }
98
99private:
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
125typedef 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
136public:
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
148GridFieldValueListener::GridFieldValueListener(DbGridControl& _rParent, const Reference< XPropertySet >& _rField, sal_uInt16 _nId)
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
167void 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
197public:
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
204DisposeListenerGridBridge::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
237bool 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
250public:
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
267void FmXGridSourcePropListener::_propertyChanged(const PropertyChangeEvent& evt)
268{
269 DBG_ASSERT(m_nSuspended>=0, "FmXGridSourcePropListener::_propertyChanged : resume > suspend !");
270 if (m_nSuspended <= 0)
271 m_pParent->DataSourcePropertyChanged(evt);
272}
273
274const int nReserveNumDigits = 7;
275
276NavigationBar::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
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
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
378IMPL_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
413void 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;
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 {
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 {
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
586DbGridRow::DbGridRow():m_eStatus(GridRowStatus::Clean), m_bIsNew(true)
587{}
588
589DbGridRow::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 {
598 Reference< XPropertySet > xColSet(
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
639void 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);
742 SetCursorColor(Color(0xFF, 0, 0));
743
745}
746
748{
749 disposeOnce();
750}
751
753{
755
756 m_bWantDestruction = true;
757 osl::MutexGuard aGuard(m_aDestructionSafety);
761
762 if (m_nDeleteEvent)
764
766 {
768 m_pDataSourcePropMultiplexer.clear(); // this should delete the multiplexer
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()));
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
864 m_aBar->SetControlFont();
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
886void DbGridControl::RemoveRows(bool bNewCursor)
887{
888 // Did the data cursor change?
889 if (!bNewCursor)
890 {
891 m_pSeekCursor.reset();
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())
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();
925 m_aBar->InvalidateAll(m_nCurrentPos, true);
926}
927
928void DbGridControl::ArrangeControls(sal_uInt16& nX, sal_uInt16 nY)
929{
930 // positioning of the controls
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
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
950namespace
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();
995 m_aBar->InvalidateAll(m_nCurrentPos, true);
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()));
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{
1021 DBG_ASSERT(!m_xCurrentRow.is() || !m_xCurrentRow->IsModified(),
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 {
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
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 {
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 }
1129
1130 bool bWasEditing = IsEditing();
1132 if (bWasEditing)
1133 ActivateCell();
1134}
1135
1137{
1138 return (m_nMode & BrowserMode::CURSOR_WO_FOCUS) && !(m_nMode & BrowserMode::HIDECURSOR);
1139}
1140
1141void DbGridControl::refreshController(sal_uInt16 _nColId, GrantControlAccess /*_aAccess*/)
1142{
1143 if ((GetCurColumnId() == _nColId) && IsEditing())
1144 { // the controller which is currently active needs to be refreshed
1146 ActivateCell();
1147 }
1148}
1149
1150void DbGridControl::setDataSource(const Reference< XRowSet >& _xCursor, DbGridControlOptions nOpts)
1151{
1152 if (!_xCursor.is() && !m_pDataCursor)
1153 return;
1154
1156 {
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
1181
1182 {
1183 ::osl::MutexGuard aGuard(m_aAdjustSafety);
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 {
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
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 {
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())
1363
1364 // now reset the mode
1365 if (m_nMode != nOldMode)
1367
1368 // RecalcRows was already called while resizing
1369 if (!IsResizing() && GetRowCount())
1371
1372 m_aBar->InvalidateAll(m_nCurrentPos, true);
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() )
1384
1385 m_aColumns.clear();
1386
1387 EditBrowseBox::RemoveColumns();
1388}
1389
1390std::unique_ptr<DbGridColumn> DbGridControl::CreateColumn(sal_uInt16 nId)
1391{
1392 return std::unique_ptr<DbGridColumn>(new DbGridColumn(nId, *this));
1393}
1394
1395sal_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
1431{
1432 EditBrowseBox::RemoveColumn(nId);
1433
1434 const sal_uInt16 nIndex = GetModelColumnPos(nId);
1436 {
1437 m_aColumns.erase( m_aColumns.begin()+nIndex );
1438 }
1439}
1440
1441void 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
1535bool 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
1568void DbGridControl::VisibleRowsChanged( sal_Int32 nNewTopRow, sal_uInt16 nLinesOnScreen )
1569{
1570 RecalcRows(nNewTopRow, nLinesOnScreen, false);
1571}
1572
1573void 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
1629void 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
1649void 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;
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())
1715 m_aBar->InvalidateAll(m_nCurrentPos, true);
1716 }
1717 else // too few
1718 RowInserted(GetRowCount(), -nDelta);
1719 }
1720
1722 {
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
1755void 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
1774bool 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
1791bool 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 {
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 !");
1862 return false;
1863 }
1864 }
1865 catch ( const Exception& )
1866 {
1869 return false;
1870 }
1871
1873 return true;
1874}
1875
1877{
1878
1879 // cursor movement due to deletion or insertion of rows
1881 {
1884 }
1885
1886 EditBrowseBox::CursorMoved();
1887 m_aBar->InvalidateAll(m_nCurrentPos);
1888
1889 // select the new column when they moved
1891 {
1893 }
1894
1895 if ( m_nLastColId != GetCurColumnId() )
1898
1899 if ( m_nLastRowId != GetCurRow() )
1900 onRowChange();
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)
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
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
1992 m_aBar->InvalidateAll(m_nCurrentPos, m_xCurrentRow.is());
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
2046bool 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?
2061 if (IsValid(m_xCurrentRow) && m_xCurrentRow->IsNew() &&
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 {
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)
2205 }
2206 else if (GetRowCount())
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;
2243 }
2244 }
2245 catch(SQLException &)
2246 {
2248 }
2249
2250 if(!bOk)
2251 {
2252 AdjustRows();
2253 if (m_nTotalCount > 0) // only to avoid infinite recursion
2254 MoveToNext();
2255 }
2256 }
2257}
2258
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);
2285 m_aBar->InvalidateAll(m_nCurrentPos);
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
2341 m_aBar->InvalidateAll(m_nCurrentPos, true);
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())
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
2377OUString 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
2387OUString 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
2396sal_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
2427void 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
2442void 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 {
2469 m_aBar->InvalidateAll(m_nCurrentPos);
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);
2481 m_aBar->InvalidateAll(m_nCurrentPos);
2482 }
2483 }
2484 }
2485 if (m_xCurrentRow.is())
2486 {
2487 m_xCurrentRow->SetStatus(::comphelper::getBOOL(evt.NewValue) ? GridRowStatus::Modified : GridRowStatus::Clean);
2488 m_xCurrentRow->SetNew( bIsNew );
2490 SAL_INFO("svx.fmcomp", "modified flag changed, new state: " << ROWSTATUS(m_xCurrentRow));
2491 }
2492}
2493
2494void 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
2513bool DbGridControl::canCopyCellText(sal_Int32 _nRow, sal_uInt16 _nColId)
2514{
2515 return (_nRow >= 0)
2516 && (_nRow < GetRowCount())
2517 && (_nColId != HandleColumnId)
2519}
2520
2521void 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
2529void 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 ) );
2561
2562 // handled
2563 return;
2564 }
2565 }
2566
2567 sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X()));
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
2596IMPL_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
2610CellController* 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 {
2625 if (::comphelper::hasProperty(FM_PROP_ENABLED, pColumn->getModel()))
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);
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
2660 }
2661 }
2662
2663 if (IsFilterMode() || !IsValid(m_xCurrentRow) || m_xCurrentRow->IsModified())
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
2678 m_aBar->InvalidateAll(m_nCurrentPos);
2679 }
2680 }
2681 else if (m_xCurrentRow->GetStatus() != GridRowStatus::Modified)
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
2691void DbGridControl::Dispatch(sal_uInt16 nId)
2692{
2694 {
2696 AppendNew();
2697 else
2698 MoveToLast();
2699 }
2700 else
2701 EditBrowseBox::Dispatch(nId);
2702}
2703
2705{
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 {
2745 }
2746
2748
2749 m_xDataRow->SetState(m_pDataCursor.get(), false);
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);
2761 m_aBar->InvalidateAll(m_nCurrentPos);
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)
2778 Reference< XPropertySet > xDataSource = getDataSource()->getPropertySet();
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);
2787 m_aBar->InvalidateAll(m_nCurrentPos);
2788 }
2789 }
2790 }
2791
2792 // update the rows
2793 m_xDataRow->SetState(m_pDataCursor.get(), false);
2796 else
2798 }
2799
2800 RowModified(GetCurRow()); // will update the current controller if affected
2801}
2802
2803void 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
2824bool 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 {
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;
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
3003bool 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
3033void DbGridControl::HideColumn(sal_uInt16 nId)
3034{
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
3062void DbGridControl::ShowColumn(sal_uInt16 nId)
3063{
3064 sal_uInt16 nPos = GetModelColumnPos(nId);
3065 DBG_ASSERT(nPos != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : invalid argument !");
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
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
3127sal_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
3154sal_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 )
3192 }
3193}
3194
3195IMPL_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{
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{
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
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
3335void 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
3342 {
3343 RemoveUserEvent(m_nAsynAdjustEvent);
3344 m_nAsynAdjustEvent = nullptr;
3345 }
3346 }
3347}
3348
3350{
3351 return EditBrowseBox::GetAccessibleControlCount() + 1; // the navigation control
3352}
3353
3354Reference<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
3366Reference< 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: */
Reference< XComponentContext > m_xContext
XSLTFilter & m_rParent
#define BROWSER_INVALIDID
BrowserMode
#define BROWSER_CURSORENDOFFILE
static bool IsMainThread()
static const AllSettings & GetSettings()
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
static std::unique_ptr< weld::Builder > CreateBuilder(weld::Widget *pParent, const OUString &rUIFile, bool bMobile=false, sal_uInt64 nLOKWindowId=0)
static void RemoveUserEvent(ImplSVEvent *nUserEvent)
sal_uInt16 GetVisibleRows() const
sal_uInt16 GetColumnId(sal_uInt16 nPos) const
void SetUpdateMode(bool bUpdate)
tools::Rectangle GetControlArea() const
bool GoToColumnId(sal_uInt16 nColId)
void SetRealRowCount(const OUString &rRealRowCount)
bool IsResizing() const
BrowserDataWin & GetDataWindow() const
void InsertDataColumn(sal_uInt16 nItemId, const OUString &rText, tools::Long nSize, HeaderBarItemBits nBits=HeaderBarItemBits::STDSTYLE, sal_uInt16 nPos=HEADERBAR_APPEND)
sal_Int32 GetCurRow() const
const MultiSelection * GetSelection() const
sal_Int32 GetRowAtYPosPixel(tools::Long nY, bool bRelToBrowser=true) const
tools::Long CalcReverseZoom(tools::Long nVal) const
sal_Int32 GetTopRow() const
sal_uInt16 ColCount() const
void InsertHandleColumn(sal_uLong nWidth)
bool GoToRowColumnId(sal_Int32 nRow, sal_uInt16 nColId)
void SetMode(BrowserMode nMode)
sal_uInt16 GetColumnPos(sal_uInt16 nColumnId) const
void SetCursorColor(const Color &_rCol)
void SelectColumnId(sal_uInt16 nColId)
sal_Int32 GetSelectRowCount() const
static const sal_uInt16 HandleColumnId
sal_uInt16 GetCurColumnId() const
sal_uLong GetDefaultColumnWidth(const OUString &_rText) const
tools::Rectangle GetRowRectPixel(sal_Int32 nRow) const
bool ReserveControlArea(sal_uInt16 nWidth=USHRT_MAX)
sal_uInt16 GetColumnAtXPosPixel(tools::Long nX) const
sal_Int32 FirstSelectedRow()
virtual sal_Int32 GetRowCount() const override
virtual sal_Int32 GetSelectedColumnCount() const override
BrowserMode GetMode() const
virtual void SetNoSelection() override
sal_uLong GetColumnWidth(sal_uInt16 nColumnId) const
void SetHeaderBar(BrowserHeader *)
virtual bool IsRowSelected(sal_Int32 nRow) const override
CommandEventId GetCommand() const
const Point & GetMousePosPixel() const
bool IsMouseEvent() const
sal_Int32 getRow() const
Definition: fmtools.hxx:115
bool rowDeleted()
Definition: fmtools.hxx:121
bool isAfterLast() const
Definition: fmtools.hxx:109
css::uno::Any getBookmark()
Definition: fmtools.hxx:101
bool isBeforeFirst() const
Definition: fmtools.hxx:108
bool Is() const
Definition: fmtools.hxx:88
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
bool moveToBookmark(const css::uno::Any &bookmark)
Definition: fmtools.hxx:105
DataChangedEventType GetType() const
AllSettingsFlags GetFlags() const
bool Commit()
Definition: gridcell.cxx:268
void UpdateFromField(const DbGridRow *pRow, const css::uno::Reference< css::util::XNumberFormatter > &xFormatter)
Definition: gridcell.cxx:258
OUString GetCellText(const DbGridRow *pRow, const css::uno::Reference< css::util::XNumberFormatter > &xFormatter) const
sal_uInt16 GetId() const
Definition: gridcell.hxx:116
bool IsAutoValue() const
Definition: gridcell.hxx:118
bool IsHidden() const
Definition: gridcell.hxx:122
FmXGridCell * GetCell() const
Definition: gridcell.hxx:127
bool m_bHidden
Definition: gridcell.hxx:85
const ::svt::CellControllerRef & GetController() const
Definition: gridcell.hxx:124
sal_Int32 m_nLastVisibleWidth
Definition: gridcell.hxx:73
void Paint(OutputDevice &rDev, const tools::Rectangle &rRect, const DbGridRow *pRow, const css::uno::Reference< css::util::XNumberFormatter > &xFormatter)
Definition: gridcell.cxx:444
const css::uno::Reference< css::beans::XPropertySet > & getModel() const
Definition: gridcell.hxx:112
void disposing(sal_uInt16 _nId)
Definition: gridctrl.cxx:3335
virtual void DeleteSelectedRows()
Definition: gridctrl.cxx:2602
void refreshController(sal_uInt16 _nColId, GrantControlAccess _aAccess)
called when a controller needs to be re-initialized
Definition: gridctrl.cxx:1141
CursorWrapper * getDataSource() const
Definition: gridctrl.hxx:405
bool IsUpdating() const
Definition: gridctrl.hxx:466
bool m_bUpdating
Definition: gridctrl.hxx:305
void EnableNavigationBar(bool bEnable)
Definition: gridctrl.cxx:984
bool SetCurrent(sal_Int32 nNewRow)
Definition: gridctrl.cxx:1791
friend class DisposeListenerGridBridge
Definition: gridctrl.hxx:223
const css::uno::Reference< css::util::XNumberFormatter > & getNumberFormatter() const
Definition: gridctrl.hxx:397
virtual void SetDesignMode(bool bMode)
Definition: gridctrl.cxx:2316
void DataSourcePropertyChanged(const css::beans::PropertyChangeEvent &evt)
Definition: gridctrl.cxx:2442
bool m_bFilterMode
Definition: gridctrl.hxx:299
Link< DbGridControlNavigationBarState, int > m_aMasterStateProvider
Definition: gridctrl.hxx:230
css::util::Date m_aNullDate
Definition: gridctrl.hxx:280
bool IsDesignMode() const
Definition: gridctrl.hxx:428
DbGridRowRef m_xPaintRow
Definition: gridctrl.hxx:272
virtual sal_Int32 GetAccessibleControlCount() const override
Definition: gridctrl.cxx:3349
bool m_bSynchDisplay
Definition: gridctrl.hxx:297
bool getDisplaySynchron() const
Definition: gridctrl.hxx:474
bool m_bDesignMode
Definition: gridctrl.hxx:293
virtual OUString GetCellText(sal_Int32 _nRow, sal_uInt16 _nColId) const override
GetCellText returns the text at the given position.
Definition: gridctrl.cxx:2377
void RowInserted(sal_Int32 nRow, sal_Int32 nNumRows=1, bool bDoPaint=true)
Definition: gridctrl.cxx:1629
DbGridRowRef m_xDataRow
Definition: gridctrl.hxx:238
sal_uInt16 GetColumnIdFromModelPos(sal_uInt16 nPos) const
Definition: gridctrl.cxx:3127
virtual void ShowColumn(sal_uInt16 nId)
show a column
Definition: gridctrl.cxx:3062
bool HasHandle() const
Definition: gridctrl.hxx:409
sal_Int32 AlignSeekCursor()
Definition: gridctrl.cxx:1995
sal_Int32 m_nCurrentPos
Definition: gridctrl.hxx:283
void AdjustDataSource(bool bFull=false)
Definition: gridctrl.cxx:1925
void RowRemoved(sal_Int32 nRow, sal_Int32 nNumRows=1, bool bDoPaint=true)
Definition: gridctrl.cxx:1649
FmXGridSourcePropListener * m_pDataSourcePropListener
Definition: gridctrl.hxx:251
bool IsFilterMode() const
Definition: gridctrl.hxx:432
void DisconnectFromFields()
Definition: gridctrl.cxx:3268
virtual ::svt::CellController * GetController(sal_Int32 nRow, sal_uInt16 nCol) override
Definition: gridctrl.cxx:2610
virtual void ArrangeControls(sal_uInt16 &nX, sal_uInt16 nY) override
Definition: gridctrl.cxx:928
virtual bool PreNotify(NotifyEvent &rEvt) override
Definition: gridctrl.cxx:2946
virtual RowStatus GetRowStatus(sal_Int32 nRow) const override
Definition: gridctrl.cxx:1731
bool m_bNavigationBar
Definition: gridctrl.hxx:295
virtual void onColumnChange()
called when the current column changed
Definition: gridctrl.cxx:1909
sal_uInt16 GetViewColumnPos(sal_uInt16 nId) const
Definition: gridctrl.hxx:413
bool m_bPendingAdjustRows
Definition: gridctrl.hxx:301
virtual void onRowChange()
called when the current row changed
Definition: gridctrl.cxx:1904
virtual bool SaveRow() override
Definition: gridctrl.cxx:2873
void MoveToLast()
Definition: gridctrl.cxx:2178
virtual void CursorMoved() override
Definition: gridctrl.cxx:1876
virtual bool IsModified() const override
Definition: gridctrl.cxx:2814
ImplSVEvent * m_nDeleteEvent
Definition: gridctrl.hxx:284
virtual void VisibleRowsChanged(sal_Int32 nNewTopRow, sal_uInt16 nNumRows) override
Definition: gridctrl.cxx:1568
bool IsInsertionRow(sal_Int32 nRow) const
Definition: gridctrl.cxx:2824
void setDataSource(const css::uno::Reference< css::sdbc::XRowSet > &rCursor, DbGridControlOptions nOpts=DbGridControlOptions::Insert|DbGridControlOptions::Update|DbGridControlOptions::Delete)
Definition: gridctrl.cxx:1150
sal_Int32 m_nLastRowId
Definition: gridctrl.hxx:291
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
bool IsOpen() const
Definition: gridctrl.hxx:429
virtual void PostExecuteRowContextMenu(const OString &rExecutionResult)
After executing the context menu for a row this method is called.
Definition: gridctrl.cxx:2427
sal_uInt16 GetColumnIdFromViewPos(sal_uInt16 nPos) const
Definition: gridctrl.hxx:424
virtual void ColumnMoved(sal_uInt16 nId) override
Definition: gridctrl.cxx:1441
void RemoveColumns()
Definition: gridctrl.cxx:1380
virtual void StartDrag(sal_Int8 nAction, const Point &rPosPixel) override
Definition: gridctrl.cxx:2494
DbGridControlOptions GetOptions() const
Definition: gridctrl.hxx:438
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: gridctrl.cxx:820
void EnableHandle(bool bEnable)
Definition: gridctrl.cxx:939
virtual void Init() override
Definition: gridctrl.cxx:735
std::vector< std::unique_ptr< DbGridColumn > > m_aColumns
Definition: gridctrl.hxx:236
friend class FmXGridSourcePropListener
Definition: gridctrl.hxx:221
virtual void HideColumn(sal_uInt16 nId)
hide a column
Definition: gridctrl.cxx:3033
virtual sal_uInt32 GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) override
Definition: gridctrl.cxx:2396
void implAdjustInSolarThread(bool _bRows)
Definition: gridctrl.cxx:3163
virtual bool IsTabAllowed(bool bForward) const override
Definition: gridctrl.cxx:3003
DbGridRowRef m_xEmptyRow
Definition: gridctrl.hxx:243
friend class GridFieldValueListener
Definition: gridctrl.hxx:222
void setDisplaySynchron(bool bSync)
Definition: gridctrl.cxx:1915
ImplSVEvent * m_nAsynAdjustEvent
Definition: gridctrl.hxx:245
osl::Mutex m_aDestructionSafety
Definition: gridctrl.hxx:276
void AdjustRows()
Definition: gridctrl.cxx:1668
void ForceHideScrollbars()
forces both scrollbars to be hidden
Definition: gridctrl.cxx:1098
virtual void Dispatch(sal_uInt16 nId) override
Definition: gridctrl.cxx:2691
bool IsPermanentCursorEnabled() const
Definition: gridctrl.cxx:1136
css::uno::Reference< css::uno::XComponentContext > m_xContext
Definition: gridctrl.hxx:234
std::unique_ptr< CursorWrapper > m_pSeekCursor
Definition: gridctrl.hxx:267
BrowserMode m_nMode
Definition: gridctrl.hxx:282
virtual ~DbGridControl() override
Definition: gridctrl.cxx:747
sal_uInt16 GetModelColumnPos(sal_uInt16 nId) const
Definition: gridctrl.cxx:3154
css::uno::Reference< css::sdb::XRowsChangeListener > m_xRowSetListener
Definition: gridctrl.hxx:253
bool canCopyCellText(sal_Int32 _nRow, sal_uInt16 _nColId)
returns <TRUE> if the text of the given cell can be copied into the clipboard
Definition: gridctrl.cxx:2513
std::unique_ptr< DisposeListenerGridBridge > m_pCursorDisposeListener
Definition: gridctrl.hxx:258
void SetFilterMode(bool bMode)
Definition: gridctrl.cxx:2344
void copyCellText(sal_Int32 _nRow, sal_uInt16 _nColId)
copies the text of the given cell into the clipboard
Definition: gridctrl.cxx:2521
bool m_bRecordCountFinal
Definition: gridctrl.hxx:294
virtual void CellModified() override
Definition: gridctrl.cxx:2642
virtual void dispose() override
Definition: gridctrl.cxx:752
virtual void PaintCell(OutputDevice &rDev, const tools::Rectangle &rRect, sal_uInt16 nColId) const override
Definition: gridctrl.cxx:1755
void RecalcRows(sal_Int32 nNewTopRow, sal_uInt16 nLinesOnScreen, bool bUpdateCursor)
Definition: gridctrl.cxx:1573
virtual bool CursorMoving(sal_Int32 nNewRow, sal_uInt16 nNewCol) override
Definition: gridctrl.cxx:1774
virtual void StateChanged(StateChangedType nType) override
Definition: gridctrl.cxx:782
bool SeekCursor(sal_Int32 nRow, bool bAbsolute=false)
Definition: gridctrl.cxx:2046
css::uno::Reference< css::util::XNumberFormatter > m_xFormatter
Definition: gridctrl.hxx:233
sal_uInt16 m_nLastColId
Definition: gridctrl.hxx:290
rtl::Reference<::comphelper::OPropertyChangeMultiplexer > m_pDataSourcePropMultiplexer
Definition: gridctrl.hxx:250
bool IsCurrentAppending() const
Definition: gridctrl.cxx:2819
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
DbGridControlOptions m_nOptionMask
Definition: gridctrl.hxx:287
DbGridRowRef m_xSeekRow
Definition: gridctrl.hxx:240
osl::Mutex m_aAdjustSafety
Definition: gridctrl.hxx:277
void RemoveColumn(sal_uInt16 nId)
Definition: gridctrl.cxx:1430
void EnablePermanentCursor(bool bEnable)
Definition: gridctrl.cxx:1109
DbGridControlOptions m_nOptions
Definition: gridctrl.hxx:285
Link< DbGridControlNavigationBarState, bool > m_aMasterSlotExecutor
Definition: gridctrl.hxx:231
void MoveToFirst()
Definition: gridctrl.cxx:2172
OUString GetCurrentRowCellText(DbGridColumn const *pCol, const DbGridRowRef &_rRow) const
Definition: gridctrl.cxx:2387
virtual bool SaveModified() override
Definition: gridctrl.cxx:2829
virtual void KeyInput(const KeyEvent &rEvt) override
Definition: gridctrl.cxx:3016
void RowModified(sal_Int32 nRow)
Definition: gridctrl.cxx:2803
void executeRowContextMenu(const Point &_rPreferredPos)
Definition: gridctrl.cxx:2529
virtual bool SeekRow(sal_Int32 nRow) override
Definition: gridctrl.cxx:1535
sal_Int32 m_nTotalCount
Definition: gridctrl.hxx:274
void resetCurrentRow()
Definition: gridctrl.cxx:2767
std::unique_ptr< CursorWrapper > m_pDataCursor
Definition: gridctrl.hxx:266
virtual void Command(const CommandEvent &rEvt) override
Definition: gridctrl.cxx:2541
virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessibleControl(sal_Int32 _nIndex) override
Creates the accessible object of an additional control.
Definition: gridctrl.cxx:3354
sal_uInt16 GetViewColCount() const
Definition: gridctrl.hxx:421
void FieldValueChanged(sal_uInt16 _nId)
Definition: gridctrl.cxx:3285
bool m_bWantDestruction
Definition: gridctrl.hxx:300
virtual void RemoveRows() override
Definition: gridctrl.cxx:905
bool m_bHideScrollbars
Definition: gridctrl.hxx:302
DbGridRowRef m_xCurrentRow
Definition: gridctrl.hxx:271
void ConnectToFields()
Definition: gridctrl.cxx:3240
FmGridListener * m_pGridListener
Definition: gridctrl.hxx:263
DbGridControl(css::uno::Reference< css::uno::XComponentContext > const &_rxContext, vcl::Window *pParent, WinBits nBits)
Definition: gridctrl.cxx:687
virtual void InitColumnsByFields(const css::uno::Reference< css::container::XIndexAccess > &xFields)=0
virtual void EndCursorAction()
Definition: gridctrl.cxx:3223
VclPtr< NavigationBar > m_aBar
Definition: gridctrl.hxx:237
std::unique_ptr< DbGridColumn > CreateColumn(sal_uInt16 nId)
Definition: gridctrl.cxx:1390
void MoveToPrev()
Definition: gridctrl.cxx:2210
void MoveToNext()
Definition: gridctrl.cxx:2217
void ImplInitWindow(const InitWindowFacet _eInitWhat)
Definition: gridctrl.cxx:842
void * m_pFieldListeners
Definition: gridctrl.hxx:255
void AppendNew()
Definition: gridctrl.cxx:2288
virtual void Select() override
Definition: gridctrl.cxx:831
virtual void PreExecuteRowContextMenu(weld::Menu &rMenu)
This is called before executing a context menu for a row.
Definition: gridctrl.cxx:2408
void MoveToPosition(sal_uInt32 nPos)
Definition: gridctrl.cxx:2259
bool IsFilterRow(sal_Int32 nRow) const
Definition: gridctrl.hxx:433
virtual void BeginCursorAction()
Definition: gridctrl.cxx:3206
DbGridControlOptions SetOptions(DbGridControlOptions nOpt)
Definition: gridctrl.cxx:1019
static bool IsValid(const DbGridRowRef &_xRow)
Definition: gridctrl.hxx:564
sal_Int32 m_nSeekPos
Definition: gridctrl.hxx:273
void FieldListenerDisposing(sal_uInt16 _nId)
Definition: gridctrl.cxx:3314
void InsertHandleColumn()
Definition: gridctrl.cxx:726
bool m_bIsNew
Definition: gridctrl.hxx:69
bool IsValid() const
Definition: gridctrl.hxx:89
::std::vector< std::unique_ptr<::svxform::DataColumn > > m_aVariants
Definition: gridctrl.hxx:67
void SetState(CursorWrapper *pCur, bool bPaintCursor)
Definition: gridctrl.cxx:639
GridRowStatus m_eStatus
Definition: gridctrl.hxx:68
virtual ~DbGridRow() override
Definition: gridctrl.cxx:635
css::uno::Any m_aBookmark
Definition: gridctrl.hxx:65
rtl::Reference< FmXDisposeMultiplexer > m_xRealListener
Definition: gridctrl.cxx:195
virtual ~DisposeListenerGridBridge() override
Definition: gridctrl.cxx:215
virtual void disposing(sal_Int16 _nId) override
Definition: gridctrl.cxx:201
DisposeListenerGridBridge(DbGridControl &_rParent, const Reference< XComponent > &_rxObject)
Definition: gridctrl.cxx:204
DbGridControl & m_rParent
Definition: gridctrl.cxx:194
virtual void columnChanged()=0
virtual void selectionChanged()=0
friend class FmXDisposeMultiplexer
Definition: fmtools.hxx:133
virtual void _propertyChanged(const PropertyChangeEvent &evt) override
Definition: gridctrl.cxx:267
FmXGridSourcePropListener(DbGridControl *_pParent)
Definition: gridctrl.cxx:259
VclPtr< DbGridControl > m_pParent
Definition: gridctrl.cxx:244
GridFieldValueListener(DbGridControl &_rParent, const Reference< XPropertySet > &xField, sal_uInt16 _nId)
Definition: gridctrl.cxx:148
rtl::Reference<::comphelper::OPropertyChangeMultiplexer > m_pRealListener
Definition: gridctrl.cxx:131
virtual ~GridFieldValueListener() override
Definition: gridctrl.cxx:162
virtual void _propertyChanged(const PropertyChangeEvent &evt) override
Definition: gridctrl.cxx:167
DbGridControl & m_rParent
Definition: gridctrl.cxx:130
virtual void dispose() override
std::unique_ptr< weld::Builder > m_xBuilder
std::unique_ptr< weld::Container > m_xContainer
sal_Unicode GetCharCode() const
const vcl::KeyCode & GetKeyCode() const
virtual bool DoKeyInput(const KeyEvent &rEvt) override
Definition: gridctrl.cxx:282
virtual void PositionFired(sal_Int64 nRecord) override
Definition: gridctrl.cxx:292
AbsolutePos(std::unique_ptr< weld::Entry > xEntry, NavigationBar *pBar)
Definition: gridctrl.cxx:276
std::unique_ptr< weld::Button > m_xPrevBtn
Definition: gridctrl.hxx:188
std::unique_ptr< weld::Label > m_xRecordOf
Definition: gridctrl.hxx:184
NavigationBar(vcl::Window *pParent)
Definition: gridctrl.cxx:309
sal_uInt16 ArrangeControls()
Definition: gridctrl.cxx:373
std::unique_ptr< weld::Label > m_xRecordCount
Definition: gridctrl.hxx:185
std::unique_ptr< weld::Button > m_xLastBtn
Definition: gridctrl.hxx:190
std::unique_ptr< weld::Label > m_xRecordText
Definition: gridctrl.hxx:182
void PositionDataSource(sal_Int32 nRecord)
Definition: gridctrl.cxx:298
void SetState(DbGridControlNavigationBarState nWhich)
Definition: gridctrl.cxx:498
std::unique_ptr< weld::Button > m_xNextBtn
Definition: gridctrl.hxx:189
virtual void dispose() override
Definition: gridctrl.cxx:359
std::shared_ptr< weld::ButtonPressRepeater > m_xNextRepeater
Definition: gridctrl.hxx:194
sal_Int32 m_nCurrentPos
Definition: gridctrl.hxx:196
std::unique_ptr< AbsolutePos > m_xAbsolute
Definition: gridctrl.hxx:183
void InvalidateAll(sal_Int32 nCurrentPos, bool bAll=false)
Definition: gridctrl.cxx:413
virtual ~NavigationBar() override
Definition: gridctrl.cxx:354
bool GetState(DbGridControlNavigationBarState nWhich) const
Definition: gridctrl.cxx:443
std::unique_ptr< weld::Button > m_xNewBtn
Definition: gridctrl.hxx:191
std::unique_ptr< weld::Button > m_xFirstBtn
Definition: gridctrl.hxx:187
bool m_bPositioning
Definition: gridctrl.hxx:198
std::shared_ptr< weld::ButtonPressRepeater > m_xPrevRepeater
Definition: gridctrl.hxx:193
const KeyEvent * GetKeyEvent() const
vcl::Window * GetWindow() const
MouseNotifyEvent GetType() const
virtual bool DoKeyInput(const KeyEvent &rEvt)
RowSetEventListener(DbGridControl *i_pControl)
Definition: gridctrl.cxx:95
VclPtr< DbGridControl > m_pControl
Definition: gridctrl.cxx:93
virtual void SAL_CALL disposing(const css::lang::EventObject &) override
Definition: gridctrl.cxx:101
virtual void SAL_CALL rowsChanged(const css::sdb::RowsChangeEvent &i_aEvt) override
Definition: gridctrl.cxx:104
constexpr tools::Long Height() const
constexpr tools::Long Width() const
void disposeAndClear()
bool IsEditing() const
virtual void DeactivateCell(bool bUpdate=true)
const CellControllerRef & Controller() const
virtual VclPtr< BrowserHeader > CreateHeaderBar(BrowseBox *pParent) override
void InvalidateStatusCell(sal_Int32 nRow)
VclPtr< BrowserHeader > pHeader
virtual void InitController(CellControllerRef &rController, sal_Int32 nRow, sal_uInt16 nCol)
constexpr Point TopLeft() const
constexpr Size GetSize() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
constexpr Point LeftCenter() const
T * get() const
bool is() const
void SetTransparent(bool bTransparent)
bool IsMod1() const
sal_uInt16 GetCode() const
KeyFuncType GetFunction() const
bool IsShift() const
bool IsMod2() const
vcl::Window * GetParent() const
virtual void KeyInput(const KeyEvent &rKEvt)
virtual void set_visible(const OString &rIdent, bool bVisible)=0
virtual void set_sensitive(bool sensitive)=0
virtual bool get_sensitive() const=0
#define DBG_ASSERT(sCon, aError)
#define DBG_UNHANDLED_EXCEPTION(...)
OUString SvxResId(TranslateId aId)
Definition: dialmgr.cxx:24
virtual void Insert(SotClipboardFormatId nFormat, const OUString &rFormatName) override
virtual sal_uInt32 GetId() const override
EditBrowseBoxFlags
sal_Int32 nState
constexpr OUStringLiteral IsHidden(u"IsHidden")
constexpr OUStringLiteral FM_PROP_ROWCOUNT
Definition: fmprop.hxx:34
constexpr OUStringLiteral FM_PROP_ISNEW
Definition: fmprop.hxx:117
constexpr OUStringLiteral FM_PROP_ENABLED
Definition: fmprop.hxx:46
constexpr OUStringLiteral FM_PROP_LABEL
Definition: fmprop.hxx:42
constexpr OUStringLiteral FM_PROP_FETCHSIZE
Definition: fmprop.hxx:36
constexpr OUStringLiteral FM_PROP_RESULTSET_CONCURRENCY
Definition: fmprop.hxx:121
constexpr OUStringLiteral FM_PROP_PRIVILEGES
Definition: fmprop.hxx:118
constexpr OUStringLiteral FM_PROP_ROWCOUNTFINAL
Definition: fmprop.hxx:35
constexpr OUStringLiteral FM_PROP_VALUE
Definition: fmprop.hxx:37
constexpr OUStringLiteral FM_PROP_ISMODIFIED
Definition: fmprop.hxx:116
OUString sName
TriState
TRISTATE_FALSE
TRISTATE_INDET
TRISTATE_TRUE
bool m_bDisposed
IMPL_LINK(NavigationBar, OnClick, weld::Button &, rButton, void)
Definition: gridctrl.cxx:378
constexpr auto DEFAULT_BROWSE_MODE
Definition: gridctrl.cxx:82
#define ROWSTATUS(row)
Definition: gridctrl.cxx:80
const DbGridControlNavigationBarState ControlMap[]
Definition: gridctrl.cxx:223
bool CompareBookmark(const Any &aLeft, const Any &aRight)
Definition: gridctrl.cxx:237
IMPL_LINK_NOARG(DbGridControl, OnDelete, void *, void)
Definition: gridctrl.cxx:2596
const int nReserveNumDigits
Definition: gridctrl.cxx:274
std::map< sal_uInt16, GridFieldValueListener * > ColumnFieldValueListeners
Definition: gridctrl.cxx:124
DbGridControlOptions
Definition: gridctrl.hxx:132
#define GRID_COLUMN_NOT_FOUND
Definition: gridctrl.hxx:110
InitWindowFacet
Definition: gridctrl.hxx:116
GridRowStatus
Definition: gridctrl.hxx:52
DbGridControlNavigationBarState
Definition: gridctrl.hxx:146
#define HEADERBAR_APPEND
constexpr OStringLiteral HID_GRID_NUMBEROFRECORDS
Definition: helpids.h:58
constexpr OStringLiteral HID_GRID_TRAVEL_FIRST
Definition: helpids.h:52
constexpr OStringLiteral HID_GRID_TRAVEL_PREV
Definition: helpids.h:53
constexpr OStringLiteral HID_GRID_TRAVEL_NEW
Definition: helpids.h:56
constexpr OStringLiteral HID_GRID_TRAVEL_NEXT
Definition: helpids.h:54
constexpr OStringLiteral HID_GRID_TRAVEL_LAST
Definition: helpids.h:55
constexpr OStringLiteral HID_GRID_TRAVEL_ABSOLUTE
Definition: helpids.h:57
std::mutex m_aMutex
sal_Int32 nIndex
OUString aName
constexpr sal_uInt16 KEY_ESCAPE
constexpr sal_uInt16 KEY_TAB
constexpr sal_uInt16 KEY_DELETE
sal_uInt16 nPos
#define SAL_INFO(area, stream)
sal_uInt16 nCode
NONE
@ Exception
OOO_DLLPUBLIC_DBTOOLS css::util::Date const & getStandardDate()
Reference< XConnection > getConnection(const Reference< XRowSet > &_rxRowSet)
Reference< XNumberFormatsSupplier > getNumberFormats(const Reference< XConnection > &_rxConn, bool _bAlloweDefault, const Reference< XComponentContext > &_rxContext)
int i
void Create(SvxOrientationItem &rItem, SvStream &rStrm, sal_uInt16)
Definition: legacyitem.cxx:34
std::shared_ptr< T > make_shared(Args &&... args)
class FmSearchEngine - Impl class for FmSearchDialog
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
long Long
Color GetFillColor(Color const &rColor, DrawModeFlags nDrawMode, StyleSettings const &rStyleSettings)
weld::Window * GetPopupParent(vcl::Window &rOutWin, tools::Rectangle &rRect)
sal_Int16 nId
sal_Int32 m_nCurrentPos
QPRO_FUNC_TYPE nType
#define DND_ACTION_COPY
constexpr auto nCacheSize
signed char sal_Int8
StateChangedType
sal_Int64 WinBits