DrawTrace.hpp 39.1 KB
Newer Older
Mathieu Faverge's avatar
Mathieu Faverge committed
1 2 3 4 5 6 7 8
/*
** This file is part of the ViTE project.
**
** This software is governed by the CeCILL-A license under French law
** and abiding by the rules of distribution of free software. You can
** use, modify and/or redistribute the software under the terms of the
** CeCILL-A license as circulated by CEA, CNRS and INRIA at the following
** URL: "http://www.cecill.info".
9
**
Mathieu Faverge's avatar
Mathieu Faverge committed
10 11 12 13 14
** As a counterpart to the access to the source code and rights to copy,
** modify and redistribute granted by the license, users are provided
** only with a limited warranty and the software's author, the holder of
** the economic rights, and the successive licensors have only limited
** liability.
15
**
Mathieu Faverge's avatar
Mathieu Faverge committed
16 17 18 19 20 21 22 23 24 25
** In this respect, the user's attention is drawn to the risks associated
** with loading, using, modifying and/or developing or reproducing the
** software by the user in light of its specific status of free software,
** that may mean that it is complicated to manipulate, and that also
** therefore means that it is reserved for developers and experienced
** professionals having in-depth computer knowledge. Users are therefore
** encouraged to load and test the software's suitability as regards
** their requirements in conditions enabling the security of their
** systems and/or data to be ensured and, more generally, to use and
** operate it in the same conditions as regards security.
26
**
Mathieu Faverge's avatar
Mathieu Faverge committed
27 28 29 30
** The fact that you are presently reading this means that you have had
** knowledge of the CeCILL-A license and that you accept its terms.
**
**
31
** ViTE developers are (for version 0.* to 1.0):
Mathieu Faverge's avatar
Mathieu Faverge committed
32 33 34 35 36 37 38 39
**
**        - COULOMB Kevin
**        - FAVERGE Mathieu
**        - JAZEIX Johnny
**        - LAGRASSE Olivier
**        - MARCOUEILLE Jule
**        - NOISETTE Pascal
**        - REDONDY Arthur
40
**        - VUCHENER Clément
Mathieu Faverge's avatar
Mathieu Faverge committed
41 42
**
*/
43 44 45 46
/*!
 *\file DrawTrace.hpp
 */

Kevin Coulomb's avatar
Kevin Coulomb committed
47

48 49 50
#ifndef DRAW_TRACE_HPP
#define DRAW_TRACE_HPP

51 52
#include <iostream>

Johnny Jazeix's avatar
Johnny Jazeix committed
53 54 55
/*
 * Theses constants can not be put as static const float because it is a template and there binary representation is not normed by the C++ langage.
 */
56

Johnny Jazeix's avatar
Johnny Jazeix committed
57
/*!
58
 * \def _DRAWING_CONTAINER_HEIGHT_DEFAULT
59
 * \brief The default height for basic containers.
60
 */
Johnny Jazeix's avatar
Johnny Jazeix committed
61
#define _DRAWING_CONTAINER_HEIGHT_DEFAULT 1.2f
62

Johnny Jazeix's avatar
Johnny Jazeix committed
63
/*!
64 65
 * \def _DRAWING_CONTAINER_WIDTH_DEFAULT
 * \brief The default width for containers.
Johnny Jazeix's avatar
Johnny Jazeix committed
66 67 68 69
 */
#define _DRAWING_CONTAINER_WIDTH_DEFAULT 2.5f

/*!
70 71
 * \def _DRAWING_CONTAINER_H_SPACE_DEFAULT
 * \brief The default horizontal space between containers.
Johnny Jazeix's avatar
Johnny Jazeix committed
72 73 74 75
 */
#define _DRAWING_CONTAINER_H_SPACE_DEFAULT 0.1f

/*!
76 77
 * \def _DRAWING_CONTAINER_V_SPACE_DEFAULT
 * \brief The default vertical space between containers.
Johnny Jazeix's avatar
Johnny Jazeix committed
78 79 80 81 82
 */
#define _DRAWING_CONTAINER_V_SPACE_DEFAULT 0.2f


/*!
83 84
 * \def _DRAWING_STATE_HEIGHT_DEFAULT
 * \brief The default height for states.
Johnny Jazeix's avatar
Johnny Jazeix committed
85 86
 */
#define _DRAWING_STATE_HEIGHT_DEFAULT 1.2f
87

Johnny Jazeix's avatar
Johnny Jazeix committed
88
/*!
89 90
 * \def _DRAWING_STATE_V_SPACE_DEFAULT
 * \brief The default vertical space between states.
Johnny Jazeix's avatar
Johnny Jazeix committed
91 92 93 94
 */
#define _DRAWING_STATE_V_SPACE_DEFAULT 0.2f


95
/*!
96 97
 * \class DrawTrace
 * \brief Browse the trace and call back T drawing methods
98
 */
