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/sdbc/XRowSet.hpp>
23 #include <com/sun/star/sdbc/XRowSetListener.hpp>
24 #include <com/sun/star/sdb/XRowsChangeListener.hpp>
25 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
26 #include <com/sun/star/util/XNumberFormatter.hpp>
27 #include <com/sun/star/util/Date.hpp>
28 #include <com/sun/star/container/XIndexAccess.hpp>
29 #include <vcl/fixed.hxx>
30 #include <vcl/field.hxx>
32 #include <vcl/button.hxx>
33 #include <tools/ref.hxx>
34 #include <svtools/editbrowsebox.hxx>
35 #include <osl/mutex.hxx>
36 #include <comphelper/propmultiplex.hxx>
37 #include <svtools/transfer.hxx>
38 #include <svx/svxdllapi.h>
39 #include <o3tl/typed_flags_set.hxx>
45 bool CompareBookmark(const css::uno::Any
& aLeft
, const css::uno::Any
& aRight
);
52 enum class GridRowStatus
61 // DbGridRow, description of rows
64 class DbGridRow
: public SvRefBase
66 css::uno::Any m_aBookmark
; // Bookmark of the row, can be set
67 ::std::vector
< ::svxform::DataColumn
* >
69 GridRowStatus m_eStatus
;
71 // row is no longer valid
72 // is removed on the next positioning
74 DbGridRow():m_eStatus(GridRowStatus::Clean
), m_bIsNew(true) { }
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
;
100 typedef ::std::vector
< DbGridColumn
* > DbGridColumns
;
106 virtual void selectionChanged() = 0;
107 virtual void columnChanged() = 0;
113 #define GRID_COLUMN_NOT_FOUND SAL_MAX_UINT16
116 // InitWindowFacet, describing which aspect of a column's Window to (re-)initialize
118 enum class InitWindowFacet
128 template<> struct typed_flags
<InitWindowFacet
> : is_typed_flags
<InitWindowFacet
, 0x0f> {};
132 // these options are or'ed and indicate, which of the single
133 // features can be released, default is readonly which means 0
134 enum class DbGridControlOptions
143 template<> struct typed_flags
<DbGridControlOptions
> : is_typed_flags
<DbGridControlOptions
, 0x07> {};
146 // StatusIds for Controls of the Bar
147 // important for invalidation
148 enum class DbGridControlNavigationBarState
160 Undo
// related to SID_FM_RECORD_UNDO
163 class FmXGridSourcePropListener
;
164 class DisposeListenerGridBridge
;
165 class SVX_DLLPUBLIC DbGridControl
: public svt::EditBrowseBox
167 friend class FmXGridSourcePropListener
;
168 friend class GridFieldValueListener
;
169 friend class DisposeListenerGridBridge
;
175 class NavigationBar
: public Control
177 class AbsolutePos
: public NumericField
180 AbsolutePos(vcl::Window
* pParent
, WinBits nStyle
);
182 virtual void KeyInput(const KeyEvent
& rEvt
) override
;
183 virtual void LoseFocus() override
;
186 friend class NavigationBar::AbsolutePos
;
188 // zusaetzliche Controls
189 VclPtr
<FixedText
> m_aRecordText
;
190 VclPtr
<AbsolutePos
> m_aAbsolute
; // absolute positioning
191 VclPtr
<FixedText
> m_aRecordOf
;
192 VclPtr
<FixedText
> m_aRecordCount
;
194 VclPtr
<ImageButton
> m_aFirstBtn
; // ImageButton for 'go to the first record'
195 VclPtr
<ImageButton
> m_aPrevBtn
; // ImageButton for 'go to the previous record'
196 VclPtr
<ImageButton
> m_aNextBtn
; // ImageButton for 'go to the next record'
197 VclPtr
<ImageButton
> m_aLastBtn
; // ImageButton for 'go to the last record'
198 VclPtr
<ImageButton
> m_aNewBtn
; // ImageButton for 'go to a new record'
199 sal_Int32 m_nCurrentPos
;
201 bool m_bPositioning
; // protect PositionDataSource against recursion
204 NavigationBar(vcl::Window
* pParent
);
205 virtual ~NavigationBar() override
;
206 virtual void dispose() override
;
208 // Status methods for Controls
209 void InvalidateAll(sal_Int32 nCurrentPos
, bool bAll
= false);
210 void InvalidateState(DbGridControlNavigationBarState nWhich
) {SetState(nWhich
);}
211 void SetState(DbGridControlNavigationBarState nWhich
);
212 bool GetState(DbGridControlNavigationBarState nWhich
) const;
213 sal_uInt16
ArrangeControls();
216 virtual void Resize() override
;
217 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
) override
;
218 virtual void StateChanged( StateChangedType nType
) override
;
221 DECL_LINK(OnClick
, Button
*, void);
223 void PositionDataSource(sal_Int32 nRecord
);
226 friend class DbGridControl::NavigationBar
;
229 Link
<DbGridControlNavigationBarState
,int> m_aMasterStateProvider
;
230 Link
<DbGridControlNavigationBarState
,bool> m_aMasterSlotExecutor
;
232 css::uno::Reference
< css::util::XNumberFormatter
> m_xFormatter
;
233 css::uno::Reference
< css::uno::XComponentContext
> m_xContext
;
235 DbGridColumns m_aColumns
; // Column description
236 VclPtr
<NavigationBar
> m_aBar
;
237 DbGridRowRef m_xDataRow
; // Row which can be modified
238 // comes from the data cursor
239 DbGridRowRef m_xSeekRow
, // Row to which the iterator can set
240 // comes from the data cursor
242 m_xEmptyRow
; // record set to insert
244 ImplSVEvent
* m_nAsynAdjustEvent
;
246 // if we modify the row for the new record, we automatically insert a "new new row".
247 // But if somebody else inserts a new record into the data source, we have to do the same.
248 // For that reason we have to listen to some properties of our data source.
249 rtl::Reference
<::comphelper::OPropertyChangeMultiplexer
> m_pDataSourcePropMultiplexer
;
250 FmXGridSourcePropListener
* m_pDataSourcePropListener
;
251 css::uno::Reference
< css::sdb::XRowsChangeListener
>
252 m_xRowSetListener
; // get notification when rows were changed
254 void* m_pFieldListeners
;
255 // property listeners for field values
257 DisposeListenerGridBridge
* m_pCursorDisposeListener
;
258 // need to know about the diposing of the seek cursor
259 // construct analogous to the data source proplistener/multiplexer above :
260 // DisposeListenerGridBridge is a bridge from FmXDisposeListener which I don't want to be derived from
262 FmGridListener
* m_pGridListener
;
265 CursorWrapper
* m_pDataCursor
; // Cursor for Updates
266 CursorWrapper
* m_pSeekCursor
; // Cursor for Seeking
269 // iteration variables
270 DbGridRowRef m_xCurrentRow
;
271 DbGridRowRef m_xPaintRow
; // Row to be displayed
272 sal_Int32 m_nSeekPos
; // Position of the SeekCursor
273 sal_Int32 m_nTotalCount
; // is set when the data cursor finished counting the
274 // records. Initial value is -1
275 osl::Mutex m_aDestructionSafety
;
276 osl::Mutex m_aAdjustSafety
;
279 m_aNullDate
; // NullDate of the Numberformatter;
282 sal_Int32 m_nCurrentPos
; // Current position;
283 ImplSVEvent
* m_nDeleteEvent
; // EventId for asychronous deletion of rows
284 DbGridControlOptions m_nOptions
; // What is the able to do (Insert, Update, Delete)
286 DbGridControlOptions m_nOptionMask
; // the mask of options to be enabled in setDataSource
287 // (with respect to the data source capabilities)
288 // defaults to (insert | update | delete)
289 sal_uInt16 m_nLastColId
;
292 bool m_bDesignMode
: 1; // default = sal_False
293 bool m_bRecordCountFinal
: 1;
294 bool m_bNavigationBar
: 1;
296 bool m_bSynchDisplay
: 1;
298 bool m_bFilterMode
: 1;
299 bool m_bWantDestruction
: 1;
300 bool m_bInAdjustDataSource
: 1;
301 bool m_bPendingAdjustRows
: 1; // if an async adjust is pending, is it for AdjustRows or AdjustDataSource ?
302 bool m_bHideScrollbars
: 1;
305 bool m_bUpdating
: 1; // are any updates being executed right now?
308 virtual bool SeekRow(long nRow
) override
;
309 virtual void VisibleRowsChanged( long nNewTopRow
, sal_uInt16 nNumRows
) override
;
310 virtual void PaintCell(OutputDevice
& rDev
, const tools::Rectangle
& rRect
, sal_uInt16 nColId
) const override
;
311 virtual RowStatus
GetRowStatus(long nRow
) const override
;
312 virtual bool CursorMoving(long nNewRow
, sal_uInt16 nNewCol
) override
;
313 virtual void CursorMoved() override
;
314 virtual void ArrangeControls(sal_uInt16
& nX
, sal_uInt16 nY
) override
;
315 virtual sal_uInt32
GetTotalCellWidth(long nRow
, sal_uInt16 nColId
) override
;
316 virtual void Command(const CommandEvent
& rEvt
) override
;
317 virtual bool PreNotify(NotifyEvent
& rEvt
) override
;
318 virtual void KeyInput(const KeyEvent
& rEvt
) override
;
319 virtual void StateChanged( StateChangedType nType
) override
;
320 virtual void DataChanged( const DataChangedEvent
& rDCEvt
) override
;
321 virtual void Select() override
;
323 virtual ::svt::CellController
* GetController(long nRow
, sal_uInt16 nCol
) override
;
325 virtual void CellModified() override
;
326 virtual bool SaveModified() override
;
327 virtual bool IsModified() const override
;
329 virtual sal_uInt16
AppendColumn(const OUString
& rName
, sal_uInt16 nWidth
, sal_uInt16 nPos
= HEADERBAR_APPEND
, sal_uInt16 nId
= (sal_uInt16
)-1) override
;
330 void RemoveColumn(sal_uInt16 nId
);
331 DbGridColumn
* CreateColumn(sal_uInt16 nId
) const;
332 virtual void ColumnMoved(sal_uInt16 nId
) override
;
333 virtual bool SaveRow() override
;
334 virtual bool IsTabAllowed(bool bForward
) const override
;
337 virtual void HideColumn(sal_uInt16 nId
);
339 virtual void ShowColumn(sal_uInt16 nId
);
341 /** This is called before executing a context menu for a row. rMenu contains the initial entries
342 handled by this base class' method (which always has to be called).
343 Derived classes may alter the menu in any way and handle any additional entries in
344 PostExecuteColumnContextMenu.
345 All disabled entries will be removed before executing the menu, so be careful with separators
346 near entries you probably wish to disable ...
348 virtual void PreExecuteRowContextMenu(sal_uInt16 nRow
, PopupMenu
& rMenu
);
349 /** After executing the context menu for a row this method is called.
351 virtual void PostExecuteRowContextMenu(sal_uInt16 nRow
, const PopupMenu
& rMenu
, sal_uInt16 nExecutionResult
);
353 /// @throws css::uno::RuntimeException
354 void DataSourcePropertyChanged(const css::beans::PropertyChangeEvent
& evt
);
356 void FieldValueChanged(sal_uInt16 _nId
);
357 void FieldListenerDisposing(sal_uInt16 _nId
);
359 void disposing(sal_uInt16 _nId
);
362 /// called when the current row changed
363 virtual void onRowChange();
364 /// called when the current column changed
365 virtual void onColumnChange();
367 // DragSourceHelper overridables
368 virtual void StartDrag( sal_Int8 nAction
, const Point
& rPosPixel
) override
;
370 void executeRowContextMenu( long _nRow
, const Point
& _rPreferredPos
);
374 css::uno::Reference
< css::uno::XComponentContext
> const & _rxContext
,
375 vcl::Window
* pParent
,
378 virtual ~DbGridControl() override
;
379 virtual void dispose() override
;
381 virtual void Init() override
;
382 virtual void InitColumnsByFields(const css::uno::Reference
< css::container::XIndexAccess
>& xFields
) = 0;
383 virtual void RemoveRows() override
;
385 /** GetCellText returns the text at the given position
387 the number of the row
391 the text out of the cell
393 virtual OUString
GetCellText(long _nRow
, sal_uInt16 _nColId
) const override
;
395 void RemoveRows(bool bNewCursor
);
397 const css::uno::Reference
< css::util::XNumberFormatter
>& getNumberFormatter() const {return m_xFormatter
;}
400 // the options can restrict but not extend the update abilities
401 void setDataSource(const css::uno::Reference
< css::sdbc::XRowSet
>& rCursor
,
402 DbGridControlOptions nOpts
= DbGridControlOptions::Insert
| DbGridControlOptions::Update
| DbGridControlOptions::Delete
);
403 virtual void Dispatch(sal_uInt16 nId
) override
;
405 CursorWrapper
* getDataSource() const {return m_pDataCursor
;}
406 const DbGridColumns
& GetColumns() const {return m_aColumns
;}
408 void EnableHandle(bool bEnable
);
409 bool HasHandle() const {return m_bHandle
;}
410 void InsertHandleColumn();
412 // which position does the column with the id in the View have, the handle column doesn't count
413 sal_uInt16
GetViewColumnPos( sal_uInt16 nId
) const { sal_uInt16 nPos
= GetColumnPos(nId
); return (nPos
==BROWSER_INVALIDID
) ? GRID_COLUMN_NOT_FOUND
: nPos
-1; }
415 // which position does the column with the id in m_aColumns have, that means the css::sdbcx::Container
416 // returned from the GetColumns (may be different from the position returned by GetViewColumnPos
417 // if there are hidden columns)
418 sal_uInt16
GetModelColumnPos( sal_uInt16 nId
) const;
420 // the number of columns in the model
421 sal_uInt16
GetViewColCount() const { return ColCount() - 1; }
422 sal_uInt16
GetModelColCount() const { return (sal_uInt16
)m_aColumns
.size(); }
423 // reverse to GetViewColumnPos: Id of position, the first non-handle column has position 0
424 sal_uInt16
GetColumnIdFromViewPos( sal_uInt16 nPos
) const { return GetColumnId(nPos
+ 1); }
425 sal_uInt16
GetColumnIdFromModelPos( sal_uInt16 nPos
) const;
427 virtual void SetDesignMode(bool bMode
);
428 bool IsDesignMode() const {return m_bDesignMode
;}
429 bool IsOpen() const {return m_pSeekCursor
!= nullptr;}
431 void SetFilterMode(bool bMode
);
432 bool IsFilterMode() const {return m_bFilterMode
;}
433 bool IsFilterRow(long nRow
) const {return m_bFilterMode
&& nRow
== 0;}
435 void EnableNavigationBar(bool bEnable
);
436 bool HasNavigationBar() const {return m_bNavigationBar
;}
438 DbGridControlOptions
GetOptions() const {return m_nOptions
;}
439 NavigationBar
& GetNavigationBar() {return *m_aBar
.get();}
440 DbGridControlOptions
SetOptions(DbGridControlOptions nOpt
);
441 // The new options are interpreted with respect to the current data source. If it is unable
442 // to update, to insert or to restore, the according options are ignored. If the grid isn't
443 // connected to a data source, all options except OPT_READONLY are ignored.
445 const css::util::Date
& getNullDate() const {return m_aNullDate
;}
448 void MoveToPosition(sal_uInt32 nPos
);
455 // adjustment of the cursors in case the data cursor has been
456 // moved from the outside.
457 // the flag indicates if an adjustment of the row count should be
459 void AdjustDataSource(bool bFull
= false);
462 virtual void BeginCursorAction();
463 virtual void EndCursorAction();
465 // is the current line being updated
466 bool IsUpdating() const {return m_bUpdating
;}
468 void RowRemoved( long nRow
, long nNumRows
= 1, bool bDoPaint
= true );
469 void RowInserted( long nRow
, long nNumRows
= 1, bool bDoPaint
= true );
470 void RowModified( long nRow
);
472 void resetCurrentRow();
474 bool getDisplaySynchron() const { return m_bSynchDisplay
; }
475 void setDisplaySynchron(bool bSync
);
476 // when set to sal_False, the display is no longer in sync with the current cursor position
477 // (means that in AdjustDataSource we are jumping to a row not belonging to CursorPosition)
478 // when using this, you should know what you are doing, because for example entering data
479 // in a row in the display that is not in sync with the position of the cursor can be very critical
481 const DbGridRowRef
& GetCurrentRow() const {return m_xCurrentRow
;}
483 void SetStateProvider(const Link
<DbGridControlNavigationBarState
,int>& rProvider
) { m_aMasterStateProvider
= rProvider
; }
484 // if this link is set the given provider will be asked for the state of my items.
485 // the return values are interpreted as follows :
486 // <0 -> not specified (use default mechanism to determine the state)
487 // ==0 -> the item is disabled
488 // >0 -> the item is enabled
489 void SetSlotExecutor(const Link
<DbGridControlNavigationBarState
,bool>& rExecutor
) { m_aMasterSlotExecutor
= rExecutor
; }
490 // analogous : if this link is set, all nav-bar slots will be routed through it when executed
491 // if the handler returns nonzero, no further handling of the slot occurs
493 void EnablePermanentCursor(bool bEnable
);
494 bool IsPermanentCursorEnabled() const;
496 /** forces both scrollbars to be hidden
498 For the horizontal scrollbar, this is overruled by enabling the navigation bar: A navigation
499 bar <b>always</b> implies a horizontal scroll bar
500 @seealso EnableNavigationBar
502 void ForceHideScrollbars();
504 const css::uno::Reference
< css::uno::XComponentContext
>&
505 getContext() const { return m_xContext
; }
507 /// returns <TRUE/> if the text of the given cell can be copied into the clipboard
508 bool canCopyCellText(sal_Int32 _nRow
, sal_uInt16 _nColId
);
509 /// copies the text of the given cell into the clipboard
510 void copyCellText(sal_Int32 _nRow
, sal_uInt16 _nColId
);
512 // select in listener handling
513 void setGridListener( FmGridListener
* _pListener
) { m_pGridListener
= _pListener
; }
515 // helper class to grant access to selected methods from within the DbCellControl class
516 struct GrantControlAccess
518 friend class DbCellControl
;
519 friend class RowSetEventListener
;
521 GrantControlAccess() { }
524 /// called when a controller needs to be re-initialized
525 void refreshController(sal_uInt16 _nColId
, GrantControlAccess _aAccess
);
527 CursorWrapper
* GetSeekCursor(GrantControlAccess
/*_aAccess*/) const { return m_pSeekCursor
; }
528 const DbGridRowRef
& GetSeekRow(GrantControlAccess
/*_aAccess*/) const { return m_xSeekRow
; }
529 void SetSeekPos(sal_Int32 nPos
,GrantControlAccess
/*_aAccess*/) {m_nSeekPos
= nPos
;}
533 The count of additional controls of the control area.
535 virtual sal_Int32
GetAccessibleControlCount() const override
;
537 /** Creates the accessible object of an additional control.
539 The 0-based index of the control.
541 The XAccessible interface of the specified control.
543 virtual css::uno::Reference
<
544 css::accessibility::XAccessible
>
545 CreateAccessibleControl( sal_Int32 _nIndex
) override
;
547 // IAccessibleTableProvider
548 /** Creates the accessible object of a data table cell.
549 @param nRow The row index of the cell.
550 @param nColumnId The column ID of the cell.
551 @return The XAccessible interface of the specified cell. */
552 virtual css::uno::Reference
<
553 css::accessibility::XAccessible
>
554 CreateAccessibleCell( sal_Int32 nRow
, sal_uInt16 nColumnId
) override
;
557 void RecalcRows(long nNewTopRow
, sal_uInt16 nLinesOnScreen
, bool bUpdateCursor
);
558 bool SeekCursor(long nRow
, bool bAbsolute
= false);
559 void RemoveColumns(); // cleaning of own structures
561 sal_Int32
AlignSeekCursor();
562 bool SetCurrent(long nNewRow
);
564 OUString
GetCurrentRowCellText(DbGridColumn
* pCol
,const DbGridRowRef
& _rRow
) const;
565 virtual void DeleteSelectedRows();
566 static bool IsValid(const DbGridRowRef
& _xRow
) { return _xRow
.is() && _xRow
->IsValid(); }
568 // row which is currently being appended
569 bool IsCurrentAppending() const;
571 // empty row for insertion
572 bool IsInsertionRow(long nRow
) const;
574 void SetSeekPos(sal_Int32 nPos
) {m_nSeekPos
= nPos
;}
575 sal_Int32
GetCurrentPos() const {return m_nCurrentPos
;}
576 sal_Int32
GetSeekPos() const {return m_nSeekPos
;}
577 sal_Int32
GetTotalCount() const {return m_nTotalCount
;}
579 const DbGridRowRef
& GetEmptyRow() const { return m_xEmptyRow
; }
580 const DbGridRowRef
& GetSeekRow() const { return m_xSeekRow
; }
581 const DbGridRowRef
& GetPaintRow() const { return m_xPaintRow
; }
583 void ConnectToFields();
584 void DisconnectFromFields();
586 void implAdjustInSolarThread(bool _bRows
);
587 // calls AdjustRows or AdjustDataSource, synchron if the caller is running in the solar thread, else asynchron
590 void ImplInitWindow( const InitWindowFacet _eInitWhat
);
591 DECL_LINK(OnDelete
, void*, void);
593 DECL_LINK(OnAsyncAdjust
, void*, void);
594 // if the param is != NULL, AdjustRows will be called, else AdjustDataSource
597 using BrowseBox::InsertHandleColumn
;
600 #endif // INCLUDED_SVX_GRIDCTRL_HXX
602 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */