blob: 9e4b316666f4dee4fe62320ffcc06247b6b81f97 [file] [log] [blame]
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the Collabora Office 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/.
*/
#include <QtInstanceTreeView.hxx>
#include <QtInstanceTreeView.moc>
#include <vcl/qt/QtUtils.hxx>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QToolTip>
// role used for the ID in the QStandardItem
constexpr int ROLE_ID = Qt::UserRole + 1000;
// Property used to store the supported roles for each of the columns
const char* const PROPERTY_COLUMN_ROLES = "column-roles";
QtInstanceTreeView::QtInstanceTreeView(QTreeView* pTreeView)
: QtInstanceWidget(pTreeView)
, m_pTreeView(pTreeView)
{
assert(m_pTreeView);
m_pModel = qobject_cast<QSortFilterProxyModel*>(m_pTreeView->model());
assert(m_pModel && "tree view doesn't have expected QSortFilterProxyModel set");
m_pSourceModel = qobject_cast<QStandardItemModel*>(m_pModel->sourceModel());
assert(m_pSourceModel && "proxy model doesn't have expected source model");
m_pSelectionModel = m_pTreeView->selectionModel();
assert(m_pSelectionModel);
m_pColumnRoles = columnRoles(*pTreeView);
assert(m_pColumnRoles.size() == m_pModel->columnCount() && "column count doesn't match");
connect(m_pTreeView, &QTreeView::activated, this, &QtInstanceTreeView::handleActivated);
connect(m_pSelectionModel, &QItemSelectionModel::selectionChanged, this,
&QtInstanceTreeView::handleSelectionChanged);
connect(m_pModel, &QSortFilterProxyModel::dataChanged, this,
&QtInstanceTreeView::handleDataChanged);
assert(m_pTreeView->viewport());
m_pTreeView->viewport()->installEventFilter(this);
}
void QtInstanceTreeView::do_insert(const weld::TreeIter* pParent, int nPos, const OUString* pStr,
const OUString* pId, const OUString* pIconName,
VirtualDevice* pImageSurface, bool bChildrenOnDemand,
weld::TreeIter* pRet)
{
assert(!bChildrenOnDemand && "Not implemented yet");
// avoid -Werror=unused-parameter for release build
(void)bChildrenOnDemand;
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
const QModelIndex aParentIndex
= pParent ? static_cast<const QtInstanceTreeIter*>(pParent)->modelIndex()
: QModelIndex();
if (nPos == -1)
nPos = m_pModel->rowCount(aParentIndex);
m_pModel->insertRow(nPos, aParentIndex);
// ensure parent has same column count as top-level
if (aParentIndex.isValid() && m_pModel->columnCount(aParentIndex) == 0)
m_pModel->insertColumns(0, m_pModel->columnCount(), aParentIndex);
const QModelIndex aIndex = modelIndex(nPos, 0, aParentIndex);
QStandardItem* pItem = itemFromIndex(aIndex);
if (pStr)
set_text(treeIter(nPos, aParentIndex), *pStr);
if (pId)
pItem->setData(toQString(*pId), ROLE_ID);
if (pIconName && !pIconName->isEmpty())
pItem->setIcon(loadQPixmapIcon(*pIconName));
else if (pImageSurface)
pItem->setIcon(toQPixmap(*pImageSurface));
if (m_bExtraToggleButtonsEnabled)
{
// avoid triggering signal_toggled via QtInstanceTreeView::handleDataChanged for new item
QSignalBlocker aSignalBlocker(m_pModel);
itemFromIndex(toggleButtonModelIndex(QtInstanceTreeIter(aIndex)))->setCheckable(true);
}
if (pRet)
static_cast<QtInstanceTreeIter*>(pRet)->setModelIndex(aIndex);
});
}
void QtInstanceTreeView::do_insert_separator(int, const OUString&)
{
assert(false && "Not implemented yet");
}
OUString QtInstanceTreeView::get_selected_text() const
{
SolarMutexGuard g;
OUString sText;
GetQtInstance().RunInMainThread([&] {
const QModelIndexList aSelectedIndexes = m_pSelectionModel->selectedIndexes();
if (aSelectedIndexes.empty())
return;
sText = toOUString(itemFromIndex(aSelectedIndexes.first())->text());
});
return sText;
}
OUString QtInstanceTreeView::get_selected_id() const
{
SolarMutexGuard g;
OUString sId;
GetQtInstance().RunInMainThread([&] {
const QModelIndexList aSelectedIndexes = m_pSelectionModel->selectedIndexes();
if (aSelectedIndexes.empty())
return;
QVariant aIdData = aSelectedIndexes.first().data(ROLE_ID);
if (aIdData.canConvert<QString>())
sId = toOUString(aIdData.toString());
});
return sId;
}
void QtInstanceTreeView::enable_toggle_buttons(weld::ColumnToggleType)
{
assert(m_pModel->rowCount() == 0 && "Must be called before inserting any data");
m_bExtraToggleButtonsEnabled = true;
m_pTreeView->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
}
void QtInstanceTreeView::set_clicks_to_toggle(int) { assert(false && "Not implemented yet"); }
int QtInstanceTreeView::get_selected_index() const
{
SolarMutexGuard g;
int nIndex = -1;
GetQtInstance().RunInMainThread([&] {
const QModelIndexList aSelectedIndexes = m_pSelectionModel->selectedIndexes();
if (aSelectedIndexes.empty())
return;
nIndex = aSelectedIndexes.first().row();
});
return nIndex;
}
void QtInstanceTreeView::do_select(int nPos) { do_select(treeIter(nPos)); }
void QtInstanceTreeView::do_unselect(int nPos) { do_unselect(treeIter(nPos)); }
void QtInstanceTreeView::do_remove(int nPos) { do_remove(treeIter(nPos)); }
OUString QtInstanceTreeView::get_text(int nRow, int nCol) const
{
return get_text(treeIter(nRow), nCol);
}
void QtInstanceTreeView::set_text(int nRow, const OUString& rText, int nCol)
{
set_text(treeIter(nRow), rText, nCol);
}
void QtInstanceTreeView::set_sensitive(int nRow, bool bSensitive, int nCol)
{
set_sensitive(treeIter(nRow), bSensitive, nCol);
}
bool QtInstanceTreeView::get_sensitive(int nRow, int nCol) const
{
return get_sensitive(treeIter(nRow), nCol);
}
void QtInstanceTreeView::set_id(int nRow, const OUString& rId) { set_id(treeIter(nRow), rId); }
void QtInstanceTreeView::set_toggle(int nRow, TriState eState, int nCol)
{
set_toggle(treeIter(nRow), eState, nCol);
}
TriState QtInstanceTreeView::get_toggle(int nRow, int nCol) const
{
return get_toggle(treeIter(nRow), nCol);
}
void QtInstanceTreeView::set_image(int nRow, const OUString& rImage, int nCol)
{
set_image(treeIter(nRow), rImage, nCol);
}
void QtInstanceTreeView::set_image(int nRow, VirtualDevice& rImage, int nCol)
{
set_image(treeIter(nRow), rImage, nCol);
}
void QtInstanceTreeView::set_image(int nRow,
const css::uno::Reference<css::graphic::XGraphic>& rImage,
int nCol)
{
set_image(treeIter(nRow), rImage, nCol);
}
void QtInstanceTreeView::set_text_emphasis(int nRow, bool bOn, int nCol)
{
return set_text_emphasis(treeIter(nRow), bOn, nCol);
}
bool QtInstanceTreeView::get_text_emphasis(int nRow, int nCol) const
{
return get_text_emphasis(treeIter(nRow), nCol);
}
void QtInstanceTreeView::set_text_align(int nRow, double fAlign, int nCol)
{
return set_text_align(treeIter(nRow), fAlign, nCol);
}
void QtInstanceTreeView::swap(int nPos1, int nPos2)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
const bool bPos1Selected = m_pSelectionModel->isRowSelected(nPos1);
const bool bPos2Selected = m_pSelectionModel->isRowSelected(nPos2);
const int nSourceModelPos1 = m_pModel->mapToSource(modelIndex(nPos1)).row();
const int nSourceModelPos2 = m_pModel->mapToSource(modelIndex(nPos2)).row();
const int nMin = std::min(nSourceModelPos1, nSourceModelPos2);
const int nMax = std::max(nSourceModelPos1, nSourceModelPos2);
QList<QStandardItem*> aMaxRow = m_pSourceModel->takeRow(nMax);
QList<QStandardItem*> aMinRow = m_pSourceModel->takeRow(nMin);
m_pSourceModel->insertRow(nMin, aMaxRow);
m_pSourceModel->insertRow(nMax, aMinRow);
// restore selection
if (bPos1Selected)
select(m_pModel->mapFromSource(m_pSourceModel->index(nSourceModelPos2, 0)).row());
if (bPos2Selected)
select(m_pModel->mapFromSource(m_pSourceModel->index(nSourceModelPos1, 0)).row());
});
}
std::vector<int> QtInstanceTreeView::get_selected_rows() const
{
SolarMutexGuard g;
std::vector<int> aSelectedRows;
GetQtInstance().RunInMainThread([&] {
const QModelIndexList aSelectionIndexes = m_pSelectionModel->selectedRows();
for (const QModelIndex& aIndex : aSelectionIndexes)
aSelectedRows.push_back(aIndex.row());
});
return aSelectedRows;
}
void QtInstanceTreeView::set_font_color(int nPos, const Color& rColor)
{
set_font_color(treeIter(nPos), rColor);
}
void QtInstanceTreeView::do_scroll_to_row(int nRow) { scroll_to_row(treeIter(nRow)); }
bool QtInstanceTreeView::is_selected(int nPos) const { return is_selected(treeIter(nPos)); }
int QtInstanceTreeView::get_cursor_index() const
{
SolarMutexGuard g;
int nIndex = -1;
GetQtInstance().RunInMainThread([&] {
const QModelIndex aCurrentIndex = m_pSelectionModel->currentIndex();
if (aCurrentIndex.isValid())
nIndex = aCurrentIndex.row();
});
return nIndex;
}
void QtInstanceTreeView::do_set_cursor(int nPos) { do_set_cursor(treeIter(nPos)); }
int QtInstanceTreeView::find_text(const OUString& rText) const
{
SolarMutexGuard g;
int nIndex = -1;
GetQtInstance().RunInMainThread([&] {
// search in underlying QStandardItemModel and map index
const QList<QStandardItem*> aItems = m_pSourceModel->findItems(toQString(rText));
if (!aItems.empty())
nIndex = m_pModel->mapFromSource(aItems.at(0)->index()).row();
});
return nIndex;
}
OUString QtInstanceTreeView::get_id(int nPos) const { return get_id(treeIter(nPos)); }
int QtInstanceTreeView::find_id(const OUString& rId) const
{
SolarMutexGuard g;
int nIndex = -1;
GetQtInstance().RunInMainThread([&] {
for (int i = 0; i < m_pModel->rowCount(); i++)
{
if (get_id(i) == rId)
{
nIndex = i;
return;
}
}
});
return nIndex;
}
std::unique_ptr<weld::TreeIter> QtInstanceTreeView::make_iterator(const weld::TreeIter* pOrig) const
{
const QModelIndex aIndex = pOrig ? modelIndex(*pOrig) : QModelIndex();
return std::make_unique<QtInstanceTreeIter>(aIndex);
}
void QtInstanceTreeView::copy_iterator(const weld::TreeIter& rSource, weld::TreeIter& rDest) const
{
const QModelIndex aModelIndex = static_cast<const QtInstanceTreeIter&>(rSource).modelIndex();
static_cast<QtInstanceTreeIter&>(rDest).setModelIndex(aModelIndex);
}
bool QtInstanceTreeView::get_selected(weld::TreeIter* pIter) const
{
SolarMutexGuard g;
bool bHasSelection = false;
GetQtInstance().RunInMainThread([&] {
const QModelIndexList aSelectedIndexes = m_pSelectionModel->selectedIndexes();
if (aSelectedIndexes.empty())
return;
bHasSelection = true;
if (pIter)
static_cast<QtInstanceTreeIter*>(pIter)->setModelIndex(aSelectedIndexes.first());
});
return bHasSelection;
}
bool QtInstanceTreeView::get_cursor(weld::TreeIter* pIter) const
{
SolarMutexGuard g;
bool bRet = false;
GetQtInstance().RunInMainThread([&] {
const QModelIndex aCurrentIndex = m_pTreeView->currentIndex();
QtInstanceTreeIter* pQtIter = static_cast<QtInstanceTreeIter*>(pIter);
if (pQtIter)
pQtIter->setModelIndex(aCurrentIndex);
bRet = aCurrentIndex.isValid();
});
return bRet;
}
void QtInstanceTreeView::do_set_cursor(const weld::TreeIter& rIter)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] { m_pTreeView->setCurrentIndex(modelIndex(rIter)); });
}
bool QtInstanceTreeView::get_iter_first(weld::TreeIter& rIter) const
{
QtInstanceTreeIter& rQtIter = static_cast<QtInstanceTreeIter&>(rIter);
const QModelIndex aIndex = modelIndex(0);
rQtIter.setModelIndex(aIndex);
return aIndex.isValid();
}
bool QtInstanceTreeView::iter_next_sibling(weld::TreeIter& rIter) const
{
QtInstanceTreeIter& rQtIter = static_cast<QtInstanceTreeIter&>(rIter);
const QModelIndex aIndex = rQtIter.modelIndex();
const QModelIndex aSiblingIndex = m_pModel->sibling(aIndex.row() + 1, 0, aIndex);
rQtIter.setModelIndex(aSiblingIndex);
return aSiblingIndex.isValid();
}
bool QtInstanceTreeView::iter_previous_sibling(weld::TreeIter& rIter) const
{
QtInstanceTreeIter& rQtIter = static_cast<QtInstanceTreeIter&>(rIter);
const QModelIndex aIndex = rQtIter.modelIndex();
const QModelIndex aSiblingIndex = m_pModel->sibling(aIndex.row() - 1, 0, aIndex);
rQtIter.setModelIndex(aSiblingIndex);
return aSiblingIndex.isValid();
}
bool QtInstanceTreeView::iter_next(weld::TreeIter& rIter) const
{
QtInstanceTreeIter& rQtIter = static_cast<QtInstanceTreeIter&>(rIter);
QModelIndex aIndex = rQtIter.modelIndex();
if (m_pModel->hasChildren(aIndex))
{
rQtIter.setModelIndex(modelIndex(0, 0, aIndex));
return true;
}
while (aIndex.isValid())
{
const QModelIndex aSiblingIndex = m_pModel->sibling(aIndex.row() + 1, 0, aIndex);
if (aSiblingIndex.isValid())
{
rQtIter.setModelIndex(aSiblingIndex);
return true;
}
aIndex = aIndex.parent();
}
return false;
}
bool QtInstanceTreeView::iter_previous(weld::TreeIter&) const
{
assert(false && "Not implemented yet");
return false;
}
bool QtInstanceTreeView::iter_children(weld::TreeIter& rIter) const
{
QtInstanceTreeIter& rQtIter = static_cast<QtInstanceTreeIter&>(rIter);
const QModelIndex aChildIndex = m_pModel->index(0, 0, rQtIter.modelIndex());
rQtIter.setModelIndex(aChildIndex);
return aChildIndex.isValid();
}
bool QtInstanceTreeView::iter_parent(weld::TreeIter& rIter) const
{
QtInstanceTreeIter& rQtIter = static_cast<QtInstanceTreeIter&>(rIter);
const QModelIndex aParentIndex = rQtIter.modelIndex().parent();
rQtIter.setModelIndex(aParentIndex);
return aParentIndex.isValid();
}
int QtInstanceTreeView::get_iter_depth(const weld::TreeIter& rIter) const
{
const QtInstanceTreeIter& rQtIter = static_cast<const QtInstanceTreeIter&>(rIter);
int nDepth = 0;
QModelIndex aParentIndex = rQtIter.modelIndex().parent();
while (aParentIndex.isValid())
{
nDepth++;
aParentIndex = aParentIndex.parent();
}
return nDepth;
}
int QtInstanceTreeView::get_iter_index_in_parent(const weld::TreeIter& rIter) const
{
SolarMutexGuard g;
int nIndex;
GetQtInstance().RunInMainThread([&] {
const QModelIndex aIndex = modelIndex(rIter);
nIndex = aIndex.row();
});
return nIndex;
}
int QtInstanceTreeView::iter_compare(const weld::TreeIter&, const weld::TreeIter&) const
{
assert(false && "Not implemented yet");
return 0;
}
bool QtInstanceTreeView::iter_has_child(const weld::TreeIter& rIter) const
{
const QtInstanceTreeIter& rQtIter = static_cast<const QtInstanceTreeIter&>(rIter);
return m_pModel->hasChildren(rQtIter.modelIndex());
}
int QtInstanceTreeView::iter_n_children(const weld::TreeIter& rIter) const
{
const QtInstanceTreeIter& rQtIter = static_cast<const QtInstanceTreeIter&>(rIter);
return m_pModel->rowCount(rQtIter.modelIndex());
}
void QtInstanceTreeView::do_remove(const weld::TreeIter& rIter)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
const QModelIndex aIndex = modelIndex(rIter);
m_pModel->removeRow(aIndex.row(), aIndex.parent());
});
}
void QtInstanceTreeView::do_select(const weld::TreeIter& rIter)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
QItemSelectionModel::SelectionFlags eFlags
= QItemSelectionModel::Select | QItemSelectionModel::Rows;
if (m_pTreeView->selectionMode() == QAbstractItemView::SingleSelection)
eFlags |= QItemSelectionModel::Clear;
m_pSelectionModel->select(modelIndex(rIter), eFlags);
});
}
void QtInstanceTreeView::do_unselect(const weld::TreeIter& rIter)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread(
[&] { m_pSelectionModel->select(modelIndex(rIter), QItemSelectionModel::Deselect); });
}
void QtInstanceTreeView::set_extra_row_indent(const weld::TreeIter&, int)
{
assert(false && "Not implemented yet");
}
void QtInstanceTreeView::set_text(const weld::TreeIter& rIter, const OUString& rStr, int nCol)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
const QModelIndex aIndex
= nCol == -1 ? firstTextColumnModelIndex(rIter) : modelIndex(rIter, nCol);
m_pModel->setData(aIndex, toQString(rStr));
});
}
void QtInstanceTreeView::set_sensitive(const weld::TreeIter& rIter, bool bSensitive, int nCol)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
// column index -1 means "all columns"
if (nCol == -1)
{
for (int i = 0; i < m_pModel->columnCount(); ++i)
set_sensitive(rIter, bSensitive, i);
return;
}
QStandardItem* pItem = itemFromIndex(modelIndex(rIter, nCol));
if (pItem)
{
if (bSensitive)
pItem->setFlags(pItem->flags() | Qt::ItemIsEnabled);
else
pItem->setFlags(pItem->flags() & ~Qt::ItemIsEnabled);
}
});
}
bool QtInstanceTreeView::get_sensitive(const weld::TreeIter& rIter, int nCol) const
{
SolarMutexGuard g;
bool bSensitive = false;
GetQtInstance().RunInMainThread([&] {
QStandardItem* pItem = itemFromIndex(modelIndex(rIter, nCol));
if (pItem)
bSensitive = pItem->flags() & Qt::ItemIsEnabled;
});
return bSensitive;
}
void QtInstanceTreeView::set_text_emphasis(const weld::TreeIter&, bool, int)
{
assert(false && "Not implemented yet");
}
bool QtInstanceTreeView::get_text_emphasis(const weld::TreeIter&, int) const
{
assert(false && "Not implemented yet");
return false;
}
void QtInstanceTreeView::set_text_align(const weld::TreeIter&, double, int)
{
assert(false && "Not implemented yet");
}
void QtInstanceTreeView::set_toggle(const weld::TreeIter& rIter, TriState eState, int nCol)
{
SolarMutexGuard g;
assert((nCol != 0 || !m_bExtraToggleButtonsEnabled)
&& "Column 0 is already used by \"expander toggle\" using special index -1");
GetQtInstance().RunInMainThread([&] {
QModelIndex aIndex = nCol == -1 ? toggleButtonModelIndex(rIter) : modelIndex(rIter, nCol);
itemFromIndex(aIndex)->setCheckState(toQtCheckState(eState));
});
}
TriState QtInstanceTreeView::get_toggle(const weld::TreeIter& rIter, int nCol) const
{
SolarMutexGuard g;
assert((nCol != 0 || !m_bExtraToggleButtonsEnabled)
&& "Column 0 is already used by \"expander toggle\" using special index -1");
TriState eState = TRISTATE_INDET;
GetQtInstance().RunInMainThread([&] {
QModelIndex aIndex = nCol == -1 ? toggleButtonModelIndex(rIter) : modelIndex(rIter, nCol);
eState = toVclTriState(itemFromIndex(aIndex)->checkState());
});
return eState;
}
OUString QtInstanceTreeView::get_text(const weld::TreeIter& rIter, int nCol) const
{
SolarMutexGuard g;
OUString sText;
GetQtInstance().RunInMainThread([&] {
const QModelIndex aIndex
= nCol == -1 ? firstTextColumnModelIndex(rIter) : modelIndex(rIter, nCol);
const QVariant aData = m_pModel->data(aIndex);
if (aData.canConvert<QString>())
sText = toOUString(aData.toString());
});
return sText;
}
void QtInstanceTreeView::set_id(const weld::TreeIter& rIter, const OUString& rId)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread(
[&] { m_pModel->setData(modelIndex(rIter), toQString(rId), ROLE_ID); });
}
OUString QtInstanceTreeView::get_id(const weld::TreeIter& rIter) const
{
SolarMutexGuard g;
OUString sId;
GetQtInstance().RunInMainThread([&] {
QVariant aRoleData = m_pModel->data(modelIndex(rIter), ROLE_ID);
if (aRoleData.canConvert<QString>())
sId = toOUString(aRoleData.toString());
});
return sId;
}
void QtInstanceTreeView::set_image(const weld::TreeIter& rIter, const OUString& rImage, int nCol)
{
if (rImage.isEmpty())
return;
setImage(rIter, loadQPixmapIcon(rImage), nCol);
}
void QtInstanceTreeView::set_image(const weld::TreeIter& rIter, VirtualDevice& rImage, int nCol)
{
setImage(rIter, toQPixmap(rImage), nCol);
}
void QtInstanceTreeView::set_image(const weld::TreeIter& rIter,
const css::uno::Reference<css::graphic::XGraphic>& rImage,
int nCol)
{
setImage(rIter, toQPixmap(rImage), nCol);
}
void QtInstanceTreeView::set_font_color(const weld::TreeIter& rIter, const Color& rColor)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
for (int nCol = 0; nCol < m_pModel->columnCount(); nCol++)
{
QModelIndex aIndex = modelIndex(rIter, nCol);
m_pModel->setData(aIndex, QBrush(toQColor(rColor)), Qt::ForegroundRole);
}
});
}
void QtInstanceTreeView::do_scroll_to_row(const weld::TreeIter& rIter)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] { m_pTreeView->scrollTo(modelIndex(rIter)); });
}
bool QtInstanceTreeView::is_selected(const weld::TreeIter& rIter) const
{
SolarMutexGuard g;
bool bSelected = false;
GetQtInstance().RunInMainThread(
[&] { bSelected = m_pSelectionModel->isSelected(modelIndex(rIter)); });
return bSelected;
}
void QtInstanceTreeView::move_subtree(weld::TreeIter&, const weld::TreeIter*, int)
{
assert(false && "Not implemented yet");
}
void QtInstanceTreeView::all_foreach(const std::function<bool(weld::TreeIter&)>& func)
{
QtInstanceTreeIter aIter({});
if (get_iter_first(aIter))
{
do
{
if (func(aIter))
return;
} while (iter_next(aIter));
}
}
void QtInstanceTreeView::selected_foreach(const std::function<bool(weld::TreeIter&)>& func)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
QModelIndexList aSelectionIndexes = m_pSelectionModel->selectedRows();
for (QModelIndex& aIndex : aSelectionIndexes)
{
QtInstanceTreeIter aIter(aIndex);
if (func(aIter))
return;
}
});
}
void QtInstanceTreeView::visible_foreach(const std::function<bool(weld::TreeIter&)>&)
{
assert(false && "Not implemented yet");
}
void QtInstanceTreeView::bulk_insert_for_each(
int nSourceCount, const std::function<void(weld::TreeIter&, int nSourceIndex)>& func,
const weld::TreeIter* pParent, const std::vector<int>* pFixedWidths, bool)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
// clear existing children
const QModelIndex aParentIndex = pParent ? modelIndex(*pParent) : QModelIndex();
const int nRows = m_pModel->rowCount(aParentIndex);
if (nRows > 0)
m_pModel->removeRows(0, nRows, aParentIndex);
// insert new rows
m_pModel->insertRows(0, nSourceCount, aParentIndex);
// call function for each row
for (int nRow = 0; nRow < nSourceCount; nRow++)
{
QtInstanceTreeIter aIter = treeIter(nRow, aParentIndex);
func(aIter, nRow);
}
// set column widths
if (pFixedWidths)
set_column_fixed_widths(*pFixedWidths);
});
}
bool QtInstanceTreeView::get_row_expanded(const weld::TreeIter& rIter) const
{
SolarMutexGuard g;
bool bExpanded = false;
GetQtInstance().RunInMainThread(
[&] { bExpanded = m_pTreeView->isExpanded(modelIndex(rIter)); });
return bExpanded;
}
void QtInstanceTreeView::expand_row(const weld::TreeIter& rIter)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] { m_pTreeView->expand(modelIndex(rIter)); });
}
void QtInstanceTreeView::collapse_row(const weld::TreeIter& rIter)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] { m_pTreeView->collapse(modelIndex(rIter)); });
}
void QtInstanceTreeView::do_set_children_on_demand(const weld::TreeIter&, bool)
{
assert(false && "Not implemented yet");
}
bool QtInstanceTreeView::get_children_on_demand(const weld::TreeIter&) const
{
assert(false && "Not implemented yet");
return false;
}
void QtInstanceTreeView::set_show_expanders(bool) { assert(false && "Not implemented yet"); }
void QtInstanceTreeView::start_editing(const weld::TreeIter&)
{
assert(false && "Not implemented yet");
}
void QtInstanceTreeView::end_editing() { assert(false && "Not implemented yet"); }
void QtInstanceTreeView::enable_drag_source(rtl::Reference<TransferDataContainer>&, sal_uInt8)
{
assert(false && "Not implemented yet");
}
void QtInstanceTreeView::select_all()
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] { m_pTreeView->selectAll(); });
}
void QtInstanceTreeView::unselect_all()
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] { m_pTreeView->clearSelection(); });
}
int QtInstanceTreeView::n_children() const
{
SolarMutexGuard g;
int nChildCount;
GetQtInstance().RunInMainThread([&] {
const QModelIndex aRootIndex
= m_pModel->mapFromSource(m_pSourceModel->invisibleRootItem()->index());
nChildCount = m_pModel->rowCount(aRootIndex);
});
return nChildCount;
}
void QtInstanceTreeView::make_sorted()
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
m_pTreeView->setSortingEnabled(true);
// sort by first column
m_pModel->sort(0);
});
}
void QtInstanceTreeView::make_unsorted()
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
m_pTreeView->setSortingEnabled(false);
m_pModel->sort(-1);
});
}
bool QtInstanceTreeView::get_sort_order() const
{
SolarMutexGuard g;
bool bAscending = true;
GetQtInstance().RunInMainThread(
[&] { bAscending = m_pModel->sortOrder() == Qt::AscendingOrder; });
return bAscending;
}
void QtInstanceTreeView::set_sort_order(bool bAscending)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
const Qt::SortOrder eOrder = bAscending ? Qt::AscendingOrder : Qt::DescendingOrder;
m_pModel->sort(m_pModel->sortColumn(), eOrder);
});
}
void QtInstanceTreeView::set_sort_indicator(TriState, int)
{
assert(false && "Not implemented yet");
}
TriState QtInstanceTreeView::get_sort_indicator(int) const
{
assert(false && "Not implemented yet");
return TRISTATE_INDET;
}
int QtInstanceTreeView::get_sort_column() const
{
SolarMutexGuard g;
int nSortColumn = 0;
GetQtInstance().RunInMainThread([&] { nSortColumn = m_pModel->sortColumn(); });
return nSortColumn;
}
void QtInstanceTreeView::set_sort_column(int nColumn)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] { m_pModel->sort(nColumn); });
}
void QtInstanceTreeView::do_clear()
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
// don't use QStandardItemModel::clear, as that would remove header data as well
m_pModel->removeRows(0, m_pModel->rowCount());
});
}
int QtInstanceTreeView::get_height_rows(int) const
{
SAL_WARN("vcl.qt", "QtInstanceTreeView::get_height_rows just returns 0 for now");
return 0;
}
void QtInstanceTreeView::columns_autosize()
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
for (int i = 0; i < m_pModel->columnCount(); i++)
m_pTreeView->resizeColumnToContents(i);
});
}
void QtInstanceTreeView::set_column_fixed_widths(const std::vector<int>& rWidths)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
assert(rWidths.size() <= o3tl::make_unsigned(m_pModel->columnCount()));
for (size_t i = 0; i < rWidths.size(); ++i)
m_pTreeView->setColumnWidth(i, rWidths.at(i));
});
}
void QtInstanceTreeView::set_column_editables(const std::vector<bool>&)
{
assert(false && "Not implemented yet");
}
int QtInstanceTreeView::get_column_width(int nCol) const
{
SolarMutexGuard g;
int nWidth = 0;
GetQtInstance().RunInMainThread([&] { nWidth = m_pTreeView->columnWidth(nCol); });
return nWidth;
}
void QtInstanceTreeView::set_centered_column(int) { assert(false && "Not implemented yet"); }
OUString QtInstanceTreeView::get_column_title(int nColumn) const
{
SolarMutexGuard g;
OUString sTitle;
GetQtInstance().RunInMainThread([&] {
const QVariant aVariant = m_pModel->headerData(nColumn, Qt::Horizontal);
assert(aVariant.isValid() && aVariant.canConvert<QString>());
sTitle = toOUString(aVariant.toString());
});
return sTitle;
}
void QtInstanceTreeView::set_column_title(int nColumn, const OUString& rTitle)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread(
[&] { m_pModel->setHeaderData(nColumn, Qt::Horizontal, toQString(rTitle)); });
}
void QtInstanceTreeView::set_selection_mode(SelectionMode eMode)
{
SolarMutexGuard g;
GetQtInstance().RunInMainThread(
[&] { m_pTreeView->setSelectionMode(mapSelectionMode(eMode)); });
}
int QtInstanceTreeView::count_selected_rows() const { return get_selected_rows().size(); }
void QtInstanceTreeView::do_remove_selection() { assert(false && "Not implemented yet"); }
bool QtInstanceTreeView::changed_by_hover() const
{
assert(false && "Not implemented yet");
return false;
}
void QtInstanceTreeView::vadjustment_set_value(int) { assert(false && "Not implemented yet"); }
int QtInstanceTreeView::vadjustment_get_value() const
{
assert(false && "Not implemented yet");
return -1;
}
void QtInstanceTreeView::set_column_custom_renderer(int, bool)
{
assert(false && "Not implemented yet");
}
void QtInstanceTreeView::queue_draw() { assert(false && "Not implemented yet"); }
bool QtInstanceTreeView::get_dest_row_at_pos(const Point&, weld::TreeIter*, bool, bool)
{
assert(false && "Not implemented yet");
return false;
}
void QtInstanceTreeView::unset_drag_dest_row() { assert(false && "Not implemented yet"); }
tools::Rectangle QtInstanceTreeView::get_row_area(const weld::TreeIter&) const
{
assert(false && "Not implemented yet");
return tools::Rectangle();
}
weld::TreeView* QtInstanceTreeView::get_drag_source() const
{
assert(false && "Not implemented yet");
return nullptr;
}
QAbstractItemView::SelectionMode QtInstanceTreeView::mapSelectionMode(SelectionMode eMode)
{
switch (eMode)
{
case SelectionMode::NONE:
return QAbstractItemView::NoSelection;
case SelectionMode::Single:
return QAbstractItemView::SingleSelection;
case SelectionMode::Range:
return QAbstractItemView::ContiguousSelection;
case SelectionMode::Multiple:
return QAbstractItemView::ExtendedSelection;
default:
assert(false && "unhandled selection mode");
return QAbstractItemView::SingleSelection;
}
}
QList<QList<Qt::ItemDataRole>> QtInstanceTreeView::columnRoles(QTreeView& rTreeView)
{
QVariant aVariant = rTreeView.property(PROPERTY_COLUMN_ROLES);
if (aVariant.isValid())
{
assert(aVariant.canConvert<QList<QList<Qt::ItemDataRole>>>());
return aVariant.value<QList<QList<Qt::ItemDataRole>>>();
}
return {};
}
void QtInstanceTreeView::setColumnRoles(QTreeView& rTreeView,
const QList<QList<Qt::ItemDataRole>>& rDataRoles)
{
rTreeView.setProperty(PROPERTY_COLUMN_ROLES, QVariant::fromValue(rDataRoles));
}
bool QtInstanceTreeView::eventFilter(QObject* pObject, QEvent* pEvent)
{
if (pEvent->type() == QEvent::ToolTip && pObject == m_pTreeView->viewport())
return handleViewPortToolTipEvent(static_cast<QHelpEvent&>(*pEvent));
return QtInstanceWidget::eventFilter(pObject, pEvent);
}
QModelIndex QtInstanceTreeView::modelIndex(int nRow, int nCol,
const QModelIndex& rParentIndex) const
{
return modelIndex(treeIter(nRow, rParentIndex), nCol);
}
QModelIndex QtInstanceTreeView::modelIndex(const weld::TreeIter& rIter, int nCol) const
{
QModelIndex aModelIndex = static_cast<const QtInstanceTreeIter&>(rIter).modelIndex();
return m_pModel->index(aModelIndex.row(), nCol, aModelIndex.parent());
}
QtInstanceTreeIter QtInstanceTreeView::treeIter(int nRow, const QModelIndex& rParentIndex) const
{
return QtInstanceTreeIter(m_pModel->index(nRow, 0, rParentIndex));
}
QStandardItem* QtInstanceTreeView::itemFromIndex(const QModelIndex& rIndex) const
{
const QModelIndex aSourceIndex = m_pModel->mapToSource(rIndex);
return m_pSourceModel->itemFromIndex(aSourceIndex);
}
QModelIndex QtInstanceTreeView::toggleButtonModelIndex(const weld::TreeIter& rIter) const
{
assert(m_bExtraToggleButtonsEnabled && "Special toggle buttons are not enabled");
const QModelIndex aIndex = modelIndex(rIter);
// Special toggle buttons are always in the first column
return m_pModel->index(aIndex.row(), 0, aIndex.parent());
}
QModelIndex QtInstanceTreeView::firstTextColumnModelIndex(const weld::TreeIter& rIter) const
{
for (qsizetype i = 0; i < m_pColumnRoles.size(); i++)
{
if (m_pColumnRoles.at(i).contains(Qt::DisplayRole))
return modelIndex(rIter, i);
}
assert(false && "No text column found");
return QModelIndex();
}
void QtInstanceTreeView::setImage(const weld::TreeIter& rIter, const QPixmap& rPixmap, int nCol)
{
// set the "expander image" for the Qt::DecorationRole in the first column
// It can still contain additional data (like text) for other roles, but not
// another image. If that turns out to be problematic, another solution needs
// to be found.
if (nCol == -1)
nCol = 0;
SolarMutexGuard g;
GetQtInstance().RunInMainThread([&] {
QModelIndex aIndex = modelIndex(rIter, nCol);
m_pModel->setData(aIndex, rPixmap, Qt::DecorationRole);
});
}
bool QtInstanceTreeView::handleViewPortToolTipEvent(const QHelpEvent& rHelpEvent)
{
QModelIndex aIndex = m_pTreeView->indexAt(rHelpEvent.pos());
if (!aIndex.isValid())
return false;
SolarMutexGuard g;
const QtInstanceTreeIter aIter(aIndex);
const OUString sToolTip = signal_query_tooltip(aIter);
if (sToolTip.isEmpty())
return false;
QToolTip::showText(rHelpEvent.globalPos(), toRichTextTooltip(sToolTip), m_pTreeView,
m_pTreeView->visualRect(aIndex));
return true;
}
void QtInstanceTreeView::handleActivated()
{
SolarMutexGuard g;
signal_row_activated();
}
void QtInstanceTreeView::handleDataChanged(const QModelIndex& rTopLeft,
const QModelIndex& rBottomRight,
const QVector<int>& rRoles)
{
SolarMutexGuard g;
// only notify about check state changes
if (!rRoles.contains(Qt::CheckStateRole))
return;
assert(rTopLeft == rBottomRight && "Case of multiple changes not implemented yet");
(void)rBottomRight;
int nColIndex = rTopLeft.column();
if (m_bExtraToggleButtonsEnabled && nColIndex == 0)
// use special index of -1 for the "expander toggle"
nColIndex = -1;
signal_toggled(iter_col(QtInstanceTreeIter(rTopLeft), nColIndex));
}
void QtInstanceTreeView::handleSelectionChanged()
{
SolarMutexGuard g;
signal_selection_changed();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */