WQtNetworkEditor.cpp 15.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
//---------------------------------------------------------------------------
//
// 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 <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------

#include <string>
#include <iostream>

28 29
#include <boost/shared_ptr.hpp>

30 31 32 33 34 35 36 37 38 39 40
#include <QtGui/QDockWidget>
#include <QtGui/QVBoxLayout>
#include <QtGui/QKeyEvent>
#include <QtGui/QGraphicsView>
#include <QtGui/QGraphicsItem>
#include <QtGui/QGraphicsItemGroup>

#include "../WMainWindow.h"
#include "WQtNetworkEditor.h"
#include "WQtNetworkPort.h"

41 42
#include "../../../kernel/WModule.h"
#include "../../../kernel/WModuleFactory.h"
Robert Frohl's avatar
Robert Frohl committed
43
#include "../controlPanel/WQtControlPanel.h"
44 45 46 47 48 49 50
#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"
51

52
WQtNetworkEditor::WQtNetworkEditor( WMainWindow* parent )
53
    : QDockWidget( "Module Graph", parent ),
skiunke's avatar
skiunke committed
54
    timerId( 0 )
55
{
56
    setObjectName( "Module Graph Dock" );
57 58 59 60 61
    m_mainWindow = parent;

    m_panel = new QWidget( this );

    m_view = new QGraphicsView();
62
    m_view->setDragMode( QGraphicsView::RubberBandDrag );
skiunke's avatar
[STYLE]  
skiunke committed
63
    m_view->setRenderHint( QPainter::Antialiasing );
skiunke's avatar
skiunke committed
64
    m_view->setMinimumSize( 20, 20 );
skiunke's avatar
[STYLE]  
skiunke committed
65

66
    m_scene = new WQtNetworkScene();
skiunke's avatar
skiunke committed
67
//    m_scene->setSceneRect( -200.0, -200.0, 400.0, 400.0 );
skiunke's avatar
[STYLE]  
skiunke committed
68
    m_scene->setSceneRect( m_scene->itemsBoundingRect() );
69 70 71 72 73 74 75 76

    m_view->setScene( m_scene );

    m_layout = new QVBoxLayout;
    m_layout->addWidget( m_view );

    m_panel->setLayout( m_layout );

77 78
    this->setAllowedAreas( Qt::AllDockWidgetAreas );
    this->setFeatures( QDockWidget::DockWidgetClosable |QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable );
79
    setWidget( m_panel );
Robert Frohl's avatar
Robert Frohl committed
80
    connect( m_scene, SIGNAL( selectionChanged() ), this, SLOT( selectItem() ) );
skiunke's avatar
skiunke committed
81

82 83 84
    // 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.
skiunke's avatar
skiunke committed
85
    QGraphicsRectItem *fake = new QGraphicsRectItem();
86
    fake->setRect( 0, 0, 10, 10 );
skiunke's avatar
skiunke committed
87 88 89 90 91
    fake->setPos( 0, 0 );
    fake->setBrush( Qt::green );
    fake->setFlag( QGraphicsItem::ItemIsMovable, true );
    m_scene->addItem( fake );
    m_scene->setFakeItem( fake );
92 93 94 95 96 97
}

WQtNetworkEditor::~WQtNetworkEditor()
{
}

98 99 100 101
void WQtNetworkEditor::selectItem()
{
    boost::shared_ptr< WModule > module;

102 103
    if ( m_scene->selectedItems().size() != 0 &&
         m_scene->selectedItems().at( 0 )->type() == WQtNetworkItem::Type )
104
    {
105
        if ( m_scene->selectedItems().at(0)->type() == WQtNetworkItem::Type )
Robert Frohl's avatar
Robert Frohl committed
106 107 108
        {
            module = ( static_cast< WQtNetworkItem* >( m_scene->selectedItems().at( 0 ) ) )->getModule();
        }
109

110 111 112 113 114 115
        // crashed modules should not provide any props
        if ( module->isCrashed()() )
        {
             return;
        }

Robert Frohl's avatar
Robert Frohl committed
116
        m_mainWindow->getControlPanel()->setNewActiveModule( module );
117 118 119
    }
    else
    {
Robert Frohl's avatar
Robert Frohl committed
120
        m_mainWindow->getControlPanel()->setNewActiveModule( module );
121 122 123
    }
}

