LibreOffice Module dbaccess (master) 1
indexfieldscontrol.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 <core_resource.hxx>
22#include <strings.hrc>
23#include <o3tl/safeint.hxx>
24#include <osl/diagnose.h>
25#include <helpids.h>
27#include <vcl/settings.hxx>
28#include <vcl/svapp.hxx>
29
30namespace dbaui
31{
32
33constexpr auto BROWSER_STANDARD_FLAGS = BrowserMode::COLUMNSELECTION | BrowserMode::HLINES | BrowserMode::VLINES |
34 BrowserMode::HIDECURSOR | BrowserMode::HIDESELECT | BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL;
35
36#define COLUMN_ID_FIELDNAME 1
37#define COLUMN_ID_ORDER 2
38
39 using namespace ::com::sun::star::uno;
40 using namespace ::svt;
41
42 // DbaMouseDownListBoxController
44 {
45 protected:
47
48 public:
50 :ListBoxCellController(_pParent)
51 {
52 }
53
55
56 protected:
57 virtual void callModifyHdl() override;
58 };
59
61 {
63 }
64
66 {
67 m_aAdditionalModifyHdl.Call(*this);
69 }
70
71 // IndexFieldsControl
72 IndexFieldsControl::IndexFieldsControl(const css::uno::Reference<css::awt::XWindow> &rParent)
74 , m_aSeekRow(m_aFields.end())
75 , m_pSortingCell(nullptr)
76 , m_pFieldNameCell(nullptr)
77 , m_bAddIndexAppendix(false)
78 {
79 }
80
82 {
83 disposeOnce();
84 }
85
87 {
88 m_pSortingCell.disposeAndClear();
89 m_pFieldNameCell.disposeAndClear();
91 }
92
93 bool IndexFieldsControl::SeekRow(sal_Int32 nRow)
94 {
95 if (!EditBrowseBox::SeekRow(nRow))
96 return false;
97
98 if (nRow < 0)
99 {
100 m_aSeekRow = m_aFields.end();
101 }
102 else
103 {
104 m_aSeekRow = m_aFields.begin() + nRow;
105 OSL_ENSURE(m_aSeekRow <= m_aFields.end(), "IndexFieldsControl::SeekRow: invalid row!");
106 }
107
108 return true;
109 }
110
111 void IndexFieldsControl::PaintCell( OutputDevice& _rDev, const tools::Rectangle& _rRect, sal_uInt16 _nColumnId ) const
112 {
113 Point aPos(_rRect.TopLeft());
114 aPos.AdjustX(1 );
115
116 OUString aText = GetRowCellText(m_aSeekRow,_nColumnId);
117 Size TxtSize(GetDataWindow().GetTextWidth(aText), GetDataWindow().GetTextHeight());
118
119 // clipping
120 if (aPos.X() < _rRect.Right() || aPos.X() + TxtSize.Width() > _rRect.Right() ||
121 aPos.Y() < _rRect.Top() || aPos.Y() + TxtSize.Height() > _rRect.Bottom())
122 _rDev.SetClipRegion(vcl::Region(_rRect));
123
124 // allow for a disabled control ...
125 bool bEnabled = IsEnabled();
126 Color aOriginalColor = _rDev.GetTextColor();
127 if (!bEnabled)
128 _rDev.SetTextColor(GetSettings().GetStyleSettings().GetDisableColor());
129
130 // draw the text
131 _rDev.DrawText(aPos, aText);
132
133 // reset the color (if necessary)
134 if (!bEnabled)
135 _rDev.SetTextColor(aOriginalColor);
136
137 if (_rDev.IsClipRegion())
138 _rDev.SetClipRegion();
139 }
140
142 {
143 // copy the field descriptions
144 m_aFields = std::move(_rFields);
145 m_aSeekRow = m_aFields.end();
146
147 SetUpdateMode(false);
148 // remove all rows
150 // insert rows for the fields
151 RowInserted(GetRowCount(), m_aFields.size(), false);
152 // insert an additional row for a new field for that index
153 RowInserted(GetRowCount(), 1, false);
154 SetUpdateMode(true);
155
157 }
158
160 {
161 // do not just copy the array, we may have empty field names (which should not be copied)
162 _rFields.resize(m_aFields.size());
163 IndexFields::iterator aDest = std::copy_if(m_aFields.begin(), m_aFields.end(), _rFields.begin(),
164 [](const OIndexField& source) { return !source.sFieldName.isEmpty(); });
165
166 _rFields.resize(aDest - _rFields.begin());
167 }
168
169 sal_uInt32 IndexFieldsControl::GetTotalCellWidth(sal_Int32 _nRow, sal_uInt16 _nColId)
170 {
171 if (COLUMN_ID_ORDER == _nColId)
172 {
173 sal_Int32 nWidthAsc = GetTextWidth(m_sAscendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
174 sal_Int32 nWidthDesc = GetTextWidth(m_sDescendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
175 // maximum plus some additional space
176 return std::max(nWidthAsc, nWidthDesc) + GetTextWidth(OUString('0')) * 2;
177 }
178 return EditBrowseBox::GetTotalCellWidth(_nRow, _nColId);
179 }
180
181 void IndexFieldsControl::Init(const Sequence< OUString >& _rAvailableFields, bool _bAddIndexAppendix)
182 {
183 m_bAddIndexAppendix = _bAddIndexAppendix;
184
186
187 // for the width: both columns together should be somewhat smaller than the whole window (without the scrollbar)
188 sal_Int32 nFieldNameWidth = GetSizePixel().Width();
189
191 {
192 m_sAscendingText = DBA_RES(STR_ORDER_ASCENDING);
193 m_sDescendingText = DBA_RES(STR_ORDER_DESCENDING);
194
195 // the "sort order" column
196 OUString sColumnName = DBA_RES(STR_TAB_INDEX_SORTORDER);
197 // the width of the order column is the maximum widths of the texts used
198 // (the title of the column)
199 sal_Int32 nSortOrderColumnWidth = GetTextWidth(sColumnName);
200 // ("ascending" + scrollbar width)
201 sal_Int32 nOther = GetTextWidth(m_sAscendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
202 nSortOrderColumnWidth = std::max(nSortOrderColumnWidth, nOther);
203 // ("descending" + scrollbar width)
204 nOther = GetTextWidth(m_sDescendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
205 nSortOrderColumnWidth = std::max(nSortOrderColumnWidth, nOther);
206 // (plus some additional space)
207 nSortOrderColumnWidth += GetTextWidth(OUString('0')) * 2;
208 InsertDataColumn(COLUMN_ID_ORDER, sColumnName, nSortOrderColumnWidth, HeaderBarItemBits::STDSTYLE, 1);
209
211 weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
212 rSortingListBox.append_text(m_sAscendingText);
213 rSortingListBox.append_text(m_sDescendingText);
215
216 nFieldNameWidth -= nSortOrderColumnWidth;
217 }
219 nFieldNameWidth -= aSystemStyle.GetScrollBarSize();
220 nFieldNameWidth -= 8;
221 // the "field name" column
222 OUString sColumnName = DBA_RES(STR_TAB_INDEX_FIELD);
223 InsertDataColumn(COLUMN_ID_FIELDNAME, sColumnName, nFieldNameWidth, HeaderBarItemBits::STDSTYLE, 0);
224
225 // create the cell controllers
226 // for the field name cell
228 weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
229 rNameListBox.append_text(OUString());
231 const OUString* pFields = _rAvailableFields.getConstArray();
232 const OUString* pFieldsEnd = pFields + _rAvailableFields.getLength();
233 for (;pFields < pFieldsEnd; ++pFields)
234 rNameListBox.append_text(*pFields);
235 }
236
237 CellController* IndexFieldsControl::GetController(sal_Int32 _nRow, sal_uInt16 _nColumnId)
238 {
239 if (!IsEnabled())
240 return nullptr;
241
242 IndexFields::const_iterator aRow;
243 bool bNewField = !implGetFieldDesc(_nRow, aRow);
244
245 DbaMouseDownListBoxController* pReturn = nullptr;
246 switch (_nColumnId)
247 {
248 case COLUMN_ID_ORDER:
249 if (!bNewField && m_pSortingCell && !aRow->sFieldName.isEmpty())
251 break;
252
255 break;
256
257 default:
258 OSL_FAIL("IndexFieldsControl::GetController: invalid column id!");
259 }
260
261 if (pReturn)
262 pReturn->SetAdditionalModifyHdl(LINK(this, IndexFieldsControl, OnListEntrySelected));
263
264 return pReturn;
265 }
266
267 bool IndexFieldsControl::implGetFieldDesc(sal_Int32 _nRow, IndexFields::const_iterator& _rPos)
268 {
269 _rPos = m_aFields.end();
270 if ((_nRow < 0) || (o3tl::make_unsigned(_nRow) >= m_aFields.size()))
271 return false;
272 _rPos = m_aFields.begin() + _nRow;
273 return true;
274 }
275
277 {
278 if (!IsModified())
279 return true;
280
281 switch (GetCurColumnId())
282 {
284 {
285 weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
286 OUString sFieldSelected = rNameListBox.get_active_text();
287 bool bEmptySelected = sFieldSelected.isEmpty();
288 if (isNewField())
289 {
290 if (!bEmptySelected)
291 {
292 // add a new field to the collection
293 OIndexField aNewField;
294 aNewField.sFieldName = sFieldSelected;
295 m_aFields.push_back(aNewField);
297 }
298 }
299 else
300 {
301 sal_Int32 nRow = GetCurRow();
302 OSL_ENSURE(nRow < static_cast<sal_Int32>(m_aFields.size()), "IndexFieldsControl::SaveModified: invalid current row!");
303 if (nRow >= 0) // may be -1 in case the control was empty
304 {
305 // remove the field from the selection
306 IndexFields::iterator aPos = m_aFields.begin() + nRow;
307
308 if (bEmptySelected)
309 {
310 aPos->sFieldName.clear();
311
312 // invalidate the row to force repaint
313 Invalidate(GetRowRectPixel(nRow));
314 return true;
315 }
316
317 if (sFieldSelected == aPos->sFieldName)
318 // nothing changed
319 return true;
320
321 aPos->sFieldName = sFieldSelected;
322 }
323 }
324
325 Invalidate(GetRowRectPixel(GetCurRow()));
326 }
327 break;
328 case COLUMN_ID_ORDER:
329 {
330 OSL_ENSURE(!isNewField(), "IndexFieldsControl::SaveModified: why the hell ...!!!");
331 // selected entry
332 weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
333 sal_Int32 nPos = rSortingListBox.get_active();
334 OSL_ENSURE(nPos != -1, "IndexFieldsControl::SaveModified: how did you get this selection??");
335 // adjust the sort flag in the index field description
336 OIndexField& rCurrentField = m_aFields[GetCurRow()];
337 rCurrentField.bSortAscending = (0 == nPos);
338
339 }
340 break;
341 default:
342 OSL_FAIL("IndexFieldsControl::SaveModified: invalid column id!");
343 }
344 return true;
345 }
346
347 void IndexFieldsControl::InitController(CellControllerRef& /*_rController*/, sal_Int32 _nRow, sal_uInt16 _nColumnId)
348 {
349 IndexFields::const_iterator aFieldDescription;
350 bool bNewField = !implGetFieldDesc(_nRow, aFieldDescription);
351
352 switch (_nColumnId)
353 {
355 {
356 weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
357 rNameListBox.set_active_text(bNewField ? OUString() : aFieldDescription->sFieldName);
358 rNameListBox.save_value();
359 break;
360 }
361
362 case COLUMN_ID_ORDER:
363 {
364 weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
365 rSortingListBox.set_active_text(aFieldDescription->bSortAscending ? m_sAscendingText : m_sDescendingText);
366 rSortingListBox.save_value();
367 break;
368 }
369
370 default:
371 OSL_FAIL("IndexFieldsControl::InitController: invalid column id!");
372 }
373 }
374
375 IMPL_LINK( IndexFieldsControl, OnListEntrySelected, DbaMouseDownListBoxController&, rController, void )
376 {
377 weld::ComboBox& rListBox = rController.GetListBox();
378 if (!rListBox.get_popup_shown())
379 m_aModifyHdl.Call(*this);
380
381 if (&rListBox != &m_pFieldNameCell->get_widget())
382 return;
383
384// a field has been selected
385 if (GetCurRow() >= GetRowCount() - 2)
386 { // and we're in one of the last two rows
387 OUString sSelectedEntry = rListBox.get_active_text();
388 sal_Int32 nCurrentRow = GetCurRow();
389 sal_Int32 rowCount = GetRowCount();
390
391 OSL_ENSURE((static_cast<sal_Int32>(m_aFields.size() + 1)) == rowCount, "IndexFieldsControl::OnListEntrySelected: inconsistence!");
392
393 if (!sSelectedEntry.isEmpty() && (nCurrentRow == rowCount - 1) /*&& (!m_nMaxColumnsInIndex || rowCount < m_nMaxColumnsInIndex )*/ )
394 { // in the last row, a non-empty string has been selected
395 // -> insert a new row
396 m_aFields.emplace_back();
397 RowInserted(GetRowCount());
398 Invalidate(GetRowRectPixel(nCurrentRow));
399 }
400 else if (sSelectedEntry.isEmpty() && (nCurrentRow == rowCount - 2))
401 { // in the (last-1)th row, an empty entry has been selected
402 // -> remove the last row
403 m_aFields.pop_back();
404 RowRemoved(GetRowCount() - 1);
405 Invalidate(GetRowRectPixel(nCurrentRow));
406 }
407 }
408
409 SaveModified();
410 }
411 OUString IndexFieldsControl::GetCellText(sal_Int32 _nRow,sal_uInt16 nColId) const
412 {
413 IndexFields::const_iterator aRow = m_aFields.end();
414 if ( _nRow >= 0 )
415 {
416 aRow = m_aFields.begin() + _nRow;
417 OSL_ENSURE(aRow <= m_aFields.end(), "IndexFieldsControl::SeekRow: invalid row!");
418 }
419 return GetRowCellText(aRow,nColId);
420 }
421 OUString IndexFieldsControl::GetRowCellText(const IndexFields::const_iterator& _rRow,sal_uInt16 nColId) const
422 {
423 if (_rRow < m_aFields.end())
424 {
425 switch (nColId)
426 {
428 return _rRow->sFieldName;
429 case COLUMN_ID_ORDER:
430 if (_rRow->sFieldName.isEmpty())
431 return OUString();
432 else
433 return _rRow->bSortAscending ? m_sAscendingText : m_sDescendingText;
434 default:
435 OSL_FAIL("IndexFieldsControl::GetCurrentRowCellText: invalid column id!");
436 }
437 }
438 return OUString();
439 }
440 bool IndexFieldsControl::IsTabAllowed(bool /*bForward*/) const
441 {
442 return false;
443 }
444
445} // namespace dbaui
446
447/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
void RowRemoved(sal_Int32 nRow, sal_Int32 nNumRows=1, bool bDoPaint=true)
void SetUpdateMode(bool bUpdate)
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
bool GoToRowColumnId(sal_Int32 nRow, sal_uInt16 nColId)
sal_uInt16 GetCurColumnId() const
tools::Rectangle GetRowRectPixel(sal_Int32 nRow) const
void RowInserted(sal_Int32 nRow, sal_Int32 nNumRows=1, bool bDoPaint=true, bool bKeepSelection=false)
virtual sal_Int32 GetRowCount() const override
void RemoveColumns()
bool IsClipRegion() const
void SetTextColor(const Color &rColor)
void SetClipRegion()
const Color & GetTextColor() const
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, std::vector< tools::Rectangle > *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
constexpr tools::Long Y() const
tools::Long AdjustX(tools::Long nHorzMove)
constexpr tools::Long X() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
sal_Int32 GetScrollBarSize() const
static VclPtr< reference_type > Create(Arg &&... arg)
void SetAdditionalModifyHdl(const Link< DbaMouseDownListBoxController &, void > &_rHdl)
DbaMouseDownListBoxController(ListBoxControl *_pParent)
Link< DbaMouseDownListBoxController &, void > m_aAdditionalModifyHdl
virtual void dispose() override
IndexFields::const_iterator m_aSeekRow
void initializeFrom(IndexFields &&_rFields)
VclPtr< ::svt::ListBoxControl > m_pSortingCell
OUString GetRowCellText(const IndexFields::const_iterator &_rRow, sal_uInt16 nColId) const
virtual sal_uInt32 GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) override
IndexFieldsControl(const css::uno::Reference< css::awt::XWindow > &rParent)
virtual void PaintCell(OutputDevice &_rDev, const tools::Rectangle &_rRect, sal_uInt16 _nColumnId) const override
VclPtr< ::svt::ListBoxControl > m_pFieldNameCell
virtual OUString GetCellText(sal_Int32 _nRow, sal_uInt16 nColId) const override
virtual bool SeekRow(sal_Int32 nRow) override
void commitTo(IndexFields &_rFields)
virtual bool IsModified() const
virtual ~IndexFieldsControl() override
bool implGetFieldDesc(sal_Int32 _nRow, IndexFields::const_iterator &_rPos)
void InitController(::svt::CellControllerRef &, sal_Int32 _nRow, sal_uInt16 _nColumnId) override
::svt::CellController * GetController(sal_Int32 _nRow, sal_uInt16 _nColumnId) override
virtual bool IsTabAllowed(bool bForward) const override
virtual void callModifyHdl()
virtual sal_uInt32 GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId)
virtual void Init()
virtual bool SeekRow(sal_Int32 nRow) override
virtual void dispose() override
constexpr tools::Long Top() const
constexpr Point TopLeft() const
constexpr tools::Long Right() const
constexpr tools::Long Bottom() const
virtual OUString get_active_text() const=0
virtual bool get_popup_shown() const=0
void append_text(const OUString &rStr)
virtual int get_active() const=0
void set_active_text(const OUString &rStr)
virtual void set_help_id(const OUString &rName)=0
#define DBA_RES(id)
EditBrowseBoxFlags
constexpr OUStringLiteral HID_DLGINDEX_INDEXDETAILS_FIELD
Definition: helpids.h:71
constexpr OUStringLiteral HID_DLGINDEX_INDEXDETAILS_SORTORDER
Definition: helpids.h:72
#define COLUMN_ID_ORDER
#define COLUMN_ID_FIELDNAME
sal_uInt16 nPos
constexpr auto BROWSER_STANDARD_FLAGS
IMPL_LINK(OApplicationController, OnSelectContainer, void *, _pType, void)
std::vector< OIndexField > IndexFields
Definition: indexes.hxx:39
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
end
OUString sFieldName
Definition: indexes.hxx:33
WinBits const WB_BORDER
WinBits const WB_TABSTOP