99
/*template<class T>*/
100
class DrawTrace
101 102 103 104 105
{

protected:

    //  Interface_graphic* _window;
106 107 108 109 110 111 112 113 114 115 116 117

    /*!
     * \brief Containers with states or events
     */
    std::list<const Container *> _entity_containers;
    /*!
     * \brief Containers with links
     */
    std::list<const Container *> _link_containers;
    /*!
     * \brief Containers with variables
     */
118
    std::list<const Container *> _variable_containers;
119
    std::map<const Container *, Element_pos, std::less<const Container *> > _container_positions;
120
    std::map<const Container *, Element_pos, std::less<const Container *> > _container_sizes;
121
    std::map<const Variable*, Element_pos> _var_positions;
122

Kevin Coulomb's avatar
Kevin Coulomb committed
123
    // Geometrical informations about the trace shape.
124
    /*!
Kevin Coulomb's avatar
Kevin Coulomb committed
125
     * \brief  _container_width width of the container
126 127
     */
    Element_pos _container_width;
Kevin Coulomb's avatar
Kevin Coulomb committed
128 129 130
    /*!
     * \brief _container_height height of the container
     */
131
    Element_pos _container_height;
Kevin Coulomb's avatar
Kevin Coulomb committed
132 133 134
    /*!
     * \brief _container_h_space Horizontal space beetween 2 containers
     */
135
    Element_pos _container_h_space;
Kevin Coulomb's avatar
Kevin Coulomb committed
136 137 138
    /*!
     * \brief _container_v_space Vertical space between 2 containers
     */
139
    Element_pos _container_v_space;
Kevin Coulomb's avatar
Kevin Coulomb committed
140 141
    /*!
     * \brief _state_height Height of the state
142
     */
143
    Element_pos _state_height;
Kevin Coulomb's avatar
Kevin Coulomb committed
144 145 146
    /*!
     * \brief _state_v_space Vertical space between 2 states
     */
147 148 149 150 151 152 153 154 155 156 157 158 159
    Element_pos _state_v_space;

public:

    /***********************************
     *
     * Constructor and destructor.
     *
     **********************************/

    /*!
     * \brief The default constructor
     */
160
    DrawTrace() {
161 162
        _container_width   = _DRAWING_CONTAINER_WIDTH_DEFAULT;
        _container_height  = _DRAWING_CONTAINER_HEIGHT_DEFAULT;
Olivier Lagrasse's avatar
Olivier Lagrasse committed
163 164
        _container_h_space = _DRAWING_CONTAINER_H_SPACE_DEFAULT;
        _container_v_space = _DRAWING_CONTAINER_V_SPACE_DEFAULT;
165

166 167
        _state_height  = _DRAWING_STATE_HEIGHT_DEFAULT;
        _state_v_space = _DRAWING_STATE_V_SPACE_DEFAULT;
168 169
    }

170

171 172 173
    /*!
     * \brief The destructor
     */
174
    virtual ~DrawTrace() {
175 176 177 178 179 180 181 182
    }

    /***********************************
      *
      * Building functions.
      *
      **********************************/

183
    /*!
Kevin Coulomb's avatar
Kevin Coulomb committed
184
     * \fn build(T* draw_object, Trace* trace)
185 186 187 188
     * \brief The trace building function that do not draw all the containers but only a part.
     * \param draw_object the kind of object which will be drawn (OpenGL, SVG...).
     * \param trace the trace data.
     */
189
    template<class T>
Kevin Coulomb's avatar
Kevin Coulomb committed
190
    void build(T* draw_object, Trace* trace) {
191
        Info::Container::y_max=0;//reset the vertical zoom when rebuilding
Kevin Coulomb's avatar
Kevin Coulomb committed
192 193
        double zoom = trace->get_filter();
        Interval * interval;// = trace->get_interval_constrained();
194 195 196 197 198 199 200 201
        //clear entities
        _container_positions.clear();
        _container_sizes.clear();
        _entity_containers.clear();
        _link_containers.clear();
        _variable_containers.clear();

        std::vector<const Container *> *container = trace->get_selected_container();
Kevin Coulomb's avatar
Kevin Coulomb committed
202 203
        if(container == NULL ||

204
           container->empty()){
205
            container = new std::vector<const Container *>();
206

Kevin Coulomb's avatar
Kevin Coulomb committed
207 208 209
            trace->set_filter(0);

            std::stack<Container *> containers;
210 211
            const Container::Vector *root_containers = trace->get_view_root_containers();
            if(root_containers->empty())root_containers= trace->get_root_containers();
Augustin Degomme's avatar
Augustin Degomme committed
212 213
            for (Container::VectorIt i = root_containers->begin();
                 i != root_containers->end();
Kevin Coulomb's avatar
Kevin Coulomb committed
214 215 216 217
                 i++){
                containers.push(*i);
                container->push_back(*i);
            }
218
            add(container, &containers);
Kevin Coulomb's avatar
Kevin Coulomb committed
219

Kevin Coulomb's avatar
Kevin Coulomb committed
220 221 222
        }
        //Adding the parent containers if not added yet
        else{
223
            bool ended = false;
224
            std::vector<const Container *> store;
225 226 227
            store.clear();
            while (!ended){
                ended = true;
228
                for(std::vector<const Container *>::const_iterator it = container->begin() ;
229 230 231 232 233 234 235 236 237 238
                    it != container->end();
                    it ++){

                    if( *it && (*it)->get_parent())
                        if(!is_in_set((*it)->get_parent(),container)){
                            store.push_back((*it)->get_parent());
                            ended = false;
                        }
                }//end for
                //TODO Warning the same container should be added more than 1 time
239
                for(std::vector<const Container *>::const_iterator it = store.begin() ;
240 241 242 243 244 245 246 247
                    it != store.end();
                    it ++){
                    if( !is_in_set(*it,container))
                        container->push_back(*it);
                }
                store.clear();
            }//end while
        }//end else
248

249

Kevin Coulomb's avatar
Kevin Coulomb committed
250
        interval = trace->get_interval_constrained();
251

252
        draw_object->start_draw();
253

254
        draw_object->start_draw_containers();
Kevin Coulomb's avatar
Kevin Coulomb committed
255
        browse_container_tree(draw_object, trace,container);
256
        draw_object->end_draw_containers();
Kevin Coulomb's avatar
Kevin Coulomb committed
257
        browse_entities(draw_object,zoom,interval,container);
258

259 260
        draw_object->end_draw();
    }
261 262 263 264 265 266

    /***********************************
     *
     * Browsing functions.
     *
     **********************************/
267
    /*
Mathieu Faverge's avatar
Mathieu Faverge committed
268 269 270
     * \fn browse_container_tree
     * \brief Function that browses the containers of the trace argument that
     * are in the set container and make them painted with a T object
271
     */
272
    template<class T>
273
    inline void browse_container_tree(T* draw_object, Trace* trace, std::vector<const Container *> *container){
274
        /*** Drawing containers ***/
275
        Element_pos y = 0.;
276

Augustin Degomme's avatar
Augustin Degomme committed
277
        const Container::Vector *root_containers = trace->get_view_root_containers();
Mathieu Faverge's avatar
Mathieu Faverge committed
278 279 280
        if (root_containers->empty())
            root_containers = trace->get_root_containers();

281
        if (root_containers->empty()) {
282
            *Message::get_instance() << QObject::tr("There is no container. The trace can not be drawn.").toStdString() << Message::endw;
283
        }
Mathieu Faverge's avatar
Mathieu Faverge committed
284
        else {
285
            for (Container::VectorIt i = root_containers->begin();
Mathieu Faverge's avatar
Mathieu Faverge committed
286 287 288
                 i != root_containers->end();
                 i++)
                // Use the fact that if a container is selected, then it implies that all his ancestors are
289
                if(is_in_set(*i,container))
Thibault Soucarre's avatar
Thibault Soucarre committed
290
                    y += browse_container(draw_object, *i, 0., y, _container_width, 0., container)+_container_v_space;
Mathieu Faverge's avatar
Mathieu Faverge committed
291
        }
Kevin Coulomb's avatar
Kevin Coulomb committed
292
    }/* end browse_container_tree */
293 294 295


    /*
Mathieu Faverge's avatar
Mathieu Faverge committed
296 297 298 299
     * \fn browse_container
     * \brief Recursive function that browse a container to draw it if it is in
     * the set of container with a T painting object in position, knowing the
     * current depth in the tree
300
     */
301
    template<class T>
302 303 304
    Element_pos browse_container(T* draw_object, const Container *container, Element_pos x, Element_pos y,
                         Element_pos w, Element_pos h, std::vector<const Container *> *set_container) {
        //int size = 0;
305

Mathieu Faverge's avatar
Mathieu Faverge committed
306 307 308 309 310
        // Draw children:
        // we want to display only children meant to be displayed
        const Container::Vector *children = container->get_view_children();
        if( children->empty() )
            children = container->get_children();
311 312
        /*if(!children.empty())
         h = 0.;*/
313
        for (Container::VectorIt i = children->begin();
314 315
            i != children->end();
            i++) {
316
            h += browse_container(draw_object, (*i), x + _container_width + _container_h_space, y + h, _container_width, 0., set_container) + _container_v_space;
317
        }
Thibault Soucarre's avatar
Thibault Soucarre committed
318

319 320 321
        // h -= _container_v_space;
        /*if(is_in_set(*i,set_container))
         size += browse_container(draw_object, (*i), position+size, depth+1,set_container);*/
322

323
            // Use one line for states and events
Augustin Degomme's avatar
Augustin Degomme committed
324
#ifdef USE_ITC
Mathieu Faverge's avatar
Mathieu Faverge committed
325 326
        if ( (container->get_states() != NULL && !container->get_states()->empty()) ||
             (container->get_events() != NULL && !container->get_events()->empty()) )
Augustin Degomme's avatar
Augustin Degomme committed
327
#else
Mathieu Faverge's avatar
Mathieu Faverge committed
328 329
        if ( !container->get_states()->empty() ||
             !container->get_events()->empty() )
Augustin Degomme's avatar
Augustin Degomme committed
330
#endif
Mathieu Faverge's avatar
Mathieu Faverge committed
331
        {
332
            h += _container_height + _container_v_space;
333 334
            _entity_containers.push_back(container);
        }
335

François Trahay's avatar
François Trahay committed
336

Thibault Soucarre's avatar
Thibault Soucarre committed
337 338 339 340
        // Store the position to draw links
        _container_positions[container] = y;
        _container_sizes[container] = h;

341 342 343
        // Use one line for each variable
        if (container->get_variable_number() > 0) {
            _variable_containers.push_back(container);
344
            h += (_container_height + _container_v_space) * container->get_variable_number();
345
        }
346

347 348
        if (h < _container_height) // Minimum size
            h = _container_height;
349

350 351 352
        // Push containers with links to draw
        if (!container->get_links()->empty())
            _link_containers.push_back(container);
353

Thibault Soucarre's avatar
Thibault Soucarre committed
354 355
        h -= _container_v_space;

356
        // Draw this container
357
        draw_container(draw_object, x, y, w, h, container->get_name().to_string());
358

359
        return h;
360 361
    }

362 363 364 365 366 367 368 369
    /*!
     * \brief Draw a container
     * \param draw_object Object that contains drawing methods to call
     * \param position Starting line of the container
     * \param size Height of the container in number of line
     * \param depth Depth of container in the tree
     * \param text Name of the container
     */
370
    template<class T>
371 372 373 374
    inline void draw_container(T* draw_object, Element_pos x, Element_pos y, Element_pos w, Element_pos h, const std::string &text) {
        //Element_pos x      = depth   *(_container_width +_container_h_space) + _container_h_space/2;
        //Element_pos y      = position*(_container_height+_container_v_space) + _container_v_space/2;
        //Element_pos height = size    *(_container_height+_container_v_space) - _container_v_space;
375 376
        draw_object->draw_container(x, y+_container_v_space/2, w, h, text);
        //draw_object->draw_container_text(x, y+h/2, text);
377
    }
Mathieu Faverge's avatar
Mathieu Faverge committed
378

379 380 381
    /*!
     * \brief Browse the states list and draw them
     */
382
    template<class T>
Kevin Coulomb's avatar
Kevin Coulomb committed
383
    inline void browse_entities(T* draw_object, double zoom, Interval* interval, std::vector<const Container *> *set_container) {
384 385
        //////////////////////////////////////////////////////////
        const Container *container;
386 387 388
        StateChange::Tree *state_tree;
        Event::Tree *event_tree;
        const Link::Vector *link_list;
389
        Link *link;
390
        const std::map<VariableType *, Variable *> *variable_map;
391
        Variable *var;
392
        const std::list<std::pair<Date, Double> > *variable_values;
393
        Element_pos position;
Olivier Lagrasse's avatar
Olivier Lagrasse committed
394 395
        const Color *color;
        std::map<std::string, Value *>::const_iterator field;
396 397
        Element_pos lvl_zoom;

Olivier Lagrasse's avatar
Olivier Lagrasse committed
398 399
        color = NULL;

400 401 402 403
        if(zoom>=0)
            lvl_zoom = zoom;
        else
            lvl_zoom = 0;
Kevin Coulomb's avatar
Kevin Coulomb committed
404

405
        draw_object->start_draw_states();
406
        draw_object->start_draw_events();
407
        for (std::list<const Container *>::const_iterator c = _entity_containers.begin();
408 409 410 411
            c != _entity_containers.end();
            c++) {
            if(is_in_set(*c,set_container)){
                container = *c;
412

413
                position = _container_positions[container] + _container_sizes[container] - (_container_height + _container_v_space);
414

415 416
                state_tree = container->get_states();
                event_tree = container->get_events();
Augustin Degomme's avatar
Augustin Degomme committed
417 418 419 420 421 422 423 424 425
#ifdef USE_ITC
                if(state_tree!=NULL){
#endif
                    if ( !state_tree->empty() ) {
                    //printf("drawing states for %s\n", container->get_name().to_string().c_str());
                        // Browse states
                        DrawTree<T, StateChange>(draw_object, position, lvl_zoom,
                                                 _container_height, _container_v_space, _state_height, _state_v_space)
                            .draw_tree(state_tree, *interval);
426
                                    }
Augustin Degomme's avatar
Augustin Degomme committed
427
#ifdef USE_ITC
428 429
                                }
                                if(event_tree!=NULL){
Augustin Degomme's avatar
Augustin Degomme committed
430
#endif
431 432
                                    if ( !event_tree->empty()){
                                        //printf("drawing events for %s\n", container->get_name().to_string().c_str());
Augustin Degomme's avatar
Augustin Degomme committed
433 434 435 436 437 438
                        // Browse events
                        DrawTree<T, Event>(draw_object, position, lvl_zoom,
                                           _container_height, _container_v_space, _state_height, _state_v_space)
                            .draw_tree(event_tree, *interval);
                    }
#ifdef USE_ITC
439
                }
Augustin Degomme's avatar
Augustin Degomme committed
440
#endif
441 442 443
            }
        }/* end for (!_stack_states.empty()) */

444
        draw_object->end_draw_events();
445
        draw_object->end_draw_states();
446

447 448 449

        draw_object->start_draw_arrows();

450
        for (std::list<const Container *>::const_iterator c = _link_containers.begin();
451 452 453 454
            c != _link_containers.end();
            c++) {
            if(is_in_set(*c,set_container)){
                container = *c;
455 456 457

                // Browse links
                link_list = container->get_links();
458
                for (Link::VectorIt it = link_list->begin();
459 460
                     it != link_list->end();
                     it++) {
461 462 463



464
                    link = *it;
465

466
                    bool display=false;
Augustin Degomme's avatar
 
Augustin Degomme committed
467
                    color=NULL;
468
                    if(!Session::get_use_palette("link_types")) display = true;
469 470
                    else{
                        if (link->get_type()){
Mathieu Faverge's avatar
Mathieu Faverge committed
471 472 473
                            Palette *lt = Session::get_palette("link_types", Session::get_current_palette("link_types"));

                            color = lt->get_color(link->get_type()->get_name().to_string());
Augustin Degomme's avatar
 
Augustin Degomme committed
474
                            if(color) display=true;
475

Augustin Degomme's avatar
 
Augustin Degomme committed
476
                        /*for(std::list<std::string>::const_iterator it2= link_types->get_->begin();
477 478 479
                            it2!= link_types->end();
                            it2++ ){
                            if(*it2 ==  link->get_type()->get_name().to_string()){
480 481
                                display=true;
                                break;
482

483
                            }
Augustin Degomme's avatar
 
Augustin Degomme committed
484
                         } */
485

486 487 488 489 490 491
                       }
                    }
                            if(display &&
                            link_is_in_set(link,set_container,interval)){

                                // Search the color
Augustin Degomme's avatar
 
Augustin Degomme committed
492
                                if (color==NULL &&
Augustin Degomme's avatar
Augustin Degomme committed
493
                                    link->get_type()&&
Augustin Degomme's avatar
 
Augustin Degomme committed
494
                                    link->get_type()->get_extra_fields()!=NULL &&
495
                                    !link->get_type()->get_extra_fields()->empty() &&
496 497
                                    ((field = link->get_type()->get_extra_fields()->find(std::string("Color"))) != link->get_type()->get_extra_fields()->end()))
                                    /* Call the object link drawing function with the link color */
498
                                    color = (const Color *)(*field).second;
499 500

                                draw_link(draw_object, link, color );
501 502 503 504
                    }
                }/* end for */
            }//end for
        }/* end while (!_stack_states.empty()) */
505

506 507
        draw_object->end_draw_arrows();
        draw_object->start_draw_counter();
508

509
        for (std::list<const Container *>::const_iterator c = _variable_containers.begin();
510
            c != _variable_containers.end();
511
            c++) {
512

513
            if(is_in_set(*c,set_container)){
514

515
                container = *c;
516
                position = _container_positions[container] + _container_sizes[container];
517

518
                // Browse variables
519
                variable_map = container->get_variables();
520

521 522 523
                for (std::map<VariableType *, Variable *>::const_iterator i = variable_map->begin();
                     i != variable_map->end();
                     i++) {
524

525 526 527 528
                    var = (*i).second;
                    double min = var->get_min().get_value();
                    double max = var->get_max().get_value();
                    variable_values = var->get_values();
529

530 531
                    double first_value = 0.;
                    double second_value = 0.;
532

Thibault Soucarre's avatar
Thibault Soucarre committed
533 534
                    //draw_object->draw_text_value((long int)var,0.0, (position+1)*(_container_height+_container_v_space) - _container_v_space/2 - 0.5*_container_height);
                    draw_object->draw_text_value((long int)var, 0.0, position + 0.5 * _container_height + _container_v_space/2);
535
                    _var_positions[var]=position;
536 537 538 539
                    draw_variable_value(draw_object, 0.0, 0.0, position);
                    for (std::list<std::pair<Date, Double> >::const_iterator value = variable_values->begin();
                         value != variable_values->end();
                         value++) {
540

541 542 543 544 545
                        /* Call the object state drawing function.
                           We pass the first value if correspond to the beginning */
                        first_value = (*value).first.get_value();
                        second_value =((*value).second.get_value()-min)/(max-min) ;
                        if(!(first_value == 0. && second_value == 0.)) {
546
                            draw_variable_value(draw_object, first_value, second_value, position);
547 548 549
                        }
                    }
                    draw_variable_value(draw_object, 0.0, 0.0, position);
Thibault Soucarre's avatar
Thibault Soucarre committed
550
                    position += _container_height + _container_v_space; // One line was used
551 552 553
                }/* end for */
            }
        }//end for
554

555 556
        draw_object->end_draw_counter();
    }
557 558


559 560 561 562 563 564 565
    /*!
     * \brief Draw a point of a variable curve
     * \param draw_object Object that contains the drawing methods
     * \param time Time of the point
     * \param value Value of of the variable (between 0.0 and 1.0)
     * \param position Line where the variable is drawn
     */
566
    template<class T>
Thibault Soucarre's avatar
Thibault Soucarre committed
567 568
    inline void draw_variable_value(T *draw_object, double time, double value, Element_pos position) {
        Element_pos y = position + (_container_height+_container_v_space) -_container_v_space/2 -
569 570 571
            value*_container_height;
        draw_object->draw_counter(time, y);
    }
572

573 574 575 576 577 578 579
    /*!
     * \brief Draw a link
     * \param draw_object Object that contains the drawing methods
     * \param starttime Time of the start of the link
     * \param endtime Time of the end of the link
     * \param start Line of the start of the link
     * \param end Line of the end of the link
Olivier Lagrasse's avatar
Olivier Lagrasse committed
580
     * \param color The link color
581
     */
582
    template<class T>
583 584 585 586 587 588 589 590 591
        inline void draw_link(T *draw_object, const Link *link, const Color* color)
    {
        double starttime = link->get_start_time().get_value();
        double endtime   = link->get_end_time().get_value();
        double srcpos    = _container_positions[link->get_source()];
        double dstpos    = _container_positions[link->get_destination()];
        double srcsize   = _container_sizes[link->get_source()];
        double dstsize   = _container_sizes[link->get_destination()];

592 593
        Element_pos y1 = (srcpos + 0.5 * srcsize);//*(_container_height+_container_v_space);
        Element_pos y2 = (dstpos + 0.5 * dstsize);//*(_container_height+_container_v_space);
Olivier Lagrasse's avatar
Olivier Lagrasse committed
594 595 596 597

        if (color != NULL)
            draw_object->draw_arrow(starttime, endtime, y1, y2, color->get_red(), color->get_green(), color->get_blue());
        else/* Draw white link */
598
            draw_object->draw_arrow(starttime, endtime, y1, y2, 1.0, 1.0, 1.0);
599
    }
600

601 602 603 604 605 606 607 608 609
    /*
     * \brief Assuming someone has clicked in (x, y), display the description corresponding to the item clicked
     */
    void display_information(const Trace *trace, double x, double y, double d) {
        const Container *container = NULL;
        const Container *ancestor = NULL;
        const Link *link;
        const Event *event;
        const State *state;
610
        const Variable *variable;
611

612
        // find container needs to know the position of each container
613
        Element_pos yr = y;
Augustin Degomme's avatar
Augustin Degomme committed
614 615
        const Container::Vector *root_containers = trace->get_view_root_containers();
        if(root_containers->empty())root_containers= trace->get_root_containers();
616
        if (!root_containers->empty())
617
            for (Container::VectorIt i = root_containers->begin();
618 619 620 621
                i != root_containers->end();
                i++)
                if ((container = search_container_by_position(*i, yr)))
                    break;
622

623 624 625
        // If the clic is out
        if (!container)
            return;
626

627 628
        // Calculate the container positions
        int position = 0;
629
        for (Container::VectorIt i = root_containers->begin();
630 631 632
                i != root_containers->end();
                i++)
                position += calc_container_positions(*i, position);
633

634
        // First we browse to find a communication
635
        ancestor = container;
636
        if (!Info::Render::_no_arrows) {
637

638 639 640 641 642 643 644
            while (ancestor) {
                if ((link = get_link(ancestor, x, y, d))) {
                *Message::get_instance() << "<center><strong>Link</strong></center>"
                    << "<strong>Value:</strong> " << link->get_value()->get_name().to_string() << "<br />"
                    << "<strong>Source:</strong> " << link->get_source()->get_name().to_string() << "<br />"
                    << "<strong>Destination:</strong> " << link->get_destination()->get_name().to_string() << "<br />"
                    << "<strong>Type:</strong> " << link->get_type()->get_name().to_string() << "<br />"
645 646
                    << "<strong>Date:</strong> " << link->get_start_time().get_value() << " - " << link->get_end_time().get_value() << "<br />"
                    << "<strong>Duration:</strong> " << link->get_duration() << "<br />";
647
                print_extra_fields("Link", link->get_extra_fields());
648
                print_extra_fields("Value", link->get_value()->get_extra_fields());
649
                print_extra_fields("Type", link->get_type()->get_extra_fields());
650 651 652 653 654
                *Message::get_instance() << Message::endsi;
                    return;
                }
                else
                    ancestor = ancestor->get_parent();
655
            }
656

657
            //if not found, the link may hav been assigned to the first root container.
658

659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
             if ((link = get_link(root_containers->front(), x, y, d))) {
                *Message::get_instance() << "<center><strong>Link</strong></center>"
                    << "<strong>Value:</strong> " << link->get_value()->get_name().to_string() << "<br />"
                    << "<strong>Source:</strong> " << link->get_source()->get_name().to_string() << "<br />"
                    << "<strong>Destination:</strong> " << link->get_destination()->get_name().to_string() << "<br />"
                    << "<strong>Type:</strong> " << link->get_type()->get_name().to_string() << "<br />"
                    << "<strong>Date:</strong> " << link->get_start_time().get_value() << " - " << link->get_end_time().get_value() << "<br />"
                    << "<strong>Duration:</strong> " << link->get_duration() << "<br />";
                print_extra_fields("Link", link->get_extra_fields());
                print_extra_fields("Value", link->get_value()->get_extra_fields());
                print_extra_fields("Type", link->get_type()->get_extra_fields());
                *Message::get_instance() << Message::endsi;
                    return;
                }
        }
674 675
        // Now browsing for the events of the container root
        // Verification if it is a clic on an event
Augustin Degomme's avatar
Augustin Degomme committed
676
#ifndef USE_ITC
677
        if ((!container->get_events()->empty() || !container->get_states()->empty()) && yr < _container_height+_container_v_space) {
Augustin Degomme's avatar
Augustin Degomme committed
678
#else
679
                if (((container->get_states()!=NULL && !container->get_states()->empty()) ||(container->get_events()!=NULL && !container->get_events()->empty())) && yr < _container_height+_container_v_space) {
Augustin Degomme's avatar
Augustin Degomme committed
680
#endif
681 682 683 684 685 686 687
            if (!Info::Render::_no_events)
                if ((event = find_event(container, x, d))) {
                *Message::get_instance() << "<center><strong>Event</strong></center>"
                    << "<strong>Value:</strong> " << event->get_value()->get_name().to_string() << "<br />"
                    << "<strong>Container:</strong> " << event->get_container()->get_name().to_string() << "<br />"
                    << "<strong>Type:</strong> " << event->get_type()->get_name().to_string() << "<br />"
                    << "<strong>Date:</strong> " << event->get_time().get_value() << "<br />";
688
                print_extra_fields("Event", event->get_extra_fields());
689
                print_extra_fields("Value", event->get_value()->get_extra_fields());
690
                print_extra_fields("Type", event->get_type()->get_extra_fields());
691 692 693
                *Message::get_instance() << Message::endsi;
                    return;
                }
694
            if ((state = find_state(container, x))) {
695 696 697 698 699 700
                *Message::get_instance() << "<center><strong>State</strong></center>"
                    << "<strong>Value:</strong> " << state->get_value()->get_name().to_string() << "<br />"
                    << "<strong>Container:</strong> " << state->get_container()->get_name().to_string() << "<br />"
                    << "<strong>Type:</strong> " << state->get_type()->get_name().to_string() << "<br />"
                    << "<strong>Date:</strong> " << state->get_start_time().get_value() << " - " << state->get_end_time().get_value() << "<br />"
                    << "<strong>Duration:</strong> " << state->get_duration() << "<br />";
701
                print_extra_fields("State", state->get_extra_fields());
702
                print_extra_fields("Value", state->get_value()->get_extra_fields());
703
                print_extra_fields("Type", state->get_type()->get_extra_fields());
704
                *Message::get_instance() << Message::endsi;
705 706 707 708
                return;
            }
        }
        else {
709
#ifdef USE_ITC
710
                        if ((container->get_states()!=NULL && !container->get_states()->empty()) ||(container->get_events()!=NULL && !container->get_events()->empty()))
Augustin Degomme's avatar
Augustin Degomme committed
711
#else
712
                        if (!container->get_events()->empty() || !container->get_states()->empty())
Augustin Degomme's avatar
Augustin Degomme committed
713
#endif
714
                yr -= _container_height+_container_v_space;
715 716
            const std::map<VariableType *, Variable *> *variable_map = container->get_variables();
            std::map<VariableType *, Variable *>::const_iterator i = variable_map->begin();
717 718
            while (yr > _container_height+_container_v_space) {
                yr -= _container_height+_container_v_space;
719
                i++;
720 721
            }
            if (i != variable_map->end()) {
722 723 724 725
                variable = (*i).second;
                *Message::get_instance() << "<center><strong>Variable</strong></center>"
                    << "<strong>Container:</strong> " << variable->get_container()->get_name().to_string() << "<br />"
                    << "<strong>Type:</strong> " << variable->get_type()->get_name().to_string() << "<br />"
726
                    << "<strong>Value:</strong> " << variable->get_value_at(x) << "<br />"
727
                    << "<strong>Value:</strong> " << variable->get_value_at(x) << "<br />"
728
                    << "<strong>Min:</strong> " << variable->get_min().get_value()  << "<br />"
729 730 731
                    << "<strong>Max:</strong> " << variable->get_max().get_value() << "<br />";
                print_extra_fields("Type", variable->get_type()->get_extra_fields());
                *Message::get_instance() << Message::endsi;
732

733 734 735
                return;
            }
        }
736

737
        *Message::get_instance() << Message::endsi;
738
        // Nothing has been found
739
        return;
740 741


742
    }
743

744
    void print_extra_fields(std::string name, const std::map<std::string, Value *> *extra_fields) {
745
        if (extra_fields!=NULL &&!extra_fields->empty()) {
746
            *Message::get_instance() << "<em>" << name << " extra fields</em><br />";
747
            for (std::map<std::string, Value *>::const_iterator i = extra_fields->begin();
748 749 750 751 752
                i != extra_fields->end();
                i++)
                *Message::get_instance() << "<strong>" << (*i).first << ":</strong> " << (*i).second->to_string() << "<br />";
        }
    }
753

754
    const Container *search_container_by_position(const Container *container, Element_pos &y) {
755 756
        const Container *result;
        // Search if the result is a descendant
Augustin Degomme's avatar
Augustin Degomme committed
757 758
        const Container::Vector *children = container->get_view_children();//we want to display only children meant to be displayed
        if(children->empty())children = container->get_children();
759
        for (Container::VectorIt i = children->begin();
760 761 762 763 764
            i != children->end();
            i++) {
            if ((result = search_container_by_position(*i, y)) != NULL)
                return result;
        }
765

766
        // Calculate the size of the container (without its children)
767
        int size = 0;
Augustin Degomme's avatar
Augustin Degomme committed
768
#ifdef USE_ITC
769
                if ((container->get_states()!=NULL && !container->get_states()->empty()) ||(container->get_events()!=NULL && !container->get_events()->empty()))
Augustin Degomme's avatar
Augustin Degomme committed
770
#else
771
                if (!container->get_states()->empty() || !container->get_events()->empty())
Augustin Degomme's avatar
Augustin Degomme committed
772
#endif
773
            size++;
774
        if (container->get_variable_number() > 0)
775
            size += container->get_variable_number();
776 777


778 779
        if (children->empty() && size < 1) // Minimum size
            size = 1;
780

781 782 783
        // Test if the position is in this container
        if (y < size*(_container_height+_container_v_space))
            return container;
784 785
        else
            y -= size*(_container_height+_container_v_space);
786

787 788
        // The position is outside this container
        return NULL;
789
    }
790

791 792 793 794 795 796
    /*
     * \fn browse_container(T* draw_object, const Container *container, int position, int depth)
     * \brief Recursive function that browse a container to draw it with a T painting object in position, knowing the current depth in the tree
     */
    int calc_container_positions(const Container *container, int position) {
        int size = 0;
797

798
        // Draw children
Augustin Degomme's avatar
Augustin Degomme committed
799
        const Container::Vector *children = container->get_view_children();//we want to display only children meant to be displayed
800 801
        if( children->empty() )
            children = container->get_children();
802
        for (Container::VectorIt i = children->begin();
803 804 805 806
            i != children->end();
            i++) {
            size += calc_container_positions((*i), position+size);
        }
807

808
        // Store the position to draw links
809 810 811
        _container_positions[container] = position; // First line after children
        _container_sizes[container]     = size; // First line after children

812
        // Use one line for states and events
Augustin Degomme's avatar
Augustin Degomme committed
813
#ifdef USE_ITC
814
                if ((container->get_states()!=NULL && !container->get_states()->empty()) ||(container->get_events()!=NULL && !container->get_events()->empty())){
Augustin Degomme's avatar
Augustin Degomme committed
815
#else
816
                if (!container->get_states()->empty() || !container->get_events()->empty()) {
Augustin Degomme's avatar
Augustin Degomme committed
817
#endif
818 819
            size++;
        }
820

821 822 823 824
        // Use one line for each variable
        if (container->get_variable_number() > 0) {
            size += container->get_variable_number();
        }
825

826 827
        return size;
    }
828

829 830 831 832
    /*!
     * \brief Tries to find a link passing by x and y in the container
     */
    const Link* get_link(const Container *container, Element_pos x, Element_pos y, Element_pos d) {
833
        const Link::Vector *link_list;
834 835 836
        Link *link;
        double a, b, c; // Equation: ax + by + c = 0
        double x1, x2, y1, y2;
837

838 839
        if(!container)
            return NULL;
840

841 842
        // Browse links
        link_list = container->get_links();
843
        for (Link::VectorIt it = link_list->begin();
844 845
             it != link_list->end();
             it++) {
846

847
            link = *it;
848 849 850 851 852 853

            double srcpos  = _container_positions[link->get_source()];
            double dstpos  = _container_positions[link->get_destination()];
            double srcsize = _container_sizes[link->get_source()];
            double dstsize = _container_sizes[link->get_destination()];

854 855
            x1 = link->get_start_time().get_value();
            x2 = link->get_end_time().get_value();
856 857 858 859

            y1 = (srcpos + 0.5 * srcsize)*(_container_height+_container_v_space);
            y2 = (dstpos + 0.5 * dstsize)*(_container_height+_container_v_space);

860 861
            if (((x1-d <= x && x <= x2+d) || (x2-d <= x && x <= x1+d)) &&
                ((y1-d <= y && y <= y2+d) || (y2-d <= y && y <= y1+d))) { // Test the interval
862 863
                a = y1 - y2;
                b = x2 - x1;
864
                c = -(a*x1 + b*y1);
865

866
                double e = a*x + b*y + c;
867

868 869 870 871
                if (e*e/(a*a + b*b) < d*d) // Test the distance
                    return link;
            }
        }
872

873 874
        return NULL;
    }
875

876 877 878 879
    /*
     * \brief Returns the event that occurs at the time x in the container
     */
    const Event *find_event(const Container *container, Element_pos x, Element_pos d) {
Augustin Degomme's avatar
Augustin Degomme committed
880
        if(!container || container->get_events()==NULL)
881
            return NULL;
882

883
        Node<Event> *node = container->get_events()->get_root();
884

885 886 887 888 889 890 891 892 893 894 895 896 897
        while(node) {
            Element_pos t = node->get_element()->get_time().get_value();
            if (x < t) {
                if (t - x < d)
                    return node->get_element();
                node = node->get_left_child();
            }
            else {
                if (x - t < d)
                    return node->get_element();
                node = node->get_right_child();
            }
        }
898

899 900
        return NULL;
    }
901

902 903 904 905
    /*
     * \brief Returns the state at the time x
     */
    const State * find_state(const Container *container, Element_pos x) {
Augustin Degomme's avatar
Augustin Degomme committed
906
        if(!container || container->get_states()==NULL)
907
            return NULL;
908

909
        Node<StateChange> *node = container->get_states()->get_root();
910

911 912 913
        while(node) {
            Element_pos t = node->get_element()->get_time().get_value();
            if (x < t) {
914
                if (node->get_element()->get_left_state() && node->get_element()->get_left_state()->get_start_time().get_value() < x)
915 916 917 918
                    return node->get_element()->get_left_state();
                node = node->get_left_child();
            }
            else {
919
                if (node->get_element()->get_right_state() && x < node->get_element()->get_right_state()->get_end_time().get_value())
920 921 922 923
                    return node->get_element()->get_right_state();
                node = node->get_right_child();
            }
        }
924

925 926
        return NULL;
    }
927 928


929
  bool link_is_in_set(Link * link, std::vecto