Commit a858b3b3 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[CHANGE #9] we now can show html-ified WModuleMetaInfo. This includes...

[CHANGE #9] we now can show html-ified WModuleMetaInfo. This includes everything supported in the META files.
parent a946994b
......@@ -57,6 +57,57 @@
*/
namespace string_utils
{
/**
* Conversion class to convert a string to a given target type. We place this in separate classes as we are not allowed to specialize
* function templates. But we need specializations for certain cases.
*
* \tparam Target target type
*/
template< typename Target >
struct fromStringImpl
{
/**
* Convert a given string to the target type. If this fails, a exception is thrown.
*
* \throw WTypeMismatch if source string cannot be converted to target type value.
*
* \param from source string
*
* \return target value
*/
static Target fromString( const std::string& from )
{
std::stringstream ss( from );
Target value;
ss >> value;
if( ss.fail() )
{
throw WTypeMismatch( "Specified string could not be converted to target type." );
}
return value;
}
};
/**
* Conversion class to convert a string to a given target type. This is a specialization whenever a string is given as input type
*/
template<>
struct fromStringImpl< std::string >
{
/**
* Convert a given string to the target type. Never fails.
*
* \param from source string
*
* \return copy of the source string
*/
static std::string fromString( const std::string& from )
{
return from;
}
};
/**
* Convert a given value to a string. The input value must provide a operator<< or be a standard scalar type.
*
......@@ -106,14 +157,7 @@ namespace string_utils
template< typename T >
inline T fromString( const std::string& str )
{
std::stringstream ss( str );
T value;
ss >> value;
if( ss.fail() )
{
throw WTypeMismatch( "Specified string could not be converted to target type." );
}
return value;
return fromStringImpl< T >::fromString( str );
}
/** We consider the following characters as whitespace:
......@@ -185,8 +229,8 @@ namespace string_utils
* \return A vector of strings containing the tokens.
*/
std::vector< std::string > tokenize( const std::string& source,
const std::string& delim = WHITESPACE,
bool compress = true );
const std::string& delim = WHITESPACE,
bool compress = true );
/**
* Writes every vector to an output stream such as cout, if its elements
......
......@@ -49,7 +49,7 @@
#include "exceptions/WNotFound.h"
/**
* This namespace contains the WStructuredTextParser data types and the parser. It builds up the abstract syntax tree (AST)
* This namespace contains the WStructuredTextParser data types and the parser. It builds up the abstract syntax tree (AST)
* for the given input which later can be traversed.
*/
namespace WStructuredTextParser
......@@ -186,14 +186,14 @@ namespace WStructuredTextParser
explicit Grammar( std::ostream& error ): Grammar::base_type( file, "WStructuredTextParser::Grammar" ) // NOLINT - non-const ref
{
// a key begins with a letter
key %= qi::char_( "a-zA-Z_" ) >> *qi::char_( "a-zA-Z_0-9" );
key %= qi::char_( "a-zA-Z_" ) >> *qi::char_( "a-zA-Z_0-9" );
// a value is a quoted string. Multi-line strings possible
value %= qi::lexeme[ '"' >> +( qi::char_ - '"' ) >> '"' ];
value %= '"' >> *( ~qi::char_( "\"" ) | qi::char_( " " ) ) >> '"';
// a pair is: key = value
kvpair %= key >> '=' >> value >> ';';
kvpair %= key >> '=' >> value >> ';';
// a comment is // + arbitrary symbols
comment %= qi::lexeme[ qi::char_( "/" ) >> qi::char_( "/" ) ] >>
qi::lexeme[ *qi::char_( "a-zA-Z_0-9!\"#$%&'()*,:;<>?@\\^`{|}~/ .@=[]§!+-" ) ];
comment %= qi::lexeme[ qi::char_( "/" ) >> qi::char_( "/" ) >> *qi::char_( "a-zA-Z_0-9!\"#$%&'()*,:;<>?@\\^`{|}~/ .@=[]§!+-" ) ];
// a object is a name, and a set of nested objects or key-value pairs
object %= ( key | value ) >> '{' >> *( object | kvpair | comment ) >> '}' >> *qi::char_( ";" );
// a file is basically an object without name.
......@@ -247,7 +247,7 @@ namespace WStructuredTextParser
/**
* Value rule. See constructor for exact definition.
*/
qi::rule< Iterator, ValueType(), ascii::space_type > value;
qi::rule< Iterator, ValueType() > value;
};
/**
......
......@@ -25,6 +25,7 @@
#ifndef WSTRUCTUREDTEXTPARSER_TEST_H
#define WSTRUCTUREDTEXTPARSER_TEST_H
#include <iostream>
#include <string>
#include <vector>
......@@ -139,8 +140,10 @@ public:
// query only values here.
// this MUST return the first found value
TS_ASSERT( t.getValue< std::string >( "level0/notuniquekv", "default" ) == "hello" );
TS_ASSERT_EQUALS( t.getValue< std::string >( "level0/notuniquekv", "default" ), "hello hallo" );
TS_ASSERT( t.getValue< std::string >( "level0/notuniquelevel1/somekv", "default" ) == "abc" );
TS_ASSERT_EQUALS( t.getValue< std::string >( "level0/uniquekv", "default" ), "hello" );
// even if the object name is not unique, it needs to find the unique key value pair
TS_ASSERT( t.getValue< std::string >( "level0/notuniquelevel1/unique", "default" ) == "yes" );
......
......@@ -31,7 +31,7 @@ level0
// test whether the parser finds these key-value pairs (KV)
uniquekv = "hello";
// test if it is able to handle multile, equally named KV
notuniquekv = "hello";
notuniquekv = "hello hallo";
notuniquekv = "world";
// test whether it can handle sub-classes
......
......@@ -22,6 +22,8 @@
//
//---------------------------------------------------------------------------
#include <vector>
#include "WDataSetDipole.h"
// prototype instance as singleton
......
......@@ -25,11 +25,12 @@
#ifndef WDATASETDIPOLE_H
#define WDATASETDIPOLE_H
#include <vector>
#include <boost/shared_ptr.hpp>
#include "WDataSet.h"
/**
* Represents a dipole dataset.
*/
......
......@@ -355,6 +355,15 @@ public:
* \return deprecation message
*/
std::string getDeprecationMessage() const;
/**
* The meta information of this module. This contains several information like name, description, icons, help links and so on. It, at least,
* contains the name.
*
* \return the meta info object for this module.
*/
virtual WModuleMetaInformation::ConstSPtr getMetaInformation() const;
protected:
/**
* Entry point after loading the module. Runs in separate thread.
......@@ -418,14 +427,6 @@ protected:
*/
virtual std::string deprecated() const;
/**
* The meta information of this module. This contains several information like name, description, icons, help links and so on. It, at least,
* contains the name.
*
* \return the meta info object for this module.
*/
virtual WModuleMetaInformation::ConstSPtr getMetaInformation() const;
/**
* Manages connector initialization. Gets called by module container.
*
......
......@@ -133,32 +133,36 @@ std::vector< WModuleMetaInformation::Author > WModuleMetaInformation::getAuthors
{
std::vector< WModuleMetaInformation::Author > r;
// did we find some author info? If not, add a nice default OpenWalnut author
WModuleMetaInformation::Author ow = { "OpenWalnut Project", "http://www.openwalnut.org", "", "Design, Development, and Bug Fixing" };
// return a default if not meta data was loaded
if( !m_loaded )
{
r.push_back( ow );
return r;
}
// how much author information is available?
std::vector< std::string > authors = m_metaData.getValues< std::string >( m_name + "/author" );
// prepare some memory
r.resize( authors.size() );
if( authors.empty() )
{
r.push_back( ow );
return r;
}
// for each author, get some associated data if available
// prepare some memory
r.resize( authors.size() );
for( std::vector< std::string >::const_iterator i = authors.begin(); i != authors.end(); ++i )
{
r[ i - authors.begin() ].m_name = *i;
r[ i - authors.begin() ].m_email = m_metaData.getValue< std::string >( m_name + "/" + *i + "/email", "" );
r[ i - authors.begin() ].m_what = m_metaData.getValue< std::string >( m_name + "/" + *i + "/what", "" );
r[ i - authors.begin() ].m_url = m_metaData.getValue< std::string >( m_name + "/" + *i + "/url", "" );
}
// did we find some author info? If not, add a nice default OpenWalnut author
if( !r.size() )
{
WModuleMetaInformation::Author ow = { "OpenWalnut Project", "", "http://www.openwalnut.org", "Design, Development and Bug fixing" };
r.push_back( ow );
}
return r;
}
......@@ -210,3 +214,38 @@ std::vector< std::string > WModuleMetaInformation::getTags() const
return m_metaData.getValues< std::string >( m_name + "/tag" );
}
std::vector< WModuleMetaInformation::Screenshot > WModuleMetaInformation::getScreenshots() const
{
std::vector< WModuleMetaInformation::Screenshot > r;
// return a default if not meta data was loaded
if( !m_loaded )
{
return r;
}
// get the "screenshot"-subtrees
typedef std::vector< WStructuredTextParser::StructuredValueTree > TreeList;
TreeList screenshotInfos = m_metaData.getSubTrees( m_name + "/screenshot" );
for( TreeList::const_iterator i = screenshotInfos.begin(); i != screenshotInfos.end(); ++i )
{
WModuleMetaInformation::Screenshot s;
// get all info:
// these are required
s.m_filename = ( *i ).getValue< boost::filesystem::path >( "filename", "" );
if( s.m_filename.empty() )
{
continue;
}
// optional
s.m_description = ( *i ).getValue< std::string >( "description", "" );
// add
r.push_back( s );
}
return r;
}
......@@ -103,6 +103,22 @@ public:
std::string m_url;
};
/**
* Structure to encapsulate a screenshot info
*/
struct Screenshot
{
/**
* The screenshot filename
*/
boost::filesystem::path m_filename;
/**
* The description text shown for the screenshot.
*/
std::string m_description;
};
/**
* Constructor. The help object will be empty, meaning there is no further meta info available. The name is the only required value. Of
* course, this is of limited use in most cases.
......@@ -179,6 +195,13 @@ public:
* \return the tag list.
*/
std::vector< std::string > getTags() const;
/**
* Returns the list of screenshots.
*
* \return the screenshot list.
*/
std::vector< Screenshot > getScreenshots() const;
protected:
private:
/**
......
......@@ -54,7 +54,7 @@
// Provide author information. Especially a contact address is very handy.
// This associates some URL and Mail contact info to "OpenWalnut Project".
"OpenWalnut Project"
"OpenWalnut Project"
{
url="http://www.openwalnut.org";
email="contact@openwalnut.org";
......@@ -68,7 +68,7 @@
// Provide some tags to have modules nicely grouped and ordered.
// NOTE: tags are handled case insesitive.
// IMPORTANT: the order of appearance will be used by OW to classify your tags
// IMPORTANT: the order of appearance will be used by OW to classify your tags
tag = "Navigation";
tag = "MRT";
......@@ -96,5 +96,12 @@
description="Video demonstration showing basic working principoles.";
url="http://www.youtube.com/watch?v=5Afw6P6wWSU&context=C375513dADOEgsToPDskJXOVbrVDAV5rydr7H173AT";
};
// You can also provide screenshots with an optional description. Multiple screenshots allowed.
screenshot
{
description = "Navigation Slices showing a scalar T1 Dataset.";
filename = "t1.png";
};
};
......@@ -24,6 +24,7 @@
#include <fstream>
#include <string>
#include <vector>
#include "core/common/WPathHelper.h"
#include "core/dataHandler/WDataSetDipole.h"
......@@ -148,7 +149,7 @@ boost::shared_ptr< WDataSetDipole > WMReadDipoles::readData( std::string filenam
{
times[timeStep] = timeFirst + timeStep * timeDistance;
}
std::cout<<times[nbTimeSteps-1]<< " " << timeLast << std::endl;
std::cout << times[nbTimeSteps-1]<< " " << timeLast << std::endl;
WAssert( std::abs( times[nbTimeSteps-1] - timeLast ) < 1e-4, "Error during filling times vector." );
while( line.find( "PositionsFixed" ) )
......
......@@ -22,15 +22,241 @@
//
//---------------------------------------------------------------------------
#include <string>
#include <vector>
#include <iostream>
#include <QtGui/QVBoxLayout>
#ifndef QT4GUI_NOWEBKIT
#include <QtWebKit/QWebView>
#include <QtWebKit/QWebFrame>
#include <QtWebKit/QWebPage>
#include <QtGui/QToolBar>
#include <QtGui/QToolButton>
#include <QtGui/QHBoxLayout>
#include <QtGui/QWidget>
#include <QtGui/QPixmap>
#include <QtGui/QIcon>
#include <QtGui/QAction>
#else
#include <QtGui/QTextEdit>
#endif
#include "core/common/WIOTools.h"
#include "core/common/WLogger.h"
#include "core/common/WPathHelper.h"
#include "WQtModuleMetaInfo.h"
#include "WQtModuleMetaInfo.moc"
std::string htmlify( WModuleMetaInformation::ConstSPtr meta )
{
typedef std::vector< WModuleMetaInformation::Author > AuthorType;
AuthorType authors = meta->getAuthors();
typedef std::vector< std::string > TagType;
TagType tags = meta->getTags();
boost::filesystem::path help = meta->getHelp();
std::string website = meta->getWebsite();
std::string description = meta->getDescription();
typedef std::vector< WModuleMetaInformation::Online > OnlineType;
OnlineType online = meta->getOnlineResources();
typedef std::vector< WModuleMetaInformation::Screenshot > ScreenshotType;
ScreenshotType screenshots = meta->getScreenshots();
// where to put in the html code
std::ostringstream ss;
// the website URL is the module dir -> so we need to explicitly specify the src for icons
std::string iconPath = WPathHelper::getSharePath().string() + "/qt4gui/";
ss << "<div style='font-family:sans-serif;'>"
// The title
<< " <div style='padding:10px; border:0px solid #000; border-bottom-width: 10px;color:#fff;background:#0c67a8;'>"
<< " <h1>"
<< meta->getName()
<< " </h1>"
<< " </div>";
// Description
ss << " <div style='padding:10px; background:#ddd;'>"
<< " <h3>DESCRIPTION</h3>"
<< " <p align='justify'>"
<< description
<< " </p>"
<< " </div>";
// this div contains tags, help, website and authors
ss << " <div style='padding:10px;background:#f3f3f3;'>";
// Taglist
if( !tags.empty() )
{
ss << " <h3>TAGS</h3>";
for( TagType::const_iterator iter = tags.begin(); iter != tags.end(); ++iter )
{
ss << *iter;
if( iter+1 != tags.end() )
{
ss << ", ";
}
}
}
// Website
if( !website.empty() )
{
ss << " <h3>WEBSITE</h3>"
<< " <a href='" << website << "'>" << website << "</a>";
}
// Help
if( !help.empty() )
{
ss << " <h3>HELP</h3>"
<< " <a href='" << help.string() << "'>Module Help</a>";
}
// The authors
if( !authors.empty() )
{
ss << " <h3>AUTHORS</h3>"
<< " <table width='100%' style='padding:10px'>";
for( AuthorType::const_iterator iter = authors.begin(); iter != authors.end(); ++iter )
{
ss << "<tr> <td style='padding:10px; background:#ddd;'>";
if( !( *iter ).m_email.empty() )
{
ss << "<a href='mailto:" << ( *iter ).m_email << "'>" << "<img width='24px' src='" << iconPath << "/email.png' />" << "</a>";
}
if( !( *iter ).m_url.empty() )
{
ss << "<a href='" << ( *iter ).m_url << "'>" << "<img width='24px' src='" << iconPath << "website.png' />" << "</a>";
}
ss << "&nbsp;";
ss << ( *iter ).m_name;
ss << "</td><td style='padding:10px; background:#e7e7e7;'><p align='justify'>" << ( *iter ).m_what << "</p></td>";
ss << "</tr>";
}
ss << " </table>";
}
// thats it. No more authors, help and similar
ss << " </div>";
// The online resources
if( !online.empty() )
{
ss << " <div style='padding:10px;background:#fff;'>"
<< " <h3>ONLINE RESOURCES</h3>"
<< " <table width='100%' style='padding:10px'>";
for( OnlineType::const_iterator iter = online.begin(); iter != online.end(); ++iter )
{
ss << " <tr>"
<< " <td style='padding:10px; background:#ddd;'>";
ss << " <a href='" << ( *iter ).m_url << "'> " << ( *iter ).m_name << "</a>";
ss << " </td>"
<< " <td style='padding:10px; background:#e7e7e7;'>";
ss << " <p align='justify'>" << ( *iter ).m_description << "</p>";
ss << " </td>"
<< " </tr>";
}
ss << " </table>"
<< " </div>";
}
// screenshots
if( !screenshots.empty() )
{
ss << " <div style='padding:10px;background:#f5f5f5;'>"
<< " <h3>SCREENSHOTS</h3>"
<< " <table width='100%' style='padding:10px'>";
for( ScreenshotType::const_iterator iter = screenshots.begin(); iter != screenshots.end(); ++iter )
{
ss << " <tr>"
<< " <td width='1%' style='padding:10px; background:#ddd;'>";
ss << " <img src='" << ( *iter ).m_filename.string() << "' width=200px>";
ss << " </td>"
<< " <td style='padding:10px; background:#e7e7e7;'>";
ss << " <p align='justify'>" << ( *iter ).m_description << "</p>";
ss << " </td>"
<< " </tr>";
}
ss << " </table>"
<< " </div>"
<< "</div>";
}
return ss.str();
}
WQtModuleMetaInfo::WQtModuleMetaInfo( WModule::SPtr module, QWidget* parent ):
QTextEdit( parent ),
QWidget( parent ),
m_module( module )
{
// initialize members
setText( "Currently in development. Check back soon." );
// some layout to place the webview
QVBoxLayout *layout = new QVBoxLayout();
setLayout( layout );
#ifndef QT4GUI_NOWEBKIT
// create the QT webview
QWebView* view = new QWebView( this );
// create a webpage and add it to the view
QWebPage* page = new QWebPage( this );
page->setLinkDelegationPolicy( QWebPage::DelegateExternalLinks );
m_frame = page->mainFrame();
view->setPage( page );
// add a toolbar for basic navigation
QWidget* toolbar = new QWidget( this );
QHBoxLayout* tbLayout = new QHBoxLayout( toolbar );
toolbar->setLayout( tbLayout );
// we need a special home-action to set the html content again
QAction* homeAction = new QAction( QIcon( QPixmap( module->getXPMIcon() ) ),
QString( "Back to " ) + QString::fromStdString( module->getName() ),
toolbar );
homeAction->setIconText( QString( "Back to " ) + QString::fromStdString( module->getName() ) );
// add the buttons
QToolButton* homeBtn = new QToolButton( toolbar );
homeBtn->setDefaultAction( homeAction );
tbLayout->addWidget( homeBtn );
homeBtn->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );