/* Schema Implementation (Parse Channel XML data) Copyright (c)2011 Mark Watkins <jedimark@users.sourceforge.net> License: GPL */ #include <QFile> #include <QDebug> #include <QDomDocument> #include <QDomElement> #include <QDomNode> #include "schema.h" namespace schema { ChannelList channel; Channel EmptyChannel; QHash<QString,ChanType> ChanTypes; QHash<QString,DataType> DataTypes; QHash<QString,ScopeType> Scopes; bool schema_initialized=false; void init() { if (schema_initialized) return; schema_initialized=true; EmptyChannel=Channel(0,DATA,DAY,"Empty","Empty Channel","",""); ChanTypes["data"]=DATA; //Types["waveform"]=WAVEFORM; ChanTypes["setting"]=SETTING; Scopes["session"]=SESSION; Scopes["day"]=DAY; Scopes["machine"]=MACHINE; Scopes["global"]=GLOBAL; DataTypes[""]=DEFAULT; DataTypes["bool"]=BOOL; DataTypes["double"]=DOUBLE; DataTypes["integer"]=INTEGER; DataTypes["string"]=STRING; DataTypes["richtext"]=RICHTEXT; DataTypes["date"]=DATE; DataTypes["datetime"]=DATETIME; DataTypes["time"]=TIME; schema::channel.Load(":/docs/channels.xml"); } Channel::Channel(int id, ChanType type, ScopeType scope, QString name, QString description, QString label, QString unit, DataType datatype, QColor color, int link): m_id(id), m_type(type), m_scope(scope), m_name(name), m_description(description), m_label(label), m_unit(unit), m_datatype(datatype), m_defaultcolor(color), m_link(link) { } bool Channel::isNull() { return (this==&EmptyChannel); } ChannelList::ChannelList() :m_doctype("channels") { } ChannelList::~ChannelList() { for (QHash<int,Channel *>::iterator i=channels.begin();i!=channels.end();i++) { delete i.value(); } } bool ChannelList::Load(QString filename) { QDomDocument doc(m_doctype); QFile file(filename); qDebug() << "Opening " << filename; if (!file.open(QIODevice::ReadOnly)) { qWarning() << "Could not open" << filename; return false; } QString errorMsg; int errorLine; if (!doc.setContent(&file,false,&errorMsg,&errorLine)) { qWarning() << "Invalid XML Content in" << filename; qWarning() << "Error line" << errorLine <<":" << errorMsg; return false; } file.close(); QDomElement root=doc.documentElement(); if (root.tagName().toLower() != "channels") { return false; } QString language=root.attribute("language","en"); QString version=root.attribute("version",""); if (version.isEmpty()) { qWarning() << "No Version Field in" << m_doctype << "Schema, assuming 1.0" << filename; version="1.0"; } qDebug() << "Processing xml file:" << m_doctype << language << version; QDomNodeList grp=root.elementsByTagName("group"); QDomNode node,n,ch; QDomElement e; bool ok; int id,linkid; QString chantype,scopestr,typestr,name,group,idtxt,details,label,unit,datatypestr,defcolor,link; ChanType type; DataType datatype; Channel *chan; QColor color; //bool multi; ScopeType scope; int line; for (int i=0;i<grp.size();i++) { node=grp.at(i); group=node.toElement().attribute("name"); //qDebug() << "Group Name" << group; // Why do I have to skip the first node here? (shows up empty) n=node.firstChildElement(); while (!n.isNull()) { line=n.lineNumber(); e=n.toElement(); if (e.nodeName().toLower()!="channel") { qWarning() << "Ignoring unrecognized schema type "<< e.nodeName() << "in" << filename << "line" << line; continue; } ch=n.firstChild(); n=n.nextSibling(); idtxt=e.attribute("id"); id=idtxt.toInt(&ok,16); if (!ok) { qWarning() << "Dodgy ID number "<< e.nodeName() << "in" << filename << "line" << line; continue; } chantype=e.attribute("class","data").toLower(); if (!ChanTypes.contains(chantype)) { qWarning() << "Dodgy class "<< chantype << "in" << filename << "line" << line; continue; } type=ChanTypes[chantype]; scopestr=e.attribute("scope","session"); if (scopestr.at(0)==QChar('!')) { scopestr=scopestr.mid(1); //multi=true; } //multi=false; if (!Scopes.contains(scopestr)) { qWarning() << "Dodgy Scope "<< scopestr << "in" << filename << "line" << line; continue; } scope=Scopes[scopestr]; name=e.attribute("name",""); details=e.attribute("details",""); label=e.attribute("label",""); if (name.isEmpty() || details.isEmpty() || label.isEmpty()) { qWarning() << "Missing name,details or label attribute in" << filename << "line" << line; continue; } unit=e.attribute("unit"); defcolor=e.attribute("color","black"); color=QColor(defcolor); if (!color.isValid()) { qWarning() << "Invalid Color "<< defcolor<< "in" << filename << "line" << line; color=Qt::black; } datatypestr=e.attribute("type","").toLower(); link=e.attribute("link",""); if (!link.isEmpty()) { linkid=link.toInt(&ok,16); if (!ok) { qWarning() << "Dodgy Link ID number "<< e.nodeName() << "in" << filename << " line" << line; } } else linkid=0; if (DataTypes.contains(datatypestr)) { datatype=DataTypes[typestr]; } else { qWarning() << "Ignoring unrecognized schema datatype in" << filename <<"line" << line; continue; } if (channels.contains(id)) { qWarning() << "Schema already contains id" << id << "in" << filename <<"line" << line; continue; } if (names.contains(name)) { qWarning() << "Schema already contains name" << name << "in" << filename <<"line" << line; continue; } chan=new Channel(id,type,scope,name,details,label,unit,datatype,color,linkid); channels[id]=chan; names[name]=chan; //qDebug() << "Channel" << id << name << label; groups[group][name]=chan; if (linkid>0) { if (channels.contains(linkid)) { Channel *it=channels[linkid]; it->m_links.push_back(chan); //int i=0; } else { qWarning() << "Linked channel must be defined first in" << filename <<"line" << line; } } // process children while(!ch.isNull()) { e=ch.toElement(); QString sub=ch.nodeName().toLower(); QString id2str,name2str; int id2; if (sub=="option") { id2str=e.attribute("id"); id2=id2str.toInt(&ok,10); name2str=e.attribute("value"); //qDebug() << sub << id2 << name2str; chan->addOption(id2,name2str); } else if (sub=="color") { } ch=ch.nextSibling(); } } } return true; } bool ChannelList::Save(QString filename) { Q_UNUSED(filename) return false; } } //typedef schema::Channel * ChannelID;