Commit 6a4961db authored by Augustin Degomme's avatar Augustin Degomme

fixes :

- fix build on windows platforms where getopt is not present : add a version of getopt called xgetopt (license ok) when called on Windows.
- fix parsing issues with Paje traces on Windows, caused by the switch to std::getline, and the fact that it now removes the endline character (the character after the end of an std::line is seen as a \n on linux, so the bug is not apparent but still present)

feature :
- add a window that allows the user to select the containers to display, reorder them or hide them (by drag and drop and checking/unchecking). The selected display can be saved to an xml file, and reloaded for another trace. Found in Preferences/Node Selection
- add the flag -c to specify such an xml file to load initially for a trace

known issues and todo :
- only works with OpenGl render : separate interface from work on the xml file to allow use with SVC
- zoom is badly handled, and containers are not redrawn with new sizes yet
- no tests done with non Paje traces, should work though
- lacks comments and cleaning
- put the window as a plugin ?
parent 887128d9
......@@ -98,8 +98,11 @@ SET(VITE_HDRS
interface/Interface.hpp
interface/Settings_window.hpp
interface/Interface_graphic.hpp
interface/Node_select.hpp
interface/viteqtreewidget.hpp
# Core header
core/Core.hpp
core/getopt.h
# Parser headers
parser/ParsingThread.hpp
parser/Parser.hpp
......@@ -132,6 +135,7 @@ SET(VITE_UIS
interface/stats_viewer.ui
interface/global_cmd.ui
interface/list_of_counter_to_export.ui
interface/node_select.ui
)
SET(VITE_SRCS
......@@ -194,12 +198,15 @@ SET(VITE_SRCS
# Interface code files
interface/Settings_window.cpp
interface/Interface_graphic.cpp
interface/Node_select.cpp
interface/viteqtreewidget.cpp
# Plugin code file
plugin/Command_window.cpp
plugin/Plugin_window.cpp
plugin/Plugin.cpp
# Core code files
core/Core.cpp
core/getopt.c
# Main
main.cpp
)
......
......@@ -55,11 +55,17 @@
#include <map>
#include <vector>
#include <stack>
#ifndef WIN32
#include <cmath>
#include <unistd.h>
#include <unistd.h>*
#if defined(HAVE_GETOPT_H)
#include <getopt.h>
#endif /* defined(HAVE_GETOPT_H) */
#else
#include <core/getopt.h>
#endif
/* -- */
#include <QObject>
//#include <QtUiTools>/* for the run-time loading .ui file */
......@@ -102,6 +108,7 @@
/* -- */
#include "statistics/Stats_window.hpp"
/* -- */
#include "interface/Node_select.hpp"
#include "interface/Interface_graphic.hpp"
#include "core/Core.hpp"
/* -- */
......@@ -320,18 +327,24 @@ bool Core::draw_trace(const string & filename, const int format) {
if (Info::Render::_x_min_visible == Info::Render::_x_max_visible){// first time
_trace->set_interval_constrained(new Interval(0,_trace->get_max_date()));
}else{
// _trace->set_interval_constrained(new Interval(Info::Render::_x_min_visible, Info::Render::_x_max_visible));
_trace->set_interval_constrained(new Interval(Info::Render::_x_min_visible, Info::Render::_x_max_visible));
//
// WARNING I HAVE COMMENTED THIS LINE BECAUSE I FOUND IT USELESS. I TRIED AFTER AND NO BUG APPEARED
// MOREOVER IT ENABLES THE PLUGIN TIME SELECTION
//
}
// if(_state & _STATE_IN_AN_INTERVAL) {
// _trace->set_interval_constrained(new Interval(_time_start,_time_end));
// }
if (_DRAW_OPENGL == format) {
if(!_xml_config_file.empty() && _trace->get_view_root_containers()->empty()){//if we have a partial loading, process it here, but only once
launch_action(_DRAW_OPENGL_PARTIAL,NULL);
}
drawing_ogl.build(&render, _trace);
_render_opengl->build();
// _render_opengl->updateGL();
......@@ -413,13 +426,14 @@ int Core::run(){
*
*
**********************************/
#define GETOPT_STRING "t:e:i:h"
#define GETOPT_STRING "t:e:c:i:h"
#if defined(HAVE_GETOPT_LONG)
static struct option long_options[] =
{
{"interval", required_argument, 0, 't'},
{"export", required_argument, 0, 'e'},
{"load_containers_config", required_argument, 0, 'c'},
{"input", required_argument, 0, 'i'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
......@@ -488,6 +502,10 @@ int Core::get_state(int argc, char** argv){
case 'h' :
return _STATE_DISPLAY_HELP;
case 'c' :
_xml_config_file = optarg;
//cerr << "Export in file: " << _path_to_export << endl;
break;
default:
continue;
......@@ -790,11 +808,30 @@ void Core::launch_action(int state, void* arg) {
case _STATE_RENDER_UPDATE:
_render_opengl->updateGL();
break;
case _STATE_CLEAN_RENDER_AREA:
if (_render_opengl->unbuild()==false)
message << "Close file : an error occured while cleaning the render." << Message::ende;
break;
case _STATE_RENDER_SHOW_MINIMAP:
_render_opengl->show_minimap();
break;
case _DRAW_OPENGL_PARTIAL:
{
_main_window->get_node_select()->set_trace(_trace);
bool xml_success = _main_window->get_node_select()->load_config_from_xml(QString(_xml_config_file.c_str()));
if(xml_success){
std::list<Container *> displayed_containers;
_main_window->get_node_select()->build_displayed_nodes(displayed_containers);
_trace->set_view_root_containers(displayed_containers);
}else{
message << "Error while parsing" << _xml_config_file << Message::ende;
}
break;
}
default:/* like _STATE_UNKNOWN */
display_help();
warning(string("Cannot determine the arguments past. Please check the correct syntax."));
......@@ -812,6 +849,7 @@ void Core::display_help(){
<< " -a display all the inputfile (Default)" << endl
<< " -t [T0]:[T1] display the interval [T0:T1] (Default: T0 = 0 and T1 = Tmax)" << endl
<< " -e outputfile export the trace file in the svg format to outpufile" << endl
<< " -c xmlfile import a list of containers to display from an xml file" << endl
<< endl;
}
......
......@@ -212,6 +212,7 @@ public:
*/
static const int _DRAW_OPENGL_PARTIAL = 24;
static const int _STATE_CLEAN_RENDER_AREA = 25;
/*!
* \brief Launch an action according to the argument state value.
* \param state An integer corresponding to a kind of action which must be executed.
......@@ -302,6 +303,11 @@ protected:
*/
std::string _file_opened;
/*!
*\brief If a container's config file has to be opened, this attribute contains its path.
*/
std::string _xml_config_file;
/*!
*\brief If a file must be exported, this attribute contains its path.
*/
......
#include <windows.h>
#include <stdio.h>
char *optarg; // global argument pointer
int optind = 0; // global argv index
char c;
char *cp;
int getopt(int argc, char *argv[], char *optstring)
{
static char *next = NULL;
if (optind == 0)
next = NULL;
optarg = NULL;
if (next == NULL || *next == '\0')
{
if (optind == 0)
optind++;
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
{
optarg = NULL;
if (optind < argc)
optarg = argv[optind];
return EOF;
}
if (strcmp(argv[optind], "--") == 0)
{
optind++;
optarg = NULL;
if (optind < argc)
optarg = argv[optind];
return EOF;
}
next = argv[optind];
next++; // skip past -
optind++;
}
c = *next++;
cp = strchr(optstring, c);
if (cp == NULL || c == ':')
return '?';
cp++;
if (*cp == ':')
{
if (*next != '\0')
{
optarg = next;
next = NULL;
}
else if (optind < argc)
{
optarg = argv[optind];
optind++;
}
else
{
return '?';
}
}
return c;
}
\ No newline at end of file
/******************************************************************************
fgdump - by fizzgig and the foofus.net group
Copyright (C) 2005 by fizzgig
http://www.foofus.net
This program 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 2
of the License, or (at your option) any later version.
This program 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 for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
******************************************************************************/
// XGetopt.h Version 1.2
//
// Author: Hans Dietrich
// hdietrich2@hotmail.com
//
// This software is released into the public domain.
// You are free to use it in any way you like.
//
// This software is provided "as is" with no expressed
// or implied warranty. I accept no liability for any
// damage or loss of business that this software may cause.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef XGETOPT_H
#define XGETOPT_H
extern "C" int optind, opterr;
extern "C" char *optarg;
extern "C" int getopt(int argc, char *argv[], char *optstring);
#endif //XGETOPT_H
\ No newline at end of file
......@@ -118,9 +118,21 @@ Interface_graphic::Interface_graphic(Core* core, QWidget *parent):QMainWindow(pa
_progress_dialog = NULL;
_plugin_window = NULL;
_ui_settings = NULL;
_ui_node_selection=NULL;
// _cmd_window = NULL;
_cmd_window = new Command_window(this,this);
if (!_ui_node_selection) {
_ui_node_selection = new Node_select(this, 0);
if(_core->get_trace()){
_ui_node_selection->set_trace(_core->get_trace());
}
//connect( _ui_node_selection, SIGNAL(settings_changed()), this, SLOT(update_settings()));
// To close the window when we quit the application
connect(quit, SIGNAL(triggered()), _ui_node_selection, SLOT(close()));
}
// For drag and drop operations
setAcceptDrops(true);
}
......@@ -837,6 +849,21 @@ void Interface_graphic::on_show_settings_triggered() {
_ui_settings->show();
}
void Interface_graphic::on_node_selection_triggered() {
if (!_ui_node_selection) {
_ui_node_selection = new Node_select(this, 0);
if(_core->get_trace()){
_ui_node_selection->set_trace(_core->get_trace());
}
//connect( _ui_node_selection, SIGNAL(settings_changed()), this, SLOT(update_settings()));
// To close the window when we quit the application
connect(quit, SIGNAL(triggered()), _ui_node_selection, SLOT(close()));
}
_ui_node_selection->show();
}
void Interface_graphic::on_actionCommand_triggered(){
if(_core->get_trace()){
if (!_cmd_window)
......@@ -985,6 +1012,9 @@ Core * Interface_graphic::get_console(){
return _core;
}
Node_select* Interface_graphic::get_node_select(){
return _ui_node_selection;
}
void Interface_graphic::update_recent_files_menu() {
const QStringList filenames = Session::get_recent_files();
QString absoluteFilename;
......
......@@ -70,6 +70,7 @@ class QProgressDialog;
/* Global informations */
#include "interface/Interface.hpp"
#include "interface/Settings_window.hpp"
#include "interface/Node_select.hpp"
/*!
*\brief This class is a graphical interface which creates a window, it inherited from the Interface interface.
......@@ -217,6 +218,11 @@ class Interface_graphic : public QMainWindow, protected Ui::main_window, public
* \brief Dialog box to allow user to set its ViTE environment. (change color, text size, etc.)
*/
Settings_window* _ui_settings;
/*!
* \brief Dialog box to allow user to select nodes to display
*/
Node_select* _ui_node_selection;
/*!
* \brief Text area which informs the user about the trace resume.
......@@ -471,6 +477,12 @@ public:
*/
Core *get_console();
/*!
* \fn get_node_select()
* \brief To get the node selection console
*/
Node_select* get_node_select();
/*!
* \fn update_recent_files_menu()
* \brief update the recent files opened menu
......@@ -589,6 +601,11 @@ protected slots:
*\brief A slot called when 'Settings' in the menu is clicked.
*/
void on_show_settings_triggered();
/*!
*\brief A slot called when 'Node selection' in the menu is clicked.
*/
void on_node_selection_triggered();
/*!
* \brief A slot called when 'command' in the menu is clicked.
......
/*
** 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".
**
** 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.
**
** 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.
**
** 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.
**
**
** ViTE developers are (for version 0.* to 1.0):
**
** - COULOMB Kevin
** - FAVERGE Mathieu
** - JAZEIX Johnny
** - LAGRASSE Olivier
** - MARCOUEILLE Jule
** - NOISETTE Pascal
** - REDONDY Arthur
** - VUCHENER Clément
**
*/
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
/* -- */
#include "common/common.hpp"
#include "common/Info.hpp"
#include "common/Message.hpp"
#include "interface/resource.hpp"
#include "interface/Interface.hpp"
#include "core/Core.hpp"
#include "interface/Interface_graphic.hpp"
/* -- */
#include "trace/values/Values.hpp"
#include "trace/EntityValue.hpp"
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/tree/Interval.hpp"
#include "trace/Container.hpp"
/* -- */
#include <QFileDialog> // To choose the file to save
#include <QKeyEvent>
#include <QDropEvent>
#include <QtXml>
#include <QFile>
#include <iostream>
#include "interface/Node_select.hpp"
Q_DECLARE_METATYPE( Container * );
using namespace std;
Node_select::Node_select(Interface_graphic * console,QWidget *parent) :_console(console), QWidget(parent) {
setupUi(this);
QMetaObject::connectSlotsByName(NULL);
}
Node_select::~Node_select() {
}
void Node_select::set_initial_container_names(){
const Container::Vector *root_containers = _trace->get_root_containers();
if(root_containers->empty()) {
*Message::get_instance() << tr("No containers in this trace").toStdString() << Message::ende;
return;
}
_nodes_original->clear();
// Add the root container names
QList<QTreeWidgetItem *> items;
QFlags<Qt::ItemFlag> flg;
for (Container::VectorIt it = root_containers->begin();
it != root_containers->end();
it ++) {
string name = (*it)->get_name().to_string();
QStringList temp(QString::fromStdString(name));
QTreeWidgetItem *current_node = new QTreeWidgetItem((QTreeWidgetItem *)0, temp);
current_node->setData(0,Qt::UserRole,qVariantFromValue(*it));//store the pointer to the container in the Data field
items.append(current_node);
// Recursivity to add the children names
set_container_names_rec(current_node, (*it), flg);
}
_nodes_original->insertTopLevelItems(0, items);
_nodes_original->expandAll();
}
void Node_select::set_displayed_container_names(){
const Container::Vector *root_containers = _trace->get_root_containers();
if(root_containers->empty()) {
*Message::get_instance() << tr("No containers in this trace").toStdString() << Message::ende;
return;
}
// Add the root container names
QList<QTreeWidgetItem *> items;
QFlags<Qt::ItemFlag> flg= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsTristate;
for (Container::VectorIt it = root_containers->begin();
it != root_containers->end();
it ++) {
string name = (*it)->get_name().to_string();
QStringList temp(QString::fromStdString(name));
QTreeWidgetItem *current_node = new QTreeWidgetItem((QTreeWidgetItem *)0, temp);
current_node->setFlags(flg);
current_node->setCheckState(0,Qt::Checked);
current_node->setData(0,Qt::UserRole,qVariantFromValue(*it));//store the pointer to the container in the Data field
items.append(current_node);
// Recursivity to add the children names
set_container_names_rec(current_node, (*it), flg);
}
_nodes_displayed->insertTopLevelItems(0, items);
_nodes_displayed->expandAll();
}
void Node_select::set_container_names_rec(QTreeWidgetItem *current_node, Container *current_container, QFlags<Qt::ItemFlag> flg) {
const Container::Vector *children = current_container->get_children();
//QFlags<Qt::ItemFlag> flg= Qt::ItemIsDragEnabled;
for (Container::VectorIt it = children->begin();
it != children->end();
it ++) {
// We create the node and we do the recursivity
string name = (*it)->get_name().to_string();
QStringList temp(QString::fromStdString(name));
QTreeWidgetItem *node = new QTreeWidgetItem(current_node, temp);
node->setFlags(flg);
node->setData(0,Qt::UserRole, qVariantFromValue(*it));//store the pointer to the container in the Data field
if(flg & Qt::ItemIsUserCheckable)node->setCheckState(0,Qt::Checked);
set_container_names_rec(node ,(*it), flg);
}
}
void Node_select::set_trace(Trace *trace) {
// Initialize _trace
_trace = trace;
// Fill the tree
set_initial_container_names();
set_displayed_container_names();
}
/*
void Stats_window::set_selected_nodes(string kind_of_state){
const list<StateType *> *states_types_list;
list<StateType *>::const_iterator itstat;
list<StateType *>::const_iterator endstat;
const ContainerType *kind_of_container = NULL;
states_types_list = _trace->get_state_types();
endstat = states_types_list->end();
for (itstat = states_types_list->begin();
itstat != endstat;
itstat++){
if ((*itstat)->get_name().to_string() == kind_of_state){
kind_of_container = (*itstat)->get_container_type();
continue;
}
}
// We delete the previous selected containers
if(!_selected_containers.empty()) {
_selected_containers.clear();
}
// We fill the new selected containers
// TODO : Use the tree instead of the list
QTreeWidgetItemIterator it(_nodes_selected);
while (*it) {
if ((*it)->checkState(0) == Qt::Checked){
Container *cont = _trace->search_container((*it)->text(0).toStdString());
//cout << ((ContainerType *)cont->get_type())->get_name().to_string() << " " << ((ContainerType *)kind_of_container)->get_name().to_string() << endl;
if (cont->get_type() == kind_of_container)
_selected_containers.push_back(cont);
}
it ++;
}
_number_of_selected_container = _selected_containers.size();
#ifdef STAT_DEBUG
for(unsigned int i = 0 ; i < _selected_containers.size() ; i ++) {
cout << _selected_containers[i]->get_name().to_string() << endl;
}
#endif
}
*/
void Node_select::on_reset_button_clicked(){
//resets to initial containers,
_displayed_containers.clear();
QList<QTreeWidgetItem *> items;
QTreeWidgetItemIterator it(_nodes_original);//browse only top containers
while (*it) {
if((*it)->parent()==NULL){//we only want parent nodes
_displayed_containers.push_back(((*it)->data(0,Qt::UserRole)).value<Container*>());
reassign_children_rec(*it, 0);
}
++it;
}
_nodes_displayed->clear();
//can we load that from _nodes_original instead ?
set_displayed_container_names();
_trace->set_view_root_containers(_displayed_containers);
//_trace->set_selected_container(_trace->get_root_containers());
_console->get_console()->launch_action(Core:: _STATE_CLEAN_RENDER_AREA);
_console->get_console()->draw_trace(_console->get_filename(),Core::_DRAW_OPENGL);
_console->get_console()->launch_action(Core:: _STATE_RENDER_UPDATE);
}
void Node_select::on_load_button_clicked(){
//load an xml file and appply the structure described inside to the trace
const QString path_by_default = QString(_file_viewed.substr(0, _file_viewed.find_last_of('.')).c_str()) + ".xml";
QString filename = QFileDialog::getOpenFileName(this, tr("Import File"),
path_by_default,
tr("Documents XML (*.xml)"));
if (filename.isEmpty()) {
*Message::get_instance() << tr("No File Selected").toStdString() << Message::ende;
return ;
}
else {
// Adding .svg to the end
if(!filename.endsWith(".xml")) {
filename += ".xml";
}
}
load_config_from_xml(filename);
}
bool Node_select::load_config_from_xml(QString filename){
QDomDocument doc( "Subset" );
QFile file( filename);
if( !file.open( QIODevice::ReadOnly ) ){
*Message::get_instance() << tr("File opening fail").toStdString() << Message::ende;
return false ;
}
if( !doc.setContent( &file ) )
{
file.close();
*Message::get_instance() << tr("File is not a valid xml file").toStdString() << Message::ende;
return false;
}
file.close();
QDomElement root = doc.documentElement();
if( root.tagName() != "nodes" ) {
*Message::get_instance() << tr("File is not a valid xml file").toStdString() << Message::ende;
return false;
}
const Container::Vector *root_containers = _trace->get_root_containers();
_nodes_displayed->clear();
QList<QTreeWidgetItem *> items;
QFlags<Qt::ItemFlag> flg=Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsTristate;
//go through all the top elements of the trace to construct a representation
QDomNode n = root.firstChild();
while( !n.isNull() )
{
QDomElement e = n.toElement();
if( !e.isNull() )
{
if( e.tagName() == "rootNode" )
{
string n(e.attribute( "name", "" ).toStdString());
Container::VectorIt it = root_containers->begin();
for (;
it != root_containers->end();
it ++) {
if((*it)->get_name().to_string()==n){//we found the root container corresponding
QTreeWidgetItem *current_node = new QTreeWidgetItem((QTreeWidgetItem *)0, QStringList(QString::fromStdString(n)));
current_node->setFlags(flg);
current_node->setData(0,Qt::UserRole,qVariantFromValue(*it));//store the pointer to the container in the Data field
current_node->setCheckState(0,Qt::Checked);
items.append(current_node);
// Recursivity to add the children names
load_names_rec(current_node, (*it), flg, e);
break;
}
}
if(it==root_containers->end())*Message::get_instance() << tr("Root node was not found, check if it exists. Continuing ...").toStdString() << Message::ende;
}else
*Message::get_instance() << tr("wrong node was found when parsing for rootNode, check xml construction. Continuing ...").toStdString() << Message::ende;
}
n = n.nextSibling();
}
_nodes_displayed->insertTopLevelItems(0, items);
_nodes_displayed->expandAll();
return true;