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   const std::string actionNoSaveButtonText)
00146 {
00147   model = new TreeModel(validParameters, dependencySheet, fileName, this);
00148   initilization(customFunc, actionButtonText, actionNoSaveButtonText);
00149 } 
00150 
00151 
00152 MetaWindow::~MetaWindow(){
00153   saveSettings();
00154 }
00155 
00156 void MetaWindow::closeEvent(QCloseEvent *event){
00157   if(!model->isSaved()){
00158     if(saveCurrentUnsavedFile()){
00159       saveSettings();
00160       event->accept();
00161     }
00162     else{
00163       event->ignore();
00164     }
00165   }
00166   else{
00167     saveSettings();
00168     event->accept();
00169   }
00170 }
00171 
00172 void MetaWindow::initilization(
00173   void (*customFunc)(RCP<const ParameterList>),
00174   const std::string actionButtonText,
00175   const std::string actionNoSaveButtonText)
00176 {
00177   this->customFunc = customFunc;
00178   delegate = new Delegate(this);
00179   view = new TreeView(model, delegate, this);
00180   view->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);
00181   searchWidget = new SearchWidget(model, view, this);
00182   searchWidget->hide();
00183   actionButton = NULL;
00184   actionNoSaveButton = NULL;
00185   if(actionButtonText != ""){
00186     actionButton = 
00187       new QPushButton(QString::fromStdString(actionButtonText), this); 
00188   }
00189   else{
00190     actionButton = new QPushButton(tr("Submit"), this);
00191   }
00192   if(actionNoSaveButtonText != ""){
00193       actionNoSaveButton = new QPushButton(QString::fromStdString(actionNoSaveButtonText), this); 
00194   }
00195   QWidget *centerWidget = new QWidget(this);
00196   QGridLayout *centerWidgetLayout = new QGridLayout(centerWidget);
00197   centerWidgetLayout->addWidget(view,0,0);
00198   connect(actionButton, SIGNAL(clicked(bool)), this, SLOT(doAction()));
00199   if(actionNoSaveButton){
00200       centerWidgetLayout->addWidget(actionButton,1,0,Qt::AlignLeft);
00201     connect(actionNoSaveButton, SIGNAL(clicked(bool)), this, SLOT(doActionNoSave()));
00202     centerWidgetLayout->addWidget(actionNoSaveButton,1,0,Qt::AlignRight);
00203   }
00204     else
00205     centerWidgetLayout->addWidget(actionButton,1,0,Qt::AlignRight);
00206   centerWidget->setLayout(centerWidgetLayout);
00207   setCentralWidget(centerWidget);
00208 
00209   createActions();
00210   createMenus();
00211   resize(800,600);
00212   currentLoadDir = QDir::homePath();
00213   currentSaveDir = QDir::homePath();
00214   loadLastSettings();
00215   setWindowTitle(tr("Parameter Input"));
00216   view->show();
00217   view->header()->resizeSections(QHeaderView::ResizeToContents);
00218   view->header()->setMovable(false);
00219 }
00220 
00221 void MetaWindow::createMenus(){
00222 //  recentMenu = new QMenu(tr("Recent Solvers"));
00223 //  QAction *noRecentAct = new QAction(tr("No Recent Documents"),this);
00224 //  noRecentAct->setEnabled(false);
00225 //  recentMenu->addAction(noRecentAct);
00226   fileMenu = menuBar()->addMenu(tr("File"));
00227   fileMenu->addAction(resetAct);
00228   //fileMenu->addMenu(recentMenu);
00229   fileMenu->addSeparator();
00230   fileMenu->addAction(saveAct);
00231   fileMenu->addAction(saveAsAct);
00232   fileMenu->addAction(loadAct);
00233   fileMenu->addSeparator();
00234   fileMenu->addAction(quitAct);
00235   helpMenu = menuBar()->addMenu(tr("Help"));
00236   helpMenu->addAction(aboutAct);
00237   helpMenu->addAction(searchAct);
00238 }
00239 
00240 void MetaWindow::createActions(){
00241   resetAct = new QAction(tr("&Reset"),this);
00242   resetAct->setShortcut(tr("Ctrl+R"));
00243   resetAct->setStatusTip(tr("Reset the list to its original state."));
00244   connect(resetAct, SIGNAL(triggered()), this, SLOT(resetModel()));
00245 
00246   saveAct = new QAction(tr("&Save"),this);
00247   saveAct->setShortcut(tr("Ctrl+S"));
00248   saveAct->setStatusTip(tr("Save the current file."));
00249   connect(saveAct, SIGNAL(triggered()), this, SLOT(saveFile()));
00250 
00251   saveAsAct = new QAction(tr("Save As..."),this);
00252   saveAsAct->setStatusTip(tr("Save the current file to a specified file name."));
00253   connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveFileAs()));
00254 
00255   loadAct = new QAction(tr("&Load"),this);
00256   loadAct->setShortcut(tr("Ctrl+L"));
00257   loadAct->setStatusTip(tr("Load input file"));
00258   connect(loadAct, SIGNAL(triggered()), this, SLOT(loadFile()));
00259 
00260   quitAct = new QAction(tr("&Quit"),this);
00261   quitAct->setShortcut(tr("Ctrl+Q"));
00262   quitAct->setStatusTip(tr("Quit"));
00263   connect(quitAct, SIGNAL(triggered()), this, SLOT(close()));
00264 
00265   aboutAct = new QAction(tr("About"),this);
00266   searchAct = new QAction(tr("Search For Parameter/Parameter List"), this);
00267   searchAct->setToolTip("Search for a particular Parameter or ParameterList");
00268   connect(aboutAct, SIGNAL(triggered()), this, SLOT(showAbout()));
00269   connect(searchAct, SIGNAL(triggered()), this, SLOT(initiateSearch()));
00270 }
00271 
00272 void MetaWindow::load(){
00273   QString fileName = QFileDialog::getOpenFileName(this, tr("Load..."), currentLoadDir, tr("Xml (*.xml)"));
00274   if(fileName != ""){
00275     model->readInput(fileName);
00276     currentLoadDir = fileName.section("/",0,-2);
00277     addRecentDocument(fileName);
00278   }
00279 }
00280 
00281 void MetaWindow::loadLastSettings(){
00282   QSettings settings(QSettings::UserScope, "Sandia", "Optika");
00283   currentSaveDir = 
00284     settings.value(lastSaveDirSetting(), currentSaveDir).toString();
00285   currentLoadDir = 
00286     settings.value(lastLoadDirSetting(), currentLoadDir).toString();
00287   resize(settings.value(xresSetting(), width()).toInt(),
00288     settings.value(yresSetting(), height()).toInt());
00289   move(settings.value(xposSetting(), x()).toInt(),
00290     settings.value(yposSetting(), y()).toInt());
00291 }
00292 
00293 
00294 void MetaWindow::saveSettings(){
00295   QSettings settings(QSettings::UserScope, "Sandia", "Optika");
00296 
00297   settings.setValue(lastSaveDirSetting(), currentSaveDir);
00298   settings.setValue(lastLoadDirSetting(), currentLoadDir);
00299   settings.setValue(xresSetting(), width());
00300   settings.setValue(yresSetting(), height());
00301   settings.setValue(xposSetting(), x());
00302   settings.setValue(yposSetting(), y());
00303 }
00304   
00305 
00306 void MetaWindow::addRecentDocument(QString recentDocument){
00307   recentDocsList.prepend(recentDocument);
00308   if(recentDocsList.size() > numRecentDocuments){
00309     recentDocsList.removeLast();
00310   }
00311 //  updateRecentDocsMenu();
00312 }
00313 
00314 void MetaWindow::updateRecentDocsMenu(){
00315   recentMenu->clear();
00316   for(int i=0; i<recentDocsList.size(); ++i){
00317     QAction *recentDocAct = new QAction(recentDocsList.at(i).section("/",-1,-1),this);
00318     connect(recentDocAct, SIGNAL(triggered()), this, SLOT(loadRecentDoc()));
00319     recentMenu->addAction(recentDocAct);
00320   }
00321 }
00322 
00323 void MetaWindow::resetModel(){
00324   if(!model->isSaved()){
00325     saveCurrentUnsavedFile();
00326   }
00327   model->reset();
00328 }
00329 
00330 bool MetaWindow::saveFileAs(){
00331   QString fileName = QFileDialog::getSaveFileName(this, tr("Save To..."), currentSaveDir, tr("XML (*.xml)"));
00332   if(fileName.toStdString() != ""){
00333     if(!fileName.endsWith(".xml")){
00334       fileName = fileName.append(".xml");
00335     }
00336     if(model->writeOutput(fileName)){
00337       currentSaveDir = fileName.section("/",0,-2);
00338       addRecentDocument(fileName);    
00339       return true;
00340     }
00341   }
00342   return false;
00343 }
00344 
00345 void MetaWindow::saveFile(){
00346   QString currentFileName = model->getSaveFileName();
00347   if(currentFileName != ""){
00348     model->writeOutput(currentFileName);
00349   }
00350   else{
00351     saveFileAs();
00352   }
00353 }
00354 
00355 
00356 void MetaWindow::loadFile(){
00357   if(!model->isSaved()){
00358     saveCurrentUnsavedFile();
00359   }
00360   load();
00361 }
00362 
00363 bool MetaWindow::saveCurrentUnsavedFile(){
00364     QMessageBox saveQuestion(QMessageBox::Question, 
00365     tr("Save?"),
00366     tr("These choices have not been saved since you last made changes. Would you like to save them now?"), 
00367     QMessageBox::Yes | QMessageBox::No,
00368     this);
00369     saveQuestion.setDefaultButton(QMessageBox::Yes);
00370     int shouldSave = saveQuestion.exec(); 
00371     if(shouldSave == QMessageBox::Yes){
00372       return saveFileAs();
00373     }
00374     return true;
00375 }
00376 
00377 void MetaWindow::loadRecentDoc(){
00378   QString docName = dynamic_cast<QAction*>(sender())->text();
00379   int i =0;
00380   for(; i<recentDocsList.size();++i){
00381     if(recentDocsList.at(i).contains(docName)){
00382       break;
00383     }
00384   }
00385   if(!model->isSaved()){
00386     if(saveCurrentUnsavedFile()){
00387       model->readInput(recentDocsList.at(i));
00388     }
00389   }
00390 }
00391 
00392 void MetaWindow::showAbout(){
00393   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";
00394   QMessageBox::about(this,
00395   "Optika Input Obtainer\n",
00396   aboutString);
00397 }
00398 
00399 void MetaWindow::initiateSearch(){
00400   searchWidget->show();
00401 }
00402 
00403 void MetaWindow::doAction(){
00404   if(customFunc == 0){
00405     close();
00406   }
00407   else{
00408     (*customFunc)(model->getCurrentParameters()); 
00409   }
00410 }
00411 
00412 void MetaWindow::doActionNoSave(){
00413   model->setIsSaved();
00414     doAction();
00415 }
00416 
00417 void MetaWindow::setAboutInfo(QString aboutInfo){
00418   this->aboutInfo = aboutInfo;
00419 }
00420 
00421 QString MetaWindow::getAboutInfo(){
00422   return aboutInfo;
00423 }
00424 
00425 void MetaWindow::setActionButtonText(QString newText){
00426   actionButton->setText(newText);
00427 }
00428 
00429 QString MetaWindow::getActionButtonText(){
00430   return actionButton->text();
00431 }
00432 
00433 
00434 } //namespace Optika
00435 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Defines