//--------------------------------------------------------------------------- // // Project: OpenWalnut ( http://www.openwalnut.org ) // // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS // For more information see http://www.openwalnut.org/copying // // This file is part of OpenWalnut. // // OpenWalnut 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 3 of the License, or // (at your option) any later version. // // OpenWalnut 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 for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenWalnut. If not, see . // //--------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include "../WMainWindow.h" #include "WQtNetworkEditor.h" #include "WQtNetworkPort.h" #include "../../../kernel/WModule.h" #include "../../../kernel/WModuleFactory.h" #include "../controlPanel/WQtControlPanel.h" #include "../events/WEventTypes.h" #include "../events/WModuleAssocEvent.h" #include "../events/WModuleConnectEvent.h" #include "../events/WModuleDeleteEvent.h" #include "../events/WModuleDisconnectEvent.h" #include "../events/WModuleReadyEvent.h" #include "../events/WModuleRemovedEvent.h" WQtNetworkEditor::WQtNetworkEditor( WMainWindow* parent ) : QDockWidget( "Module Graph", parent ), timerId( 0 ) { setObjectName( "Module Graph Dock" ); m_mainWindow = parent; m_panel = new QWidget( this ); m_view = new QGraphicsView(); m_view->setDragMode( QGraphicsView::RubberBandDrag ); m_view->setRenderHint( QPainter::Antialiasing ); m_view->setMinimumSize( 20, 20 ); m_scene = new WQtNetworkScene(); // m_scene->setSceneRect( -200.0, -200.0, 400.0, 400.0 ); m_scene->setSceneRect( m_scene->itemsBoundingRect() ); m_view->setScene( m_scene ); m_layout = new QVBoxLayout; m_layout->addWidget( m_view ); m_panel->setLayout( m_layout ); this->setAllowedAreas( Qt::AllDockWidgetAreas ); this->setFeatures( QDockWidget::DockWidgetClosable |QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable ); setWidget( m_panel ); connect( m_scene, SIGNAL( selectionChanged() ), this, SLOT( selectItem() ) ); // this fakeitem is added to the scene to get a better behavior of the forced // based layout. ALL WQtNetworkItems in the scene are "connected" to this // object to avoid that conneceted groups push away each other. QGraphicsRectItem *fake = new QGraphicsRectItem(); fake->setRect( 0, 0, 10, 10 ); fake->setPos( 0, 0 ); fake->setBrush( Qt::green ); fake->setFlag( QGraphicsItem::ItemIsMovable, true ); m_scene->addItem( fake ); m_scene->setFakeItem( fake ); } WQtNetworkEditor::~WQtNetworkEditor() { } void WQtNetworkEditor::selectItem() { boost::shared_ptr< WModule > module; if ( m_scene->selectedItems().size() != 0 && m_scene->selectedItems().at( 0 )->type() == WQtNetworkItem::Type ) { if ( m_scene->selectedItems().at(0)->type() == WQtNetworkItem::Type ) { module = ( static_cast< WQtNetworkItem* >( m_scene->selectedItems().at( 0 ) ) )->getModule(); } // crashed modules should not provide any props if ( module->isCrashed()() ) { return; } m_mainWindow->getControlPanel()->setNewActiveModule( module ); } else { m_mainWindow->getControlPanel()->setNewActiveModule( module ); } } void WQtNetworkEditor::addModule( boost::shared_ptr< WModule > module ) { WQtNetworkItem *netItem = new WQtNetworkItem( this, module ); m_items.push_back( netItem ); // set the object at a random start position time( &m_time ); #ifndef _MSC_VER netItem->setPos( rand_r( ( unsigned int * ) &m_time ) % 200, rand_r( ( unsigned int * ) &m_time ) % 200 ); #else netItem->setPos( ( rand() + m_time ) % 200, ( rand() + m_time ) % 200 ); #endif m_scene->addItem( netItem ); itemMoved(); } bool WQtNetworkEditor::event( QEvent* event ) { // a module got associated with the root container -> add it to the list if ( event->type() == WQT_ASSOC_EVENT ) { // convert event to assoc event WModuleAssocEvent* e1 = dynamic_cast< WModuleAssocEvent* >( event ); // NOLINT if ( e1 ) { WLogger::getLogger()->addLogMessage( "Inserting module \"" + e1->getModule()->getName() + "\" to network editor.", "NetworkEditor", LL_DEBUG ); addModule( e1->getModule() ); } //TODO(skiunke): disablen des moduls solange nicht rdy! return true; } // a module changed its state to "ready" -> activate it in dataset browser if ( event->type() == WQT_READY_EVENT ) { // convert event to ready event WModuleReadyEvent* e = dynamic_cast< WModuleReadyEvent* >( event ); // NOLINT if ( !e ) { // this should never happen, since the type is set to WQT_READY_EVENT. WLogger::getLogger()->addLogMessage( "Event is not an WModueReadyEvent although its type claims it. Ignoring event.", "NetworkEditor", LL_WARNING ); return true; } WLogger::getLogger()->addLogMessage( "Activating module \"" + e->getModule()->getName() + "\" in network editor.", "NetworkEditor", LL_DEBUG ); // search all the item matching the module WQtNetworkItem *item = findItemByModule( e->getModule() ); if( item != 0 ) { item->activate( true ); } return true; } // a module tree item was connected to another one if ( event->type() == WQT_MODULE_CONNECT_EVENT ) { WModuleConnectEvent* e = dynamic_cast< WModuleConnectEvent* >( event ); // NOLINT if ( !e ) { // this should never happen, since the type is set to WQT_MODULE_CONNECT_EVENT. WLogger::getLogger()->addLogMessage( "Event is not an WModuleConnectEvent although its type claims it. Ignoring event.", "NetworkEditor", LL_WARNING ); return true; } WLogger::getLogger()->addLogMessage( "Connecting \"" + e->getInput()->getModule()->getName() + "\" and \"" + e->getOutput()->getModule()->getName() + "\".", "NetworkEditor", LL_DEBUG ); boost::shared_ptr< WModule > mIn; boost::shared_ptr< WModule > mOut; if( e->getInput()->isInputConnector() == true && e->getOutput()->isOutputConnector() == true ) { mIn = e->getInput()->getModule(); mOut = e->getOutput()->getModule(); } else if ( e->getInput()->isOutputConnector() == true && e->getOutput()->isInputConnector() == true ) { mIn = e->getOutput()->getModule(); mOut = e->getInput()->getModule(); } else { return true; //TODO(skiunke): warning } WQtNetworkItem *inItem = findItemByModule( mIn ); WQtNetworkItem *outItem = findItemByModule( mOut ); WQtNetworkInputPort *ip = NULL; WQtNetworkOutputPort *op = NULL; for ( QList< WQtNetworkInputPort* >::const_iterator iter = inItem->getInPorts().begin(); iter != inItem->getInPorts().end(); ++iter ) { WQtNetworkInputPort *inP = dynamic_cast< WQtNetworkInputPort* >( *iter ); if( e->getInput() == inP->getConnector() ) { ip = inP; } } for ( QList< WQtNetworkOutputPort* >::const_iterator iter = outItem->getOutPorts().begin(); iter != outItem->getOutPorts().end(); ++iter ) { WQtNetworkOutputPort *outP = dynamic_cast< WQtNetworkOutputPort* >( *iter ); if( e->getOutput() == outP->getConnector() ) { op = outP; } } if( ip != NULL && op != NULL ) { WQtNetworkArrow *arrow = new WQtNetworkArrow( op, ip ); arrow->setZValue( -1000.0 ); op->addArrow( arrow ); ip->addArrow( arrow ); arrow->updatePosition(); m_scene->addItem( arrow ); } } // a module tree item was disconnected from another one if ( event->type() == WQT_MODULE_DISCONNECT_EVENT ) { WLogger::getLogger()->addLogMessage( "DISCONNECT.", "NetworkEditor", LL_ERROR ); WModuleDisconnectEvent* e = dynamic_cast< WModuleDisconnectEvent* >( event ); // NOLINT if ( !e ) { // this should never happen, since the type is set to WQT_MODULE_DISCONNECT_EVENT. WLogger::getLogger()->addLogMessage( "Event is not an WModuleDisconnectEvent although its type claims it. Ignoring event.", "NetworkEditor", LL_WARNING ); return true; } WLogger::getLogger()->addLogMessage( "Disonnecting \"" + e->getInput()->getCanonicalName() + "\" and \"" + e->getOutput()->getCanonicalName() + "\"." , "NetworkEditor", LL_DEBUG ); boost::shared_ptr< WModule > mIn; boost::shared_ptr< WModule > mOut; if( e->getInput()->isInputConnector() == true && e->getOutput()->isOutputConnector() == true ) { mIn = e->getInput()->getModule(); mOut = e->getOutput()->getModule(); } else if( e->getInput()->isOutputConnector() == true && e->getOutput()->isInputConnector() == true ) { mIn = e->getOutput()->getModule(); mOut = e->getInput()->getModule(); } else { return true; //TODO(skiunke): warning } WQtNetworkItem *inItem = findItemByModule( mIn ); WQtNetworkItem *outItem = findItemByModule( mOut ); WQtNetworkInputPort *ip = NULL; WQtNetworkOutputPort *op = NULL; for ( QList< WQtNetworkInputPort* >::const_iterator iter = inItem->getInPorts().begin(); iter != inItem->getInPorts().end(); ++iter ) { WQtNetworkInputPort *inP = dynamic_cast< WQtNetworkInputPort* >( *iter ); if( e->getInput() == inP->getConnector() ) { ip = inP; } } for ( QList< WQtNetworkOutputPort* >::const_iterator iter = outItem->getOutPorts().begin(); iter != outItem->getOutPorts().end(); ++iter ) { WQtNetworkOutputPort *outP = dynamic_cast< WQtNetworkOutputPort* >( *iter ); if( e->getOutput() == outP->getConnector() ) { op = outP; } } WQtNetworkArrow *ar = NULL; for ( QList< QGraphicsItem * >::const_iterator iter = m_scene->items().begin(); iter != m_scene->items().end(); ++iter ) { ar = dynamic_cast< WQtNetworkArrow* >( *iter ); if( ar && ar->getStartPort() == op && ar->getEndPort() == ip ) { break; } } if ( ar ) { op->removeArrow( ar ); ip->removeArrow( ar ); m_scene->removeItem( ar ); } else { WLogger::getLogger()->addLogMessage( "Arrow not found!.", "NetworkEditor", LL_ERROR ); } return true; } // a module was removed from the container if ( event->type() == WQT_MODULE_REMOVE_EVENT ) { WLogger::getLogger()->addLogMessage( "REMOVE.", "NetworkEditor", LL_ERROR ); WModuleRemovedEvent* e = dynamic_cast< WModuleRemovedEvent* >( event ); if ( !e ) { // this should never happen, since the type is set to WQT_MODULE_REMOVE_EVENT. WLogger::getLogger()->addLogMessage( "Event is not an WModuleRemovedEvent although its type claims it. Ignoring event.", "NetworkEditor", LL_WARNING ); return true; } WLogger::getLogger()->addLogMessage( "Removing \"" + e->getModule()->getName() + "\"from network editor.", "NetworkEditor", LL_DEBUG ); WQtNetworkItem *item = findItemByModule( e->getModule() ); if( item != 0 ) { item->activate( false ); e->getModule()->requestStop(); // TODO(rfrohl): do we need this ? } return true; } // a module tree item should be deleted if ( event->type() == WQT_MODULE_DELETE_EVENT ) { WLogger::getLogger()->addLogMessage( "DELETE.", "NetworkEditor", LL_ERROR ); WModuleDeleteEvent* e = dynamic_cast< WModuleDeleteEvent* >( event ); if ( !e ) { // this should never happen, since the type is set to WQT_MODULE_REMOVE_EVENT. WLogger::getLogger()->addLogMessage( "Event is not an WModuleRemovedEvent although" "its type claims it. Ignoring event.", "NetworkEditor", LL_WARNING ); return true; } WLogger::getLogger()->addLogMessage( "Delete \"" + e->getTreeItem()->getModule()->getName() + "\" from network editor", "NetworkEditor", LL_DEBUG ); WQtNetworkItem *item = findItemByModule( e->getTreeItem()->getModule() ); if( item != 0 ) { m_scene->removeItem( item ); m_items.removeAll( item ); delete item; } return true; } return QDockWidget::event( event ); } WQtNetworkItem* WQtNetworkEditor::findItemByModule( boost::shared_ptr< WModule > module ) { for( QList< WQtNetworkItem* >::const_iterator iter = m_items.begin(); iter != m_items.end(); ++iter ) { WQtNetworkItem *itemModule = dynamic_cast< WQtNetworkItem* >( *iter ); if( itemModule && itemModule->getModule() == module ) { return itemModule; } } return 0; } void WQtNetworkEditor::itemMoved() { if ( !timerId ) timerId = startTimer( 1000 / 25 ); } void WQtNetworkEditor::timerEvent( QTimerEvent *event ) { Q_UNUSED( event ); QList< WQtNetworkItem *> items; foreach( QGraphicsItem *item, m_scene->items() ) { if ( WQtNetworkItem *netItem = dynamic_cast< WQtNetworkItem *>( item ) ) items << netItem; } foreach( WQtNetworkItem *netItem, items ) netItem->calculateForces(); bool itemsMoved = false; foreach( WQtNetworkItem *netItem, items ) { if ( netItem->advance() ) itemsMoved = true; } if ( !itemsMoved ) { killTimer( timerId ); timerId = 0; } }