source: palm/trunk/UTIL/mrungui/mainwindow.cpp @ 1723

Last change on this file since 1723 was 1723, checked in by boeske, 9 years ago

Added checkbox for cyclic fill flag in mrungui

  • Property svn:keywords set to Id
File size: 47.0 KB
RevLine 
[1046]1//------------------------------------------------------------------------------//
2// This file is part of PALM.
3//
4// PALM is free software: you can redistribute it and/or modify it under the terms
5// of the GNU General Public License as published by the Free Software Foundation,
6// either version 3 of the License, or (at your option) any later version.
7//
8// PALM is distributed in the hope that it will be useful, but WITHOUT ANY
9// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
10// A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
11//
12// You should have received a copy of the GNU General Public License along with
13// PALM. If not, see <http://www.gnu.org/licenses/>.
14//
15// Copyright 1997-2012  Leibniz University Hannover
16//--------------------------------------------------------------------------------//
17//
[793]18// Current revisions:
19// -----------------
[1612]20//
[793]21//
22// Former revisions:
23// -----------------
24// $Id: mainwindow.cpp 1723 2015-11-16 15:25:51Z boeske $
25//
[1612]26// 1611 2015-07-07 12:23:22Z maronga
27// Added routine start_watchdog.
28//
[1047]29// 1046 2012-11-09 14:38:45Z maronga
30// code put under GPL (PALM 3.9)
31//
[921]32// mainwindow.cpp 920 2012-06-05 09:56:53Z maronga
33// Added -Z option (disable combine_plot_fields)
34//
[819]35// 818 2012-02-08 16:11:23Z maronga
36// New: flag parameter -z implemented (used for skipping parameter file check)
37//
[812]38// 811 2012-01-31 09:45:54Z maronga
39// Bugfix: waitForFinished time exceeded limits, adjusted to 1h waiting time
40//
[810]41// 809 2012-01-30 13:32:58Z marong
42// Bugfix: waiting for 20 minutes does not suffice for local runs
43//
[794]44// 793 2011-12-12 15:15:24Z maronga
45// Initial revision
46//
[793]47// Description:
48// ------------
49// All subroutines for mrungui
50//----------------------------------------------------------------------------//
51
52#include <QtGui/QApplication>
53#include "mainwindow.h"
54#include "ui_mainwindow.h"
55#include "ui_about.h"
56#include "ui_help.h"
57#include <QString>
58#include <QFileDialog>
59#include <QDateTime>
60#include "stdlib.h"
61#include <QProcess>
62#include <QTextStream>
63
64
65// Define username on host as global variable
66QString username = getenv("USER");
67// Define variable branch (location of mrungui, e.g.
68// "/home/user/palm/current_version"
69QString branch;
70
71
72//****************************************************************************//
73//  Initialization of the main window
74MainWindow::MainWindow(QWidget *parent) :
75    QMainWindow(parent),
76    ui(new Ui::MainWindow)
77{
78    ui->setupUi(this);
79
80//  Empty the mrun command line (hereafter mrunline)
81    ui->commandline->setText("");
82
83//  Get path of the program and set default file
84    branch = QCoreApplication::applicationDirPath();
85    branch = branch.left(branch.length() - 14);
86
87
88    QFile file(branch+"/.mrun.gui.default");
89
90//  Read default settings
91    if ( file.exists() == true && file.size() > 10)
92    {
93
94       QString mrunline;
95       if ( file.open(QIODevice::ReadOnly | QIODevice::Text ) )
96       {
97
98//        File opened successfully
99          QTextStream in(&file);
100
101          QString line = in.readLine();
102          while (!line.isNull())
103          {
104             mrunline = line;
105             line = in.readLine();
106          }
107
108          file.close();
109       }
110
111       mrunline = mrunline.right(mrunline.length() - 17);
112       ui->commandline->setText(mrunline);
113
114       setup_gui(mrunline);
115
116    }
117
118//  Load jobs into the recent jobs list
119    recent_jobs(10);
120}
121
122
123//****************************************************************************//
124//  Routine for listing jobs in the recent jobs list
125int MainWindow::recent_jobs(int noj)
126{
127    branch = QCoreApplication::applicationDirPath();
128    branch = branch.left(branch.length() - 14);
129
130    QFile file(branch+"/.mrun.history");
131    QString listitem, timestamp;
132
133//  Read mrun history and select the last used jobs
134    if ( file.exists() == true && file.size() > 10)
135    {
136
137//     Open history
138       QStringList history, tmphistory;
139       if ( file.open(QIODevice::ReadOnly | QIODevice::Text ) )
140       {
141
142//        file opened successfully
143          QTextStream in(&file);
144
145          QString line = in.readLine();
146          while (!line.isNull())
147          {
148             history.append(line);
149             line = in.readLine();
150          }
151
152          file.close();
153       }
154
155       int j = 0;
156
157       ui->list_jobname->clear();
158
159//     Read history entries and append to recent job list
160       for (int i=history.count(); i>=1; i--)
161       {
162           timestamp = history[i-1].left(16);
163           listitem = history[i-1].right(history[i-1].length() - 17);
164           listitem = listitem.split("-d ", QString::SkipEmptyParts)[1];
165           listitem = listitem.split(" -", QString::SkipEmptyParts)[0];
166           listitem = listitem.replace(" ","");
167
168           QList<QListWidgetItem *> matchitems = \
169                   ui->list_jobname->findItems(listitem, Qt::MatchExactly);
170
171           if ( matchitems.count() == 0 )
172           {
173              ui->list_jobname->addItem(listitem);
174              tmphistory.append(listitem+" ("+timestamp+")");
175              j++;
176           }
177           if ( j == noj )
178           {
179               break;
180           }
181       }
182
183//     Send to list
184       ui->list_jobname->clear();
185       for (int i=tmphistory.count(); i>=1; i--)
186       {
187           ui->list_jobname->addItem(tmphistory[i-1]);
188       }
189
190    }
191    return 0;
192}
193
194//****************************************************************************//
195//  Exit program
196MainWindow::~MainWindow()
197{
198
199    delete ui;
200}
201
202
203//****************************************************************************//
204//  Start the mrun command via xterm
205int MainWindow::startmrun()
206{
207
208    QString xtermoutput;
209    QString mrunline_save;
210    QString history_line;
211    QString mrunline = ui->commandline->text();
212    QString userline = ui->line_user->text();
213
214//  Check for empty line
215    mrunline_save = mrunline;
216    if (userline != "")
217    {
218        mrunline = mrunline + " " + userline;
219    }
220    history_line = mrunline;
221
222//  Disable the main window
223    ui->group_job->setEnabled(false);
224    ui->group_execution->setEnabled(false);
225    ui->group_runcontrol->setEnabled(false);
226    ui->group_advanced->setEnabled(false);
227    ui->check_advanced->setEnabled(false);
228    ui->check_verbose->setEnabled(false);
[818]229    ui->check_namelist_check->setEnabled(false);
[793]230    ui->button_start->setEnabled(false);
231    ui->button_start->setText("wait...");
232
233    branch = QCoreApplication::applicationDirPath();
234    branch = branch.left(branch.length() - 14);
235
236    ui->commandline->setText("Executing MRUN in xterm...");
237
238//  Wait until all commands have been executed (ugly)
239    for(int i=0; i<20; i++)
240       qApp->processEvents();
241
242//  Start xterm as QProcess
243    QProcess mrun;
244    mrun.setProcessChannelMode(QProcess::MergedChannels);
245    mrun.setWorkingDirectory(branch);
246
247    mrunline = " -title \"Executing MRUN...\" -geometry \"100x55+970+0\" -e \""\
248          +mrunline.replace("\"","\'")\
249          +";echo -n '--> Press Enter to continue...';read yesno\"";
250
251    mrun.start("xterm"+mrunline);
252
253    if(!mrun.waitForStarted())
254        return 0;
255
256//    while(mrun.waitForReadyRead())
257//        xtermoutput = xtermoutput+mrun.readAllStandardOutput();
258
[811]259//  Wait until mrun has finished or wait for 200 minutes
260    mrun.waitForFinished(3600000);
[793]261
262
263//  Jobs has been submitted or aborted. Continuing...
264//  Save the mrun command to history file
265    QString filename = branch+"/.mrun.history";
266
267    QDateTime time = QDateTime::currentDateTime();
268    QString tmptime = time.toString("yyyy/MM/dd hh:mm");
269
270    QFile file(filename);
271    file.open(QIODevice::Append | QIODevice::Text);
272    QTextStream out(&file);
273    out << tmptime + " " + history_line + "\n";
274    file.close();
275
276//  Enable main window again
277    ui->group_job->setEnabled(true);
278    ui->group_execution->setEnabled(true);
279    ui->group_runcontrol->setEnabled(true);
280    if ( ui->check_advanced->isChecked() == true)
281    {
282       ui->group_advanced->setEnabled(true);
283    }
284    ui->check_advanced->setEnabled(true);
285    ui->check_verbose->setEnabled(true);
[818]286    ui->check_namelist_check->setEnabled(true);
[793]287    ui->button_start->setEnabled(true);
288    ui->action_save->setEnabled(true);
289    ui->button_start->setText("MRUN Start");
290    ui->commandline->setText(mrunline_save);
291
292//  Reload recent jobs
293    recent_jobs(10);
294
295    return 0;
296}
297
298
299//****************************************************************************//
300//  Disable/Enable advanced settings dialog
301int MainWindow::enable_advanced()
302{
303    bool status;
304
305    status = ui->group_advanced->isEnabled();
306    if (status == true)
307    {
308       ui->group_advanced->setEnabled(false);
309    }
310    else
311    {
312       ui->group_advanced->setEnabled(true);
313    }
314
315    return 0;
316}
317
318
319//****************************************************************************//
320//  Disable/enable dialog for coupled runs
321int MainWindow::enable_coupled()
322{
323    QString status;
324
325    status = ui->drop_job->currentText();
326    if (status == "Coupled restart")
327    {
328       ui->label_coupled1->setEnabled(true);
329       ui->label_coupled2->setEnabled(true);
330       ui->label_coupled3->setEnabled(true);
331       ui->line_PE_atmos->setEnabled(true);
332       ui->line_PE_ocean->setEnabled(true);
333
334       QString pe_total = ui->line_pe->text();
335       QString pe_atmos = ui->line_PE_atmos->text();
336       QString pe_ocean = ui->line_PE_ocean->text();
337       if (pe_total != "")
338       {
339           int PE_split = pe_total.toInt()/2;
340           ui->line_PE_atmos->setText(QString::number(PE_split));
341           ui->line_PE_ocean->setText(QString::number(PE_split));
342       }
343    }
344    else
345    {
346        ui->label_coupled1->setEnabled(false);
347        ui->label_coupled2->setEnabled(false);
348        ui->label_coupled3->setEnabled(false);
349        ui->line_PE_atmos->setEnabled(false);
350        ui->line_PE_ocean->setEnabled(false);
351    }
352
353    return 0;
354}
355
356
357//****************************************************************************//
358//  Choose job from dialog
359int MainWindow::choosejob()
360{
361    QString filename;
362    branch = QCoreApplication::applicationDirPath();
363    branch = branch.left(branch.length() - 14);
364
365    QString jobdir = branch+"/JOBS";
366
367
368//  Pick a job from dialog
369    filename = QFileDialog::getExistingDirectory(this, \
370                            tr("Choose a job directory"), branch+"/JOBS", \
371               QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks | \
372               QFileDialog::DontUseNativeDialog | QFileDialog::ReadOnly | \
373               QFileDialog::DontConfirmOverwrite);
374
375
376
377
378
379//  If a file was selected, load it into mainwindow
380    if ( filename != "")
381    {
382        filename = filename.right(filename.length() - jobdir.length() - 1);
383
384        ui->line_jobname->setText(filename);
385        ui->list_jobname->clearSelection();
386
387//      Change mrunline accordingly
388        change_commandline("d","");
389        change_commandline("r","");
390        return 0;
391    }
392    else
393    {
394        return 1;
395    }
396}
397
398
399//****************************************************************************//
400//  Choose job from the recent job list and load all settings
401int MainWindow::choosejob_list()
402{
403    QString filename, timestamp, jobname;
404
405//  Get selected item from list
406    filename = ui->list_jobname->currentItem()->text();
407    int itemint = ui->list_jobname->currentRow();
408
409//  Reload list
410    ui->setupUi(this);
411    recent_jobs(10);
412
413//  Set selected item to jobname
414    ui->list_jobname->item(itemint)->setSelected(true);
415
416    timestamp = filename.right(17).left(16);
417    jobname = filename.left(filename.length() - 19);
418
419    branch = QCoreApplication::applicationDirPath();
420    branch = branch.left(branch.length() - 14);
421    QFile file(branch+"/.mrun.history");
422    QString listitem;
423
424//  Load history
425    if ( file.exists() == true && file.size() > 10)
426    {
427
428       QStringList history;
429       if ( file.open(QIODevice::ReadOnly | QIODevice::Text ) )
430       {
431
432//        file opened successfully
433          QTextStream in(&file);
434
435          QString line = in.readLine();
436          while (!line.isNull())
437          {
438             history.append(line);
439             line = in.readLine();
440          }
441
442          file.close();
443       }
444
445       for (int i=history.count(); i>=1; i--)
446       {
447           listitem = history[i-1].right(history[i-1].length() - 17);
448           listitem = listitem.split("-d ", QString::SkipEmptyParts)[1];
449           listitem = listitem.split(" -", QString::SkipEmptyParts)[0];
450           listitem = listitem.replace(" ","");
451
452
453//         Select command line with correct timestamp and jobname
454           if (history[i-1].left(16) == timestamp && listitem == jobname)
455           {
456              QString mrunline = history[i-1];
457              mrunline = mrunline.right(mrunline.length() - 17);
458              ui->commandline->setText(mrunline);
459
460              setup_gui(mrunline);
461           }
462       }
463    }
464
465     return 0;
466}
467
468
469//****************************************************************************//
470//  Change run identifer (initial, restart, coupled...)
471int MainWindow::change_rc_list()
472{
473
474
475   QString drop_job = ui->drop_job->currentText();
476
477   change_commandline("r","");
478
479// Enable PE distribution for atmosphere/ocean
480   if ( drop_job == "Coupled restart")
481   {
482       QString drop_atmos = ui->line_PE_atmos->text();
483       QString drop_ocean = ui->line_PE_ocean->text();
484
485       change_commandline("Y",drop_atmos+" "+drop_ocean);
486   }
487
488// Check of ocean runs
489   else
490   {
491      delete_commandline("Y");
492      if (drop_job == "Precursor run (Ocean)")
493      {
494          activate_flag("y");
495      }
496      else
497      {
498          deactivate_flag("y");
499      }
500   }
501
502
503    return 0;
504}
505
506
507//****************************************************************************//
508//  Routine for processing any changes in the mainwindow settings
509int MainWindow::change_commandline(QString id,QString fwstring)
510{
511
512//  First get the mrunline
513    QString newmrunline;
514    bool    initialize=false;
515
516    QString mrunline = ui->commandline->text();
517
518    QStringList splitline = mrunline.split(" -"+id+"", QString::SkipEmptyParts);
519    if ( splitline.count() == 1)
520    {
521        splitline.append(" ");
522    }
523    else if ( splitline.count() == 0 )
524    {
525       splitline.append("mrun");
526       splitline.append(" ");
527       initialize = true;
528    }
529
530    QStringList param = splitline[1].split("-");
531
532//  Change in parameter "d" (jobname)
533    if (id == "d")
534    {
535       QString filename = ui->line_jobname->text();
536
537       param[0] = filename.replace(" ","");
538
539       if ( initialize == true && ui->group_runcontrol->isEnabled() == true )
540       {
541           ui->group_runcontrol->setEnabled(true);
542           ui->group_execution->setEnabled(true);
543           ui->drop_job->setEnabled(true);
544           ui->check_advanced->setEnabled(true);
545           ui->button_start->setEnabled(true);
546           ui->action_save->setEnabled(true);
547       }
548       else if ( param[0] == "")
549       {
550           ui->group_runcontrol->setEnabled(false);
551           ui->group_execution->setEnabled(false);
552           ui->drop_job->setEnabled(false);
553           ui->button_start->setEnabled(false);
554           ui->action_save->setEnabled(false);
555           ui->group_advanced->setEnabled(false);
556           ui->check_advanced->setEnabled(false);
557           delete_commandline("d");
558           change_commandline("r","remove");
559           ui->label_usercode->setText("");
560           return 1;
561       }
562       else
563       {
564
565//         Check if user code is available
566           branch = QCoreApplication::applicationDirPath();
567           branch = branch.left(branch.length() - 14);
568           QDir usercode = branch+"/USER_CODE/"+param[0];
569           if (usercode.exists() == true)
570           {
571               ui->label_usercode->setText("User code found.");
572           }
573           else
574           {
575               ui->label_usercode->setText("Warning: no user code found!");
576           }
577
578//         Check if _pdf file is available, otherwise notice user
579           if (ui->check_restarts->checkState() == 2)
580           {
581              QString jobname = ui->line_jobname->text();
582              QFile restartfile(branch+"/JOBS/"+jobname+"/INPUT/"+jobname+"_p3df");
583              if (restartfile.exists() == true)
584              {
585                 ui->label_restart->setText("");
586              }
587              else
588              {
589                 ui->label_restart->setText("Warning: No p3df file found!");
590              }
591           }
592
593           ui->group_runcontrol->setEnabled(true);
594           ui->group_execution->setEnabled(true);
595           ui->drop_job->setEnabled(true);
596           ui->check_advanced->setEnabled(true);
597
598           if ( ui->check_advanced->isChecked() == true )
599           {
600              ui->group_advanced->setEnabled(true);
601              if ( ui->line_i->text() != "" || ui->line_o->text() != "")
602              {
603                 change_commandline("r","remove");
604                 ui->group_runcontrol->setEnabled(false);
605              }
606           }
607       }
608
609    }
610
611//  Change in parameter "r" (run control list)
612    else if (id == "r")
613    {
614        int status_ts = ui->check_ts->checkState();
615        int status_pr = ui->check_pr->checkState();
616        int status_xy = ui->check_xy->checkState();
617        int status_xz = ui->check_xz->checkState();
618        int status_yz = ui->check_yz->checkState();
619        int status_3d = ui->check_3d->checkState();
620        int status_ma = ui->check_ma->checkState();
621        int status_sp = ui->check_sp->checkState();
622        int status_pts = ui->check_pts->checkState();
623        int status_prt = ui->check_prt->checkState();
624
625        QString drop_job = ui->drop_job->currentText();
626        QString rc_flag = "#";
627
628        if (drop_job == "Initial run")
629        {
630            rc_flag = "#";
631        }
632        else if (drop_job == "Restart run")
633        {
634            rc_flag = "f";
635        }
636        else if (drop_job == "Precursor run (Atmosphere)")
637        {
638            rc_flag = "#";
639        }
640        else if (drop_job == "Precursor run (Ocean)")
641        {
642           rc_flag = "o#";
643        }
644        else if (drop_job == "Coupled restart")
645        {
646           rc_flag = "f";
647        }
648
649        param[0] = "\"d3"+rc_flag;
650
651        if (status_ts == 2)
652        {
653            param[0] = param[0]+" ts"+rc_flag;
654        }
655        if (status_pr == 2)
656        {
657           param[0] = param[0]+" pr"+rc_flag;
658        }
659        if (status_xy == 2)
660        {
661           param[0] = param[0]+" xy"+rc_flag;
662        }
663        if (status_xz == 2)
664        {
665           param[0] = param[0]+" xz"+rc_flag;
666        }
667        if (status_yz == 2)
668        {
669           param[0] = param[0]+" yz"+rc_flag;
670        }
671        if (status_3d == 2)
672        {
673           param[0] = param[0]+" 3d"+rc_flag;
674        }
675        if (status_ma == 2)
676        {
677           param[0] = param[0]+" ma"+rc_flag;
678        }
679        if (status_sp == 2)
680        {
681           param[0] = param[0]+" sp"+rc_flag;
682        }
683        if (status_prt == 2)
684        {
685           param[0] = param[0]+" prt"+rc_flag;
686        }
687        if (status_pts == 2)
688        {
689           param[0] = param[0]+" pts"+rc_flag;
690        }
691
692        if (drop_job == "Coupled restart")
693        {
694            rc_flag = "of";
695            param[0] = param[0]+" d3"+rc_flag;
696
697            if (status_ts == 2)
698            {
699                param[0] = param[0]+" ts"+rc_flag;
700            }
701            if (status_pr == 2)
702            {
703               param[0] = param[0]+" pr"+rc_flag;
704            }
705            if (status_xy == 2)
706            {
707               param[0] = param[0]+" xy"+rc_flag;
708            }
709            if (status_xz == 2)
710            {
711               param[0] = param[0]+" xz"+rc_flag;
712            }
713            if (status_yz == 2)
714            {
715               param[0] = param[0]+" yz"+rc_flag;
716            }
717            if (status_3d == 2)
718            {
719               param[0] = param[0]+" 3d"+rc_flag;
720            }
721            if (status_ma == 2)
722            {
723               param[0] = param[0]+" ma"+rc_flag;
724            }
725            if (status_sp == 2)
726            {
727               param[0] = param[0]+" sp"+rc_flag;
728            }
729            if (status_prt == 2)
730            {
731               param[0] = param[0]+" prt"+rc_flag;
732            }
733            if (status_pts == 2)
734            {
735               param[0] = param[0]+" pts"+rc_flag;
736            }
737        }
738
739        int status_restarts = ui->check_restarts->checkState();
740
741
742
743        if (status_restarts == 2)
744        {
745            param[0]=param[0]+" restart";
746
747//          Check if _pdf file is available, otherwise notice user
748            if (ui->check_restarts->checkState() == 2)
749            {
750               QString jobname = ui->line_jobname->text();
751               branch = QCoreApplication::applicationDirPath();
752               branch = branch.left(branch.length() - 14);
753               QFile restartfile(branch+"/JOBS/"+jobname+"/INPUT/"+jobname+ \
754                                 "_p3df");
755               if (restartfile.exists() == true)
756               {
757                  ui->label_restart->setText("");
758               }
759               else
760               {
761                  ui->label_restart->setText("Warning: No p3df file found!");
762               }
763            }
764
765        }
766        else  {
767          ui->label_restart->setText("");
768        }
769
[1723]770       
771       
772        int status_cycfill = ui->check_cycfill->checkState();
773
774        if (status_cycfill == 2)
775        {
776            param[0]=param[0]+" cycfill";
777        }
778
779
780       
[793]781        param[0]=param[0]+"\" ";
782
783        if ( fwstring == "remove")
784        {
785            delete_commandline(id);
786            return 1;
787        }
788        else
789        {
790           ui->button_start->setEnabled(true);
791           ui->action_save->setEnabled(true);
792        }
793    }
794//  Change in any other parameter
795    else
796    {
797        if ( fwstring != "")
798        {
799           param[0] = "\""+fwstring+"\"";
800        }
801        else
802        {
803            delete_commandline(id);
804            return 1;
805        }
806
807    }
808    param[0] = param[0] + " ";
809
810//  Join the new mrunline
811    splitline[1]= param.join("-");
812    newmrunline = splitline.join(" -"+id+" ");
813
814//  Print the new mrunline to mainwindow
815    newmrunline.replace("  "," ");
816    ui->commandline->setText(newmrunline);
817
818    return 0;
819}
820
821
822//****************************************************************************//
823//  Get all signals from mainwindow and perform change via change_commandline()
824int MainWindow::change_lineinput()
825{
826    QString tmptext;
827
828    if ( sender() == ui->line_host )
829    {
830        tmptext = ui->line_host->text();
831        change_commandline("h",tmptext);
832    }
833    else if ( sender() == ui->line_jobname)
834    {
835        tmptext = ui->line_jobname->text();
836        change_commandline("d",tmptext);
837    }
838    else if ( sender() == ui->line_q)
839    {
840        tmptext = ui->line_q->text();
841        change_commandline("q",tmptext);
842    }
843    else if ( sender() == ui->line_account)
844    {
845        tmptext = ui->line_account->text();
846        change_commandline("u",tmptext);
847    }
848    else if ( sender() ==  ui->line_pe)
849    {
850        tmptext = ui->line_pe->text();
851        change_commandline("X",tmptext);
852    }
853    else if ( sender() == ui->line_tpn)
854    {
855        tmptext = ui->line_tpn->text();
856        change_commandline("T",tmptext);
857    }
858    else if ( sender() == ui->line_branch)
859    {
860        tmptext = ui->line_branch->text();
861        change_commandline("K",tmptext);
862    }
863    else if ( sender() == ui->line_time)
864    {
865        tmptext = ui->line_time->text();
866        change_commandline("t",tmptext);
867    }
868    else if ( sender() == ui->line_M)
869    {
870        tmptext = ui->line_M->text();
871        change_commandline("M",tmptext);
872    }
873    else if ( sender() == ui->line_m)
874    {
875        tmptext = ui->line_m->text();
876        change_commandline("m",tmptext);
877    }
878    else if ( sender() == ui->line_a)
879    {
880        tmptext = ui->line_a->text();
881        change_commandline("a",tmptext);
882    }
883    else if ( sender() == ui->line_D)
884    {
885        tmptext = ui->line_D->text();
886        change_commandline("D",tmptext);
887    }
888    else if ( sender() == ui->line_c)
889    {
890        tmptext = ui->line_c->text();
891        if ( tmptext == ".mrun.config")
892        {
893            tmptext = "";
894        }
895        change_commandline("c",tmptext);
896    }
897    else if ( sender() == ui->line_p)
898    {
899        tmptext = ui->line_p->text();
900        change_commandline("p",tmptext);
901    }
902    else if ( sender() == ui->line_s)
903    {
904        tmptext = ui->line_s->text();
905        change_commandline("s",tmptext);
906    }
907    else if ( sender() == ui->line_i)
908    {
909        tmptext = ui->line_i->text();
910        if ( tmptext != "")
911        {
912            change_commandline("r","remove");
913            ui->group_runcontrol->setEnabled(false);
914
915            ui->button_start->setEnabled(true);
916            ui->action_save->setEnabled(true);
917        }
918        else if (ui->line_o->text() == "" )
919        {
920           ui->group_runcontrol->setEnabled(true);
921           change_commandline("r","");
922        }
923
924        change_commandline("i",tmptext);
925    }
926    else if ( sender() == ui->line_o)
927    {
928        tmptext = ui->line_o->text();
929        if ( tmptext != "")
930        {
931            change_commandline("r","remove");
932            ui->button_start->setEnabled(true);
933            ui->action_save->setEnabled(true);
934            ui->group_runcontrol->setEnabled(false);
935        }
936        else if (ui->line_i->text() == "" )
937        {
938           ui->group_runcontrol->setEnabled(true);
939           change_commandline("r","");
940        }
941
942        change_commandline("o",tmptext);
943
944    }
945    else if ( sender() == ui->line_w)
946    {
947        tmptext = ui->line_w->text();
948        change_commandline("w",tmptext);
949    }
950    else if ( sender() == ui->line_PE_atmos || sender() == ui->line_PE_ocean)
951    {
952        tmptext = ui->line_PE_atmos->text() + " "  + ui->line_PE_ocean->text();
953        change_commandline("Y",tmptext);
954        int PE_total = ui->line_PE_atmos->text().toInt() + \
955                        ui->line_PE_ocean->text().toInt();
956        ui->line_pe->setText(QString::number(PE_total));
957        change_commandline("X",QString::number(PE_total));
958    }
959
960    else if ( sender() == ui->combo_n)
961    {
962        tmptext = ui->combo_n->currentText();
963        if ( tmptext == "default")
964        {
965            tmptext = "";
966        }
967        change_commandline("n",tmptext);
968    }
969    else if ( sender() == ui->line_user)
970    {
971       return 0;
972    }
973
974    return 0;
975}
976
977
978//****************************************************************************//
979//  Delete a parameter from mrunline
980int MainWindow::delete_commandline(QString id)
981{
982
983//  Read mrunline
984    QString newmrunline;
985    QString mrunline = ui->commandline->text();
986    QStringList splitline = mrunline.split(" -"+id, QString::SkipEmptyParts);
987    if ( splitline.count() == 1)
988    {
989       return 0;
990    }
991    else
992    {
993       QStringList param = splitline[1].split("-");
994       param[0] = "";
995       splitline[1]= param.join(" -");
996       newmrunline = splitline.join("");
997
998//     Print new mrunline to screen
999       ui->commandline->setText(newmrunline);
1000
1001       return 0;
1002    }
1003}
1004
1005
1006//****************************************************************************//
1007//  Check routine for all flag parameters
1008int MainWindow::check_flags()
1009{
1010
1011    int status = ui->check_delete_tmp_files->checkState();
1012
1013    if (status == 2)
1014    {
1015        activate_flag("B");
1016    }
1017    else
1018    {
1019        deactivate_flag("B");
1020    }
1021
1022    status = ui->check_verbose->checkState();
1023
1024    if (status == 2)
1025    {
1026        activate_flag("v");
1027    }
1028    else
1029    {
1030        deactivate_flag("v");
1031    }
1032
[818]1033    status = ui->check_namelist_check->checkState();
1034
1035    if (status == 2)
1036    {
1037        activate_flag("z");
1038    }
1039    else
1040    {
1041        deactivate_flag("z");
1042    }
1043
[793]1044    status = ui->check_A->checkState();
1045
1046    if (status == 2)
1047    {
1048        activate_flag("A");
1049    }
1050    else
1051    {
1052        deactivate_flag("A");
1053    }
1054
1055    status = ui->check_b->checkState();
1056
1057    if (status == 2)
1058    {
1059        activate_flag("b");
1060    }
1061    else
1062    {
1063        deactivate_flag("b");
1064    }
1065
1066    status = ui->check_F->checkState();
1067
1068    if (status == 2)
1069    {
1070        activate_flag("F");
1071    }
1072    else
1073    {
1074        deactivate_flag("F");
1075    }
1076    status = ui->check_I->checkState();
1077
1078    if (status == 2)
1079    {
1080        activate_flag("I");
1081    }
1082    else
1083    {
1084        deactivate_flag("I");
1085    }
1086    status = ui->check_k->checkState();
1087
1088    if (status == 2)
1089    {
1090        activate_flag("k");
1091    }
1092    else
1093    {
1094        deactivate_flag("k");
1095    }
1096    status = ui->check_O->checkState();
1097
1098    if (status == 2)
1099    {
1100        activate_flag("O");
1101    }
1102    else
1103    {
1104        deactivate_flag("O");
1105    }
1106    status = ui->check_S->checkState();
1107
1108    if (status == 2)
1109    {
1110        activate_flag("S");
1111    }
1112    else
1113    {
1114        deactivate_flag("S");
1115    }
1116    status = ui->check_x->checkState();
1117
1118    if (status == 2)
1119    {
1120        activate_flag("x");
1121    }
1122    else
1123    {
1124        deactivate_flag("x");
1125    }
[920]1126   
1127    status = ui->check_Z->checkState();
1128
1129    if (status == 2)
1130    {
1131        activate_flag("Z");
1132    }
1133    else
1134    {
1135        deactivate_flag("Z");
1136    }
[793]1137    return 0;
1138
1139}
1140
1141
1142//****************************************************************************//
1143//  Activate flag
1144int MainWindow::activate_flag(QString id)
1145{
1146    QString newmrunline;
1147
1148    QString mrunline = ui->commandline->text();
1149
1150    QStringList splitline = mrunline.split(" -"+id, QString::SkipEmptyParts);
1151    if ( splitline.count() == 1)
1152    {
1153        splitline.append("");
1154        newmrunline = splitline.join(" -"+id);
1155
1156 //     print new commandline to screen
1157        newmrunline.replace("  "," ");
1158        ui->commandline->setText(newmrunline);
1159
1160       return 0;
1161    }
1162    else
1163    {
1164       return 0;
1165    }
1166}
1167
1168
1169//****************************************************************************//
1170//  Deactivate flag
1171int MainWindow::deactivate_flag(QString id)
1172{
1173    QString newmrunline;
1174
1175    QString mrunline = ui->commandline->text();
1176
1177    QStringList splitline = mrunline.split(" -"+id, QString::SkipEmptyParts);
1178
1179    newmrunline = splitline.join("");
1180//  print new commandline to screen
1181    newmrunline.replace("  "," ");
1182    ui->commandline->setText(newmrunline);
1183
1184    return 0;
1185}
1186
1187
1188//****************************************************************************//
1189//  Mainwindow reset
1190int MainWindow::reset_window()
1191{
1192    ui->setupUi(this);
1193    recent_jobs(10);
1194    return 0;
1195}
1196
1197
1198//****************************************************************************//
1199//  Save current setting as default
1200int MainWindow::save_default()
1201{
1202
1203//  Get mrunline
1204    QString mrunline_save;
1205    QString mrunline = ui->commandline->text();
1206    QString userline = ui->line_user->text();
1207
1208    mrunline_save = mrunline;
1209    if (userline != "")
1210    {
1211        mrunline = mrunline + " " + userline;
1212    }
1213
1214
1215//  Define filename
1216    branch = QCoreApplication::applicationDirPath();
1217    branch = branch.left(branch.length() - 14);
1218
1219    QString filename = branch+"/.mrun.gui.default";
1220
1221//  Prepare data output
1222    QDateTime time = QDateTime::currentDateTime();
1223    QString tmptime = time.toString("yyyy/MM/dd hh:mm");
1224
1225//  Write to file
1226    QFile file(filename);
1227    file.open(QIODevice::WriteOnly | QIODevice::Text);
1228    QTextStream out(&file);
1229    if ( mrunline == "" || mrunline == " ")
1230    {
1231        out << "";
1232    }
1233    else
1234    {
1235       out << tmptime + " " + mrunline;
1236    }
1237
1238    file.close();
1239
1240    return 0;
1241}
1242
1243
1244//****************************************************************************//
1245//  Save current settings to a file of choice
1246int MainWindow::save_to_file()
1247{
1248
1249//  Get mrunline
1250    QString mrunline_save;
1251    QString mrunline = ui->commandline->text();
1252    QString userline = ui->line_user->text();
1253
1254    mrunline_save = mrunline;
1255    if (userline != "")
1256    {
1257        mrunline = mrunline + " " + userline;
1258    }
1259
1260//  Define a filename
1261    QString filename = QFileDialog::getSaveFileName(this, tr("Save to file"), \
1262                                    "", tr("Save files (*.sav)"));
1263    QString extension = filename.right(4);
1264
1265    if ( extension != ".sav" )
1266    {
1267        filename = filename + ".sav";
1268    }
1269
1270//  Prepare data output
1271    QDateTime time = QDateTime::currentDateTime();
1272    QString tmptime = time.toString("yyyy/MM/dd hh:mm");
1273
1274//  Write to file
1275    QFile file(filename);
1276    file.open(QIODevice::WriteOnly | QIODevice::Text);
1277    QTextStream out(&file);
1278    out << tmptime + " " + mrunline;
1279    file.close();
1280
1281    return 0;
1282}
1283
[1611]1284//****************************************************************************//
1285//  Start watchdog (palm_wd)
1286int MainWindow::start_watchdog()
1287{
1288    system("nohup palm_wd >> /dev/null 2>&1 &");
[793]1289
[1611]1290    return 0;
1291}
1292
1293
[793]1294//****************************************************************************//
1295//  Open job from file (previously saved by the user)
1296int MainWindow::open_from_file()
1297{
1298
1299//  Select filename and open it
1300    QString filename = QFileDialog::getOpenFileName(this, tr("Open File"), \
1301                                    "", tr("Save files (*.sav)"));
1302
1303    QFile file(filename);
1304    QString mrunline;
1305    if ( filename != "")
1306    {
1307       if ( file.open(QIODevice::ReadOnly | QIODevice::Text ) )
1308       {
1309
1310//        File opened successfully
1311          QTextStream in(&file);
1312
1313          QString line = in.readLine();
1314          while (!line.isNull())
1315          {
1316             mrunline = line;
1317             line = in.readLine();
1318          }
1319          file.close();
1320       }
1321
1322//     In case a mrunline was found, load it to mainwindow
1323       if ( mrunline != "")
1324       {
1325
1326          mrunline = mrunline.right(mrunline.length() - 17);
1327          ui->commandline->setText(mrunline);
1328
1329          setup_gui(mrunline);
1330       }
1331    }
1332    return 0;
1333}
1334
1335
1336//****************************************************************************//
1337//  Open the last submitted job
1338int MainWindow::open_last()
1339{
1340    branch = QCoreApplication::applicationDirPath();
1341    branch = branch.left(branch.length() - 14);
1342
1343    QFile file(branch+"/.mrun.history");
1344
1345//  Load mrun history
1346    QString mrunline;
1347    if ( file.open(QIODevice::ReadOnly | QIODevice::Text ) )
1348    {
1349
1350//     file opened successfully
1351       QTextStream in(&file);
1352
1353       QString line = in.readLine();
1354       while (!line.isNull())
1355       {
1356          mrunline = line;
1357          line = in.readLine();
1358       }
1359
1360       file.close();
1361    }
1362
1363//  Select the last submitted job and print it to mainwindow
1364    if ( mrunline != "" )
1365    {
1366       mrunline = mrunline.right(mrunline.length() - 17);
1367       ui->commandline->setText(mrunline);
1368
1369       setup_gui(mrunline);
1370    }
1371    return 0;
1372}
1373
1374//****************************************************************************//
1375//  Display help window
1376int MainWindow::help()
1377{
1378
1379    QDialog *child_help = new QDialog;
1380    Ui::child_help ui;
1381    ui.setupUi(child_help);
1382    child_help->show();
1383
1384
1385    return 0;
1386}
1387
1388//****************************************************************************//
1389//  Display about window
1390int MainWindow::about_gui()
1391{
1392
1393    QDialog *about = new QDialog;
1394    Ui::about ui;
1395    ui.setupUi(about);
1396    about->show();
1397
1398    return 0;
1399}
1400
1401//****************************************************************************//
1402//  Setup mainwindow according to a given mrunline
1403int MainWindow::setup_gui(QString mrunline)
1404{
1405
1406//  Some initial settings
1407    QString user = "";
1408
1409    bool coupled_run = false;
1410    bool ocean_run   = false;
1411    bool advanced    = false;
1412    bool nojob       = false;
1413    bool rc_manual   = false;
1414
1415//  Split parameters in mrunline
1416    QStringList splitline = mrunline.split(" -", QString::SkipEmptyParts);
1417
1418    if ( splitline[0] != "mrun")
1419    {
1420        return 1;
1421
1422    }
1423    else
1424    {
1425        ui->group_job->setEnabled(true);
1426
1427//      Loop for all parameters in mrunline
1428        for(int i=splitline.count()-1; i>=1; i--)
1429        {
1430
1431//          Determine parameter
1432            QStringList splitparameter = splitline[i].split(" ", \
1433                                                      QString::SkipEmptyParts);
1434
1435            QString parameter = splitparameter[0];
1436            splitparameter.removeFirst();
1437            QString options = splitparameter.join(" ");
1438            options = options.replace("\"","");
1439
1440//          Check for suitable switch
1441            if ( parameter == "d")
1442            {
1443               if ( options != "")
1444               {
1445                  ui->line_jobname->setText(options);
1446                  nojob = false;
1447               }
1448               else
1449               {
1450                  nojob = true;
1451               }
1452            }
1453            else if ( parameter == "h")
1454            {
1455               ui->line_host->setText(options);
1456            }
1457            else if ( parameter == "q")
1458            {
1459               ui->line_q->setText(options);
1460            }
1461            else if ( parameter == "K")
1462            {
1463               ui->line_branch->setText(options);
1464            }
1465            else if ( parameter == "u")
1466            {
1467               ui->line_account->setText(options);
1468            }
1469            else if ( parameter == "X")
1470            {
1471               ui->line_pe->setText(options);
1472            }
1473            else if ( parameter == "T")
1474            {
1475               ui->line_tpn->setText(options);
1476            }
1477            else if ( parameter == "t")
1478            {
1479               ui->line_time->setText(options);
1480            }
1481            else if ( parameter == "B")
1482            {
1483               ui->check_delete_tmp_files->setChecked(true);
1484            }
1485            else if ( parameter == "v")
1486            {
1487               ui->check_verbose->setChecked(true);
1488            }
[818]1489            else if ( parameter == "z")
1490            {
1491               ui->check_namelist_check->setChecked(true);
1492            }
[793]1493            else if ( parameter == "A")
1494            {
1495               ui->check_A->setChecked(true);
1496            }
1497            else if ( parameter == "b")
1498            {
1499               ui->check_b->setChecked(true);
1500               advanced = true;
1501            }
1502            else if ( parameter == "F")
1503            {
1504               ui->check_F->setChecked(true);
1505               advanced = true;
1506            }
1507            else if ( parameter == "I")
1508            {
1509               ui->check_I->setChecked(true);
1510               advanced = true;
1511            }
1512            else if ( parameter == "k")
1513            {
1514               ui->check_k->setChecked(true);
1515               advanced = true;
1516            }
1517            else if ( parameter == "O")
1518            {
1519               ui->check_O->setChecked(true);
1520               advanced = true;
1521            }
1522            else if ( parameter == "S")
1523            {
1524               ui->check_S->setChecked(true);
1525               advanced = true;
1526            }
1527            else if ( parameter == "x")
1528            {
1529               ui->check_x->setChecked(true);
1530               advanced = true;
1531            }
[920]1532            else if ( parameter == "Z")
1533            {
1534               ui->check_Z->setChecked(true);
1535               advanced = true;
1536            } 
[793]1537            else if ( parameter == "m")
1538            {
1539               ui->line_m->setText(options);
1540               advanced = true;
1541            }
1542            else if ( parameter == "M")
1543            {
1544               ui->line_M->setText(options);
1545               advanced = true;
1546            }
1547            else if ( parameter == "a")
1548            {
1549               ui->line_a->setText(options);
1550               advanced = true;
1551            }
1552            else if ( parameter == "D")
1553            {
1554               ui->line_D->setText(options);
1555               advanced = true;
1556            }
1557            else if ( parameter == "c")
1558            {
1559               ui->line_c->setText(options);
1560               advanced = true;
1561            }
1562            else if ( parameter == "p")
1563            {
1564               ui->line_p->setText(options);
1565               advanced = true;
1566            }
1567            else if ( parameter == "s")
1568            {
1569               ui->line_s->setText(options);
1570               advanced = true;
1571            }
1572            else if ( parameter == "i")
1573            {
1574               ui->line_i->setText(options);
1575               advanced = true;
1576               rc_manual = true;
1577            }
1578            else if ( parameter == "o")
1579            {
1580               ui->line_o->setText(options);
1581               advanced = true;
1582               rc_manual = true;
1583            }
1584            else if ( parameter == "w")
1585            {
1586               ui->line_w->setText(options);
1587               advanced = true;
1588            }
1589
1590//          Determine settings for coupled restart runs
1591            else if ( parameter == "Y")
1592            {
1593                QStringList optionssplit = options.split(" ", \
1594                                                   QString::SkipEmptyParts);
1595
1596                ui->line_PE_atmos->setEnabled(true);
1597                ui->line_PE_ocean->setEnabled(true);
1598                ui->label_coupled1->setEnabled(true);
1599                ui->label_coupled2->setEnabled(true);
1600                ui->label_coupled3->setEnabled(true);
1601                ui->label_coupling->setEnabled(true);
1602
1603                if (optionssplit.count() == 2)
1604                {
1605                   ui->line_PE_atmos->setText(optionssplit[0]);
1606                   ui->line_PE_ocean->setText(optionssplit[1]);
1607                }
1608                else
1609                {
1610                   ui->line_PE_atmos->setText("");
1611                   ui->line_PE_ocean->setText("");
1612                }
1613                coupled_run = true;
1614            }
1615            else if ( parameter == "n")
1616            {
1617                if ( options == "shared")
1618                {
1619                    ui->combo_n->setCurrentIndex(1);
1620                }
1621                else if ( options == "non_shared")
1622                {
1623                    ui->combo_n->setCurrentIndex(2);
1624                }
1625                else
1626                {
1627                    ui->combo_n->setCurrentIndex(0);
1628                }
1629            }
1630            else if ( parameter == "y")
1631            {
1632               ui->drop_job->setCurrentIndex(3);
1633            }
1634
1635//          Determine settings for the run control list
1636            else if ( parameter == "r")
1637            {
1638               QStringList optionssplit = options.split(" ", \
1639                                          QString::SkipEmptyParts);
1640
1641               QString options_2;
1642               QString options_all;
1643               for (int j=0; j<optionssplit.count(); j++)
1644               {
1645                   options_all = optionssplit[j];
1646                   options_2 = optionssplit[j].left(2);
1647                   if (options_2 == "ts")
1648                   {
1649                       ui->check_ts->setChecked(true);
1650                   }
1651                   if (options_2 == "pr" && options_all.left(3) != "prt")
1652                   {
1653                       ui->check_pr->setChecked(true);
1654                   }
1655                   if (options_2 == "xy")
1656                   {
1657                       ui->check_xy->setChecked(true);
1658                   }
1659                   if (options_2 == "xz")
1660                   {
1661                       ui->check_xz->setChecked(true);
1662                   }
1663                   if (options_2 == "yz")
1664                   {
1665                       ui->check_yz->setChecked(true);
1666                   }
1667                   if (options_2 == "3d")
1668                   {
1669                       ui->check_3d->setChecked(true);
1670                   }
1671                   if (options_2 == "ma")
1672                   {
1673                       ui->check_ma->setChecked(true);
1674                   }
1675                   if (options_2 == "sp")
1676                   {
1677                       ui->check_sp->setChecked(true);
1678                   }
1679                   if (options_all.left(3) == "prt")
1680                   {
1681                       ui->check_prt->setChecked(true);
1682                   }
1683                   if (options_all.left(3) == "pts")
1684                   {
1685                       ui->check_pts->setChecked(true);
1686                   }
1687                   if (options_2 == "d3")
1688                   {
1689                       if (options_all.left(3).right(1) == "#")
1690                       {
1691                          ui->drop_job->setCurrentIndex(0);
1692                       }
1693                       else if (options_all.left(3).right(1) == "f")
1694                       {
1695                          ui->drop_job->setCurrentIndex(1);
1696                       }
1697                       else if (options_all.left(3).right(1) == "o")
1698                       {
1699                          ocean_run = true;
1700                       }
1701                   }
1702                   if (options_all == "restart")
1703                   {
1704                      ui->check_restarts->setChecked(true);
1705//                    Check if _pdf file is available, otherwise notice user
1706                      QString jobname = ui->line_jobname->text();
1707                      branch = QCoreApplication::applicationDirPath();
1708                      branch = branch.left(branch.length() - 14);
1709
1710                      QFile restartfile(branch+"/JOBS/"+jobname+"/INPUT/"+ \
1711                                        jobname+"_p3df");
1712                      if (restartfile.exists() == true)
1713                      {
1714                         ui->label_restart->setText("");
1715                      }
1716                      else
1717                      {
1718                         ui->label_restart->setText("Warning: No p3df file \
1719                                                    found!");
1720                      }
1721                   }
1722
1723               }
1724
1725            }
1726
1727//          All unknown parameters are set as extra user parameters
1728            else
1729            {
1730                user = user + "-" + parameter + " \"" + options + "\" ";
1731                splitline.removeAt(i);
1732            }
1733        }
1734
1735//      Change drop box state in case of ocean precursor or coupled restart runs
1736        if ( ocean_run == true )
1737        {
1738           if ( coupled_run == true )
1739           {
1740             ui->drop_job->setCurrentIndex(4);
1741           }
1742           else
1743           {
1744              ui->drop_job->setCurrentIndex(3);
1745           }
1746        }
1747
1748        if ( user != "")
1749        {
1750           ui->line_user->setText(user);
1751        }
1752
1753//      Join mrunline and post it to mainwindow
1754        mrunline = splitline.join(" -");
1755        ui->commandline->setText(mrunline);
1756
1757//      Check if advanced settings are used and enable advanced dialog
1758        if ( advanced == true )
1759        {
1760           ui->check_advanced->setChecked(true);
1761        }
1762
1763//      Disable mainwindow if no job was found, otherwise enable
1764        if ( nojob == true )
1765        {
1766           ui->group_execution->setEnabled(false);
1767           ui->group_runcontrol->setEnabled(false);
1768           ui->button_start->setEnabled(false);
1769           ui->action_save->setEnabled(false);
1770           ui->drop_job->setEnabled(false);
1771           ui->group_advanced->setEnabled(false);
1772           ui->check_advanced->setEnabled(false);
1773        }
1774        else
1775        {
1776           ui->group_execution->setEnabled(true);
1777           ui->group_runcontrol->setEnabled(true);
1778           ui->button_start->setEnabled(true);
1779           ui->action_save->setEnabled(true);
1780           ui->check_advanced->setEnabled(true);
1781           ui->drop_job->setEnabled(true);
1782           if ( advanced == true )
1783           {
1784              ui->group_advanced->setEnabled(true);
1785           }
1786           else
1787           {
1788              ui->group_advanced->setEnabled(false);
1789           }
1790        }
1791
1792//      Disable run control box, if manual settings of -i and -o are used
1793        if ( rc_manual == true )
1794        {
1795           ui->group_runcontrol->setEnabled(false);
1796           change_commandline("r","remove");
1797           ui->button_start->setEnabled(true);
1798           ui->action_save->setEnabled(true);
1799        }
1800
1801    }
1802
1803    return 0;
1804}
Note: See TracBrowser for help on using the repository browser.