124
void WQtNetworkEditor::addModule( boost::shared_ptr< WModule > module )
125
{
skiunke's avatar
skiunke committed
126
    WQtNetworkItem *netItem = new WQtNetworkItem( this, module );
127
    m_items.push_back( netItem );
skiunke's avatar
skiunke committed
128

129 130
    // set the object at a random start position
    time( &m_time );
131
#ifndef _MSC_VER
132 133
    netItem->setPos( rand_r( ( unsigned int * ) &m_time ) % 200,
                     rand_r( ( unsigned int * ) &m_time ) % 200 );
134 135 136 137
#else
    netItem->setPos( ( rand() + m_time ) % 200,
                     ( rand() + m_time ) % 200 );
#endif
138

139
    m_scene->addItem( netItem );
skiunke's avatar
skiunke committed
140 141

    itemMoved();
142
}
143

144
bool WQtNetworkEditor::event( QEvent* event )
145
{
146 147 148 149 150 151 152
    // 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 )
        {
skiunke's avatar
skiunke committed
153 154
            WLogger::getLogger()->addLogMessage( "Inserting module \"" + e1->getModule()->getName() +
                                                "\" to network editor.", "NetworkEditor", LL_DEBUG );
155
            addModule( e1->getModule() );
156
        }
skiunke's avatar
skiunke committed
157

158
        //TODO(skiunke): disablen des moduls solange nicht rdy!
159 160
        return true;
    }
161

162 163
    // a module changed its state to "ready" -> activate it in dataset browser
    if ( event->type() == WQT_READY_EVENT )
164
    {
skiunke's avatar
skiunke committed
165
        // convert event to ready event
166 167 168 169 170 171 172 173 174 175
        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;
        }

skiunke's avatar
skiunke committed
176
        WLogger::getLogger()->addLogMessage( "Activating module \"" + e->getModule()->getName() + "\" in network editor.",
177 178 179
                                             "NetworkEditor", LL_DEBUG );

        // search all the item matching the module
180
        WQtNetworkItem *item = findItemByModule( e->getModule() );
skiunke's avatar
skiunke committed
181 182 183 184
        if( item != 0 )
        {
            item->activate( true );
        }
185 186 187

        return true;
    }
188

189 190 191 192 193 194 195 196
    // 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.",
skiunke's avatar
skiunke committed
197
                                                 "NetworkEditor", LL_WARNING );
198 199 200
            return true;
        }

skiunke's avatar
skiunke committed
201 202 203 204 205
        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;
206

skiunke's avatar
skiunke committed
207 208 209 210 211
        if( e->getInput()->isInputConnector() == true &&
            e->getOutput()->isOutputConnector() == true )
        {
            mIn = e->getInput()->getModule();
            mOut = e->getOutput()->getModule();
212 213
        }
        else if ( e->getInput()->isOutputConnector() == true &&
skiunke's avatar
skiunke committed
214 215 216 217
                    e->getOutput()->isInputConnector() == true )
        {
            mIn = e->getOutput()->getModule();
            mOut = e->getInput()->getModule();
218 219 220
        }
        else
        {
skiunke's avatar
skiunke committed
221
            return true;
222
            //TODO(skiunke): warning
skiunke's avatar
skiunke committed
223
        }
224

225 226
        WQtNetworkItem *inItem = findItemByModule( mIn );
        WQtNetworkItem *outItem = findItemByModule( mOut );
227

228 229
        WQtNetworkInputPort *ip = NULL;
        WQtNetworkOutputPort *op = NULL;
