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>
24 #include <tools/ref.hxx>
25 #include <svtools/editbrowsebox.hxx>
26 #include <svtools/recorditemwindow.hxx>
27 #include <osl/mutex.hxx>
28 #include <svx/svxdllapi.h>
29 #include <o3tl/typed_flags_set.hxx>
34 namespace comphelper
{ class OPropertyChangeMultiplexer
; }
35 namespace com::sun::star::beans
{ struct PropertyChangeEvent
; }
36 namespace com::sun::star::container
{ class XIndexAccess
; }
37 namespace com::sun::star::sdbc
{ class XRowSet
; }
38 namespace com::sun::star::sdb
{ class XRowsChangeListener
; }
39 namespace com::sun::star::uno
{ class XComponentContext
; }
40 namespace com::sun::star::util
{ class XNumberFormatter
; }
41 namespace weld
{ class Menu
; }
44 class GridFieldValueListener
;
46 bool CompareBookmark(const css::uno::Any
& aLeft
, const css::uno::Any
& aRight
);
53 enum class GridRowStatus
62 // DbGridRow, description of rows
65 class SAL_DLLPUBLIC_RTTI DbGridRow final
: public SvRefBase
67 css::uno::Any m_aBookmark
; // Bookmark of the row, can be set
68 ::std::vector
< std::unique_ptr
<::svxform::DataColumn
> >
70 GridRowStatus m_eStatus
;
72 // row is no longer valid
73 // is removed on the next positioning
76 DbGridRow(CursorWrapper
* pCur
, bool bPaintCursor
);
77 void SetState(CursorWrapper
* pCur
, bool bPaintCursor
);
79 virtual ~DbGridRow() override
;
81 bool HasField(sal_uInt32 nPos
) const { return nPos
< m_aVariants
.size(); }
82 const ::svxform::DataColumn
& GetField(sal_uInt32 nPos
) const { return *m_aVariants
[ nPos
]; }
84 void SetStatus(GridRowStatus _eStat
) { m_eStatus
= _eStat
; }
85 GridRowStatus
GetStatus() const { return m_eStatus
; }
86 void SetNew(bool _bNew
) { m_bIsNew
= _bNew
; }
87 bool IsNew() const { return m_bIsNew
; }
89 const css::uno::Any
& GetBookmark() const { return m_aBookmark
; }
91 bool IsValid() const { return m_eStatus
== GridRowStatus::Clean
|| m_eStatus
== GridRowStatus::Modified
; }
92 bool IsModified() const { return m_eStatus
== GridRowStatus::Modified
; }
95 typedef tools::SvRef
<DbGridRow
> DbGridRowRef
;
105 virtual void selectionChanged() = 0;
106 virtual void columnChanged() = 0;
112 #define GRID_COLUMN_NOT_FOUND SAL_MAX_UINT16
115 // InitWindowFacet, describing which aspect of a column's Window to (re-)initialize
117 enum class InitWindowFacet
127 template<> struct typed_flags
<InitWindowFacet
> : is_typed_flags
<InitWindowFacet
, 0x0f> {};
131 // these options are or'ed and indicate, which of the single
132 // features can be released, default is readonly which means 0
133 enum class DbGridControlOptions
142 template<> struct typed_flags
<DbGridControlOptions
> : is_typed_flags
<DbGridControlOptions
, 0x07> {};
145 // StatusIds for Controls of the Bar
146 // important for invalidation
147 enum class DbGridControlNavigationBarState
159 Undo
// related to SID_FM_RECORD_UNDO
162 class FmXGridSourcePropListener
;
163 class DisposeListenerGridBridge
;
166 class NavigationBar final
: public InterimItemWindow
168 class AbsolutePos final
: public RecordItemWindowBase
171 AbsolutePos(std::unique_ptr
<weld::Entry
> xEntry
, NavigationBar
* pBar
);
173 virtual bool DoKeyInput(const KeyEvent
& rEvt
) override
;
174 virtual void PositionFired(sal_Int64 nRecord
) override
;
176 weld::Entry
* GetWidget() { return m_xWidget
.get(); }
178 VclPtr
<NavigationBar
> m_xParent
;
181 friend class NavigationBar::AbsolutePos
;
183 // additional controls
184 std::unique_ptr
<weld::Label
> m_xRecordText
;
185 std::unique_ptr
<AbsolutePos
> m_xAbsolute
; // absolute positioning
186 std::unique_ptr
<weld::Label
> m_xRecordOf
;
187 std::unique_ptr
<weld::Label
> m_xRecordCount
;
189 std::unique_ptr
<weld::Button
> m_xFirstBtn
; // Button for 'go to the first record'
190 std::unique_ptr
<weld::Button
> m_xPrevBtn
; // Button for 'go to the previous record'
191 std::unique_ptr
<weld::Button
> m_xNextBtn
; // Button for 'go to the next record'
192 std::unique_ptr
<weld::Button
> m_xLastBtn
; // Button for 'go to the last record'
193 std::unique_ptr
<weld::Button
> m_xNewBtn
; // Button for 'go to a new record'
195 std::shared_ptr
<weld::ButtonPressRepeater
> m_xPrevRepeater
;
196 std::shared_ptr
<weld::ButtonPressRepeater
> m_xNextRepeater
;
198 sal_Int32 m_nCurrentPos
;
200 bool m_bPositioning
; // protect PositionDataSource against recursion
203 NavigationBar(vcl::Window
* pParent
);
204 virtual ~NavigationBar() override
;
205 virtual void dispose() override
;
207 // Status methods for Controls
208 void InvalidateAll(sal_Int32 nCurrentPos
, bool bAll
= false);
209 void InvalidateState(DbGridControlNavigationBarState nWhich
) {SetState(nWhich
);}
210 void SetState(DbGridControlNavigationBarState nWhich
);
211 bool GetState(DbGridControlNavigationBarState nWhich
) const;
212 sal_uInt16
ArrangeControls();
216 DECL_LINK(OnClick
, weld::Button
&, void);
218 void PositionDataSource(sal_Int32 nRecord
);
221 class SVXCORE_DLLPUBLIC DbGridControl
: public svt::EditBrowseBox
223 friend class FmXGridSourcePropListener
;
224 friend class GridFieldValueListener
;
225 friend class DisposeListenerGridBridge
;
229 friend class NavigationBar
;
232 Link
<DbGridControlNavigationBarState
,int> m_aMasterStateProvider
;
233 Link
<DbGridControlNavigationBarState
,bool> m_aMasterSlotExecutor
;
235 css::uno::Reference
< css::util::XNumberFormatter
> m_xFormatter
;
236 css::uno::Reference
< css::uno::XComponentContext
> m_xContext
;
238 std::vector
< std::unique_ptr
<DbGridColumn
> > m_aColumns
; // Column description
239 VclPtr
<NavigationBar
> m_aBar
;
240 DbGridRowRef m_xDataRow
; // Row which can be modified
241 // comes from the data cursor
242 DbGridRowRef m_xSeekRow
, // Row to which the iterator can set
243 // comes from the data cursor
245 m_xEmptyRow
; // record set to insert
247 ImplSVEvent
* m_nAsynAdjustEvent
;
249 // if we modify the row for the new record, we automatically insert a "new new row".
250 // But if somebody else inserts a new record into the data source, we have to do the same.
251 // For that reason we have to listen to some properties of our data source.
252 rtl::Reference
<::comphelper::OPropertyChangeMultiplexer
> m_pDataSourcePropMultiplexer
;
253 FmXGridSourcePropListener
* m_pDataSourcePropListener
;
254 css::uno::Reference
< css::sdb::XRowsChangeListener
>
255 m_xRowSetListener
; // get notification when rows were changed
257 std::map
<sal_uInt16
, GridFieldValueListener
*> m_aFieldListeners
;
258 // property listeners for field values
260 std::unique_ptr
<DisposeListenerGridBridge
> m_pCursorDisposeListener
;
261 // need to know about the disposing of the seek cursor
262 // construct analogous to the data source proplistener/multiplexer above :
263 // DisposeListenerGridBridge is a bridge from FmXDisposeListener which I don't want to be derived from
265 FmGridListener
* m_pGridListener
;
268 std::unique_ptr
<CursorWrapper
> m_pDataCursor
; // Cursor for Updates
269 std::unique_ptr
<CursorWrapper
> m_pSeekCursor
; // Cursor for Seeking
272 // iteration variables
273 DbGridRowRef m_xCurrentRow
;
274 DbGridRowRef m_xPaintRow
; // Row to be displayed
275 sal_Int32 m_nSeekPos
; // Position of the SeekCursor
276 sal_Int32 m_nTotalCount
; // is set when the data cursor finished counting the
277 // records. Initial value is -1
278 osl::Mutex m_aDestructionSafety
;
279 osl::Mutex m_aAdjustSafety
;
282 m_aNullDate
; // NullDate of the Numberformatter;
285 sal_Int32 m_nCurrentPos
; // Current position;
286 ImplSVEvent
* m_nDeleteEvent
; // EventId for asynchronous deletion of rows
287 DbGridControlOptions m_nOptions
; // What is the able to do (Insert, Update, Delete)
289 DbGridControlOptions m_nOptionMask
; // the mask of options to be enabled in setDataSource
290 // (with respect to the data source capabilities)
291 // defaults to (insert | update | delete)
292 sal_uInt16 m_nLastColId
;
293 sal_Int32 m_nLastRowId
;
295 bool m_bDesignMode
: 1; // default = sal_False
296 bool m_bRecordCountFinal
: 1;
298 bool m_bSynchDisplay
: 1;
300 bool m_bFilterMode
: 1;
301 bool m_bWantDestruction
: 1;
302 bool m_bPendingAdjustRows
: 1; // if an async adjust is pending, is it for AdjustRows or AdjustDataSource ?
303 bool m_bHideScrollbars
: 1;
306 bool m_bUpdating
: 1; // are any updates being executed right now?
309 virtual bool SeekRow(sal_Int32 nRow
) override
;
310 virtual void VisibleRowsChanged( sal_Int32 nNewTopRow
, sal_uInt16 nNumRows
) override
;
311 virtual void PaintCell(OutputDevice
& rDev
, const tools::Rectangle
& rRect
, sal_uInt16 nColId
) const override
;
312 virtual RowStatus
GetRowStatus(sal_Int32 nRow
) const override
;
313 virtual bool CursorMoving(sal_Int32 nNewRow
, sal_uInt16 nNewCol
) override
;
314 virtual void CursorMoved() override
;
315 virtual void ArrangeControls(sal_uInt16
& nX
, sal_uInt16 nY
) override
;
316 virtual sal_uInt32
GetTotalCellWidth(sal_Int32 nRow
, sal_uInt16 nColId
) override
;
317 virtual void Command(const CommandEvent
& rEvt
) override
;
318 virtual bool PreNotify(NotifyEvent
& rEvt
) override
;
319 virtual void KeyInput(const KeyEvent
& rEvt
) override
;
320 virtual void StateChanged( StateChangedType nType
) override
;
321 virtual void DataChanged( const DataChangedEvent
& rDCEvt
) override
;
322 virtual void Select() override
;
324 virtual ::svt::CellController
* GetController(sal_Int32 nRow
, sal_uInt16 nCol
) override
;
326 virtual void CellModified() override
;
327 virtual bool SaveModified() override
;
328 virtual bool IsModified() const override
;
330 virtual sal_uInt16
AppendColumn(const OUString
& rName
, sal_uInt16 nWidth
, sal_uInt16 nPos
= HEADERBAR_APPEND
, sal_uInt16 nId
= sal_uInt16(-1)) override
;
331 void RemoveColumn(sal_uInt16 nId
);
332 std::unique_ptr
<DbGridColumn
> CreateColumn(sal_uInt16 nId
);
333 virtual void ColumnMoved(sal_uInt16 nId
) override
;
334 virtual bool SaveRow() override
;
335 virtual bool IsTabAllowed(bool bForward
) const override
;
338 virtual void HideColumn(sal_uInt16 nId
);
340 virtual void ShowColumn(sal_uInt16 nId
);
342 /** This is called before executing a context menu for a row. rMenu contains the initial entries
343 handled by this base class' method (which always has to be called).
344 Derived classes may alter the menu in any way and handle any additional entries in
345 PostExecuteColumnContextMenu.
346 All disabled entries will be removed before executing the menu, so be careful with separators
347 near entries you probably wish to disable ...
349 virtual void PreExecuteRowContextMenu(weld::Menu
& rMenu
);
350 /** After executing the context menu for a row this method is called.
352 virtual void PostExecuteRowContextMenu(const OUString
& rExecutionResult
);
354 /// @throws css::uno::RuntimeException
355 void DataSourcePropertyChanged(const css::beans::PropertyChangeEvent
& evt
);
357 void FieldValueChanged(sal_uInt16 _nId
);
358 void FieldListenerDisposing(sal_uInt16 _nId
);
360 void disposing(sal_uInt16 _nId
);
363 /// called when the current row changed
364 virtual void onRowChange();
365 /// called when the current column changed
366 virtual void onColumnChange();
368 // DragSourceHelper overridables
369 virtual void StartDrag( sal_Int8 nAction
, const Point
& rPosPixel
) override
;
371 void executeRowContextMenu(const Point
& _rPreferredPos
);
375 css::uno::Reference
< css::uno::XComponentContext
> const & _rxContext
,
376 vcl::Window
* pParent
,
379 virtual ~DbGridControl() override
;
380 virtual void dispose() override
;
382 virtual void Init() override
;
383 virtual void InitColumnsByFields(const css::uno::Reference
< css::container::XIndexAccess
>& xFields
) = 0;
384 virtual void RemoveRows() override
;
386 /** GetCellText returns the text at the given position
388 the number of the row
392 the text out of the cell
394 virtual OUString
GetCellText(sal_Int32 _nRow
, sal_uInt16 _nColId
) const override
;
396 void RemoveRows(bool bNewCursor
);
398 const css::uno::Reference
< css::util::XNumberFormatter
>& getNumberFormatter() const {return m_xFormatter
;}
401 // the options can restrict but not extend the update abilities
402 void setDataSource(const css::uno::Reference
< css::sdbc::XRowSet
>& rCursor
,
403 DbGridControlOptions nOpts
= DbGridControlOptions::Insert
| DbGridControlOptions::Update
| DbGridControlOptions::Delete
);
404 virtual void Dispatch(sal_uInt16 nId
) override
;
406 CursorWrapper
* getDataSource() const {return m_pDataCursor
.get();}
407 const std::vector
< std::unique_ptr
<DbGridColumn
> >& GetColumns() const {return m_aColumns
;}
409 void EnableHandle(bool bEnable
);
410 bool HasHandle() const {return m_bHandle
;}
411 void InsertHandleColumn();
413 // which position does the column with the id in the View have, the handle column doesn't count
414 sal_uInt16
GetViewColumnPos( sal_uInt16 nId
) const { sal_uInt16 nPos
= GetColumnPos(nId
); return (nPos
==BROWSER_INVALIDID
) ? GRID_COLUMN_NOT_FOUND
: nPos
-1; }
416 // which position does the column with the id in m_aColumns have, that means the css::sdbcx::Container
417 // returned from the GetColumns (may be different from the position returned by GetViewColumnPos
418 // if there are hidden columns)
419 sal_uInt16
GetModelColumnPos( sal_uInt16 nId
) const;
421 // the number of columns in the model
422 sal_uInt16
GetViewColCount() const { return ColCount() - 1; }
423 sal_uInt16
GetModelColCount() const { return static_cast<sal_uInt16
>(m_aColumns
.size()); }
424 // reverse to GetViewColumnPos: Id of position, the first non-handle column has position 0
425 sal_uInt16
GetColumnIdFromViewPos( sal_uInt16 nPos
) const { return GetColumnId(nPos
+ 1); }
426 sal_uInt16
GetColumnIdFromModelPos( sal_uInt16 nPos
) const;
428 virtual void SetDesignMode(bool bMode
);
429 bool IsDesignMode() const {return m_bDesignMode
;}
430 bool IsOpen() const {return m_pSeekCursor
!= nullptr;}
432 void SetFilterMode(bool bMode
);
433 bool IsFilterMode() const {return m_bFilterMode
;}
434 bool IsFilterRow(sal_Int32 nRow
) const {return m_bFilterMode
&& nRow
== 0;}
436 void EnableNavigationBar(bool bEnable
);
437 bool HasNavigationBar() const {return m_bNavigationBar
;}
439 DbGridControlOptions
GetOptions() const {return m_nOptions
;}
440 NavigationBar
& GetNavigationBar() {return *m_aBar
;}
441 DbGridControlOptions
SetOptions(DbGridControlOptions nOpt
);
442 // The new options are interpreted with respect to the current data source. If it is unable
443 // to update, to insert or to restore, the according options are ignored. If the grid isn't
444 // connected to a data source, all options except OPT_READONLY are ignored.
446 const css::util::Date
& getNullDate() const {return m_aNullDate
;}
449 void MoveToPosition(sal_uInt32 nPos
);
456 // adjustment of the cursors in case the data cursor has been
457 // moved from the outside.
458 // the flag indicates if an adjustment of the row count should be
460 void AdjustDataSource(bool bFull
= false);
463 virtual void BeginCursorAction();
464 virtual void EndCursorAction();
466 // is the current line being updated
467 bool IsUpdating() const {return m_bUpdating
;}
469 void RowRemoved( sal_Int32 nRow
, sal_Int32 nNumRows
= 1, bool bDoPaint
= true );
470 void RowInserted( sal_Int32 nRow
, sal_Int32 nNumRows
= 1, bool bDoPaint
= true );
471 void RowModified( sal_Int32 nRow
);
473 void resetCurrentRow();
475 bool getDisplaySynchron() const { return m_bSynchDisplay
; }
476 void setDisplaySynchron(bool bSync
);
477 // when set to sal_False, the display is no longer in sync with the current cursor position
478 // (means that in AdjustDataSource we are jumping to a row not belonging to CursorPosition)
479 // when using this, you should know what you are doing, because for example entering data
480 // in a row in the display that is not in sync with the position of the cursor can be very critical
482 const DbGridRowRef
& GetCurrentRow() const {return m_xCurrentRow
;}
484 void SetStateProvider(const Link
<DbGridControlNavigationBarState
,int>& rProvider
) { m_aMasterStateProvider
= rProvider
; }
485 // if this link is set the given provider will be asked for the state of my items.
486 // the return values are interpreted as follows :
487 // <0 -> not specified (use default mechanism to determine the state)
488 // ==0 -> the item is disabled
489 // >0 -> the item is enabled
490 void SetSlotExecutor(const Link
<DbGridControlNavigationBarState
,bool>& rExecutor
) { m_aMasterSlotExecutor
= rExecutor
; }
491 // analogous : if this link is set, all nav-bar slots will be routed through it when executed
492 // if the handler returns nonzero, no further handling of the slot occurs
494 void EnablePermanentCursor(bool bEnable
);
495 bool IsPermanentCursorEnabled() const;
497 /** forces both scrollbars to be hidden
499 For the horizontal scrollbar, this is overruled by enabling the navigation bar: A navigation
500 bar <b>always</b> implies a horizontal scroll bar
501 @seealso EnableNavigationBar
503 void ForceHideScrollbars();
505 const css::uno::Reference
< css::uno::XComponentContext
>&
506 getContext() const { return m_xContext
; }
508 /// returns <TRUE/> if the text of the given cell can be copied into the clipboard
509 bool canCopyCellText(sal_Int32 _nRow
, sal_uInt16 _nColId
);
510 /// copies the text of the given cell into the clipboard
511 void copyCellText(sal_Int32 _nRow
, sal_uInt16 _nColId
);
513 // select in listener handling
514 void setGridListener( FmGridListener
* _pListener
) { m_pGridListener
= _pListener
; }
516 // helper class to grant access to selected methods from within the DbCellControl class
517 struct GrantControlAccess final
519 friend class DbCellControl
;
520 friend class RowSetEventListener
;
523 /// called when a controller needs to be re-initialized
524 void refreshController(sal_uInt16 _nColId
, GrantControlAccess _aAccess
);
526 CursorWrapper
* GetSeekCursor(GrantControlAccess
/*_aAccess*/) const { return m_pSeekCursor
.get(); }
527 const DbGridRowRef
& GetSeekRow(GrantControlAccess
/*_aAccess*/) const { return m_xSeekRow
; }
528 void SetSeekPos(sal_Int32 nPos
,GrantControlAccess
/*_aAccess*/) {m_nSeekPos
= nPos
;}
532 The count of additional controls of the control area.
534 virtual sal_Int32
GetAccessibleControlCount() const override
;
536 /** Creates the accessible object of an additional control.
538 The 0-based index of the control.
540 The XAccessible interface of the specified control.
542 virtual css::uno::Reference
<
543 css::accessibility::XAccessible
>
544 CreateAccessibleControl( sal_Int32 _nIndex
) override
;
546 // IAccessibleTableProvider
547 /** Creates the accessible object of a data table cell.
548 @param nRow The row index of the cell.
549 @param nColumnId The column ID of the cell.
550 @return The XAccessible interface of the specified cell. */
551 virtual css::uno::Reference
<
552 css::accessibility::XAccessible
>
553 CreateAccessibleCell( sal_Int32 nRow
, sal_uInt16 nColumnId
) override
;
556 void RecalcRows(sal_Int32 nNewTopRow
, sal_uInt16 nLinesOnScreen
, bool bUpdateCursor
);
557 bool SeekCursor(sal_Int32 nRow
, bool bAbsolute
= false);
558 void RemoveColumns(); // cleaning of own structures
560 sal_Int32
AlignSeekCursor();
561 bool SetCurrent(sal_Int32 nNewRow
);
563 OUString
GetCurrentRowCellText(DbGridColumn
const * pCol
,const DbGridRowRef
& _rRow
) const;
564 virtual void DeleteSelectedRows();
565 static bool IsValid(const DbGridRowRef
& _xRow
) { return _xRow
.is() && _xRow
->IsValid(); }
567 // row which is currently being appended
568 bool IsCurrentAppending() const;
570 // empty row for insertion
571 bool IsInsertionRow(sal_Int32 nRow
) const;
573 void SetSeekPos(sal_Int32 nPos
) {m_nSeekPos
= nPos
;}
574 sal_Int32
GetCurrentPos() const {return m_nCurrentPos
;}
575 sal_Int32
GetSeekPos() const {return m_nSeekPos
;}
576 sal_Int32
GetTotalCount() const {return m_nTotalCount
;}
578 const DbGridRowRef
& GetEmptyRow() const { return m_xEmptyRow
; }
579 const DbGridRowRef
& GetSeekRow() const { return m_xSeekRow
; }
580 const DbGridRowRef
& GetPaintRow() const { return m_xPaintRow
; }
582 void ConnectToFields();
583 void DisconnectFromFields();
585 void implAdjustInSolarThread(bool _bRows
);
586 // calls AdjustRows or AdjustDataSource, synchron if the caller is running in the solar thread, else asynchron
589 void ImplInitWindow( const InitWindowFacet _eInitWhat
);
590 DECL_DLLPRIVATE_LINK(OnDelete
, void*, void);
592 DECL_DLLPRIVATE_LINK(OnAsyncAdjust
, void*, void);
593 // if the param is != NULL, AdjustRows will be called, else AdjustDataSource
596 using BrowseBox::InsertHandleColumn
;
599 #endif // INCLUDED_SVX_GRIDCTRL_HXX
601 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */