1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
19 #ifndef INCLUDED_SVX_GRIDCTRL_HXX
20 #define INCLUDED_SVX_GRIDCTRL_HXX
22 #include <com/sun/star/util/Date.hpp>
23 #include <vcl/fixed.hxx>
24 #include <vcl/field.hxx>
26 #include <vcl/button.hxx>
27 #include <tools/ref.hxx>
28 #include <svtools/editbrowsebox.hxx>
29 #include <osl/mutex.hxx>
30 #include <svx/svxdllapi.h>
31 #include <o3tl/typed_flags_set.hxx>
35 namespace comphelper
{ class OPropertyChangeMultiplexer
; }
36 namespace com::sun::star::beans
{ struct PropertyChangeEvent
; }
37 namespace com::sun::star::container
{ class XIndexAccess
; }
38 namespace com::sun::star::sdbc
{ class XRowSet
; }
39 namespace com::sun::star::sdb
{ class XRowsChangeListener
; }
40 namespace com::sun::star::uno
{ class XComponentContext
; }
41 namespace com::sun::star::util
{ class XNumberFormatter
; }
45 bool CompareBookmark(const css::uno::Any
& aLeft
, const css::uno::Any
& aRight
);
52 enum class GridRowStatus
61 // DbGridRow, description of rows
64 class SAL_DLLPUBLIC_RTTI DbGridRow final
: public SvRefBase
66 css::uno::Any m_aBookmark
; // Bookmark of the row, can be set
67 ::std::vector
< std::unique_ptr
<::svxform::DataColumn
> >
69 GridRowStatus m_eStatus
;
71 // row is no longer valid
72 // is removed on the next positioning
75 DbGridRow(CursorWrapper
* pCur
, bool bPaintCursor
);
76 void SetState(CursorWrapper
* pCur
, bool bPaintCursor
);
78 virtual ~DbGridRow() override
;
80 bool HasField(sal_uInt32 nPos
) const { return nPos
< m_aVariants
.size(); }
81 const ::svxform::DataColumn
& GetField(sal_uInt32 nPos
) const { return *m_aVariants
[ nPos
]; }
83 void SetStatus(GridRowStatus _eStat
) { m_eStatus
= _eStat
; }
84 GridRowStatus
GetStatus() const { return m_eStatus
; }
85 void SetNew(bool _bNew
) { m_bIsNew
= _bNew
; }
86 bool IsNew() const { return m_bIsNew
; }
88 const css::uno::Any
& GetBookmark() const { return m_aBookmark
; }
90 bool IsValid() const { return m_eStatus
== GridRowStatus::Clean
|| m_eStatus
== GridRowStatus::Modified
; }
91 bool IsModified() const { return m_eStatus
== GridRowStatus::Modified
; }
94 typedef tools::SvRef
<DbGridRow
> DbGridRowRef
;
104 virtual void selectionChanged() = 0;
105 virtual void columnChanged() = 0;
111 #define GRID_COLUMN_NOT_FOUND SAL_MAX_UINT16
114 // InitWindowFacet, describing which aspect of a column's Window to (re-)initialize
116 enum class InitWindowFacet
126 template<> struct typed_flags
<InitWindowFacet
> : is_typed_flags
<InitWindowFacet
, 0x0f> {};
130 // these options are or'ed and indicate, which of the single
131 // features can be released, default is readonly which means 0
132 enum class DbGridControlOptions
141 template<> struct typed_flags
<DbGridControlOptions
> : is_typed_flags
<DbGridControlOptions
, 0x07> {};
144 // StatusIds for Controls of the Bar
145 // important for invalidation
146 enum class DbGridControlNavigationBarState
158 Undo
// related to SID_FM_RECORD_UNDO
161 class FmXGridSourcePropListener
;
162 class DisposeListenerGridBridge
;
163 class SVX_DLLPUBLIC DbGridControl
: public svt::EditBrowseBox
165 friend class FmXGridSourcePropListener
;
166 friend class GridFieldValueListener
;
167 friend class DisposeListenerGridBridge
;
173 class NavigationBar final
: public Control
175 class AbsolutePos
: public NumericField
178 AbsolutePos(vcl::Window
* pParent
, WinBits nStyle
);
180 virtual void KeyInput(const KeyEvent
& rEvt
) override
;
181 virtual void LoseFocus() override
;
184 friend class NavigationBar::AbsolutePos
;
186 // additional controls
187 VclPtr
<FixedText
> m_aRecordText
;
188 VclPtr
<AbsolutePos
> m_aAbsolute
; // absolute positioning
189 VclPtr
<FixedText
> m_aRecordOf
;
190 VclPtr
<FixedText
> m_aRecordCount
;
192 VclPtr
<ImageButton
> m_aFirstBtn
; // ImageButton for 'go to the first record'
193 VclPtr
<ImageButton
> m_aPrevBtn
; // ImageButton for 'go to the previous record'
194 VclPtr
<ImageButton
> m_aNextBtn
; // ImageButton for 'go to the next record'
195 VclPtr
<ImageButton
> m_aLastBtn
; // ImageButton for 'go to the last record'
196 VclPtr
<ImageButton
> m_aNewBtn
; // ImageButton for 'go to a new record'
197 sal_Int32 m_nCurrentPos
;
199 bool m_bPositioning
; // protect PositionDataSource against recursion
202 NavigationBar(vcl::Window
* pParent
);
203 virtual ~NavigationBar() override
;
204 virtual void dispose() override
;
206 // Status methods for Controls
207 void InvalidateAll(sal_Int32 nCurrentPos
, bool bAll
= false);
208 void InvalidateState(DbGridControlNavigationBarState nWhich
) {SetState(nWhich
);}
209 void SetState(DbGridControlNavigationBarState nWhich
);
210 bool GetState(DbGridControlNavigationBarState nWhich
) const;
211 sal_uInt16
ArrangeControls();
214 virtual void Resize() override
;
215 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
) override
;
216 virtual void StateChanged( StateChangedType nType
) override
;
218 DECL_LINK(OnClick
, Button
*, void);
220 void PositionDataSource(sal_Int32 nRecord
);
223 friend class DbGridControl::NavigationBar
;
226 Link
<DbGridControlNavigationBarState
,int> m_aMasterStateProvider
;
227 Link
<DbGridControlNavigationBarState
,bool> m_aMasterSlotExecutor
;
229 css::uno::Reference
< css::util::XNumberFormatter
> m_xFormatter
;
230 css::uno::Reference
< css::uno::XComponentContext
> m_xContext
;
232 std::vector
< std::unique_ptr
<DbGridColumn
> > m_aColumns
; // Column description
233 VclPtr
<NavigationBar
> m_aBar
;
234 DbGridRowRef m_xDataRow
; // Row which can be modified
235 // comes from the data cursor
236 DbGridRowRef m_xSeekRow
, // Row to which the iterator can set
237 // comes from the data cursor
239 m_xEmptyRow
; // record set to insert
241 ImplSVEvent
* m_nAsynAdjustEvent
;
243 // if we modify the row for the new record, we automatically insert a "new new row".
244 // But if somebody else inserts a new record into the data source, we have to do the same.
245 // For that reason we have to listen to some properties of our data source.
246 rtl::Reference
<::comphelper::OPropertyChangeMultiplexer
> m_pDataSourcePropMultiplexer
;
247 FmXGridSourcePropListener
* m_pDataSourcePropListener
;
248 css::uno::Reference
< css::sdb::XRowsChangeListener
>
249 m_xRowSetListener
; // get notification when rows were changed
251 void* m_pFieldListeners
;
252 // property listeners for field values
254 std::unique_ptr
<DisposeListenerGridBridge
> m_pCursorDisposeListener
;
255 // need to know about the disposing of the seek cursor
256 // construct analogous to the data source proplistener/multiplexer above :
257 // DisposeListenerGridBridge is a bridge from FmXDisposeListener which I don't want to be derived from
259 FmGridListener
* m_pGridListener
;
262 std::unique_ptr
<CursorWrapper
> m_pDataCursor
; // Cursor for Updates
263 std::unique_ptr
<CursorWrapper
> m_pSeekCursor
; // Cursor for Seeking
266 // iteration variables
267 DbGridRowRef m_xCurrentRow
;
268 DbGridRowRef m_xPaintRow
; // Row to be displayed
269 sal_Int32 m_nSeekPos
; // Position of the SeekCursor
270 sal_Int32 m_nTotalCount
; // is set when the data cursor finished counting the
271 // records. Initial value is -1
272 osl::Mutex m_aDestructionSafety
;
273 osl::Mutex m_aAdjustSafety
;
276 m_aNullDate
; // NullDate of the Numberformatter;
279 sal_Int32 m_nCurrentPos
; // Current position;
280 ImplSVEvent
* m_nDeleteEvent
; // EventId for asynchronous deletion of rows
281 DbGridControlOptions m_nOptions
; // What is the able to do (Insert, Update, Delete)
283 DbGridControlOptions m_nOptionMask
; // the mask of options to be enabled in setDataSource
284 // (with respect to the data source capabilities)
285 // defaults to (insert | update | delete)
286 sal_uInt16 m_nLastColId
;
289 bool m_bDesignMode
: 1; // default = sal_False
290 bool m_bRecordCountFinal
: 1;
291 bool m_bNavigationBar
: 1;
293 bool m_bSynchDisplay
: 1;
295 bool m_bFilterMode
: 1;
296 bool m_bWantDestruction
: 1;
297 bool m_bPendingAdjustRows
: 1; // if an async adjust is pending, is it for AdjustRows or AdjustDataSource ?
298 bool m_bHideScrollbars
: 1;
301 bool m_bUpdating
: 1; // are any updates being executed right now?
304 virtual bool SeekRow(long nRow
) override
;
305 virtual void VisibleRowsChanged( long nNewTopRow
, sal_uInt16 nNumRows
) override
;
306 virtual void PaintCell(OutputDevice
& rDev
, const tools::Rectangle
& rRect
, sal_uInt16 nColId
) const override
;
307 virtual RowStatus
GetRowStatus(long nRow
) const override
;
308 virtual bool CursorMoving(long nNewRow
, sal_uInt16 nNewCol
) override
;
309 virtual void CursorMoved() override
;
310 virtual void ArrangeControls(sal_uInt16
& nX
, sal_uInt16 nY
) override
;
311 virtual sal_uInt32
GetTotalCellWidth(long nRow
, sal_uInt16 nColId
) override
;
312 virtual void Command(const CommandEvent
& rEvt
) override
;
313 virtual bool PreNotify(NotifyEvent
& rEvt
) override
;
314 virtual void KeyInput(const KeyEvent
& rEvt
) override
;
315 virtual void StateChanged( StateChangedType nType
) override
;
316 virtual void DataChanged( const DataChangedEvent
& rDCEvt
) override
;
317 virtual void Select() override
;
319 virtual ::svt::CellController
* GetController(long nRow
, sal_uInt16 nCol
) override
;
321 virtual void CellModified() override
;
322 virtual bool SaveModified() override
;
323 virtual bool IsModified() const override
;
325 virtual sal_uInt16
AppendColumn(const OUString
& rName
, sal_uInt16 nWidth
, sal_uInt16 nPos
= HEADERBAR_APPEND
, sal_uInt16 nId
= sal_uInt16(-1)) override
;
326 void RemoveColumn(sal_uInt16 nId
);
327 std::unique_ptr
<DbGridColumn
> CreateColumn(sal_uInt16 nId
) const;
328 virtual void ColumnMoved(sal_uInt16 nId
) override
;
329 virtual bool SaveRow() override
;
330 virtual bool IsTabAllowed(bool bForward
) const override
;
333 virtual void HideColumn(sal_uInt16 nId
);
335 virtual void ShowColumn(sal_uInt16 nId
);
337 /** This is called before executing a context menu for a row. rMenu contains the initial entries
338 handled by this base class' method (which always has to be called).
339 Derived classes may alter the menu in any way and handle any additional entries in
340 PostExecuteColumnContextMenu.
341 All disabled entries will be removed before executing the menu, so be careful with separators
342 near entries you probably wish to disable ...
344 virtual void PreExecuteRowContextMenu(sal_uInt16 nRow
, PopupMenu
& rMenu
);
345 /** After executing the context menu for a row this method is called.
347 virtual void PostExecuteRowContextMenu(sal_uInt16 nRow
, const PopupMenu
& rMenu
, sal_uInt16 nExecutionResult
);
349 /// @throws css::uno::RuntimeException
350 void DataSourcePropertyChanged(const css::beans::PropertyChangeEvent
& evt
);
352 void FieldValueChanged(sal_uInt16 _nId
);
353 void FieldListenerDisposing(sal_uInt16 _nId
);
355 void disposing(sal_uInt16 _nId
);
358 /// called when the current row changed
359 virtual void onRowChange();
360 /// called when the current column changed
361 virtual void onColumnChange();
363 // DragSourceHelper overridables
364 virtual void StartDrag( sal_Int8 nAction
, const Point
& rPosPixel
) override
;
366 void executeRowContextMenu( long _nRow
, const Point
& _rPreferredPos
);
370 css::uno::Reference
< css::uno::XComponentContext
> const & _rxContext
,
371 vcl::Window
* pParent
,
374 virtual ~DbGridControl() override
;
375 virtual void dispose() override
;
377 virtual void Init() override
;
378 virtual void InitColumnsByFields(const css::uno::Reference
< css::container::XIndexAccess
>& xFields
) = 0;
379 virtual void RemoveRows() override
;
381 /** GetCellText returns the text at the given position
383 the number of the row
387 the text out of the cell
389 virtual OUString
GetCellText(long _nRow
, sal_uInt16 _nColId
) const override
;
391 void RemoveRows(bool bNewCursor
);
393 const css::uno::Reference
< css::util::XNumberFormatter
>& getNumberFormatter() const {return m_xFormatter
;}
396 // the options can restrict but not extend the update abilities
397 void setDataSource(const css::uno::Reference
< css::sdbc::XRowSet
>& rCursor
,
398 DbGridControlOptions nOpts
= DbGridControlOptions::Insert
| DbGridControlOptions::Update
| DbGridControlOptions::Delete
);
399 virtual void Dispatch(sal_uInt16 nId
) override
;
401 CursorWrapper
* getDataSource() const {return m_pDataCursor
.get();}
402 const std::vector
< std::unique_ptr
<DbGridColumn
> >& GetColumns() const {return m_aColumns
;}
404 void EnableHandle(bool bEnable
);
405 bool HasHandle() const {return m_bHandle
;}
406 void InsertHandleColumn();
408 // which position does the column with the id in the View have, the handle column doesn't count
409 sal_uInt16
GetViewColumnPos( sal_uInt16 nId
) const { sal_uInt16 nPos
= GetColumnPos(nId
); return (nPos
==BROWSER_INVALIDID
) ? GRID_COLUMN_NOT_FOUND
: nPos
-1; }
411 // which position does the column with the id in m_aColumns have, that means the css::sdbcx::Container
412 // returned from the GetColumns (may be different from the position returned by GetViewColumnPos
413 // if there are hidden columns)
414 sal_uInt16
GetModelColumnPos( sal_uInt16 nId
) const;
416 // the number of columns in the model
417 sal_uInt16
GetViewColCount() const { return ColCount() - 1; }
418 sal_uInt16
GetModelColCount() const { return static_cast<sal_uInt16
>(m_aColumns
.size()); }
419 // reverse to GetViewColumnPos: Id of position, the first non-handle column has position 0
420 sal_uInt16
GetColumnIdFromViewPos( sal_uInt16 nPos
) const { return GetColumnId(nPos
+ 1); }
421 sal_uInt16
GetColumnIdFromModelPos( sal_uInt16 nPos
) const;
423 virtual void SetDesignMode(bool bMode
);
424 bool IsDesignMode() const {return m_bDesignMode
;}
425 bool IsOpen() const {return m_pSeekCursor
!= nullptr;}
427 void SetFilterMode(bool bMode
);
428 bool IsFilterMode() const {return m_bFilterMode
;}
429 bool IsFilterRow(long nRow
) const {return m_bFilterMode
&& nRow
== 0;}
431 void EnableNavigationBar(bool bEnable
);
432 bool HasNavigationBar() const {return m_bNavigationBar
;}
434 DbGridControlOptions
GetOptions() const {return m_nOptions
;}
435 NavigationBar
& GetNavigationBar() {return *m_aBar
.get();}
436 DbGridControlOptions
SetOptions(DbGridControlOptions nOpt
);
437 // The new options are interpreted with respect to the current data source. If it is unable
438 // to update, to insert or to restore, the according options are ignored. If the grid isn't
439 // connected to a data source, all options except OPT_READONLY are ignored.
441 const css::util::Date
& getNullDate() const {return m_aNullDate
;}
444 void MoveToPosition(sal_uInt32 nPos
);
451 // adjustment of the cursors in case the data cursor has been
452 // moved from the outside.
453 // the flag indicates if an adjustment of the row count should be
455 void AdjustDataSource(bool bFull
= false);
458 virtual void BeginCursorAction();
459 virtual void EndCursorAction();
461 // is the current line being updated
462 bool IsUpdating() const {return m_bUpdating
;}
464 void RowRemoved( long nRow
, long nNumRows
= 1, bool bDoPaint
= true );
465 void RowInserted( long nRow
, long nNumRows
= 1, bool bDoPaint
= true );
466 void RowModified( long nRow
);
468 void resetCurrentRow();
470 bool getDisplaySynchron() const { return m_bSynchDisplay
; }
471 void setDisplaySynchron(bool bSync
);
472 // when set to sal_False, the display is no longer in sync with the current cursor position
473 // (means that in AdjustDataSource we are jumping to a row not belonging to CursorPosition)
474 // when using this, you should know what you are doing, because for example entering data
475 // in a row in the display that is not in sync with the position of the cursor can be very critical
477 const DbGridRowRef
& GetCurrentRow() const {return m_xCurrentRow
;}
479 void SetStateProvider(const Link
<DbGridControlNavigationBarState
,int>& rProvider
) { m_aMasterStateProvider
= rProvider
; }
480 // if this link is set the given provider will be asked for the state of my items.
481 // the return values are interpreted as follows :
482 // <0 -> not specified (use default mechanism to determine the state)
483 // ==0 -> the item is disabled
484 // >0 -> the item is enabled
485 void SetSlotExecutor(const Link
<DbGridControlNavigationBarState
,bool>& rExecutor
) { m_aMasterSlotExecutor
= rExecutor
; }
486 // analogous : if this link is set, all nav-bar slots will be routed through it when executed
487 // if the handler returns nonzero, no further handling of the slot occurs
489 void EnablePermanentCursor(bool bEnable
);
490 bool IsPermanentCursorEnabled() const;
492 /** forces both scrollbars to be hidden
494 For the horizontal scrollbar, this is overruled by enabling the navigation bar: A navigation
495 bar <b>always</b> implies a horizontal scroll bar
496 @seealso EnableNavigationBar
498 void ForceHideScrollbars();
500 const css::uno::Reference
< css::uno::XComponentContext
>&
501 getContext() const { return m_xContext
; }
503 /// returns <TRUE/> if the text of the given cell can be copied into the clipboard
504 bool canCopyCellText(sal_Int32 _nRow
, sal_uInt16 _nColId
);
505 /// copies the text of the given cell into the clipboard
506 void copyCellText(sal_Int32 _nRow
, sal_uInt16 _nColId
);
508 // select in listener handling
509 void setGridListener( FmGridListener
* _pListener
) { m_pGridListener
= _pListener
; }
511 // helper class to grant access to selected methods from within the DbCellControl class
512 struct GrantControlAccess final
514 friend class DbCellControl
;
515 friend class RowSetEventListener
;
516 GrantControlAccess() { }
519 /// called when a controller needs to be re-initialized
520 void refreshController(sal_uInt16 _nColId
, GrantControlAccess _aAccess
);
522 CursorWrapper
* GetSeekCursor(GrantControlAccess
/*_aAccess*/) const { return m_pSeekCursor
.get(); }
523 const DbGridRowRef
& GetSeekRow(GrantControlAccess
/*_aAccess*/) const { return m_xSeekRow
; }
524 void SetSeekPos(sal_Int32 nPos
,GrantControlAccess
/*_aAccess*/) {m_nSeekPos
= nPos
;}
528 The count of additional controls of the control area.
530 virtual sal_Int32
GetAccessibleControlCount() const override
;
532 /** Creates the accessible object of an additional control.
534 The 0-based index of the control.
536 The XAccessible interface of the specified control.
538 virtual css::uno::Reference
<
539 css::accessibility::XAccessible
>
540 CreateAccessibleControl( sal_Int32 _nIndex
) override
;
542 // IAccessibleTableProvider
543 /** Creates the accessible object of a data table cell.
544 @param nRow The row index of the cell.
545 @param nColumnId The column ID of the cell.
546 @return The XAccessible interface of the specified cell. */
547 virtual css::uno::Reference
<
548 css::accessibility::XAccessible
>
549 CreateAccessibleCell( sal_Int32 nRow
, sal_uInt16 nColumnId
) override
;
552 void RecalcRows(long nNewTopRow
, sal_uInt16 nLinesOnScreen
, bool bUpdateCursor
);
553 bool SeekCursor(long nRow
, bool bAbsolute
= false);
554 void RemoveColumns(); // cleaning of own structures
556 sal_Int32
AlignSeekCursor();
557 bool SetCurrent(long nNewRow
);
559 OUString
GetCurrentRowCellText(DbGridColumn
const * pCol
,const DbGridRowRef
& _rRow
) const;
560 virtual void DeleteSelectedRows();
561 static bool IsValid(const DbGridRowRef
& _xRow
) { return _xRow
.is() && _xRow
->IsValid(); }
563 // row which is currently being appended
564 bool IsCurrentAppending() const;
566 // empty row for insertion
567 bool IsInsertionRow(long nRow
) const;
569 void SetSeekPos(sal_Int32 nPos
) {m_nSeekPos
= nPos
;}
570 sal_Int32
GetCurrentPos() const {return m_nCurrentPos
;}
571 sal_Int32
GetSeekPos() const {return m_nSeekPos
;}
572 sal_Int32
GetTotalCount() const {return m_nTotalCount
;}
574 const DbGridRowRef
& GetEmptyRow() const { return m_xEmptyRow
; }
575 const DbGridRowRef
& GetSeekRow() const { return m_xSeekRow
; }
576 const DbGridRowRef
& GetPaintRow() const { return m_xPaintRow
; }
578 void ConnectToFields();
579 void DisconnectFromFields();
581 void implAdjustInSolarThread(bool _bRows
);
582 // calls AdjustRows or AdjustDataSource, synchron if the caller is running in the solar thread, else asynchron
585 void ImplInitWindow( const InitWindowFacet _eInitWhat
);
586 DECL_LINK(OnDelete
, void*, void);
588 DECL_LINK(OnAsyncAdjust
, void*, void);
589 // if the param is != NULL, AdjustRows will be called, else AdjustDataSource
592 using BrowseBox::InsertHandleColumn
;
595 #endif // INCLUDED_SVX_GRIDCTRL_HXX
597 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */