00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <QtGui>
00021
00022 #include "MainWindow.h"
00023 #include "ScenarioSelectionWidget.h"
00024
00025 using namespace std;
00026
00027
00028
00029
00035 MainWindow::MainWindow() {
00036 yearSBLabel=NULL;
00037 mainSBLabel=NULL;
00038 for (uint i=0;i<MaxRecentFiles;i++) recentFileActions[i] = NULL;
00039 separatorAction=NULL;
00040
00041 setupUi(this);
00042 unsavedStatus=false;
00043 curModelFileName="data/regmasInput.ods";
00044 curBaseDirectory = "data/";
00045 outputDirName="output/";
00046 setCurrentLogFileName("");
00047 createStatusBar();
00048 curLogFileName ="";
00049 debugMsgsEnable = true;
00050
00051 for (int i = 0; i < MaxRecentFiles; ++i) {
00052 recentFileActions[i] = new QAction(this);
00053 recentFileActions[i]->setVisible(false);
00054 connect(recentFileActions[i], SIGNAL(triggered()), this, SLOT(openRecentFile()));
00055 }
00056
00057 separatorAction = menuFile->addSeparator();
00058 for (int i = 0; i < MaxRecentFiles; ++i)
00059 menuFile->addAction(recentFileActions[i]);
00060 menuFile->addSeparator();
00061 menuFile->addAction(actionExit);
00062
00063 readSettings();
00064 modelMainThread.setInputFileName(curModelFileName);
00065
00066
00067
00068 statusView->setColumnCount(2);
00069 statusView->setHeaderLabels(QStringList()<< tr ("Label") << tr ("Value"));
00070 statusView->clear();
00071 statusView->sortByColumn(0);
00072 statusView->setFocus();
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 qRegisterMetaType<string>("string");
00105 qRegisterMetaType<QString>("QString");
00106 qRegisterMetaType< QVector<QString> >("QVector<QString>");
00107
00108
00109 connect(actionRun, SIGNAL(triggered()), this, SLOT(startModelMainThread()));
00110 connect(actionPause, SIGNAL(triggered()), this, SLOT(pauseOrResumeModelMainThread()));
00111 connect(actionStop, SIGNAL(triggered()), this, SLOT(stopModelMainThread()));
00112 connect(actionExit, SIGNAL(triggered()), this, SLOT(close()));
00113 connect(actionSaveLog, SIGNAL(triggered()), this, SLOT(save()));
00114 connect(actionSaveLogAs, SIGNAL(triggered()), this, SLOT(saveAs()));
00115 connect(actionLoadConfiguration, SIGNAL(triggered()), this, SLOT(open()));
00116 connect(actionHideDebugMsgs, SIGNAL(triggered(bool)), this, SLOT(hideDebugMsgs(bool)));
00117 connect(actionAboutRegMAS, SIGNAL(triggered()), this, SLOT(about()));
00118 connect(actionRegMASDocumentation, SIGNAL(triggered()), this, SLOT(showDocumentation()));
00119 connect(actionFitMap, SIGNAL(triggered()), mapBox, SLOT(fitInWindow()));
00120
00121 connect(&modelMainThread, SIGNAL(upgradeLogArea(const QString&)), this, SLOT(processLogArea(const QString&)));
00122 connect(&modelMainThread, SIGNAL(addLayerToGui(QString, QString)), this, SLOT( addLayer(QString, QString)));
00123 connect(layerSelector, SIGNAL(activated(int)), this, SLOT(switchToLayerFromLayerSelector(int)));
00124 connect(&modelMainThread, SIGNAL(updatePixelToGui(QString, int, int, QColor)), this, SLOT (updatePixel(QString, int, int, QColor)));
00125 connect(&modelMainThread, SIGNAL(updateImageToGui(QString, QImage)), this, SLOT (updateImage(QString, QImage)));
00126 connect(&modelMainThread, SIGNAL(setOutputDirNameToGui(string)), this, SLOT(setOutputDirName(string)));
00127 connect(&modelMainThread, SIGNAL(setGUIUnsavedStatus(bool)), this, SLOT(setUnsavedStatus(bool)));
00128 connect(&modelMainThread, SIGNAL(sendScenarioOptionsToGUI(const QVector<QString> &)), this, SLOT( receiveScenarioOptions(const QVector<QString> &) ));
00129
00130
00131 scenarioWidget = new ScenarioSelectionWidget(this);
00132 connect(scenarioWidget->scenarioSelector, SIGNAL( activated(const QString&)), scenarioWidget, SLOT( close()));
00133 connect(scenarioWidget->scenarioSelector, SIGNAL( activated(const QString&)), &modelMainThread, SLOT( retrieveScenarioNameFromGUI(const QString &)));
00134
00135
00136
00137
00138 connect(&modelMainThread, SIGNAL( treeViewerItemChangeValueToGui(string, string) ), this, SLOT( treeViewerItemChangeValue(string, string) ));
00139 connect(&modelMainThread, SIGNAL( treeViewerItemRemoveToGui(string) ), this, SLOT( treeViewerItemRemove(string) ));
00140 connect(&modelMainThread, SIGNAL( treeViewerAddItemToGui(string, string, string) ), this, SLOT( treeViewerAddItem(string, string, string) ));
00141 connect(&modelMainThread, SIGNAL( fitInWindowToGui()), mapBox, SLOT(fitInWindow()));
00142
00143 connect(mapBox, SIGNAL( queryRequestOnPx(int, int, bool) ), &modelMainThread, SLOT ( checkQuery(int, int, bool) ) );
00144 connect(&modelMainThread,SIGNAL(publishQueryResults(const QString&)), pxInfoArea, SLOT (setHtml(const QString&)));
00145 connect(&modelMainThread,SIGNAL(activateTab(int)), tabWidget, SLOT (setCurrentIndex(int)));
00146
00147 connect(&modelMainThread, SIGNAL( resetGUIForNewSimulation() ), this, SLOT( resetGUIForNewSimulation() ));
00148
00149 }
00150
00151 void
00152 MainWindow::createStatusBar() {
00153 yearSBLabel = new QLabel(" 2000 ");
00154 yearSBLabel->setAlignment(Qt::AlignHCenter);
00155 yearSBLabel->setMinimumSize(yearSBLabel->sizeHint());
00156
00157 mainSBLabel = new QLabel;
00158 mainSBLabel->setIndent(3);
00159
00160 statusBar()->addWidget(yearSBLabel);
00161 statusBar()->addWidget(mainSBLabel, 1);
00162
00163 yearSBLabel->setText("0");
00164 mainSBLabel->setText("Welcome on RegMAS!");
00165
00166 connect(&modelMainThread, SIGNAL(upgradeYearSBLabelToGui(const QString&)), yearSBLabel, SLOT(setText(const QString&)));
00167 connect(&modelMainThread, SIGNAL(upgradeMainSBLabelToGui(const QString&)), mainSBLabel, SLOT(setText(const QString&)));
00168
00169 }
00170
00171
00172 void
00173 MainWindow::closeEvent(QCloseEvent *event) {
00174 if (okToContinue()) {
00175 writeSettings();
00176 modelMainThread.stop();
00177 modelMainThread.wait();
00178 event->accept();
00179 } else {
00180 event->ignore();
00181 }
00182 }
00183
00184
00185
00186
00187 void
00188 MainWindow::setCurrentLogFileName(const QString &fileName) {
00189 curLogFileName = fileName;
00190 }
00191
00192 void
00193 MainWindow::setCurrentModelFileName(const QString &fileName) {
00194 curModelFileName = fileName;
00195
00196 modelMainThread.setInputFileName(curModelFileName);
00197
00198 QString shownName = "Untitled";
00199 if (!curModelFileName.isEmpty()) {
00200 shownName = strippedName(curModelFileName);
00201 recentFiles.removeAll(curModelFileName);
00202 recentFiles.prepend(curModelFileName);
00203 updateRecentFileActions();
00204 }
00205 setWindowTitle(tr("%2 - [%1]").arg(shownName).arg(tr("RegMAS - Regional Multi Agent Simulator")));
00206 }
00207
00208 QString
00209 MainWindow::strippedName(const QString &fullFileName) {
00210 return QFileInfo(fullFileName).fileName();
00211 }
00212
00213 void
00214 MainWindow::updateRecentFileActions() {
00215 QMutableStringListIterator i(recentFiles);
00216 while (i.hasNext()) {
00217 if (!QFile::exists(i.next()))
00218 i.remove();
00219 }
00220
00221 for (int j = 0; j < MaxRecentFiles; ++j) {
00222 if (j < recentFiles.count()) {
00223 QString text = tr("&%1 %2")
00224 .arg(j + 1)
00225 .arg(strippedName(recentFiles.at(j)));
00226
00227 recentFileActions[j]->setText(text);
00228 recentFileActions[j]->setData(recentFiles.at(j));
00229 recentFileActions[j]->setVisible(true);
00230 } else {
00231 recentFileActions[j]->setVisible(false);
00232 }
00233 }
00234 separatorAction->setVisible(!recentFiles.isEmpty());
00235 }
00236
00237 bool
00238 MainWindow::okToContinue() {
00239 if (modelMainThread.isRunning()) {
00240 int t = QMessageBox::warning(
00241 this,
00242 tr("RegMAS"),
00243 tr("The model is still running.\n"
00244 "Do you want to stop it?"),
00245 QMessageBox::Yes | QMessageBox::Default,
00246 QMessageBox::Cancel | QMessageBox::Escape
00247 );
00248 if (t == QMessageBox::Yes) {
00249 modelMainThread.stop();
00250 modelMainThread.wait();
00251 } else if (t == QMessageBox::Cancel) {
00252 return false;
00253 }
00254 }
00255
00256 if (unsavedStatus) {
00257 int r = QMessageBox::warning(
00258 this,
00259 tr("RegMAS"),
00260 tr("The model log has not been saved.\n"
00261 "Do you want to save it?"),
00262 QMessageBox::Yes ,
00263 QMessageBox::No | QMessageBox::Default,
00264 QMessageBox::Cancel | QMessageBox::Escape
00265 );
00266 if (r == QMessageBox::Yes) {
00267 return save();
00268 } else if (r == QMessageBox::Cancel) {
00269 return false;
00270 }
00271 }
00272 return true;
00273 }
00274
00275 void
00276 MainWindow::open() {
00277 if (okToContinue()) {
00278 QString fileName = QFileDialog::getOpenFileName(
00279 this,
00280 tr("Load model file.."),
00281 "data/",
00282 tr("OpenDocument Spreadsheet (*.ods)\n" "All files (*.*)")
00283 );
00284 if (!fileName.isEmpty()){
00285 statusBar()->showMessage(tr("Loaded new RegMAS model file"), 2000);
00286 setCurrentModelFileName(fileName);
00287
00288 QFileInfo info(fileName);
00289 QString path;
00290 path = info.absolutePath();
00291 path = path+"/";
00292 curBaseDirectory = path;
00293
00294 }
00295 }
00296 }
00297
00298 void
00299 MainWindow::readSettings() {
00300 QSettings settings("UNIVPM", "RegMAS");
00301 recentFiles = settings.value("recentFiles").toStringList();
00302 updateRecentFileActions();
00303 }
00304
00305 void
00306 MainWindow::openRecentFile() {
00307 if (okToContinue()) {
00308 QAction *action = qobject_cast<QAction *>(sender());
00309 if (action){
00310 curModelFileName=action->data().toString();
00311 setCurrentModelFileName(curModelFileName);
00312
00313 QFileInfo info(curModelFileName);
00314 QString path;
00315 path = info.absolutePath();
00316 path = path+"/";
00317 curBaseDirectory = path;
00318
00319 }
00320 }
00321 }
00322
00323 bool
00324 MainWindow::save() {
00325 if (curLogFileName.isEmpty()) {
00326 return saveAs();
00327 } else {
00328 cerr <<(curLogFileName.toStdString())<<endl;
00329 cerr <<(outputDirName.toStdString())<<endl;
00330 return saveLogFile(curLogFileName);
00331 }
00332 unsavedStatus = false;
00333 return true;
00334 }
00335
00336 bool
00337 MainWindow::saveAs() {
00338 QString logFileName = QFileDialog::getSaveFileName(
00339 this,
00340 tr("Save output log"),
00341 outputDirName,
00342 tr("Log files (*.log)\n" "All files (*.*)")
00343 );
00344 if (logFileName.isEmpty())
00345 return false;
00346 return saveLogFile(logFileName);
00347 unsavedStatus = false;
00348 return true;
00349 }
00350
00351 bool
00352 MainWindow::saveLogFile(const QString &logFileName) {
00353 QFile file(logFileName);
00354 if (!file.open(QIODevice::WriteOnly)) {
00355 QMessageBox::warning(this, tr("RegMAS"),
00356 tr("Cannot write log file file %1:\n%2.")
00357 .arg(file.fileName())
00358 .arg(file.errorString()));
00359 return false;
00360 }
00361
00362 QString logAreaContent = logArea->toPlainText();
00363 QTextStream stream( &file );
00364 stream << logAreaContent;
00365 file.close();
00366
00367 setCurrentLogFileName(logFileName);
00368 statusBar()->showMessage(tr("Log file saved"), 2000);
00369 unsavedStatus = false;
00370 return true;
00371 }
00372
00373 void MainWindow::writeSettings() {
00374 QSettings settings("UNIVPM", "RegMAS");
00375 settings.setValue("recentFiles", recentFiles);
00376 }
00377
00378
00379
00380 void
00381 MainWindow::startModelMainThread() {
00382 if (modelMainThread.isRunning()) {
00383 return ;
00384 cout <<"It seems that the model is already running..."<<endl;
00385 } else {
00386 logArea->clear();
00387 modelMainThread.start();
00388 unsavedStatus=true;
00389 }
00390 }
00391
00392 void
00393 MainWindow::stopModelMainThread() {
00394 if (! modelMainThread.isRunning()) {
00395 return ;
00396 } else {
00397 modelMainThread.stop();
00398 modelMainThread.wait();
00399 }
00400 }
00401
00402 void
00403 MainWindow::pauseOrResumeModelMainThread() {
00404 modelMainThread.pauseOrResume();
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00426 void
00427 MainWindow::addLayer(QString layerName_h, QString layerLabel_h) {
00428 static int counter =0;
00429 mapBox->addLayer(layerName_h);
00430 layerSelector->addItem(layerLabel_h,layerName_h);
00431
00432
00433 update();
00434 counter ++;
00435 }
00436
00443 void
00444 MainWindow::switchToLayer(QString layerName_h) {
00445 mapBox->switchToLayer(layerName_h);
00446 int index = mapBox->getLayerIndex(layerName_h);
00447 layerSelector->setCurrentIndex(index);
00448 update();
00449 }
00450
00451 void
00452 MainWindow::switchToLayerFromLayerSelector(int layerIndex_h) {
00453 QString layerName= layerSelector->itemData(layerIndex_h, Qt::UserRole ).toString();
00454 mapBox->switchToLayer(layerName);
00455 update();
00456 }
00457
00458 void
00459 MainWindow::updatePixel(QString layerName_h, int x_h, int y_h, QColor color_h) {
00460 mapBox->updatePixel(layerName_h,x_h,y_h,color_h.rgb());
00461 update();
00462 }
00463
00464 void
00465 MainWindow::updateImage(QString layerName_h, const QImage &image_h) {
00466 mapBox->updateImage(layerName_h, image_h);
00467 update();
00468 }
00469
00470
00471 void
00472 MainWindow::treeViewerItemChangeValue(string itemID, string newValue) {
00473
00474 map<string, QTreeWidgetItem*>::iterator p;
00475 p=svIndex.find(itemID);
00476 if(p != svIndex.end())
00477 p->second->setText(1,newValue.c_str());
00478 else {
00479 QString tempString;
00480 QString tempString2 = itemID.c_str();
00481 tempString = "**** ERROR, Coud not change value for item "+tempString2+" in the Model Status Viewer. Item doesn't found.";
00482 logArea->append(tempString);
00483 }
00484 return;
00485
00486 }
00487
00488 void
00489 MainWindow::treeViewerItemRemove(string itemID) {
00490 map<string, QTreeWidgetItem*>::iterator p;
00491 p=svIndex.find(itemID);
00492 if(p != svIndex.end()){
00493 QTreeWidgetItem *parent = p->second->parent();
00494 int index;
00495 if (parent) {
00496 index = parent->indexOfChild(p->second);
00497 delete parent->takeChild(index);
00498 svIndex.erase(p);
00499 } else {
00500 QString tempString = "**** ERROR, I will not delete a top level item in the Model Satus Viewer";
00501 logArea->append(tempString);
00502 }
00503
00504 }
00505 else {
00506 QString tempString;
00507 QString tempString2 = itemID.c_str();
00508 tempString = "**** ERROR, Coud not delete for item "+tempString2+" in the Model Status Viewer. Item doesn't found.";
00509
00510 }
00511 return;
00512 }
00513
00514 void
00515 MainWindow::treeViewerAddItem(string text, string itemID, string parentID){
00516
00517 map<string, QTreeWidgetItem*>::iterator p;
00518 QTreeWidgetItem *parentItem;
00519
00520 p=svIndex.find(parentID);
00521 if(p != svIndex.end()){
00522 parentItem = p->second;
00523 QTreeWidgetItem *node = new QTreeWidgetItem(parentItem);
00524 svIndex.insert(pair<string, QTreeWidgetItem*>(itemID, node));
00525 node->setText(0, text.c_str());
00526 }
00527 else {
00528 QString tempString;
00529 QString tempString2 = itemID.c_str();
00530 QString tempString3 = parentID.c_str();
00531 tempString = "**** ERROR, Coud not add sub item "+tempString2+" to the Model Status Viewer. Parent item ("+tempString3+") doesn't found.";
00532 logArea->append(tempString);
00533 }
00534
00535 }
00536
00537
00538 void
00539 MainWindow::processLogArea(const QString& message_h){
00540 if(debugMsgsEnable){
00541 logArea->append(message_h);
00542 }
00543 else {
00544 if( ! message_h.startsWith("*DEBUG")){
00545 logArea->append(message_h);
00546 }
00547 }
00548 }
00549
00550 void
00551 MainWindow::hideDebugMsgs(bool hide){
00552 if(hide) debugMsgsEnable = false;
00553 else debugMsgsEnable = true;
00554 }
00555
00556 void
00557 MainWindow::about(){
00558 QMessageBox::about(this, tr("About RegMAS"),
00559 tr("<h2><u>Reg</u>ional <u>M</u>ulti <u>A</u>gent <u>S</u>imulator</h2>"
00560 "<p>Copyright © 2006-2008 Antonello Lobianco & contributors"
00561 "<br/>Version 1.3.0"
00562 "<p>RegMAS is a spatially explicit, multi-agent simulation framework "
00563 "designed for long-term simulations of effects of government policies "
00564 "over rural and agricultural systems."
00565 "<br>It is released under the GNU GPL licence."
00566 "<p>For documentation and credits please refer to the project site:"
00567 "<br><a href=\"http://www.regmas.org\">http://www.regmas.org</a>"
00568 ));
00569 }
00570
00571 void
00572 MainWindow::showDocumentation(){
00573 QMessageBox::question(this, tr("RegMAS Documentation"),
00574 tr("<h2>RegMAS Documentation</h2>"
00575 "<p align=\"justify\">RegMAS documentation is organised in three main categories: "
00576 "<p align=\"justify\">(1) <b>official documentation</b> "
00577 "(comprising the <i>User Manual</i> and the <i>Reference Manual</i>); <br>(2) <b>contributed "
00578 "documentation</b> (<i>wiki</i>);<br>(3) <b>community project</b> (<i>forum</i> and <i>mailing list</i>). "
00579 "<p align=\"justify\">The documentation is located at "
00580 "<a href=\"http://www.regmas.org/doc\">http://www.regmas.org/doc</a>"
00581 "<p align=\"justify\">If you have chosen to instal a local copy of the documentation, "
00582 "you can access it also from the <i>Start menu</i>-><i>Programs</i>-><i>RegMAS</i> "
00583 "(MS Windows) or directly from the following links (Linux):"
00584 "<br><a href=\"doc/userManual/regmasUserManual.pdf\">User Manual</a> "
00585 " - <a href=\"doc/referenceManual/html/index.html\">Reference Manual</a> "
00586 "<p>Tips:"
00587 "<br> - right click on a pixel to get its value across the layers;"
00588 "<br> - use the mouse and its wheel over the map to zoom/scroll it;"
00589 "<br> - use the <i>subRegionMode</i> setting within the model to select the simulation area;</p>"
00590 ));
00591 }
00592
00593 void
00594 MainWindow::resetGUIForNewSimulation(){
00595
00596 static int simulationCounter = 0;
00597
00598 statusView->clear();
00599 map<string, QTreeWidgetItem*>::iterator p;
00600
00601
00602
00603 svIndex.clear();
00604
00605 QTreeWidgetItem* svGeneralNode = new QTreeWidgetItem(statusView);
00606 svIndex.insert(pair<string, QTreeWidgetItem*>("general", svGeneralNode));
00607 svGeneralNode -> setText(0, "General");
00608 QTreeWidgetItem* svYearItem = new QTreeWidgetItem(svGeneralNode);
00609 svIndex.insert(pair<string, QTreeWidgetItem*>("general_year", svYearItem));
00610 svYearItem->setText(0, "year");
00611 svYearItem->setText(1, "0");
00612 QTreeWidgetItem* svTotalPlotsItem = new QTreeWidgetItem(svGeneralNode);
00613 svIndex.insert(pair<string, QTreeWidgetItem*>("general_total plots", svTotalPlotsItem));
00614 svTotalPlotsItem->setText(0, "total plots");
00615 svTotalPlotsItem->setText(1, "0");
00616 QTreeWidgetItem* svTotalLandItem = new QTreeWidgetItem(svGeneralNode);
00617 svIndex.insert(pair<string, QTreeWidgetItem*>("general_total land", svTotalLandItem));
00618 svTotalLandItem->setText(0, "total land");
00619 QTreeWidgetItem* svTotalAgrLandItem = new QTreeWidgetItem(svGeneralNode);
00620 svIndex.insert(pair<string, QTreeWidgetItem*>("general_total agr land", svTotalAgrLandItem));
00621 svTotalAgrLandItem->setText(0, "total agr land");
00622 QTreeWidgetItem* svOwnedAgrLandItem = new QTreeWidgetItem(svGeneralNode);
00623 svIndex.insert(pair<string, QTreeWidgetItem*>("general_owned agr land", svOwnedAgrLandItem));
00624 svOwnedAgrLandItem->setText(0, "owned agr land");
00625 QTreeWidgetItem* svRentedAgrLandItem = new QTreeWidgetItem(svGeneralNode);
00626 svIndex.insert(pair<string, QTreeWidgetItem*>("general_rented agr land", svRentedAgrLandItem));
00627 svRentedAgrLandItem->setText(0, "rented agr land");
00628
00629 QTreeWidgetItem* svManagersNode = new QTreeWidgetItem(statusView);
00630 svIndex.insert(pair<string, QTreeWidgetItem*>("managers", svManagersNode));
00631 svManagersNode->setText(0,"Managers");
00632
00633 QTreeWidgetItem* svAgentsNode = new QTreeWidgetItem(statusView);
00634 svIndex.insert(pair<string, QTreeWidgetItem*>("agents", svAgentsNode));
00635 svAgentsNode->setText(0,"Agents");
00636
00637
00638 layerSelector->clear();
00639
00640 pxInfoArea->setHtml("<i>Tip: Right click over a plot to retrieve its values across layers.</i>");
00641
00642 logArea->clear();
00643
00644
00645 if (simulationCounter) logArea->append("***WARNING: You are running more simulations from the GUI without closing/reopening it. It should works, but there are no guarantees. The best way is to run only one simulation from the GUI, eventually closing and opening RegMAS again for further simulations.");
00646 simulationCounter++;
00647
00648 };
00649
00650 void
00651 MainWindow::receiveScenarioOptions(const QVector<QString> &scenarios_h){
00652
00653
00654
00655
00656
00657 scenarioWidget->receiveScenarioOptions(scenarios_h);
00658 scenarioWidget->show();
00659 scenarioWidget->scenarioSelector->setFocus();
00660
00661
00662
00663
00664 }