Optika GUI Toolik Version of the Day
Optika_metawindow.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 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Kurtis Nusbaum (klnusbaum@gmail.com) 
00038 // 
00039 // ***********************************************************************
00040 // @HEADER
00041 #include "Optika_metawindow.hpp"
00042 #include "Optika_Version.hpp"
00043 #include <QLineEdit>
00044 #include <QLabel>
00045 #include <QPushButton>
00046 #include <QFileDialog>
00047 #include <QMessageBox> 
00048 #include <QAction>
00049 #include <QMenu>
00050 #include <QMenuBar>
00051 #include <QtGui>
00052 #include <QIcon>
00053 #include <iostream>
00054 #include <algorithm>
00055 #include <QSettings>
00056 namespace Optika{
00057 
00058 
00059 const int numRecentDocuments = 7; 
00060 
00061 SearchWidget::SearchWidget(TreeModel *treeModel, TreeView *treeView, QWidget *parent):
00062   QDialog(parent),
00063   treeModel(treeModel),
00064   treeView(treeView)
00065 {
00066   matchesLabel = new QLabel(tr("Matches"));
00067   searchButton = new QPushButton(tr("Search"));
00068   connect(searchButton, SIGNAL(clicked(bool)), this, SLOT(search()));
00069   closeButton = new QPushButton(tr("Close"));
00070   connect(closeButton, SIGNAL(clicked(bool)), this, SLOT(hide()));
00071   nextButton = new QPushButton(tr("Next"));
00072   connect(nextButton, SIGNAL(clicked(bool)), this, SLOT(next()));
00073   previousButton = new QPushButton(tr("Previous"));
00074   connect(previousButton, SIGNAL(clicked(bool)), this, SLOT(previous()));
00075   searchTermsEdit = new QLineEdit(tr("Enter Search Terms Here"));
00076   QGridLayout *layout = new QGridLayout(this);
00077   layout->addWidget(searchTermsEdit,0,0);
00078   layout->addWidget(searchButton,0,1);
00079   layout->addWidget(nextButton,0,3);
00080   layout->addWidget(previousButton,0,2);
00081   layout->addWidget(closeButton,2,3);
00082   layout->addWidget(matchesLabel,3,0);
00083   setLayout(layout);
00084   nextButton->setDisabled(true);
00085   previousButton->setDisabled(true);
00086   setSizeGripEnabled(true);
00087   setWindowTitle(tr("Search..."));
00088 }
00089 
00090 void SearchWidget::search(){
00091   currentSearchResults = treeModel->match(treeModel->index(0,0,QModelIndex()), Qt::DisplayRole, searchTermsEdit->text(), 
00092   -1, Qt::MatchWrap | Qt::MatchContains | Qt::MatchRecursive);
00093   currentSearchResults = removeHiddenItems(currentSearchResults);
00094   currentSearchIterator = currentSearchResults.begin(); 
00095   int searchSize = currentSearchResults.size();
00096   matchesLabel->setText("Matches ("+ QString::number(searchSize) + ")");
00097   if(searchSize <= 0){
00098     nextButton->setDisabled(true);
00099     previousButton->setDisabled(true);
00100   }
00101   else if(searchSize == 1){
00102     nextButton->setDisabled(true);
00103     previousButton->setDisabled(true);
00104     treeView->setCurrentIndex(*currentSearchIterator);
00105   }
00106   else{
00107     nextButton->setDisabled(false);
00108     previousButton->setDisabled(false);
00109     treeView->setCurrentIndex(*currentSearchIterator);
00110   }
00111 }
00112 
00113 void SearchWidget::next(){
00114   currentSearchIterator++;
00115   if(currentSearchIterator == currentSearchResults.end()){
00116     currentSearchIterator = currentSearchResults.begin();
00117   }
00118   treeView->setCurrentIndex(*currentSearchIterator);
00119 }
00120 
00121 void SearchWidget::previous(){
00122   currentSearchIterator--;
00123   if(currentSearchIterator == currentSearchResults.begin()-1){
00124     currentSearchIterator = currentSearchResults.end() -1;
00125   }
00126   treeView->setCurrentIndex(*currentSearchIterator);
00127 }
00128 
00129 QModelIndexList SearchWidget::removeHiddenItems(QModelIndexList& items){
00130   QModelIndexList toReturn;
00131   for(QModelIndexList::iterator it = items.begin(); it != items.end(); ++it){
00132     if(!treeView->isRowHidden(it->row(), it->parent())){
00133       toReturn.append(*it);
00134     }
00135   }
00136   return toReturn;
00137 }
00138 
00139 MetaWindow::MetaWindow(
00140   RCP<ParameterList> validParameters, 
00141   RCP<DependencySheet> dependencySheet, 
00142   void (*customFunc)(RCP<const ParameterList>), 
00143   QString fileName,
00144   const std::string actionButtonText)
00145 {
00146   model = new TreeModel(validParameters, dependencySheet, fileName, this);
00147   initilization(customFunc, actionButtonText);
00148 } 
00149 
00150 
00151 MetaWindow::~MetaWindow(){
00152   saveSettings();
00153 }
00154 
00155 void MetaWindow::closeEvent(QCloseEvent *event){
00156   if(!model->isSaved()){
00157     if(saveCurrentUnsavedFile()){
00158       saveSettings();
00159       event->accept();
00160     }
00161     else{
00162       event->ignore();
00163     }
00164   }
00165   else{
00166     saveSettings();
00167     event->accept();
00168   }
00169 }
00170 
00171 void MetaWindow::initilization(
00172   void (*customFunc)(RCP<const ParameterList>),
00173   const std::string actionButtonText)
00174 {
00175   this->customFunc = customFunc;
00176   delegate = new Delegate(this);
00177   view = new TreeView(model, delegate, this);
00178   view->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);
00179   searchWidget = new SearchWidget(model, view, this);
00180   searchWidget->hide();
00181   actionButton = NULL;
00182   if(actionButtonText != ""){
00183     actionButton = new QPushButton(tr("Submit"), this);
00184   }
00185   else{
00186     actionButton = 
00187       new QPushButton(QString::fromStdString(actionButtonText), this); 
00188   }
00189   QWidget *centerWidget = new QWidget(this);
00190   QGridLayout *centerWidgetLayout = new QGridLayout(centerWidget);
00191   centerWidgetLayout->addWidget(view,0,0);
00192   connect(actionButton, SIGNAL(clicked(bool)), this, SLOT(doAction()));
00193   centerWidgetLayout->addWidget(actionButton,1,0,Qt::AlignRight);
00194   centerWidget->setLayout(centerWidgetLayout);
00195   setCentralWidget(centerWidget);
00196 
00197   createActions();
00198   createMenus();
00199   resize(800,600);
00200   currentLoadDir = QDir::homePath();
00201   currentSaveDir = QDir::homePath();
00202   loadLastSettings();
00203   setWindowTitle(tr("Parameter Input"));
00204   view->show();
00205   view->header()->resizeSections(QHeaderView::ResizeToContents);
00206   view->header()->setMovable(false);
00207 }
00208 
00209 void MetaWindow::createMenus(){
00210 //  recentMenu = new QMenu(tr("Recent Solvers"));
00211 //  QAction *noRecentAct = new QAction(tr("No Recent Documents"),this);
00212 //  noRecentAct->setEnabled(false);
00213 //  recentMenu->addAction(noRecentAct);
00214   fileMenu = menuBar()->addMenu(tr("File"));
00215   fileMenu->addAction(resetAct);
00216   //fileMenu->addMenu(recentMenu);
00217   fileMenu->addSeparator();
00218   fileMenu->addAction(saveAct);
00219   fileMenu->addAction(saveAsAct);
00220   fileMenu->addAction(loadAct);
00221   fileMenu->addSeparator();
00222   fileMenu->addAction(quitAct);
00223   helpMenu = menuBar()->addMenu(tr("Help"));
00224   helpMenu->addAction(aboutAct);
00225   helpMenu->addAction(searchAct);
00226 }
00227 
00228 void MetaWindow::createActions(){
00229   resetAct = new QAction(tr("&Reset"),this);
00230   resetAct->setShortcut(tr("Ctrl+R"));
00231   resetAct->setStatusTip(tr("Reset the list to its original state."));
00232   connect(resetAct, SIGNAL(triggered()), this, SLOT(resetModel()));
00233 
00234   saveAct = new QAction(tr("&Save"),this);
00235   saveAct->setShortcut(tr("Ctrl+S"));
00236   saveAct->setStatusTip(tr("Save the current file."));
00237   connect(saveAct, SIGNAL(triggered()), this, SLOT(saveFile()));
00238 
00239   saveAsAct = new QAction(tr("Save As..."),this);
00240   saveAsAct->setStatusTip(tr("Save the current file to a specified file name."));
00241   connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveFileAs()));
00242 
00243   loadAct = new QAction(tr("&Load"),this);
00244   loadAct->setShortcut(tr("Ctrl+L"));
00245   loadAct->setStatusTip(tr("Load input file"));
00246   connect(loadAct, SIGNAL(triggered()), this, SLOT(loadFile()));
00247 
00248   quitAct = new QAction(tr("&Quit"),this);
00249   quitAct->setShortcut(tr("Ctrl+Q"));
00250   quitAct->setStatusTip(tr("Quit"));
00251   connect(quitAct, SIGNAL(triggered()), this, SLOT(close()));
00252 
00253   aboutAct = new QAction(tr("About"),this);
00254   searchAct = new QAction(tr("Search For Parameter/Parameter List"), this);
00255   searchAct->setToolTip("Search for a particular Parameter or ParameterList");
00256   connect(aboutAct, SIGNAL(triggered()), this, SLOT(showAbout()));
00257   connect(searchAct, SIGNAL(triggered()), this, SLOT(initiateSearch()));
00258 }
00259 
00260 void MetaWindow::load(){
00261   QString fileName = QFileDialog::getOpenFileName(this, tr("Load..."), currentLoadDir, tr("Xml (*.xml)"));
00262   if(fileName != ""){
00263     model->readInput(fileName);
00264     currentLoadDir = fileName.section("/",0,-2);
00265     addRecentDocument(fileName);
00266   }
00267 }
00268 
00269 void MetaWindow::loadLastSettings(){
00270   QSettings settings(QSettings::UserScope, "Sandia", "Optika");
00271   currentSaveDir = 
00272     settings.value(lastSaveDirSetting(), currentSaveDir).toString();
00273   currentLoadDir = 
00274     settings.value(lastLoadDirSetting(), currentLoadDir).toString();
00275   resize(settings.value(xresSetting(), width()).toInt(),
00276     settings.value(yresSetting(), height()).toInt());
00277   move(settings.value(xposSetting(), x()).toInt(),
00278     settings.value(yposSetting(), y()).toInt());
00279 }
00280 
00281 
00282 void MetaWindow::saveSettings(){
00283   QSettings settings(QSettings::UserScope, "Sandia", "Optika");
00284 
00285   settings.setValue(lastSaveDirSetting(), currentSaveDir);
00286   settings.setValue(lastLoadDirSetting(), currentLoadDir);
00287   settings.setValue(xresSetting(), width());
00288   settings.setValue(yresSetting(), height());
00289   settings.setValue(xposSetting(), x());
00290   settings.setValue(yposSetting(), y());
00291 }
00292   
00293 
00294 void MetaWindow::addRecentDocument(QString recentDocument){
00295   recentDocsList.prepend(recentDocument);
00296   if(recentDocsList.size() > numRecentDocuments){
00297     recentDocsList.removeLast();
00298   }
00299 //  updateRecentDocsMenu();
00300 }
00301 
00302 void MetaWindow::updateRecentDocsMenu(){
00303   recentMenu->clear();
00304   for(int i=0; i<recentDocsList.size(); ++i){
00305     QAction *recentDocAct = new QAction(recentDocsList.at(i).section("/",-1,-1),this);
00306     connect(recentDocAct, SIGNAL(triggered()), this, SLOT(loadRecentDoc()));
00307     recentMenu->addAction(recentDocAct);
00308   }
00309 }
00310 
00311 void MetaWindow::resetModel(){
00312   if(!model->isSaved()){
00313     saveCurrentUnsavedFile();
00314   }
00315   model->reset();
00316 }
00317 
00318 bool MetaWindow::saveFileAs(){
00319   QString fileName = QFileDialog::getSaveFileName(this, tr("Save To..."), currentSaveDir, tr("XML (*.xml)"));
00320   if(fileName.toStdString() != ""){
00321     if(!fileName.endsWith(".xml")){
00322       fileName = fileName.append(".xml");
00323     }
00324     if(model->writeOutput(fileName)){
00325       currentSaveDir = fileName.section("/",0,-2);
00326       addRecentDocument(fileName);    
00327       return true;
00328     }
00329   }
00330   return false;
00331 }
00332 
00333 void MetaWindow::saveFile(){
00334   QString currentFileName = model->getSaveFileName();
00335   if(currentFileName != ""){
00336     model->writeOutput(currentFileName);
00337   }
00338   else{
00339     saveFileAs();
00340   }
00341 }
00342 
00343 
00344 void MetaWindow::loadFile(){
00345   if(!model->isSaved()){
00346     saveCurrentUnsavedFile();
00347   }
00348   load();
00349 }
00350 
00351 bool MetaWindow::saveCurrentUnsavedFile(){
00352     QMessageBox saveQuestion(QMessageBox::Question, 
00353     tr("Save?"),
00354     tr("These choices have not been saved since you last made changes. Would you like to save them now?"), 
00355     QMessageBox::Yes | QMessageBox::No,
00356     this);
00357     saveQuestion.setDefaultButton(QMessageBox::Yes);
00358     int shouldSave = saveQuestion.exec(); 
00359     if(shouldSave == QMessageBox::Yes){
00360       return saveFileAs();
00361     }
00362     return true;
00363 }
00364 
00365 void MetaWindow::loadRecentDoc(){
00366   QString docName = dynamic_cast<QAction*>(sender())->text();
00367   int i =0;
00368   for(; i<recentDocsList.size();++i){
00369     if(recentDocsList.at(i).contains(docName)){
00370       break;
00371     }
00372   }
00373   if(!model->isSaved()){
00374     if(saveCurrentUnsavedFile()){
00375       model->readInput(recentDocsList.at(i));
00376     }
00377   }
00378 }
00379 
00380 void MetaWindow::showAbout(){
00381   QString aboutString = aboutInfo + "\nThis input obtainer was generated by Kurtis Nusbaum's Optika package, part of the Trilinos Project.\n\nVersion: " + QString::fromStdString(Optika_Version()) + "\nWebsite: trilinos.sandia.gov/packages/optika\nLicense: LGPL\nContact: klnusbaum@gmail.com";
00382   QMessageBox::about(this,
00383   "Optika Input Obtainer\n",
00384   aboutString);
00385 }
00386 
00387 void MetaWindow::initiateSearch(){
00388   searchWidget->show();
00389 }
00390 
00391 void MetaWindow::doAction(){
00392   if(customFunc == 0){
00393     close();
00394   }
00395   else{
00396     (*customFunc)(model->getCurrentParameters()); 
00397   }
00398 }
00399 
00400 void MetaWindow::setAboutInfo(QString aboutInfo){
00401   this->aboutInfo = aboutInfo;
00402 }
00403 
00404 QString MetaWindow::getAboutInfo(){
00405   return aboutInfo;
00406 }
00407 
00408 void MetaWindow::setActionButtonText(QString newText){
00409   actionButton->setText(newText);
00410 }
00411 
00412 QString MetaWindow::getActionButtonText(){
00413   return actionButton->text();
00414 }
00415 
00416 
00417 } //namespace Optika
00418 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Defines