230 231

        for ( QList< WQtNetworkInputPort* >::const_iterator iter = inItem->getInPorts().begin();
232 233 234 235 236 237 238 239 240
                iter != inItem->getInPorts().end();
                ++iter )
        {
            WQtNetworkInputPort *inP = dynamic_cast< WQtNetworkInputPort* >( *iter );
            if( e->getInput() == inP->getConnector() )
            {
                ip = inP;
            }
        }
241

242 243 244 245 246 247 248 249 250 251
        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;
            }
        }
252

253 254 255 256
        if( ip != NULL &&
            op != NULL )
        {
            WQtNetworkArrow *arrow = new WQtNetworkArrow( op, ip );
257

258 259 260 261
            arrow->setZValue( -1000.0 );
            op->addArrow( arrow );
            ip->addArrow( arrow );
            arrow->updatePosition();
262

263 264
            m_scene->addItem( arrow );
        }
265
    }
skiunke's avatar
skiunke committed
266 267 268 269 270


    // a module tree item was disconnected from another one
    if ( event->type() == WQT_MODULE_DISCONNECT_EVENT )
    {
271 272
        WLogger::getLogger()->addLogMessage( "DISCONNECT.", "NetworkEditor", LL_ERROR );

skiunke's avatar
skiunke committed
273 274 275 276 277 278 279 280
        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;
        }
281

282 283 284
        WLogger::getLogger()->addLogMessage( "Disonnecting \"" + e->getInput()->getCanonicalName() +
                                             "\" and \"" + e->getOutput()->getCanonicalName() +
                                             "\"." , "NetworkEditor", LL_DEBUG );
285

skiunke's avatar
skiunke committed
286 287
        boost::shared_ptr< WModule > mIn;
        boost::shared_ptr< WModule > mOut;
288

skiunke's avatar
skiunke committed
289 290 291 292 293
        if( e->getInput()->isInputConnector() == true &&
            e->getOutput()->isOutputConnector() == true )
        {
            mIn = e->getInput()->getModule();
            mOut = e->getOutput()->getModule();
294 295
        }
        else if( e->getInput()->isOutputConnector() == true &&
skiunke's avatar
skiunke committed
296 297 298 299
                    e->getOutput()->isInputConnector() == true )
        {
            mIn = e->getOutput()->getModule();
            mOut = e->getInput()->getModule();
300 301 302
        }
        else
        {
skiunke's avatar
skiunke committed
303
            return true;
304
            //TODO(skiunke): warning
skiunke's avatar
skiunke committed
305 306 307 308 309
        }


        WQtNetworkItem *inItem = findItemByModule( mIn );
        WQtNetworkItem *outItem = findItemByModule( mOut );
skiunke's avatar
skiunke committed
310

311 312 313
        WQtNetworkInputPort *ip = NULL;
        WQtNetworkOutputPort *op = NULL;

314 315 316 317 318 319 320 321 322 323
        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;
           }
        }
324 325 326 327 328 329 330 331 332 333 334
            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;
                }
            }

335
        WQtNetworkArrow *ar = NULL;
336

337
        for ( QList< QGraphicsItem * >::const_iterator iter = m_scene->items().begin();
338 339 340
                iter != m_scene->items().end();
                ++iter )
        {
341
            ar = dynamic_cast< WQtNetworkArrow* >( *iter );
342 343 344 345 346 347 348
            if( ar &&
                ar->getStartPort() == op &&
                ar->getEndPort() == ip )
            {
                break;
            }
        }
349 350
        if ( ar )
        {
351 352
            op->removeArrow( ar );
            ip->removeArrow( ar );
353 354 355 356 357 358
            m_scene->removeItem( ar );
        }
        else
        {
            WLogger::getLogger()->addLogMessage( "Arrow not found!.", "NetworkEditor", LL_ERROR );
        }
359 360

        return true;
skiunke's avatar
skiunke committed
361 362 363 364 365
    }

    // a module was removed from the container
    if ( event->type() == WQT_MODULE_REMOVE_EVENT )
    {
366 367
        WLogger::getLogger()->addLogMessage( "REMOVE.", "NetworkEditor", LL_ERROR );

skiunke's avatar
skiunke committed
368 369 370 371 372 373 374 375 376
        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;
        }

