// SPDX-License-Identifier: LGPL-2.1-or-later /*************************************************************************** * Copyright (c) 2011 Thomas Anderson * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "Base/Console.h" #include "Command.h" #include "Dialogs/DlgCustomizeSpaceball.h" #include "Application.h" #include "BitmapFactory.h" #include "GuiApplicationNativeEventAware.h" #include "SpaceballEvent.h" using GroupVector = std::vector>; using namespace Gui::Dialog; ButtonView::ButtonView(QWidget* parent) : QListView(parent) {} void ButtonView::selectButton(int number) { this->selectionModel()->select(this->model()->index(number, 0), QItemSelectionModel::ClearAndSelect); this->scrollTo(this->model()->index(number, 0), QAbstractItemView::EnsureVisible); } void ButtonView::goSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { Q_UNUSED(deselected); if (selected.indexes().isEmpty()) { return; } QModelIndex select(selected.indexes().at(0)); Q_EMIT changeCommandSelection(this->model()->data(select, Qt::UserRole).toString()); } void ButtonView::goChangedCommand(const QString& commandName) { QModelIndex index(this->currentIndex()); auto model = dynamic_cast(this->model()); if (model && index.isValid()) { model->setCommand(index.row(), commandName); } } /////////////////////////////////////////////////////////////////////////////////////// ButtonModel::ButtonModel(QObject* parent) : QAbstractListModel(parent) { // load3DConnexionButtons("SpacePilot Pro"); } // Process the given Mapping tree to load in the Button mappings. void ButtonModel::load3DConnexionButtonMapping(boost::property_tree::ptree ButtonMapTree) { spaceballButtonGroup()->Clear(); BOOST_FOREACH ( const boost::property_tree::ptree::value_type& Map, ButtonMapTree.get_child("Mapping") ) { if ("Map" == Map.first) { std::string ButtonDescription; std::string ButtonCode; std::string ButtonCommand; std::string ButtonDownTime; // Inspect Map attributes BOOST_FOREACH ( const boost::property_tree::ptree::value_type& kv, Map.second.get_child("") ) { std::string Attribute; std::string Value; Attribute = kv.first.data(); Value = kv.second.data(); if (0 == Attribute.compare("Description")) { ButtonDescription = Value; } if (0 == Attribute.compare("KeyCode")) { ButtonCode = Value; } if (0 == Attribute.compare("DownTime")) { ButtonDownTime = Value; } if (0 == Attribute.compare("Command")) { ButtonCommand = Value; } } // ButtonCode is mandatory, the remaining attributes optional. if (!ButtonCode.empty()) { Base::Reference newGroup; newGroup = spaceballButtonGroup()->GetGroup(ButtonCode.c_str()); newGroup->SetASCII("Command", ButtonCommand.c_str()); newGroup->SetASCII("Description", ButtonDescription.c_str()); } } } } // Optionally preload Button model with 3DConnexion configuration to match Solidworks // For now the Button mapping file (3DConnexion.xml) is held the same folder as the FreeCAD executable. void ButtonModel::load3DConnexionButtons(const char* RequiredDeviceName) { try { boost::property_tree::ptree tree; boost::property_tree::ptree DeviceTree; // exception thrown if no file found std::string path = App::Application::getResourceDir(); path += "3Dconnexion/3DConnexion.xml"; read_xml(path.c_str(), tree); BOOST_FOREACH (const boost::property_tree::ptree::value_type& ButtonMap, tree.get_child("")) { if ("ButtonMap" == ButtonMap.first) { // Inspect ButtonMap attributes for DeviceName BOOST_FOREACH ( const boost::property_tree::ptree::value_type& kv, ButtonMap.second.get_child("") ) { std::string Attribute; std::string Value; Attribute = kv.first.data(); Value = kv.second.data(); if (0 == Attribute.compare("DeviceName")) { if (0 == Value.compare(RequiredDeviceName)) { // We found the ButtonMap we want to load up DeviceTree = ButtonMap.second; } } } } } // If we found the required devices ButtonMap if (!DeviceTree.empty()) { load3DConnexionButtonMapping(DeviceTree); } } catch (const std::exception& e) { // We don't mind not finding the file to be opened Base::Console().warning("%s\n", e.what()); } } int ButtonModel::rowCount(const QModelIndex& parent) const { Q_UNUSED(parent); return spaceballButtonGroup()->GetGroups().size(); } QVariant ButtonModel::data(const QModelIndex& index, int role) const { GroupVector groupVector = spaceballButtonGroup()->GetGroups(); if (index.row() >= (int)groupVector.size()) { Base::Console().log("index error in ButtonModel::data\n"); return {}; } if (role == Qt::DisplayRole) { return {getLabel(index.row())}; } if (role == Qt::DecorationRole) { static QPixmap icon( BitmapFactory() .pixmap("spaceball_button") .scaled(32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation) ); return QVariant(QIcon(icon)); // Cannot make a QPixmap into a QVariant, so convert to a // QIcon first } if (role == Qt::UserRole) { return {QString::fromStdString(groupVector.at(index.row())->GetASCII("Command"))}; } if (role == Qt::SizeHintRole) { return {QSize(32, 32)}; } return {}; } void ButtonModel::insertButtonRows(int number) { int buttonCount = spaceballButtonGroup()->GetGroups().size(); beginInsertRows(QModelIndex(), buttonCount, number - buttonCount + 1); for (int index = buttonCount; index < number + 1; ++index) { QString groupName; groupName.setNum(index); Base::Reference newGroup = spaceballButtonGroup()->GetGroup( groupName.toLatin1() ); // builds the group. newGroup->SetASCII("Command", ""); newGroup->SetASCII("Description", ""); } endInsertRows(); return; } void ButtonModel::setCommand(int row, QString command) { GroupVector groupVector = spaceballButtonGroup()->GetGroups(); groupVector.at(row)->SetASCII("Command", command.toLatin1()); } void ButtonModel::goButtonPress(int number) { QString numberString; numberString.setNum(number); if (!spaceballButtonGroup()->HasGroup(numberString.toLatin1())) { insertButtonRows(number); } } void ButtonModel::goMacroRemoved(const QByteArray& macroName) { GroupVector groupVector = spaceballButtonGroup()->GetGroups(); for (auto& it : groupVector) { if (std::string(macroName.data()) == it->GetASCII("Command")) { it->SetASCII("Command", ""); } } } void ButtonModel::goClear() { if (this->rowCount() < 1) { return; } this->beginRemoveRows(QModelIndex(), 0, this->rowCount() - 1); spaceballButtonGroup()->Clear(); this->endRemoveRows(); } ParameterGrp::handle ButtonModel::spaceballButtonGroup() const { static ParameterGrp::handle group = App::GetApplication() .GetUserParameter() .GetGroup("BaseApp") ->GetGroup("Spaceball") ->GetGroup("Buttons"); return group; } QString ButtonModel::getLabel(const int& number) const { if (number > -1 && number < 32) { QString numberString; numberString.setNum(number); QString desc = QString::fromStdString( spaceballButtonGroup()->GetGroup(numberString.toLatin1())->GetASCII("Description", "") ); if (desc.length()) { desc = QStringLiteral(" \"") + desc + QStringLiteral("\""); } return tr("Button %1").arg(number + 1) + desc; } else { return tr("Out of range"); } } void ButtonModel::loadConfig(const char* RequiredDeviceName) { goClear(); if (!RequiredDeviceName) { return; } load3DConnexionButtons(RequiredDeviceName); } ////////////////////////////////////////////////////////////////////////////////////////// CommandView::CommandView(QWidget* parent) : QTreeView(parent) { this->setEnabled(false); connect(this, &QTreeView::clicked, this, &CommandView::goClicked); } void CommandView::goChangeCommandSelection(const QString& commandName) { if (!this->isEnabled()) { this->setEnabled(true); } this->selectionModel()->clear(); this->collapseAll(); if (commandName.isEmpty()) { return; } QModelIndexList index(this->model()->match( this->model()->index(0, 0), Qt::UserRole, QVariant(commandName), 1, Qt::MatchWrap | Qt::MatchRecursive )); if (index.empty()) { return; } this->expand(index.at(0)); this->setCurrentIndex(index.at(0)); } void CommandView::goClicked(const QModelIndex& index) { if (index.flags() & Qt::ItemIsSelectable) { QString commandName = this->model()->data(index, Qt::UserRole).toString(); if (commandName.isEmpty()) { return; } Q_EMIT changedCommand(commandName); } } ///////////////////////////////////////////////////////////////////////////////////////// CommandNode::CommandNode(NodeType typeIn) { // NOLINTBEGIN nodeType = typeIn; parent = nullptr; children.clear(); aCommand = nullptr; // NOLINTEND } CommandNode::~CommandNode() { qDeleteAll(children); } ///////////////////////////////////////////////////////////////////////////////////////// CommandModel::CommandModel(QObject* parent) : QAbstractItemModel(parent) { // NOLINTBEGIN rootNode = nullptr; initialize(); // NOLINTEND } CommandModel::~CommandModel() { delete rootNode; rootNode = nullptr; } QModelIndex CommandModel::index(int row, int column, const QModelIndex& parent) const { if (!rootNode) { return {}; } if (!parent.isValid()) { return createIndex(row, column, rootNode->children.at(row)); } CommandNode* parentNode = nodeFromIndex(parent); if (!parentNode) { return {}; } return createIndex(row, column, parentNode->children.at(row)); } QModelIndex CommandModel::parent(const QModelIndex& index) const { CommandNode* base = nodeFromIndex(index); if (!base) { return {}; } CommandNode* parentNode = base->parent; if (!parentNode) { return {}; } CommandNode* grandParentNode = parentNode->parent; if (!grandParentNode) { return {}; } int row = grandParentNode->children.indexOf(parentNode); if (row == -1) { return {}; } return createIndex(row, index.column(), parentNode); } int CommandModel::rowCount(const QModelIndex& parent) const { if (!parent.isValid()) { return rootNode->children.size(); } CommandNode* parentNode = nodeFromIndex(parent); if (!parentNode) { return 0; } return parentNode->children.count(); } int CommandModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return 1; } QVariant CommandModel::data(const QModelIndex& index, int role) const { CommandNode* node = nodeFromIndex(index); if (!node) { return {}; } if (role == Qt::DisplayRole) { if (node->nodeType == CommandNode::CommandType) { return {qApp->translate(node->aCommand->className(), node->aCommand->getMenuText())}; } if (node->nodeType == CommandNode::GroupType) { if (node->children.empty()) { return {}; } CommandNode* childNode = node->children.at(0); return { qApp->translate(childNode->aCommand->className(), childNode->aCommand->getGroupName()) }; } return {}; } if (role == Qt::DecorationRole) { if (node->nodeType == CommandNode::CommandType) { if (node->aCommand->getPixmap()) { return QVariant( BitmapFactory() .pixmap(node->aCommand->getPixmap()) .scaled(32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation) ); } } } if (role == Qt::SizeHintRole) { if (node->nodeType == CommandNode::CommandType) { return {QSize(32, 32)}; } } if (role == Qt::UserRole) { if (node->nodeType == CommandNode::CommandType) { return {QString::fromLatin1(node->aCommand->getName())}; } if (node->nodeType == CommandNode::GroupType) { if (node->children.empty()) { return {}; } CommandNode* childNode = node->children.at(0); return {QString::fromLatin1(childNode->aCommand->getGroupName())}; } return {}; } if (role == Qt::ToolTipRole) { if (node->nodeType == CommandNode::CommandType) { return {QString::fromLatin1(node->aCommand->getToolTipText())}; } } return {}; } QVariant CommandModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal && section == 0) { return {tr("Commands")}; } return {}; } Qt::ItemFlags CommandModel::flags(const QModelIndex& index) const { if (!index.isValid()) { return Qt::NoItemFlags; } CommandNode* node = nodeFromIndex(index); if (!node) { return Qt::NoItemFlags; } if (node->nodeType == CommandNode::CommandType) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } return Qt::NoItemFlags; } CommandNode* CommandModel::nodeFromIndex(const QModelIndex& index) const { if (index.isValid()) { return static_cast(index.internalPointer()); } return rootNode; } void CommandModel::goAddMacro(const QByteArray& macroName) { QModelIndexList indexList(this->match( this->index(0, 0), Qt::UserRole, QVariant(QStringLiteral("Macros")), 1, Qt::MatchWrap | Qt::MatchRecursive )); QModelIndex macrosIndex; if (indexList.empty()) { // this is the first macro and we have to add the Macros item. // figure out where to insert it. Should be in the command groups now. QStringList groups = orderedGroups(); int location(groups.indexOf(QStringLiteral("Macros"))); if (location == -1) { location = groups.size(); } // add row this->beginInsertRows(QModelIndex(), location, location); auto macroNode = new CommandNode(CommandNode::GroupType); macroNode->parent = rootNode; rootNode->children.insert(location, macroNode); this->endInsertRows(); macrosIndex = this->index(location, 0); } else { macrosIndex = indexList.at(0); } Command* command = nullptr; command = Application::Instance->commandManager().getCommandByName(macroName); if (!command) { return; } CommandNode* parentNode = nodeFromIndex(macrosIndex); if (!parentNode) { return; } this->beginInsertRows(macrosIndex, parentNode->children.size(), parentNode->children.size()); auto childNode = new CommandNode(CommandNode::CommandType); childNode->parent = parentNode; parentNode->children.push_back(childNode); childNode->aCommand = command; this->endInsertRows(); } void CommandModel::goRemoveMacro(const QByteArray& macroName) { QModelIndexList macroList(this->match( this->index(0, 0), Qt::UserRole, QVariant(QString::fromLatin1(macroName.data())), 1, Qt::MatchWrap | Qt::MatchRecursive )); if (macroList.isEmpty()) { return; } QModelIndex childIndex(macroList.at(0)); QModelIndex parentIndex(this->parent(childIndex)); if (!childIndex.isValid() || !parentIndex.isValid()) { return; } CommandNode* parentNode = nodeFromIndex(parentIndex); if (!parentNode) { return; } this->beginRemoveRows(parentIndex, childIndex.row(), childIndex.row()); delete parentNode->children.takeAt(childIndex.row()); this->endRemoveRows(); if (parentNode->children.isEmpty()) { QModelIndex grandParentIndex(this->parent(parentIndex)); // this should be root. CommandNode* grandParentNode = nodeFromIndex(grandParentIndex); this->beginRemoveRows(grandParentIndex, parentIndex.row(), parentIndex.row()); delete grandParentNode->children.takeAt(parentIndex.row()); this->endRemoveRows(); } } void CommandModel::initialize() { rootNode = new CommandNode(CommandNode::RootType); QStringList groups(orderedGroups()); for (const auto& group : groups) { groupCommands(group); } } void CommandModel::groupCommands(const QString& groupName) { auto parentNode = new CommandNode(CommandNode::GroupType); parentNode->parent = rootNode; rootNode->children.push_back(parentNode); std::vector commands = Application::Instance->commandManager().getGroupCommands( groupName.toLatin1() ); for (const auto& command : commands) { auto childNode = new CommandNode(CommandNode::CommandType); childNode->parent = parentNode; parentNode->children.push_back(childNode); childNode->aCommand = command; } } QStringList CommandModel::orderedGroups() { QStringList groups; std::vector commands = Application::Instance->commandManager().getAllCommands(); for (const auto& command : commands) { QString groupName(QString::fromLatin1(command->getGroupName())); if (!groups.contains(groupName)) { groups << groupName; } } // how to sort? groups.sort(); return groups; } /////////////////////////////////////////////////////////////////////////////////////// PrintModel::PrintModel(QObject* parent, ButtonModel* buttonModelIn, CommandModel* commandModelIn) : QAbstractTableModel(parent) { // NOLINTBEGIN buttonModel = buttonModelIn; commandModel = commandModelIn; // NOLINTEND } int PrintModel::rowCount(const QModelIndex& parent) const { Q_UNUSED(parent); return buttonModel->rowCount(); } int PrintModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return 2; } QVariant PrintModel::data(const QModelIndex& index, int role) const { if (index.column() == 0) { // button column; return buttonModel->data(buttonModel->index(index.row(), 0), role); } if (index.column() == 1) { // command column; QString commandName( buttonModel->data(buttonModel->index(index.row(), 0), Qt::UserRole).toString() ); if (commandName.isEmpty()) { return {}; } QModelIndexList indexList(commandModel->match( commandModel->index(0, 0), Qt::UserRole, QVariant(commandName), 1, Qt::MatchWrap | Qt::MatchRecursive )); if (indexList.isEmpty()) { return {}; } return commandModel->data(indexList.at(0), role); } return {}; } QVariant PrintModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole || orientation != Qt::Horizontal) { return {}; } if (section == 0) { return {tr("Button")}; } if (section == 1) { return {tr("Command")}; } else { return {}; } } /////////////////////////////////////////////////////////////////////////////////////// DlgCustomizeSpaceball::DlgCustomizeSpaceball(QWidget* parent) : CustomizeActionPage(parent) , buttonView(nullptr) , buttonModel(nullptr) , commandView(nullptr) , commandModel(nullptr) , clearButton(nullptr) , printReference(nullptr) , devModel(nullptr) { this->setWindowTitle(tr("Spaceball Buttons")); auto app = qobject_cast(QApplication::instance()); if (!app) { return; } if (!app->isSpaceballPresent()) { this->setMessage(tr("No Spaceball present")); return; } setupButtonModelView(); setupCommandModelView(); connect( buttonView, &ButtonView::changeCommandSelection, commandView, &CommandView::goChangeCommandSelection ); connect(commandView, &CommandView::changedCommand, buttonView, &ButtonView::goChangedCommand); setupLayout(); connect(clearButton, &QPushButton::clicked, this, &DlgCustomizeSpaceball::goClear); connect(printReference, &QPushButton::clicked, this, &DlgCustomizeSpaceball::goPrint); } DlgCustomizeSpaceball::~DlgCustomizeSpaceball() = default; void DlgCustomizeSpaceball::setMessage(const QString& message) { auto messageLabel = new QLabel(message, this); auto layout = new QVBoxLayout(); auto layout2 = new QHBoxLayout(); layout2->addStretch(); layout2->addWidget(messageLabel); layout2->addStretch(); layout->addItem(layout2); this->setLayout(layout); } void DlgCustomizeSpaceball::setupButtonModelView() { buttonModel = new ButtonModel(this); buttonView = new ButtonView(this); buttonView->setModel(buttonModel); // had to do this here as the views default selection model is not created until after construction. connect( buttonView->selectionModel(), &QItemSelectionModel::selectionChanged, buttonView, &ButtonView::goSelectionChanged ); } void DlgCustomizeSpaceball::setupCommandModelView() { commandModel = new CommandModel(this); commandView = new CommandView(this); commandView->setModel(commandModel); } void DlgCustomizeSpaceball::setupLayout() { auto buttonLabel = new QLabel(tr("Buttons"), this); clearButton = new QPushButton(tr("Reset"), this); devModel = new QComboBox(this); // Load the devModel(s) from the config xml file devModel->addItems(getModels()); // Select the current preference or the first entry QString model = QString::fromStdString( App::GetApplication() .GetUserParameter() .GetGroup("BaseApp") ->GetGroup("Spaceball") ->GetASCII("Model", "") ); if (model.length() > 0) { devModel->setCurrentIndex(devModel->findText(model)); } else { devModel->setCurrentIndex(0); } auto buttonGroup = new QVBoxLayout(); buttonGroup->addWidget(buttonLabel); buttonGroup->addWidget(buttonView); auto clearLayout = new QHBoxLayout(); clearLayout->addWidget(devModel); clearLayout->addWidget(clearButton); clearLayout->addStretch(); buttonGroup->addLayout(clearLayout); auto splitter = new QSplitter(this); auto leftPane = new QWidget(this); leftPane->setLayout(buttonGroup); splitter->addWidget(leftPane); splitter->addWidget(commandView); printReference = new QPushButton(tr("Print Reference"), this); auto printLayout = new QHBoxLayout(); printLayout->addStretch(); printLayout->addWidget(printReference); auto layout = new QVBoxLayout(); layout->addWidget(splitter); layout->addLayout(printLayout); this->setLayout(layout); QList sizes; sizes << this->size().width() * 0.40; sizes << this->size().width() - sizes.at(0); splitter->setSizes(sizes); } void DlgCustomizeSpaceball::goClear() { commandView->clearSelection(); commandView->collapseAll(); commandView->setDisabled(true); // buttonModel->goClear(); QByteArray currentDevice = devModel->currentText().toLocal8Bit(); App::GetApplication() .GetUserParameter() .GetGroup("BaseApp") ->GetGroup("Spaceball") ->SetASCII("Model", currentDevice.data()); buttonModel->loadConfig(currentDevice.data()); } void DlgCustomizeSpaceball::goPrint() { auto view = new QTableView(this); auto model = new PrintModel(this, buttonModel, commandModel); view->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed); view->setModel(model); view->horizontalHeader()->resizeSection(0, 150); view->horizontalHeader()->resizeSection(1, 300); view->resize(600, 600); QPrinter printer; QPrintDialog printDialog(&printer, this); if (printDialog.exec() == QDialog::Accepted) { QPainter p(&printer); view->render(&p); } } bool DlgCustomizeSpaceball::event(QEvent* event) { if (event->type() != Spaceball::ButtonEvent::ButtonEventType) { return CustomizeActionPage::event(event); } auto buttonEvent = dynamic_cast(event); if (!buttonEvent) { return true; } buttonEvent->setHandled(true); if (buttonEvent->buttonStatus() == Spaceball::BUTTON_PRESSED) { buttonModel->goButtonPress(buttonEvent->buttonNumber()); } buttonView->selectButton(buttonEvent->buttonNumber()); return true; } void DlgCustomizeSpaceball::hideEvent(QHideEvent* event) { // having a crash with the last item of the macro command list // being selected and that macro is removed from the macro tab. Hopefully // clearing the selection will cure the problem. if (buttonView) { buttonView->selectionModel()->clear(); } if (commandView) { commandView->selectionModel()->clear(); commandView->collapseAll(); commandView->setEnabled(false); } CustomizeActionPage::hideEvent(event); } void DlgCustomizeSpaceball::showEvent(QShowEvent* event) { if (buttonView) { buttonView->setFocus(); } CustomizeActionPage::showEvent(event); } void DlgCustomizeSpaceball::changeEvent(QEvent* e) { if (e->type() == QEvent::LanguageChange) { // I don't think I need do anything here. Qt should take care of it? // this->setWindowTitle(tr("Spaceball")); } QWidget::changeEvent(e); } void DlgCustomizeSpaceball::onAddMacroAction(const QByteArray& macroName) { // need to get the new macro to model. if (commandModel) { commandModel->goAddMacro(macroName); } } void DlgCustomizeSpaceball::onRemoveMacroAction(const QByteArray& macroName) { // need to remove macro from model. if (commandModel) { commandModel->goRemoveMacro(macroName); } // need to change any button mapped to macro to an empty string. if (buttonModel) { buttonModel->goMacroRemoved(macroName); } } void DlgCustomizeSpaceball::onModifyMacroAction(const QByteArray& macroName) { // don't think I need to do anything here. Q_UNUSED(macroName); } QStringList DlgCustomizeSpaceball::getModels() { QStringList modelList; try { boost::property_tree::ptree tree; boost::property_tree::ptree DeviceTree; // exception thrown if no file found std::string path = App::Application::getResourceDir(); path += "3Dconnexion/3DConnexion.xml"; read_xml(path.c_str(), tree); BOOST_FOREACH (const boost::property_tree::ptree::value_type& ButtonMap, tree.get_child("")) { if ("ButtonMap" == ButtonMap.first) { // Inspect ButtonMap attributes for DeviceName BOOST_FOREACH ( const boost::property_tree::ptree::value_type& kv, ButtonMap.second.get_child("") ) { std::string Attribute; std::string Value; Attribute = kv.first.data(); Value = kv.second.data(); if (0 == Attribute.compare("DeviceName")) { modelList << QString::fromStdString(Value); } } } } } catch (const std::exception& e) { // We don't mind not finding the file to be opened Base::Console().warning("%s\n", e.what()); } return modelList; } #include "moc_DlgCustomizeSpaceball.cpp"