tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / dbaccess / source / ui / dlg / indexfieldscontrol.cxx
blobd8c1c962809b5d97dbb4b85e1bda839fba129ff8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <core_resource.hxx>
21 #include <indexfieldscontrol.hxx>
22 #include <strings.hrc>
23 #include <o3tl/safeint.hxx>
24 #include <osl/diagnose.h>
25 #include <helpids.h>
26 #include <toolkit/helper/vclunohelper.hxx>
27 #include <vcl/settings.hxx>
28 #include <vcl/svapp.hxx>
30 namespace dbaui
33 constexpr auto BROWSER_STANDARD_FLAGS = BrowserMode::COLUMNSELECTION | BrowserMode::HLINES | BrowserMode::VLINES |
34 BrowserMode::HIDECURSOR | BrowserMode::HIDESELECT | BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL;
36 #define COLUMN_ID_FIELDNAME 1
37 #define COLUMN_ID_ORDER 2
39 using namespace ::com::sun::star::uno;
40 using namespace ::svt;
42 // DbaMouseDownListBoxController
43 class DbaMouseDownListBoxController : public ListBoxCellController
45 protected:
46 Link<DbaMouseDownListBoxController&,void> m_aAdditionalModifyHdl;
48 public:
49 explicit DbaMouseDownListBoxController(ListBoxControl* _pParent)
50 :ListBoxCellController(_pParent)
54 void SetAdditionalModifyHdl(const Link<DbaMouseDownListBoxController&,void>& _rHdl);
56 protected:
57 virtual void callModifyHdl() override;
60 void DbaMouseDownListBoxController::SetAdditionalModifyHdl(const Link<DbaMouseDownListBoxController&,void>& _rHdl)
62 m_aAdditionalModifyHdl = _rHdl;
65 void DbaMouseDownListBoxController::callModifyHdl()
67 m_aAdditionalModifyHdl.Call(*this);
68 ListBoxCellController::callModifyHdl();
71 // IndexFieldsControl
72 IndexFieldsControl::IndexFieldsControl(const css::uno::Reference<css::awt::XWindow> &rParent)
73 : EditBrowseBox(VCLUnoHelper::GetWindow(rParent), EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN, WB_TABSTOP | WB_BORDER, BROWSER_STANDARD_FLAGS)
74 , m_aSeekRow(m_aFields.end())
75 , m_pSortingCell(nullptr)
76 , m_pFieldNameCell(nullptr)
77 , m_bAddIndexAppendix(false)
81 IndexFieldsControl::~IndexFieldsControl()
83 disposeOnce();
86 void IndexFieldsControl::dispose()
88 m_pSortingCell.disposeAndClear();
89 m_pFieldNameCell.disposeAndClear();
90 ::svt::EditBrowseBox::dispose();
93 bool IndexFieldsControl::SeekRow(sal_Int32 nRow)
95 if (!EditBrowseBox::SeekRow(nRow))
96 return false;
98 if (nRow < 0)
100 m_aSeekRow = m_aFields.end();
102 else
104 m_aSeekRow = m_aFields.begin() + nRow;
105 OSL_ENSURE(m_aSeekRow <= m_aFields.end(), "IndexFieldsControl::SeekRow: invalid row!");
108 return true;
111 void IndexFieldsControl::PaintCell( OutputDevice& _rDev, const tools::Rectangle& _rRect, sal_uInt16 _nColumnId ) const
113 Point aPos(_rRect.TopLeft());
114 aPos.AdjustX(1 );
116 OUString aText = GetRowCellText(m_aSeekRow,_nColumnId);
117 Size TxtSize(GetDataWindow().GetTextWidth(aText), GetDataWindow().GetTextHeight());
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));
124 // allow for a disabled control ...
125 bool bEnabled = IsEnabled();
126 Color aOriginalColor = _rDev.GetTextColor();
127 if (!bEnabled)
128 _rDev.SetTextColor(GetSettings().GetStyleSettings().GetDisableColor());
130 // draw the text
131 _rDev.DrawText(aPos, aText);
133 // reset the color (if necessary)
134 if (!bEnabled)
135 _rDev.SetTextColor(aOriginalColor);
137 if (_rDev.IsClipRegion())
138 _rDev.SetClipRegion();
141 void IndexFieldsControl::initializeFrom(IndexFields&& _rFields)
143 // copy the field descriptions
144 m_aFields = std::move(_rFields);
145 m_aSeekRow = m_aFields.end();
147 SetUpdateMode(false);
148 // remove all rows
149 RowRemoved(1, GetRowCount());
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);
156 GoToRowColumnId(0, COLUMN_ID_FIELDNAME);
159 void IndexFieldsControl::commitTo(IndexFields& _rFields)
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(); });
166 _rFields.resize(aDest - _rFields.begin());
169 sal_uInt32 IndexFieldsControl::GetTotalCellWidth(sal_Int32 _nRow, sal_uInt16 _nColId)
171 if (COLUMN_ID_ORDER == _nColId)
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;
178 return EditBrowseBox::GetTotalCellWidth(_nRow, _nColId);
181 void IndexFieldsControl::Init(const Sequence< OUString >& _rAvailableFields, bool _bAddIndexAppendix)
183 m_bAddIndexAppendix = _bAddIndexAppendix;
185 RemoveColumns();
187 // for the width: both columns together should be somewhat smaller than the whole window (without the scrollbar)
188 sal_Int32 nFieldNameWidth = GetSizePixel().Width();
190 if ( m_bAddIndexAppendix )
192 m_sAscendingText = DBA_RES(STR_ORDER_ASCENDING);
193 m_sDescendingText = DBA_RES(STR_ORDER_DESCENDING);
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);
210 m_pSortingCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
211 weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
212 rSortingListBox.append_text(m_sAscendingText);
213 rSortingListBox.append_text(m_sDescendingText);
214 rSortingListBox.set_help_id(HID_DLGINDEX_INDEXDETAILS_SORTORDER);
216 nFieldNameWidth -= nSortOrderColumnWidth;
218 StyleSettings aSystemStyle = Application::GetSettings().GetStyleSettings();
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);
225 // create the cell controllers
226 // for the field name cell
227 m_pFieldNameCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
228 weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
229 rNameListBox.append_text(OUString());
230 rNameListBox.set_help_id(HID_DLGINDEX_INDEXDETAILS_FIELD);
231 for (auto& text : _rAvailableFields)
232 rNameListBox.append_text(text);
235 CellController* IndexFieldsControl::GetController(sal_Int32 _nRow, sal_uInt16 _nColumnId)
237 if (!IsEnabled())
238 return nullptr;
240 IndexFields::const_iterator aRow;
241 bool bNewField = !implGetFieldDesc(_nRow, aRow);
243 DbaMouseDownListBoxController* pReturn = nullptr;
244 switch (_nColumnId)
246 case COLUMN_ID_ORDER:
247 if (!bNewField && m_pSortingCell && !aRow->sFieldName.isEmpty())
248 pReturn = new DbaMouseDownListBoxController(m_pSortingCell);
249 break;
251 case COLUMN_ID_FIELDNAME:
252 pReturn = new DbaMouseDownListBoxController(m_pFieldNameCell);
253 break;
255 default:
256 OSL_FAIL("IndexFieldsControl::GetController: invalid column id!");
259 if (pReturn)
260 pReturn->SetAdditionalModifyHdl(LINK(this, IndexFieldsControl, OnListEntrySelected));
262 return pReturn;
265 bool IndexFieldsControl::implGetFieldDesc(sal_Int32 _nRow, IndexFields::const_iterator& _rPos)
267 _rPos = m_aFields.end();
268 if ((_nRow < 0) || (o3tl::make_unsigned(_nRow) >= m_aFields.size()))
269 return false;
270 _rPos = m_aFields.begin() + _nRow;
271 return true;
274 bool IndexFieldsControl::SaveModified()
276 if (!IsModified())
277 return true;
279 switch (GetCurColumnId())
281 case COLUMN_ID_FIELDNAME:
283 weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
284 OUString sFieldSelected = rNameListBox.get_active_text();
285 bool bEmptySelected = sFieldSelected.isEmpty();
286 if (isNewField())
288 if (!bEmptySelected)
290 // add a new field to the collection
291 OIndexField aNewField;
292 aNewField.sFieldName = sFieldSelected;
293 m_aFields.push_back(aNewField);
294 RowInserted(GetRowCount());
297 else
299 sal_Int32 nRow = GetCurRow();
300 OSL_ENSURE(nRow < static_cast<sal_Int32>(m_aFields.size()), "IndexFieldsControl::SaveModified: invalid current row!");
301 if (nRow >= 0) // may be -1 in case the control was empty
303 // remove the field from the selection
304 IndexFields::iterator aPos = m_aFields.begin() + nRow;
306 if (bEmptySelected)
308 aPos->sFieldName.clear();
310 // invalidate the row to force repaint
311 Invalidate(GetRowRectPixel(nRow));
312 return true;
315 if (sFieldSelected == aPos->sFieldName)
316 // nothing changed
317 return true;
319 aPos->sFieldName = sFieldSelected;
323 Invalidate(GetRowRectPixel(GetCurRow()));
325 break;
326 case COLUMN_ID_ORDER:
328 OSL_ENSURE(!isNewField(), "IndexFieldsControl::SaveModified: why the hell ...!!!");
329 // selected entry
330 weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
331 sal_Int32 nPos = rSortingListBox.get_active();
332 OSL_ENSURE(nPos != -1, "IndexFieldsControl::SaveModified: how did you get this selection??");
333 // adjust the sort flag in the index field description
334 OIndexField& rCurrentField = m_aFields[GetCurRow()];
335 rCurrentField.bSortAscending = (0 == nPos);
338 break;
339 default:
340 OSL_FAIL("IndexFieldsControl::SaveModified: invalid column id!");
342 return true;
345 void IndexFieldsControl::InitController(CellControllerRef& /*_rController*/, sal_Int32 _nRow, sal_uInt16 _nColumnId)
347 IndexFields::const_iterator aFieldDescription;
348 bool bNewField = !implGetFieldDesc(_nRow, aFieldDescription);
350 switch (_nColumnId)
352 case COLUMN_ID_FIELDNAME:
354 weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
355 rNameListBox.set_active_text(bNewField ? OUString() : aFieldDescription->sFieldName);
356 rNameListBox.save_value();
357 break;
360 case COLUMN_ID_ORDER:
362 weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
363 rSortingListBox.set_active_text(aFieldDescription->bSortAscending ? m_sAscendingText : m_sDescendingText);
364 rSortingListBox.save_value();
365 break;
368 default:
369 OSL_FAIL("IndexFieldsControl::InitController: invalid column id!");
373 IMPL_LINK( IndexFieldsControl, OnListEntrySelected, DbaMouseDownListBoxController&, rController, void )
375 weld::ComboBox& rListBox = rController.GetListBox();
376 if (!rListBox.get_popup_shown())
377 m_aModifyHdl.Call(*this);
379 if (&rListBox != &m_pFieldNameCell->get_widget())
380 return;
382 // a field has been selected
383 if (GetCurRow() >= GetRowCount() - 2)
384 { // and we're in one of the last two rows
385 OUString sSelectedEntry = rListBox.get_active_text();
386 sal_Int32 nCurrentRow = GetCurRow();
387 sal_Int32 rowCount = GetRowCount();
389 OSL_ENSURE((static_cast<sal_Int32>(m_aFields.size() + 1)) == rowCount, "IndexFieldsControl::OnListEntrySelected: inconsistence!");
391 if (!sSelectedEntry.isEmpty() && (nCurrentRow == rowCount - 1) /*&& (!m_nMaxColumnsInIndex || rowCount < m_nMaxColumnsInIndex )*/ )
392 { // in the last row, a non-empty string has been selected
393 // -> insert a new row
394 m_aFields.emplace_back();
395 RowInserted(GetRowCount());
396 Invalidate(GetRowRectPixel(nCurrentRow));
398 else if (sSelectedEntry.isEmpty() && (nCurrentRow == rowCount - 2))
399 { // in the (last-1)th row, an empty entry has been selected
400 // -> remove the last row
401 m_aFields.pop_back();
402 RowRemoved(GetRowCount() - 1);
403 Invalidate(GetRowRectPixel(nCurrentRow));
407 SaveModified();
409 OUString IndexFieldsControl::GetCellText(sal_Int32 _nRow,sal_uInt16 nColId) const
411 IndexFields::const_iterator aRow = m_aFields.end();
412 if ( _nRow >= 0 )
414 aRow = m_aFields.begin() + _nRow;
415 OSL_ENSURE(aRow <= m_aFields.end(), "IndexFieldsControl::SeekRow: invalid row!");
417 return GetRowCellText(aRow,nColId);
419 OUString IndexFieldsControl::GetRowCellText(const IndexFields::const_iterator& _rRow,sal_uInt16 nColId) const
421 if (_rRow < m_aFields.end())
423 switch (nColId)
425 case COLUMN_ID_FIELDNAME:
426 return _rRow->sFieldName;
427 case COLUMN_ID_ORDER:
428 if (_rRow->sFieldName.isEmpty())
429 return OUString();
430 else
431 return _rRow->bSortAscending ? m_sAscendingText : m_sDescendingText;
432 default:
433 OSL_FAIL("IndexFieldsControl::GetCurrentRowCellText: invalid column id!");
436 return OUString();
438 bool IndexFieldsControl::IsTabAllowed(bool /*bForward*/) const
440 return false;
443 } // namespace dbaui
445 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */