//################################################################################################## // // Custom Visualization Core library // Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: // // GNU General Public License Usage // This library is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 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 General Public License at <> // for more details. // // GNU Lesser General Public License Usage // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2.1 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 Lesser General Public License at <> // for more details. // //################################################################################################## #include "cafPdmUiCommandSystemProxy.h" #include "cafInternalPdmUiCommandSystemInterface.h" #include "cafPdmFieldHandle.h" #include "cafPdmObjectHandle.h" #include "cafPdmUiFieldHandle.h" #include "cafPdmUiObjectHandle.h" #include "cafSelectionManager.h" #include #include namespace caf { //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- PdmUiCommandSystemProxy* PdmUiCommandSystemProxy::instance() { static PdmUiCommandSystemProxy staticInstance; return &staticInstance; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- PdmUiCommandSystemProxy::PdmUiCommandSystemProxy() { m_commandInterface = nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PdmUiCommandSystemProxy::setCommandInterface( PdmUiCommandSystemInterface* commandInterface ) { m_commandInterface = commandInterface; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PdmUiCommandSystemProxy::setUiValueToField( PdmUiFieldHandle* uiFieldHandle, const QVariant& newUiValue ) { if ( uiFieldHandle && uiFieldHandle->fieldHandle() ) { // Handle editing multiple objects when several objects are selected PdmFieldHandle* editorField = uiFieldHandle->fieldHandle(); std::vector fieldsToUpdate; fieldsToUpdate.push_back( editorField ); std::vector otherSelectedFields = fieldsFromSelection( editorField ); // If current edited field is part of the selection, update all fields in selection if ( std::find( otherSelectedFields.begin(), otherSelectedFields.end(), editorField ) != otherSelectedFields.end() ) { for ( auto otherField : otherSelectedFields ) { if ( otherField != editorField ) { fieldsToUpdate.push_back( otherField ); } } } if ( m_commandInterface && !fieldsToUpdate.empty() ) { auto firstField = fieldsToUpdate.front(); if ( m_commandInterface->isFieldWritable( firstField ) ) { caf::PdmUiObjectHandle* uiOwnerObjectHandle = uiObj( editorField->ownerObject() ); if ( uiOwnerObjectHandle && uiOwnerObjectHandle->useUndoRedoForFieldChanged() ) { m_commandInterface->fieldChangedCommand( fieldsToUpdate, newUiValue ); return; } } } // Fallback to update field values without undo/redo support for ( auto fieldHandle : fieldsToUpdate ) { fieldHandle->uiCapability()->setValueFromUiEditor( newUiValue, true ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PdmUiCommandSystemProxy::setCurrentContextMenuTargetWidget( QWidget* targetWidget ) { if ( m_commandInterface ) { m_commandInterface->setCurrentContextMenuTargetWidget( targetWidget ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PdmUiCommandSystemProxy::populateMenuWithDefaultCommands( const QString& uiConfigName, QMenu* menu ) { if ( m_commandInterface ) { m_commandInterface->populateMenuWithDefaultCommands( uiConfigName, menu ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector PdmUiCommandSystemProxy::fieldsFromSelection( PdmFieldHandle* editorField ) { if ( !editorField ) return {}; if ( !editorField->ownerObject() ) return {}; std::vector items; // Find all selected items at one level starting from the largest level. This is required to be able to modify // multiple rows in the table editor. Items in the table editor use by default SelectionManager::FIRST_LEVEL for ( int candidateSelectionLevel = SelectionManager::SECOND_LEVEL; candidateSelectionLevel != SelectionManager::UNDEFINED; candidateSelectionLevel-- ) { SelectionManager::instance()->selectedItems( items, candidateSelectionLevel ); if ( !items.empty() ) break; } if ( items.size() < 2 ) return {}; const auto fieldKeyword = editorField->keyword(); auto ownerObject = editorField->ownerObject(); const auto& fieldOwnerTypeId = typeid( *ownerObject ); std::vector additionalFieldsToUpdate; for ( auto& item : items ) { auto* objectHandle = dynamic_cast( item ); if ( objectHandle ) { if ( typeid( *objectHandle ) == fieldOwnerTypeId ) { // An object of same type is selected, find field with same keyword as the current field being edited PdmFieldHandle* fieldHandle = objectHandle->findField( fieldKeyword ); if ( fieldHandle ) { additionalFieldsToUpdate.push_back( fieldHandle ); } } else { // Search one level in the project tree for fields in child objects // Searching in deeper levels is currently not supported, and is considered difficult to match // correctly and robust // // Check for identical owner class to guard for matching field names in multiple child objects of a // different type const auto editorFieldOwnerClass = editorField->ownerClass(); std::vector childFields = objectHandle->fields(); for ( auto field : childFields ) { std::vector childObjects = field->children(); for ( auto childObj : childObjects ) { auto childFieldHandle = childObj->findField( fieldKeyword ); if ( childFieldHandle && childFieldHandle->ownerClass() == editorFieldOwnerClass ) { additionalFieldsToUpdate.push_back( childFieldHandle ); } } } } } else { // Todo Remove when dust has settled. Selection manager is not supposed to select single fields // A field is selected, check if keywords are identical auto* itemFieldHandle = dynamic_cast( item ); if ( itemFieldHandle ) { PdmFieldHandle* field = itemFieldHandle->fieldHandle(); if ( field && field->keyword() == fieldKeyword ) { additionalFieldsToUpdate.push_back( field ); } } } } return additionalFieldsToUpdate; } } // end namespace caf