DataSourceTreeWidgetItem.cpp
225 lines
| 6.9 KiB
| text/x-c
|
CppLexer
Alexandre Leroux
|
r80 | #include <DataSource/DataSourceItem.h> | ||
Alexandre Leroux
|
r145 | #include <DataSource/DataSourceItemAction.h> | ||
Alexandre Leroux
|
r80 | #include <DataSource/DataSourceTreeWidgetItem.h> | ||
Alexandre Leroux
|
r142 | #include <QAction> | ||
Alexandre Leroux
|
r80 | Q_LOGGING_CATEGORY(LOG_DataSourceTreeWidgetItem, "DataSourceTreeWidgetItem") | ||
Alexandre Leroux
|
r81 | namespace { | ||
Alexandre Leroux
|
r343 | // Column indexes | ||
const auto NAME_COLUMN = 0; | ||||
Alexandre Leroux
|
r1037 | /** | ||
* Generates the full name of an item. | ||||
* | ||||
* The full name of an item is its name possibly suffixed by the name of its plugin, in case there | ||||
* are items of the same name in its relatives | ||||
* @param item the item for which to generate the complete name | ||||
* @return the complete name of the item | ||||
*/ | ||||
QString completeName(const DataSourceItem &item) | ||||
{ | ||||
auto name = item.name(); | ||||
if (item.type() == DataSourceItemType::NODE) { | ||||
return name; | ||||
} | ||||
auto parentItem = item.parentItem(); | ||||
if (!parentItem) { | ||||
return name; | ||||
} | ||||
// Finds in item's relatives items that have the same name | ||||
bool foundSameName = false; | ||||
for (auto i = 0, count = parentItem->childCount(); i < count && !foundSameName; ++i) { | ||||
auto child = parentItem->child(i); | ||||
foundSameName = child != &item | ||||
&& QString::compare(child->name(), item.name(), Qt::CaseInsensitive) == 0; | ||||
} | ||||
// If the name of the item is not unique, it is completed by the plugin suffix | ||||
return foundSameName | ||||
? QString{"%1 (%2)"}.arg(name, item.data(DataSourceItem::PLUGIN_DATA_KEY).toString()) | ||||
: name; | ||||
} | ||||
Alexandre Leroux
|
r81 | QIcon itemIcon(const DataSourceItem *dataSource) | ||
{ | ||||
if (dataSource) { | ||||
auto dataSourceType = dataSource->type(); | ||||
switch (dataSourceType) { | ||||
Alexandre Leroux
|
r345 | case DataSourceItemType::NODE: { | ||
return dataSource->isRoot() ? QIcon{":/icones/dataSourceRoot.png"} | ||||
: QIcon{":/icones/dataSourceNode.png"}; | ||||
} | ||||
Alexandre Leroux
|
r81 | case DataSourceItemType::PRODUCT: | ||
Alexandre Leroux
|
r344 | return QIcon{":/icones/dataSourceProduct.png"}; | ||
case DataSourceItemType::COMPONENT: | ||||
return QIcon{":/icones/dataSourceComponent.png"}; | ||||
Alexandre Leroux
|
r81 | default: | ||
// No action | ||||
break; | ||||
} | ||||
Alexandre Leroux
|
r93 | |||
qCWarning(LOG_DataSourceTreeWidgetItem()) | ||||
<< QObject::tr("Can't set data source icon : unknown data source type"); | ||||
} | ||||
else { | ||||
Alexandre Leroux
|
r345 | qCCritical(LOG_DataSourceTreeWidgetItem()) | ||
Alexandre Leroux
|
r93 | << QObject::tr("Can't set data source icon : the data source is null"); | ||
Alexandre Leroux
|
r81 | } | ||
// Default cases | ||||
return QIcon{}; | ||||
} | ||||
Alexandre Leroux
|
r346 | /// @return the tooltip text for a variant. The text depends on whether the data is a simple variant | ||
/// or a list of variants | ||||
QString tooltipValue(const QVariant &variant) noexcept | ||||
{ | ||||
// If the variant is a list of variants, the text of the tooltip is of the form: {val1, val2, | ||||
// ...} | ||||
if (variant.canConvert<QVariantList>()) { | ||||
auto valueString = QStringLiteral("{"); | ||||
auto variantList = variant.value<QVariantList>(); | ||||
for (auto it = variantList.cbegin(), end = variantList.cend(); it != end; ++it) { | ||||
valueString.append(it->toString()); | ||||
if (std::distance(it, end) != 1) { | ||||
valueString.append(", "); | ||||
} | ||||
} | ||||
valueString.append(QStringLiteral("}")); | ||||
return valueString; | ||||
} | ||||
else { | ||||
return variant.toString(); | ||||
} | ||||
} | ||||
QString itemTooltip(const DataSourceItem *dataSource) noexcept | ||||
{ | ||||
// The tooltip displays all item's data | ||||
if (dataSource) { | ||||
auto result = QString{}; | ||||
const auto &data = dataSource->data(); | ||||
for (auto it = data.cbegin(), end = data.cend(); it != end; ++it) { | ||||
result.append(QString{"<b>%1:</b> %2<br/>"}.arg(it.key(), tooltipValue(it.value()))); | ||||
} | ||||
return result; | ||||
} | ||||
else { | ||||
qCCritical(LOG_DataSourceTreeWidgetItem()) | ||||
<< QObject::tr("Can't set data source tooltip : the data source is null"); | ||||
return QString{}; | ||||
} | ||||
} | ||||
Alexandre Leroux
|
r81 | } // namespace | ||
Alexandre Leroux
|
r80 | struct DataSourceTreeWidgetItem::DataSourceTreeWidgetItemPrivate { | ||
Alexandre Leroux
|
r1037 | explicit DataSourceTreeWidgetItemPrivate(const DataSourceItem *data) | ||
: m_Data{data}, m_Name{completeName(*m_Data)} | ||||
{ | ||||
} | ||||
Alexandre Leroux
|
r80 | |||
/// Model used to retrieve data source information | ||||
const DataSourceItem *m_Data; | ||||
Alexandre Leroux
|
r1037 | /// Name displayed | ||
QString m_Name; | ||||
Alexandre Leroux
|
r142 | /// Actions associated to the item. The parent of the item (QTreeWidget) takes the ownership of | ||
/// the actions | ||||
QList<QAction *> m_Actions; | ||||
Alexandre Leroux
|
r80 | }; | ||
DataSourceTreeWidgetItem::DataSourceTreeWidgetItem(const DataSourceItem *data, int type) | ||||
: DataSourceTreeWidgetItem{nullptr, data, type} | ||||
{ | ||||
} | ||||
DataSourceTreeWidgetItem::DataSourceTreeWidgetItem(QTreeWidget *parent, const DataSourceItem *data, | ||||
int type) | ||||
: QTreeWidgetItem{parent, type}, | ||||
impl{spimpl::make_unique_impl<DataSourceTreeWidgetItemPrivate>(data)} | ||||
{ | ||||
Alexandre Leroux
|
r346 | // Sets the icon and the tooltip depending on the data source | ||
Alexandre Leroux
|
r81 | setIcon(0, itemIcon(impl->m_Data)); | ||
Alexandre Leroux
|
r346 | setToolTip(0, itemTooltip(impl->m_Data)); | ||
Alexandre Leroux
|
r142 | |||
Alexandre Leroux
|
r145 | // Generates tree actions based on the item actions | ||
auto createTreeAction = [this, &parent](const auto &itemAction) { | ||||
auto treeAction = new QAction{itemAction->name(), parent}; | ||||
// Executes item action when tree action is triggered | ||||
QObject::connect(treeAction, &QAction::triggered, itemAction, | ||||
&DataSourceItemAction::execute); | ||||
return treeAction; | ||||
}; | ||||
auto itemActions = impl->m_Data->actions(); | ||||
std::transform(std::cbegin(itemActions), std::cend(itemActions), | ||||
std::back_inserter(impl->m_Actions), createTreeAction); | ||||
r870 | ||||
// Sets the flags of the items | ||||
auto flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; | ||||
if (data->type() == DataSourceItemType::COMPONENT | ||||
|| data->type() == DataSourceItemType::PRODUCT) { | ||||
flags |= Qt::ItemIsDragEnabled; | ||||
} | ||||
setFlags(flags); | ||||
Alexandre Leroux
|
r80 | } | ||
Alexandre Leroux
|
r477 | const DataSourceItem *DataSourceTreeWidgetItem::data() const | ||
{ | ||||
return impl->m_Data; | ||||
} | ||||
Alexandre Leroux
|
r80 | QVariant DataSourceTreeWidgetItem::data(int column, int role) const | ||
{ | ||||
if (role == Qt::DisplayRole) { | ||||
Alexandre Leroux
|
r343 | if (impl->m_Data) { | ||
switch (column) { | ||||
case NAME_COLUMN: | ||||
Alexandre Leroux
|
r1037 | return impl->m_Name; | ||
Alexandre Leroux
|
r343 | default: | ||
// No action | ||||
break; | ||||
} | ||||
qCWarning(LOG_DataSourceTreeWidgetItem()) | ||||
<< QObject::tr("Can't get data (unknown column %1)").arg(column); | ||||
} | ||||
else { | ||||
qCCritical(LOG_DataSourceTreeWidgetItem()) << QObject::tr("Can't get data (null item)"); | ||||
} | ||||
return QVariant{}; | ||||
Alexandre Leroux
|
r80 | } | ||
else { | ||||
return QTreeWidgetItem::data(column, role); | ||||
} | ||||
} | ||||
void DataSourceTreeWidgetItem::setData(int column, int role, const QVariant &value) | ||||
{ | ||||
// Data can't be changed by edition | ||||
if (role != Qt::EditRole) { | ||||
QTreeWidgetItem::setData(column, role, value); | ||||
} | ||||
} | ||||
Alexandre Leroux
|
r142 | |||
QList<QAction *> DataSourceTreeWidgetItem::actions() const noexcept | ||||
{ | ||||
return impl->m_Actions; | ||||
} | ||||