#include #include #include #include Q_LOGGING_CATEGORY(LOG_DataSourceTreeWidgetItem, "DataSourceTreeWidgetItem") namespace { // Column indexes const auto NAME_COLUMN = 0; /** * 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; } QIcon itemIcon(const DataSourceItem *dataSource) { if (dataSource) { auto dataSourceType = dataSource->type(); switch (dataSourceType) { case DataSourceItemType::NODE: { return dataSource->isRoot() ? QIcon{":/icones/dataSourceRoot.png"} : QIcon{":/icones/dataSourceNode.png"}; } case DataSourceItemType::PRODUCT: return QIcon{":/icones/dataSourceProduct.png"}; case DataSourceItemType::COMPONENT: return QIcon{":/icones/dataSourceComponent.png"}; default: // No action break; } qCWarning(LOG_DataSourceTreeWidgetItem()) << QObject::tr("Can't set data source icon : unknown data source type"); } else { qCCritical(LOG_DataSourceTreeWidgetItem()) << QObject::tr("Can't set data source icon : the data source is null"); } // Default cases return QIcon{}; } /// @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()) { auto valueString = QStringLiteral("{"); auto variantList = variant.value(); 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{"%1: %2
"}.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{}; } } } // namespace struct DataSourceTreeWidgetItem::DataSourceTreeWidgetItemPrivate { explicit DataSourceTreeWidgetItemPrivate(const DataSourceItem *data) : m_Data{data}, m_Name{completeName(*m_Data)} { } /// Model used to retrieve data source information const DataSourceItem *m_Data; /// Name displayed QString m_Name; /// Actions associated to the item. The parent of the item (QTreeWidget) takes the ownership of /// the actions QList m_Actions; //TODO check if no memory leak here }; 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(data)} { // Sets the icon and the tooltip depending on the data source setIcon(0, itemIcon(impl->m_Data)); setToolTip(0, itemTooltip(impl->m_Data)); // 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); // 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); } const DataSourceItem *DataSourceTreeWidgetItem::data() const { return impl->m_Data; } QVariant DataSourceTreeWidgetItem::data(int column, int role) const { if (role == Qt::DisplayRole) { if (impl->m_Data) { switch (column) { case NAME_COLUMN: return impl->m_Name; 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{}; } 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); } } QList DataSourceTreeWidgetItem::actions() const noexcept { return impl->m_Actions; }