445 lines
17 KiB
C++
445 lines
17 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <core_resource.hxx>
|
|
#include <indexfieldscontrol.hxx>
|
|
#include <strings.hrc>
|
|
#include <o3tl/safeint.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <helpids.h>
|
|
#include <toolkit/helper/vclunohelper.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
|
|
namespace dbaui
|
|
{
|
|
|
|
constexpr auto BROWSER_STANDARD_FLAGS = BrowserMode::COLUMNSELECTION | BrowserMode::HLINES | BrowserMode::VLINES |
|
|
BrowserMode::HIDECURSOR | BrowserMode::HIDESELECT | BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL;
|
|
|
|
#define COLUMN_ID_FIELDNAME 1
|
|
#define COLUMN_ID_ORDER 2
|
|
|
|
using namespace ::com::sun::star::uno;
|
|
using namespace ::svt;
|
|
|
|
// DbaMouseDownListBoxController
|
|
class DbaMouseDownListBoxController : public ListBoxCellController
|
|
{
|
|
protected:
|
|
Link<DbaMouseDownListBoxController&,void> m_aAdditionalModifyHdl;
|
|
|
|
public:
|
|
explicit DbaMouseDownListBoxController(ListBoxControl* _pParent)
|
|
:ListBoxCellController(_pParent)
|
|
{
|
|
}
|
|
|
|
void SetAdditionalModifyHdl(const Link<DbaMouseDownListBoxController&,void>& _rHdl);
|
|
|
|
protected:
|
|
virtual void callModifyHdl() override;
|
|
};
|
|
|
|
void DbaMouseDownListBoxController::SetAdditionalModifyHdl(const Link<DbaMouseDownListBoxController&,void>& _rHdl)
|
|
{
|
|
m_aAdditionalModifyHdl = _rHdl;
|
|
}
|
|
|
|
void DbaMouseDownListBoxController::callModifyHdl()
|
|
{
|
|
m_aAdditionalModifyHdl.Call(*this);
|
|
ListBoxCellController::callModifyHdl();
|
|
}
|
|
|
|
// IndexFieldsControl
|
|
IndexFieldsControl::IndexFieldsControl(const css::uno::Reference<css::awt::XWindow> &rParent)
|
|
: EditBrowseBox(VCLUnoHelper::GetWindow(rParent), EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN, WB_TABSTOP | WB_BORDER, BROWSER_STANDARD_FLAGS)
|
|
, m_aSeekRow(m_aFields.end())
|
|
, m_pSortingCell(nullptr)
|
|
, m_pFieldNameCell(nullptr)
|
|
, m_bAddIndexAppendix(false)
|
|
{
|
|
}
|
|
|
|
IndexFieldsControl::~IndexFieldsControl()
|
|
{
|
|
disposeOnce();
|
|
}
|
|
|
|
void IndexFieldsControl::dispose()
|
|
{
|
|
m_pSortingCell.disposeAndClear();
|
|
m_pFieldNameCell.disposeAndClear();
|
|
::svt::EditBrowseBox::dispose();
|
|
}
|
|
|
|
bool IndexFieldsControl::SeekRow(sal_Int32 nRow)
|
|
{
|
|
if (!EditBrowseBox::SeekRow(nRow))
|
|
return false;
|
|
|
|
if (nRow < 0)
|
|
{
|
|
m_aSeekRow = m_aFields.end();
|
|
}
|
|
else
|
|
{
|
|
m_aSeekRow = m_aFields.begin() + nRow;
|
|
OSL_ENSURE(m_aSeekRow <= m_aFields.end(), "IndexFieldsControl::SeekRow: invalid row!");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void IndexFieldsControl::PaintCell( OutputDevice& _rDev, const tools::Rectangle& _rRect, sal_uInt16 _nColumnId ) const
|
|
{
|
|
Point aPos(_rRect.TopLeft());
|
|
aPos.AdjustX(1 );
|
|
|
|
OUString aText = GetRowCellText(m_aSeekRow,_nColumnId);
|
|
Size TxtSize(GetDataWindow().GetTextWidth(aText), GetDataWindow().GetTextHeight());
|
|
|
|
// clipping
|
|
if (aPos.X() < _rRect.Right() || aPos.X() + TxtSize.Width() > _rRect.Right() ||
|
|
aPos.Y() < _rRect.Top() || aPos.Y() + TxtSize.Height() > _rRect.Bottom())
|
|
_rDev.SetClipRegion(vcl::Region(_rRect));
|
|
|
|
// allow for a disabled control ...
|
|
bool bEnabled = IsEnabled();
|
|
Color aOriginalColor = _rDev.GetTextColor();
|
|
if (!bEnabled)
|
|
_rDev.SetTextColor(GetSettings().GetStyleSettings().GetDisableColor());
|
|
|
|
// draw the text
|
|
_rDev.DrawText(aPos, aText);
|
|
|
|
// reset the color (if necessary)
|
|
if (!bEnabled)
|
|
_rDev.SetTextColor(aOriginalColor);
|
|
|
|
if (_rDev.IsClipRegion())
|
|
_rDev.SetClipRegion();
|
|
}
|
|
|
|
void IndexFieldsControl::initializeFrom(IndexFields&& _rFields)
|
|
{
|
|
// copy the field descriptions
|
|
m_aFields = std::move(_rFields);
|
|
m_aSeekRow = m_aFields.end();
|
|
|
|
SetUpdateMode(false);
|
|
// remove all rows
|
|
RowRemoved(1, GetRowCount());
|
|
// insert rows for the fields
|
|
RowInserted(GetRowCount(), m_aFields.size(), false);
|
|
// insert an additional row for a new field for that index
|
|
RowInserted(GetRowCount(), 1, false);
|
|
SetUpdateMode(true);
|
|
|
|
GoToRowColumnId(0, COLUMN_ID_FIELDNAME);
|
|
}
|
|
|
|
void IndexFieldsControl::commitTo(IndexFields& _rFields)
|
|
{
|
|
// do not just copy the array, we may have empty field names (which should not be copied)
|
|
_rFields.resize(m_aFields.size());
|
|
IndexFields::iterator aDest = std::copy_if(m_aFields.begin(), m_aFields.end(), _rFields.begin(),
|
|
[](const OIndexField& source) { return !source.sFieldName.isEmpty(); });
|
|
|
|
_rFields.resize(aDest - _rFields.begin());
|
|
}
|
|
|
|
sal_uInt32 IndexFieldsControl::GetTotalCellWidth(sal_Int32 _nRow, sal_uInt16 _nColId)
|
|
{
|
|
if (COLUMN_ID_ORDER == _nColId)
|
|
{
|
|
sal_Int32 nWidthAsc = GetTextWidth(m_sAscendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
|
|
sal_Int32 nWidthDesc = GetTextWidth(m_sDescendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
|
|
// maximum plus some additional space
|
|
return std::max(nWidthAsc, nWidthDesc) + GetTextWidth(OUString('0')) * 2;
|
|
}
|
|
return EditBrowseBox::GetTotalCellWidth(_nRow, _nColId);
|
|
}
|
|
|
|
void IndexFieldsControl::Init(const Sequence< OUString >& _rAvailableFields, bool _bAddIndexAppendix)
|
|
{
|
|
m_bAddIndexAppendix = _bAddIndexAppendix;
|
|
|
|
RemoveColumns();
|
|
|
|
// for the width: both columns together should be somewhat smaller than the whole window (without the scrollbar)
|
|
sal_Int32 nFieldNameWidth = GetSizePixel().Width();
|
|
|
|
if ( m_bAddIndexAppendix )
|
|
{
|
|
m_sAscendingText = DBA_RES(STR_ORDER_ASCENDING);
|
|
m_sDescendingText = DBA_RES(STR_ORDER_DESCENDING);
|
|
|
|
// the "sort order" column
|
|
OUString sColumnName = DBA_RES(STR_TAB_INDEX_SORTORDER);
|
|
// the width of the order column is the maximum widths of the texts used
|
|
// (the title of the column)
|
|
sal_Int32 nSortOrderColumnWidth = GetTextWidth(sColumnName);
|
|
// ("ascending" + scrollbar width)
|
|
sal_Int32 nOther = GetTextWidth(m_sAscendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
|
|
nSortOrderColumnWidth = std::max(nSortOrderColumnWidth, nOther);
|
|
// ("descending" + scrollbar width)
|
|
nOther = GetTextWidth(m_sDescendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
|
|
nSortOrderColumnWidth = std::max(nSortOrderColumnWidth, nOther);
|
|
// (plus some additional space)
|
|
nSortOrderColumnWidth += GetTextWidth(OUString('0')) * 2;
|
|
InsertDataColumn(COLUMN_ID_ORDER, sColumnName, nSortOrderColumnWidth, HeaderBarItemBits::STDSTYLE, 1);
|
|
|
|
m_pSortingCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
|
|
weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
|
|
rSortingListBox.append_text(m_sAscendingText);
|
|
rSortingListBox.append_text(m_sDescendingText);
|
|
rSortingListBox.set_help_id(HID_DLGINDEX_INDEXDETAILS_SORTORDER);
|
|
|
|
nFieldNameWidth -= nSortOrderColumnWidth;
|
|
}
|
|
StyleSettings aSystemStyle = Application::GetSettings().GetStyleSettings();
|
|
nFieldNameWidth -= aSystemStyle.GetScrollBarSize();
|
|
nFieldNameWidth -= 8;
|
|
// the "field name" column
|
|
OUString sColumnName = DBA_RES(STR_TAB_INDEX_FIELD);
|
|
InsertDataColumn(COLUMN_ID_FIELDNAME, sColumnName, nFieldNameWidth, HeaderBarItemBits::STDSTYLE, 0);
|
|
|
|
// create the cell controllers
|
|
// for the field name cell
|
|
m_pFieldNameCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
|
|
weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
|
|
rNameListBox.append_text(OUString());
|
|
rNameListBox.set_help_id(HID_DLGINDEX_INDEXDETAILS_FIELD);
|
|
for (auto& text : _rAvailableFields)
|
|
rNameListBox.append_text(text);
|
|
}
|
|
|
|
CellController* IndexFieldsControl::GetController(sal_Int32 _nRow, sal_uInt16 _nColumnId)
|
|
{
|
|
if (!IsEnabled())
|
|
return nullptr;
|
|
|
|
IndexFields::const_iterator aRow;
|
|
bool bNewField = !implGetFieldDesc(_nRow, aRow);
|
|
|
|
DbaMouseDownListBoxController* pReturn = nullptr;
|
|
switch (_nColumnId)
|
|
{
|
|
case COLUMN_ID_ORDER:
|
|
if (!bNewField && m_pSortingCell && !aRow->sFieldName.isEmpty())
|
|
pReturn = new DbaMouseDownListBoxController(m_pSortingCell);
|
|
break;
|
|
|
|
case COLUMN_ID_FIELDNAME:
|
|
pReturn = new DbaMouseDownListBoxController(m_pFieldNameCell);
|
|
break;
|
|
|
|
default:
|
|
OSL_FAIL("IndexFieldsControl::GetController: invalid column id!");
|
|
}
|
|
|
|
if (pReturn)
|
|
pReturn->SetAdditionalModifyHdl(LINK(this, IndexFieldsControl, OnListEntrySelected));
|
|
|
|
return pReturn;
|
|
}
|
|
|
|
bool IndexFieldsControl::implGetFieldDesc(sal_Int32 _nRow, IndexFields::const_iterator& _rPos)
|
|
{
|
|
_rPos = m_aFields.end();
|
|
if ((_nRow < 0) || (o3tl::make_unsigned(_nRow) >= m_aFields.size()))
|
|
return false;
|
|
_rPos = m_aFields.begin() + _nRow;
|
|
return true;
|
|
}
|
|
|
|
bool IndexFieldsControl::SaveModified()
|
|
{
|
|
if (!IsModified())
|
|
return true;
|
|
|
|
switch (GetCurColumnId())
|
|
{
|
|
case COLUMN_ID_FIELDNAME:
|
|
{
|
|
weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
|
|
OUString sFieldSelected = rNameListBox.get_active_text();
|
|
bool bEmptySelected = sFieldSelected.isEmpty();
|
|
if (isNewField())
|
|
{
|
|
if (!bEmptySelected)
|
|
{
|
|
// add a new field to the collection
|
|
OIndexField aNewField;
|
|
aNewField.sFieldName = sFieldSelected;
|
|
m_aFields.push_back(aNewField);
|
|
RowInserted(GetRowCount());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sal_Int32 nRow = GetCurRow();
|
|
OSL_ENSURE(nRow < static_cast<sal_Int32>(m_aFields.size()), "IndexFieldsControl::SaveModified: invalid current row!");
|
|
if (nRow >= 0) // may be -1 in case the control was empty
|
|
{
|
|
// remove the field from the selection
|
|
IndexFields::iterator aPos = m_aFields.begin() + nRow;
|
|
|
|
if (bEmptySelected)
|
|
{
|
|
aPos->sFieldName.clear();
|
|
|
|
// invalidate the row to force repaint
|
|
Invalidate(GetRowRectPixel(nRow));
|
|
return true;
|
|
}
|
|
|
|
if (sFieldSelected == aPos->sFieldName)
|
|
// nothing changed
|
|
return true;
|
|
|
|
aPos->sFieldName = sFieldSelected;
|
|
}
|
|
}
|
|
|
|
Invalidate(GetRowRectPixel(GetCurRow()));
|
|
}
|
|
break;
|
|
case COLUMN_ID_ORDER:
|
|
{
|
|
OSL_ENSURE(!isNewField(), "IndexFieldsControl::SaveModified: why the hell ...!!!");
|
|
// selected entry
|
|
weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
|
|
sal_Int32 nPos = rSortingListBox.get_active();
|
|
OSL_ENSURE(nPos != -1, "IndexFieldsControl::SaveModified: how did you get this selection??");
|
|
// adjust the sort flag in the index field description
|
|
OIndexField& rCurrentField = m_aFields[GetCurRow()];
|
|
rCurrentField.bSortAscending = (0 == nPos);
|
|
|
|
}
|
|
break;
|
|
default:
|
|
OSL_FAIL("IndexFieldsControl::SaveModified: invalid column id!");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void IndexFieldsControl::InitController(CellControllerRef& /*_rController*/, sal_Int32 _nRow, sal_uInt16 _nColumnId)
|
|
{
|
|
IndexFields::const_iterator aFieldDescription;
|
|
bool bNewField = !implGetFieldDesc(_nRow, aFieldDescription);
|
|
|
|
switch (_nColumnId)
|
|
{
|
|
case COLUMN_ID_FIELDNAME:
|
|
{
|
|
weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
|
|
rNameListBox.set_active_text(bNewField ? OUString() : aFieldDescription->sFieldName);
|
|
rNameListBox.save_value();
|
|
break;
|
|
}
|
|
|
|
case COLUMN_ID_ORDER:
|
|
{
|
|
weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
|
|
rSortingListBox.set_active_text(aFieldDescription->bSortAscending ? m_sAscendingText : m_sDescendingText);
|
|
rSortingListBox.save_value();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
OSL_FAIL("IndexFieldsControl::InitController: invalid column id!");
|
|
}
|
|
}
|
|
|
|
IMPL_LINK( IndexFieldsControl, OnListEntrySelected, DbaMouseDownListBoxController&, rController, void )
|
|
{
|
|
weld::ComboBox& rListBox = rController.GetListBox();
|
|
if (!rListBox.get_popup_shown())
|
|
m_aModifyHdl.Call(*this);
|
|
|
|
if (&rListBox != &m_pFieldNameCell->get_widget())
|
|
return;
|
|
|
|
// a field has been selected
|
|
if (GetCurRow() >= GetRowCount() - 2)
|
|
{ // and we're in one of the last two rows
|
|
OUString sSelectedEntry = rListBox.get_active_text();
|
|
sal_Int32 nCurrentRow = GetCurRow();
|
|
sal_Int32 rowCount = GetRowCount();
|
|
|
|
OSL_ENSURE((static_cast<sal_Int32>(m_aFields.size() + 1)) == rowCount, "IndexFieldsControl::OnListEntrySelected: inconsistence!");
|
|
|
|
if (!sSelectedEntry.isEmpty() && (nCurrentRow == rowCount - 1) /*&& (!m_nMaxColumnsInIndex || rowCount < m_nMaxColumnsInIndex )*/ )
|
|
{ // in the last row, a non-empty string has been selected
|
|
// -> insert a new row
|
|
m_aFields.emplace_back();
|
|
RowInserted(GetRowCount());
|
|
Invalidate(GetRowRectPixel(nCurrentRow));
|
|
}
|
|
else if (sSelectedEntry.isEmpty() && (nCurrentRow == rowCount - 2))
|
|
{ // in the (last-1)th row, an empty entry has been selected
|
|
// -> remove the last row
|
|
m_aFields.pop_back();
|
|
RowRemoved(GetRowCount() - 1);
|
|
Invalidate(GetRowRectPixel(nCurrentRow));
|
|
}
|
|
}
|
|
|
|
SaveModified();
|
|
}
|
|
OUString IndexFieldsControl::GetCellText(sal_Int32 _nRow,sal_uInt16 nColId) const
|
|
{
|
|
IndexFields::const_iterator aRow = m_aFields.end();
|
|
if ( _nRow >= 0 )
|
|
{
|
|
aRow = m_aFields.begin() + _nRow;
|
|
OSL_ENSURE(aRow <= m_aFields.end(), "IndexFieldsControl::SeekRow: invalid row!");
|
|
}
|
|
return GetRowCellText(aRow,nColId);
|
|
}
|
|
OUString IndexFieldsControl::GetRowCellText(const IndexFields::const_iterator& _rRow,sal_uInt16 nColId) const
|
|
{
|
|
if (_rRow < m_aFields.end())
|
|
{
|
|
switch (nColId)
|
|
{
|
|
case COLUMN_ID_FIELDNAME:
|
|
return _rRow->sFieldName;
|
|
case COLUMN_ID_ORDER:
|
|
if (_rRow->sFieldName.isEmpty())
|
|
return OUString();
|
|
else
|
|
return _rRow->bSortAscending ? m_sAscendingText : m_sDescendingText;
|
|
default:
|
|
OSL_FAIL("IndexFieldsControl::GetCurrentRowCellText: invalid column id!");
|
|
}
|
|
}
|
|
return OUString();
|
|
}
|
|
bool IndexFieldsControl::IsTabAllowed(bool /*bForward*/) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
} // namespace dbaui
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|