Robert Frohl's avatar
Robert Frohl committed
377
        WLogger::getLogger()->addLogMessage( "Removing \"" + e->getModule()->getName() +
378
                                             "\"from network editor.", "NetworkEditor", LL_DEBUG );
skiunke's avatar
skiunke committed
379 380


381
        WQtNetworkItem *item = findItemByModule( e->getModule() );
382 383
        if( item != 0 )
        {
384
            item->activate( false );
385
            e->getModule()->requestStop(); // TODO(rfrohl): do we need this ?
386 387 388 389 390 391 392 393
        }

        return true;
    }

    // a module tree item should be deleted
    if ( event->type() == WQT_MODULE_DELETE_EVENT )
    {
394 395
        WLogger::getLogger()->addLogMessage( "DELETE.", "NetworkEditor", LL_ERROR );

396 397 398 399
        WModuleDeleteEvent* e = dynamic_cast< WModuleDeleteEvent* >( event );
        if ( !e )
        {
            // this should never happen, since the type is set to WQT_MODULE_REMOVE_EVENT.
400 401
            WLogger::getLogger()->addLogMessage( "Event is not an WModuleRemovedEvent although"
                                                 "its type claims it. Ignoring event.",
402 403 404 405
                                                 "NetworkEditor", LL_WARNING );
            return true;
        }

406 407
        WLogger::getLogger()->addLogMessage( "Delete \"" + e->getTreeItem()->getModule()->getName() +
                                             "\" from network editor", "NetworkEditor", LL_DEBUG );
408

409
        WQtNetworkItem *item = findItemByModule( e->getTreeItem()->getModule() );
skiunke's avatar
skiunke committed
410

411 412
        if( item != 0 )
        {
413
            m_scene->removeItem( item );
414
            m_items.removeAll( item );
415
            delete item;
416
        }
skiunke's avatar
skiunke committed
417 418 419 420

        return true;
    }

421 422 423
    return QDockWidget::event( event );
}

424
WQtNetworkItem* WQtNetworkEditor::findItemByModule( boost::shared_ptr< WModule > module )
425
{
426
    for( QList< WQtNetworkItem* >::const_iterator iter = m_items.begin(); iter != m_items.end(); ++iter )
427 428
    {
       WQtNetworkItem *itemModule = dynamic_cast< WQtNetworkItem* >( *iter );
429 430
       if( itemModule &&
           itemModule->getModule() == module )
431
       {
skiunke's avatar
skiunke committed
432
           return itemModule;
433
       }
434
    }
skiunke's avatar
skiunke committed
435
    return 0;
436
}
skiunke's avatar
skiunke committed
437

438
void WQtNetworkEditor::itemMoved()
skiunke's avatar
skiunke committed
439
{
440 441
    if ( !timerId )
        timerId = startTimer( 1000 / 25 );
skiunke's avatar
skiunke committed
442 443
}

444
void WQtNetworkEditor::timerEvent( QTimerEvent *event )
skiunke's avatar
skiunke committed
445
{
446
    Q_UNUSED( event );
skiunke's avatar
skiunke committed
447

448 449 450 451 452
    QList< WQtNetworkItem *> items;
    foreach( QGraphicsItem *item, m_scene->items() )
    {
        if ( WQtNetworkItem *netItem = dynamic_cast< WQtNetworkItem  *>( item ) )
            items << netItem;
skiunke's avatar
skiunke committed
453 454
    }

455
    foreach( WQtNetworkItem *netItem, items )
skiunke's avatar
skiunke committed
456 457 458
        netItem->calculateForces();

    bool itemsMoved = false;
459 460
    foreach( WQtNetworkItem *netItem, items )
    {
skiunke's avatar
skiunke committed
461 462 463 464
        if ( netItem->advance() )
            itemsMoved = true;
    }

465 466
    if ( !itemsMoved )
    {
skiunke's avatar
skiunke committed
467 468 469 470
        killTimer( timerId );
        timerId = 0;
    }
}