Optika_treemodel.cpp

Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //         Optika: A Tool For Developing Parameter Obtaining GUIs
00005 //                Copyright (2009) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, with Sandia Corporation, the 
00008 // U.S. Government retains certain rights in this software.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Kurtis Nusbaum (klnusbaum@gmail.com) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 #include <iostream>
00029 #include "Optika_treemodel.hpp"
00030 #include "Teuchos_XMLParameterListWriter.hpp"
00031 #include <QTextStream>
00032 
00033 namespace Optika{
00034 
00035 
00036 TreeModel::TreeModel(Teuchos::RCP<Teuchos::ParameterList> validParameters, QString saveFileName, QObject *parent):
00037   QAbstractItemModel(parent),
00038   dependencies(false),
00039   validParameters(validParameters)
00040 {
00041   basicSetup(saveFileName);
00042 }
00043 
00044 TreeModel::TreeModel(Teuchos::RCP<Teuchos::ParameterList> validParameters, Teuchos::RCP<Optika::DependencySheet> dependencySheet,
00045      QString saveFileName, QObject *parent):
00046    QAbstractItemModel(parent),
00047    dependencies(true),
00048    validParameters(validParameters),
00049    dependencySheet(dependencySheet)
00050 {
00051   basicSetup(saveFileName);
00052   connect(this, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), 
00053     this, SLOT(dataChangedListener(const QModelIndex&, const QModelIndex&)));
00054 }
00055 
00056 TreeModel::~TreeModel() {
00057   delete rootItem;
00058 }
00059 
00060 QVariant TreeModel::data(const QModelIndex &index, int role) const {
00061   if(!index.isValid()){
00062     return QVariant();
00063   }
00064   if(role != Qt::DisplayRole && role != Qt::ToolTipRole){
00065     return QVariant();
00066   }
00067   TreeItem *item = (TreeItem*)(index.internalPointer());
00068   return item->data(index.column(), role);
00069 }
00070 
00071 Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const {
00072   if(!index.isValid()){
00073     return Qt::ItemIsEnabled;
00074   }
00075   else if(index.column() == 1){
00076     return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
00077   }
00078   else{
00079     return QAbstractItemModel::flags(index);
00080   }
00081 }
00082 
00083 QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const{
00084   if(orientation == Qt::Horizontal && role == Qt::DisplayRole){
00085     return rootItem->data(section);
00086   }
00087   return QVariant();
00088 }
00089 
00090 QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const{
00091   if(!hasIndex(row, column, parent)){
00092     return QModelIndex();
00093   }
00094   TreeItem *parentItem;
00095 
00096   if(!parent.isValid()){
00097     parentItem = rootItem;
00098   }
00099   else{
00100     parentItem = (TreeItem*)(parent.internalPointer());
00101   }
00102   TreeItem *childItem = parentItem->child(row);
00103 
00104   if(childItem){
00105     return createIndex(row, column, childItem);
00106   }
00107   return QModelIndex();
00108 }
00109 
00110 QModelIndex TreeModel::parent(const QModelIndex &index) const{
00111   if(!index.isValid()){
00112     return QModelIndex();
00113   }
00114 
00115   TreeItem *childItem = (TreeItem*)(index.internalPointer());
00116   TreeItem *parentItem = childItem->parent();
00117 
00118   if(parentItem == rootItem){
00119     return QModelIndex();
00120   }
00121 
00122   return createIndex(parentItem->row(), 0, parentItem);
00123 }
00124 
00125 bool TreeModel::setData(const QModelIndex & index, const QVariant &value, int role){
00126   if(index.isValid() && index.column() == 1 && role == Qt::EditRole){
00127     TreeItem *item = (TreeItem*)(index.internalPointer());
00128     if(item->changeValue(value)){
00129       emit dataChanged(index, index);
00130     }
00131     return true;
00132   }
00133   return false;
00134 }
00135 
00136 int TreeModel::rowCount(const QModelIndex &parent) const{
00137   TreeItem *parentItem;
00138   if(parent.column() > 0){
00139     return 0;
00140   }
00141 
00142   if (!parent.isValid()){
00143     parentItem = rootItem;
00144   }
00145   else{
00146     parentItem = (TreeItem*)(parent.internalPointer());
00147   }
00148 
00149   return parentItem->childCount();
00150 }
00151 
00152 int TreeModel::columnCount(const QModelIndex &parent) const {
00153   if(parent.isValid()){
00154     return ((TreeItem*)(parent.internalPointer()))->columnCount();
00155   }
00156   else{
00157     return rootItem->columnCount();
00158   }
00159 }
00160 
00161 void TreeModel::issueInitilizationSignals(){
00162   for(DependencySheet::DepMap::const_iterator it = dependencySheet->depBegin(); it != dependencySheet->depEnd(); ++it){
00163     QModelIndex dependeeIndex = findParameterEntryIndex(it->first, (*(it->second.begin()))->getDependeeName(it->first));
00164     dataChangedListener(dependeeIndex, dependeeIndex);
00165   }
00166 }
00167 
00168 void TreeModel::printOut() const{
00169   rootItem->printOut();
00170 }
00171 
00172 bool TreeModel::writeOutput(QString fileName){
00173   QFile *file = new QFile(fileName);
00174   if(!file->open(QIODevice::WriteOnly)){
00175     return false;
00176   }
00177   std::ofstream outputFile;
00178   Teuchos::XMLParameterListWriter plWriter;
00179   Teuchos::XMLObject xmlOutput = plWriter.toXML(*validParameters);
00180   QTextStream outStream(file);
00181   outStream << QString::fromStdString(xmlOutput.toString());
00182   file->close();
00183   delete file;
00184   saved = true;
00185   saveFileName = fileName;
00186   return true;
00187 }
00188 
00189 void TreeModel::readInput(QString fileName){
00190   QFile *file = new QFile(fileName);
00191   file->open(QIODevice::ReadOnly);
00192   QXmlStreamReader xmlReader(file);
00193   while(!xmlReader.atEnd()){
00194     xmlReader.readNext();
00195     if(xmlReader.name().toString() == "Parameter" && xmlReader.isStartElement()){
00196       QList<QModelIndex> matches = match(index(0,0), Qt::DisplayRole, xmlReader.attributes().value("name").toString(),
00197                  1, Qt::MatchExactly | Qt::MatchRecursive);
00198       if(matches.size() !=0){
00199         QModelIndex valueToEdit = matches.at(0).sibling(matches.at(0).row(), 1);
00200         setData(valueToEdit,xmlReader.attributes().value("value").toString(), Qt::EditRole);
00201       }
00202     }
00203   }
00204   file->close();
00205   delete file;
00206   saved = true;
00207   saveFileName = fileName;
00208 }
00209 
00210 QString TreeModel::getSaveFileName(){
00211   return saveFileName;
00212 }
00213 
00214 bool TreeModel::isSaved(){
00215   return saved;
00216 }
00217 
00218 void TreeModel::reset(){
00219   delete rootItem;
00220   QList<QVariant> headers;
00221   headers  << "Parameter" << "Value" << "Type";
00222   rootItem = new TreeItem(headers, 0, 0, true); 
00223   validParameters->setParameters(*canonicalList);
00224   readInParameterList(validParameters, rootItem);
00225   this->saveFileName = saveFileName;
00226   if(saveFileName != ""){
00227     saved = true;
00228     readInput(saveFileName);
00229   }
00230   else{
00231     saved = false;
00232   }
00233   if(dependencies){
00234     issueInitilizationSignals();
00235   }
00236   currentFileNowModified();
00237 }
00238 
00239 QString TreeModel::itemType(const QModelIndex &index) const{
00240   int row = index.row(); 
00241   QModelIndex itemTypeIndex = index.sibling(row, 2);
00242   return index.model()->data(itemTypeIndex, Qt::DisplayRole).toString();
00243 }
00244 
00245 bool TreeModel::hasDependencies(){
00246   return dependencies;
00247 }
00248 
00249 bool TreeModel::hasValidValue(QModelIndex valueToCheck) const{
00250   TreeItem *item = static_cast<TreeItem*>(valueToCheck.internalPointer());
00251   return item->hasValidValue();
00252 }
00253 
00254 Teuchos::RCP<const Teuchos::ParameterEntryValidator> TreeModel::getValidator(const QModelIndex &index) const{
00255   return itemEntry(index)->validator();
00256 }
00257 
00258 Teuchos::RCP<const Teuchos::ParameterList> TreeModel::getCurrentParameters(){
00259   return validParameters;
00260 }
00261 
00262 QModelIndex TreeModel::findParameterEntryIndex(const Teuchos::ParameterEntry *parameterEntry, const std::string parameterName){
00263   QString targetName = QString::fromStdString(parameterName);
00264   QList<QModelIndex> potentialMatches = match(index(0,0), Qt::DisplayRole, QString::fromStdString(parameterName),
00265                       -1, Qt::MatchExactly | Qt::MatchRecursive );
00266   for(QList<QModelIndex>::const_iterator it = potentialMatches.begin(); it != potentialMatches.end(); ++it){
00267     if(parameterEntry == itemEntry(*it)){
00268       return *it;
00269     }
00270   }
00271   return QModelIndex();
00272 }
00273 
00274 
00275 const Teuchos::ParameterEntry* TreeModel::itemEntry(const QModelIndex &index) const{
00276   TreeItem *item = (TreeItem*)(index.internalPointer());
00277   return item->entry();
00278 }
00279 
00280 void TreeModel::readInParameterList(Teuchos::RCP<Teuchos::ParameterList> parameterList, TreeItem *parentItem){
00281   for(Teuchos::ParameterList::ConstIterator itr = parameterList->begin(); itr != parameterList->end(); ++itr){
00282     std::string name = parameterList->name(itr);
00283     if(parameterList->isSublist(name)){
00284       insertParameterList(sublist(parameterList, name), parameterList->getEntryPtr(name), name, parentItem);
00285     }
00286     else if(parameterList->isParameter(name)){
00287       insertParameter(parameterList->getEntryPtr(name), name, parentItem);
00288     }
00289   }
00290 }
00291 
00292 void TreeModel::insertParameterList(Teuchos::RCP<Teuchos::ParameterList> parameterList, Teuchos::ParameterEntry *listEntry, 
00293             std::string name, TreeItem *parent)
00294 {
00295   QList<QVariant> values = QList<QVariant>() << QString::fromStdString(name).section("->",-1) << QString("") << listId;
00296 
00297   TreeItem *newList = new TreeItem(values, listEntry, parent);
00298   parent->appendChild(newList);
00299   for(Teuchos::ParameterList::ConstIterator itr = parameterList->begin(); itr != parameterList->end(); ++itr){
00300     std::string name = parameterList->name(itr);
00301     if(parameterList->isSublist(name)){
00302       insertParameterList(sublist(parameterList, name), parameterList->getEntryPtr(name), name,  newList);
00303     }
00304     else if(parameterList->isParameter(name)){
00305       insertParameter(parameterList->getEntryPtr(name), name, newList);
00306     }
00307   }
00308 }
00309 
00310 void TreeModel::insertParameter(Teuchos::ParameterEntry *parameter, std::string name, TreeItem *parent){
00311   QList<QVariant> values;
00312   values.append(QString::fromStdString(name));
00313   if(parameter->isType<int>()){
00314     values.append(Teuchos::getValue<int>(*parameter));
00315     values.append(intId);
00316   }
00317   else if(parameter->isType<short>()){
00318     values.append(Teuchos::getValue<short>(*parameter));
00319     values.append(shortId);
00320   }
00321   /*else if(parameter->isType<long long>()){
00322     values.append(Teuchos::getValue<long long>(*parameter));
00323     value.append(longlongId);
00324   }*/
00325   else if(parameter->isType<double>()){
00326     values.append(Teuchos::getValue<double>(*parameter));
00327     values.append(doubleId);
00328   }
00329   else if(parameter->isType<float>()){
00330     values.append(Teuchos::getValue<float>(*parameter));
00331     values.append(floatId);
00332   }
00333   else if(parameter->isType<bool>()){
00334     values.append(Teuchos::getValue<bool>(*parameter));
00335     values.append(boolId);
00336   }
00337   else if(parameter->isType<std::string>()){
00338     values.append(QString::fromStdString(Teuchos::getValue<std::string>(*parameter)));
00339     values.append(stringId);
00340   }
00341   else if(doesParameterContainArray(parameter)){
00342     QString determinedId = determineArrayType(parameter);
00343     if( determinedId != unrecognizedId){
00344       values.append(QString::fromStdString(Teuchos::toString(parameter->getAny())));
00345       values.append(QString(arrayId + " "+ determinedId));
00346     }
00347     else{
00348       values.append("");
00349       values.append("");
00350       parent->appendChild(new TreeItem(values, parameter, parent, true));
00351       return;
00352     }
00353   }
00354   else{
00355     values.append("");
00356     values.append("");
00357     parent->appendChild(new TreeItem(values, parameter, parent, true));
00358     return;
00359   }
00360   parent->appendChild(new TreeItem(values, parameter, parent));
00361 }
00362 
00363 void TreeModel::basicSetup(QString saveFileName){
00364   QList<QVariant> headers;
00365   headers  << "Parameter" << "Value" << "Type";
00366   rootItem = new TreeItem(headers, 0, 0); 
00367   canonicalList = Teuchos::RCP<const Teuchos::ParameterList>(new Teuchos::ParameterList(*validParameters));
00368   readInParameterList(validParameters, rootItem);
00369   this->saveFileName = saveFileName;
00370   if(saveFileName != ""){
00371     saved = true;
00372     readInput(saveFileName);
00373   }
00374   else{
00375     saved = false;
00376   }
00377 }
00378 
00379 void TreeModel::checkDependentState(const QModelIndex dependee, Teuchos::RCP<Dependency> dependency){
00380   Dependency::Type type = dependency->getType();
00381   QModelIndex dependent;
00382   Teuchos::ParameterEntry *currentDependent;
00383   Dependency::ParameterParentMap dependents= dependency->getDependents();
00384   for(Dependency::ParameterParentMap::iterator it = dependents.begin(); it != dependents.end(); ++it ){ 
00385     currentDependent = it->second->getEntryPtr(it->first);
00386     dependent = findParameterEntryIndex(currentDependent, it->first);
00387     if(type == Dependency::NumberArrayLengthDep){
00388       redrawArray(dependent.sibling(dependent.row(),1));
00389     }
00390     else if(type == Dependency::VisualDep){
00391       Teuchos::RCP<VisualDependency> visDep = Teuchos::rcp_static_cast<VisualDependency>(dependency);
00392       visDep->isDependentVisible() ? emit showData(dependent.row(), dependent.parent()) :
00393                  emit hideData(dependent.row(), dependent.parent());
00394     }
00395 
00396     if(!hasValidValue(dependent)){
00397       QString message = "Because you recently modified the " + data(dependee, Qt::DisplayRole).toString() +
00398       " parameter, the valid values for the " + data(dependent, Qt::DisplayRole).toString() +
00399       " parameter have changed.\n\nPlease modify the " +  data(dependent,Qt::DisplayRole).toString() + " value.\n";
00400       emit badValue(dependent.sibling(dependent.row(), 1), message);
00401     }
00402   }
00403 }
00404 
00405 void TreeModel::redrawArray(const QModelIndex arrayIndex){
00406   if(Teuchos::toString(itemEntry(arrayIndex)->getAny()).size() <= 2){
00407     emit hideData(arrayIndex.row(), arrayIndex.parent());
00408   }
00409   else{
00410     setData(arrayIndex, QString::fromStdString(Teuchos::toString(itemEntry(arrayIndex)->getAny())));
00411     emit showData(arrayIndex.row(), arrayIndex.parent());
00412   }
00413 }
00414 
00415 void TreeModel::currentFileNowModified(){
00416   saved = false;
00417 }
00418 
00419 void TreeModel::dataChangedListener(const QModelIndex& index1, const QModelIndex& /*index2*/){
00420   const Teuchos::ParameterEntry* changedIndexEntry = itemEntry(index1); 
00421   QModelIndex dependee = index1.sibling(index1.row(), 0);
00422   if(dependencySheet->hasDependents(changedIndexEntry)){
00423     DependencySheet::DepSet deps =  dependencySheet->getDependenciesForParameter(changedIndexEntry);
00424     for(DependencySheet::DepSet::iterator it = deps.begin(); it != deps.end(); ++it){
00425       (*it)->evaluate();
00426       checkDependentState(dependee,*it);
00427     }
00428   }
00429 }
00430 
00431 
00432 
00433 }
00434 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
Generated on Wed Apr 13 10:05:58 2011 for Optika GUI Toolik by  doxygen 1.6.3