492912b10e41b3f7ce3da5e3dff705e70d353577
[platform/upstream/doxygen.git] / addon / doxywizard / doxywizard.cpp
1 #include "doxywizard.h"
2 #include "version.h"
3 #include "expert.h"
4 #include "wizard.h"
5
6 #include <QMenu>
7 #include <QMenuBar>
8 #include <QPushButton>
9 #include <QMessageBox>
10 #include <QVBoxLayout>
11 #include <QLineEdit>
12 #include <QLabel>
13 #include <QTextBrowser>
14 #include <QStatusBar>
15 #include <QProcess>
16 #include <QTimer>
17 #include <QCloseEvent>
18 #include <QApplication>
19 #include <QDir>
20 #include <QFileDialog>
21 #include <QDesktopServices>
22 #include <QUrl>
23 #include <QTextStream>
24 #include <QDebug>
25
26 #ifdef WIN32
27 #include <windows.h>
28 #endif
29
30 #define MAX_RECENT_FILES 10
31
32 const int messageTimeout = 5000; //!< status bar message timeout in milliseconds.
33
34 #define APPQT(x) QString::fromLatin1("<qt><pre>") + x + QString::fromLatin1("</pre></qt>")
35
36 static QString text1  = QString::fromLatin1("");
37
38 MainWindow &MainWindow::instance()
39 {
40   static MainWindow *theInstance = new MainWindow;
41   return *theInstance;
42 }
43
44 MainWindow::MainWindow()
45   : m_settings(QString::fromLatin1("Doxygen.org"), QString::fromLatin1("Doxywizard"))
46 {
47   QMenu *file = menuBar()->addMenu(tr("File"));
48   file->addAction(tr("Open..."), 
49                   this, SLOT(openConfig()), Qt::CTRL+Qt::Key_O);
50   m_recentMenu = file->addMenu(tr("Open recent"));
51   file->addAction(tr("Save"), 
52                   this, SLOT(saveConfig()), Qt::CTRL+Qt::Key_S);
53   file->addAction(tr("Save as..."), 
54                   this, SLOT(saveConfigAs()), Qt::SHIFT+Qt::CTRL+Qt::Key_S);
55   file->addAction(tr("Quit"),  
56                   this, SLOT(quit()), Qt::CTRL+Qt::Key_Q);
57
58   QMenu *settings = menuBar()->addMenu(tr("Settings"));
59   settings->addAction(tr("Reset to factory defaults"),
60                   this,SLOT(resetToDefaults()));
61   settings->addAction(tr("Use current settings at startup"),
62                   this,SLOT(makeDefaults()));
63   settings->addAction(tr("Clear recent list"),
64                   this,SLOT(clearRecent()));
65
66   QMenu *help = menuBar()->addMenu(tr("Help"));
67   help->addAction(tr("Online manual"), 
68                   this, SLOT(manual()), Qt::Key_F1);
69   help->addAction(tr("About"), 
70                   this, SLOT(about()) );
71
72   m_expert = new Expert;
73   m_wizard = new Wizard(m_expert->modelData());
74
75   // ----------- top part ------------------
76   QWidget *topPart = new QWidget;
77   QVBoxLayout *rowLayout = new QVBoxLayout(topPart);
78
79   // select working directory
80   QHBoxLayout *dirLayout = new QHBoxLayout;
81   m_workingDir = new QLineEdit;
82   m_selWorkingDir = new QPushButton(tr("Select..."));
83   dirLayout->addWidget(m_workingDir);
84   dirLayout->addWidget(m_selWorkingDir);
85
86   //------------- bottom part --------------
87   QWidget *runTab = new QWidget;
88   QVBoxLayout *runTabLayout = new QVBoxLayout(runTab);
89
90   // run doxygen
91   QHBoxLayout *runLayout = new QHBoxLayout;
92   m_run = new QPushButton(tr("Run doxygen"));
93   m_run->setEnabled(false);
94   m_runStatus = new QLabel(tr("Status: not running"));
95   m_saveLog = new QPushButton(tr("Save log..."));
96   m_saveLog->setEnabled(false);
97   QPushButton *showSettings = new QPushButton(tr("Show configuration"));
98   runLayout->addWidget(m_run);
99   runLayout->addWidget(m_runStatus);
100   runLayout->addStretch(1);
101   runLayout->addWidget(showSettings);
102   runLayout->addWidget(m_saveLog);
103
104   // output produced by Doxygen
105   runTabLayout->addLayout(runLayout);
106   runTabLayout->addWidget(new QLabel(tr("Output produced by doxygen")));
107   QGridLayout *grid = new QGridLayout;
108   //m_outputLog = new QTextEdit;
109   m_outputLog = new QTextBrowser;
110   //m_outputLog = new QPlainTextEdit;
111   m_outputLog->setReadOnly(true);
112   m_outputLog->setFontFamily(QString::fromLatin1("courier"));
113   m_outputLog->setMinimumWidth(600);
114   grid->addWidget(m_outputLog,0,0);
115   grid->setColumnStretch(0,1);
116   grid->setRowStretch(0,1);
117   QHBoxLayout *launchLayout = new QHBoxLayout;
118   m_launchHtml = new QPushButton(tr("Show HTML output"));
119   launchLayout->addWidget(m_launchHtml);
120
121   launchLayout->addStretch(1);
122   grid->addLayout(launchLayout,1,0);
123   runTabLayout->addLayout(grid);
124
125   m_tabs = new QTabWidget;
126   m_tabs->addTab(m_wizard,tr("Wizard"));
127   m_tabs->addTab(m_expert,tr("Expert"));
128   m_tabs->addTab(runTab,tr("Run"));
129
130   rowLayout->addWidget(new QLabel(tr("Step 1: Specify the working directory from which doxygen will run")));
131   rowLayout->addLayout(dirLayout);
132   rowLayout->addWidget(new QLabel(tr("Step 2: Configure doxygen using the Wizard and/or Expert tab, then switch to the Run tab to generate the documentation")));
133   rowLayout->addWidget(m_tabs);
134
135   setCentralWidget(topPart);
136   statusBar()->showMessage(tr("Welcome to Doxygen"),messageTimeout);
137
138   m_runProcess = new QProcess;
139   m_running = false;
140   m_timer = new QTimer;
141
142   // connect signals and slots
143   connect(m_tabs,SIGNAL(currentChanged(int)),SLOT(selectTab(int)));
144   connect(m_selWorkingDir,SIGNAL(clicked()),SLOT(selectWorkingDir()));
145   connect(m_recentMenu,SIGNAL(triggered(QAction*)),SLOT(openRecent(QAction*)));
146   connect(m_workingDir,SIGNAL(returnPressed()),SLOT(updateWorkingDir()));
147   connect(m_runProcess,SIGNAL(readyReadStandardOutput()),SLOT(readStdout()));
148   connect(m_runProcess,SIGNAL(finished(int, QProcess::ExitStatus)),SLOT(runComplete()));
149   connect(m_timer,SIGNAL(timeout()),SLOT(readStdout()));
150   connect(m_run,SIGNAL(clicked()),SLOT(runDoxygen()));
151   connect(m_launchHtml,SIGNAL(clicked()),SLOT(showHtmlOutput()));
152   connect(m_saveLog,SIGNAL(clicked()),SLOT(saveLog()));
153   connect(showSettings,SIGNAL(clicked()),SLOT(showSettings()));
154   connect(m_expert,SIGNAL(changed()),SLOT(configChanged()));
155   connect(m_wizard,SIGNAL(done()),SLOT(selectRunTab()));
156   connect(m_expert,SIGNAL(done()),SLOT(selectRunTab()));
157
158   loadSettings();
159   updateLaunchButtonState();
160   m_modified = false;
161   updateTitle();
162   m_wizard->refresh();
163 }
164
165 void MainWindow::closeEvent(QCloseEvent *event)
166 {
167   if (discardUnsavedChanges())
168   {
169     saveSettings();
170     event->accept();
171   }
172   else
173   {
174     event->ignore();
175   }
176 }
177
178 void MainWindow::quit()
179 {
180   if (discardUnsavedChanges())
181   {
182     saveSettings();
183   }
184   QApplication::exit(0);
185 }
186
187 void MainWindow::setWorkingDir(const QString &dirName)
188 {
189     QDir::setCurrent(dirName);
190     m_workingDir->setText(dirName);
191     m_run->setEnabled(!dirName.isEmpty());
192 }
193
194 void MainWindow::selectWorkingDir()
195 {
196   QString dirName = QFileDialog::getExistingDirectory(this,
197         tr("Select working directory"),m_workingDir->text());
198   if (!dirName.isEmpty())
199   {
200     setWorkingDir(dirName);
201   }
202 }
203
204 void MainWindow::updateWorkingDir()
205 {
206   setWorkingDir(m_workingDir->text());
207 }
208
209 void MainWindow::manual()
210 {
211   QDesktopServices::openUrl(QUrl(QString::fromLatin1("http://www.doxygen.org/manual.html")));
212 }
213
214 void MainWindow::about()
215 {
216   QString msg;
217   QTextStream t(&msg,QIODevice::WriteOnly);
218   t << QString::fromLatin1("<qt><center>A tool to configure and run doxygen version ")+
219        QString::fromLatin1(versionString)+
220        QString::fromLatin1(" on your source files.</center><p><br>"
221        "<center>Written by<br> Dimitri van Heesch<br>&copy; 2000-2015</center><p>"
222        "</qt>");
223   QMessageBox::about(this,tr("Doxygen GUI"),msg);
224 }
225
226 void MainWindow::openConfig()
227 {
228   if (discardUnsavedChanges(false))
229   {
230     QString fn = QFileDialog::getOpenFileName(this,
231         tr("Open configuration file"),
232         m_workingDir->text());
233     if (!fn.isEmpty())
234     {
235       loadConfigFromFile(fn);
236     }
237   }
238 }
239
240 void MainWindow::updateConfigFileName(const QString &fileName)
241 {
242   if (m_fileName!=fileName)
243   {
244     m_fileName = fileName;
245     QString curPath = QFileInfo(fileName).path();
246     setWorkingDir(curPath);
247     addRecentFile(fileName);
248     updateTitle();
249   }
250 }
251
252 void MainWindow::loadConfigFromFile(const QString & fileName)
253 {
254   // save full path info of original file
255   QString absFileName = QFileInfo(fileName).absoluteFilePath();
256   // updates the current directory
257   updateConfigFileName(fileName);
258   // open the specified configuration file
259   m_expert->loadConfig(absFileName);
260   m_wizard->refresh();
261   updateLaunchButtonState();
262   m_modified = false;
263   updateTitle();
264 }
265
266 void MainWindow::saveConfig(const QString &fileName)
267 {
268   if (fileName.isEmpty()) return;
269   QFile f(fileName);
270   if (!f.open(QIODevice::WriteOnly)) 
271   {
272     QMessageBox::warning(this,
273         tr("Error saving"),
274         tr("Error: cannot open the file ")+fileName+tr(" for writing!\n")+
275         tr("Reason given: ")+f.error());
276     return;
277   }
278   QTextStream t(&f);
279   m_expert->writeConfig(t,false);
280   updateConfigFileName(fileName);
281   m_modified = false;
282   updateTitle();
283 }
284
285 bool MainWindow::saveConfig()
286 {
287   if (m_fileName.isEmpty())
288   {
289     return saveConfigAs();
290   }
291   else
292   {
293     saveConfig(m_fileName);
294     return true;
295   }
296 }
297
298 bool MainWindow::saveConfigAs()
299 {
300   QString fileName = QFileDialog::getSaveFileName(this, QString(), 
301              m_workingDir->text()+QString::fromLatin1("/Doxyfile"));
302   if (fileName.isEmpty()) return false;
303   saveConfig(fileName);
304   return true;
305 }
306
307 void MainWindow::makeDefaults()
308 {
309   if (QMessageBox::question(this,tr("Use current setting at startup?"),
310                         tr("Do you want to save the current settings "
311                            "and use them next time Doxywizard starts?"),
312                         QMessageBox::Save|
313                         QMessageBox::Cancel)==QMessageBox::Save)
314   {
315     //printf("MainWindow:makeDefaults()\n");
316     m_expert->saveSettings(&m_settings);
317     m_settings.setValue(QString::fromLatin1("wizard/loadsettings"), true);
318     m_settings.sync();
319   }
320 }
321
322 void MainWindow::clearRecent()
323 {
324   if (QMessageBox::question(this,tr("Clear the list of recent files?"),
325                         tr("Do you want to clear the list of recently "
326                            "loaded configuration files?"),
327                         QMessageBox::Yes|
328                         QMessageBox::Cancel)==QMessageBox::Yes)
329   {
330     m_recentMenu->clear();
331     m_recentFiles.clear();
332     for (int i=0;i<MAX_RECENT_FILES;i++)
333     {
334       m_settings.setValue(QString().sprintf("recent/config%d",i++),QString::fromLatin1(""));
335     }
336     m_settings.sync();
337   }
338   
339 }
340
341 void MainWindow::resetToDefaults()
342 {
343   if (QMessageBox::question(this,tr("Reset settings to their default values?"),
344                         tr("Do you want to revert all settings back "
345                            "to their original values?"),
346                         QMessageBox::Reset|
347                         QMessageBox::Cancel)==QMessageBox::Reset)
348   {
349     //printf("MainWindow:resetToDefaults()\n");
350     m_expert->resetToDefaults();
351     m_settings.setValue(QString::fromLatin1("wizard/loadsettings"), false);
352     m_settings.sync();
353     m_wizard->refresh();
354   }
355 }
356
357 void MainWindow::loadSettings()
358 {
359   QVariant geometry     = m_settings.value(QString::fromLatin1("main/geometry"), QVariant::Invalid);
360   QVariant state        = m_settings.value(QString::fromLatin1("main/state"),    QVariant::Invalid);
361   QVariant wizState     = m_settings.value(QString::fromLatin1("wizard/state"),  QVariant::Invalid);
362   QVariant loadSettings = m_settings.value(QString::fromLatin1("wizard/loadsettings"),  QVariant::Invalid);
363   QVariant workingDir   = m_settings.value(QString::fromLatin1("wizard/workingdir"), QVariant::Invalid);
364
365   if (geometry  !=QVariant::Invalid) restoreGeometry(geometry.toByteArray());
366   if (state     !=QVariant::Invalid) restoreState   (state.toByteArray());
367   if (wizState  !=QVariant::Invalid) m_wizard->restoreState(wizState.toByteArray());
368   if (loadSettings!=QVariant::Invalid && loadSettings.toBool())
369   {
370     m_expert->loadSettings(&m_settings);
371     if (workingDir!=QVariant::Invalid && QDir(workingDir.toString()).exists())
372     {
373       setWorkingDir(workingDir.toString());
374     }
375   }
376
377   /* due to prepend use list in reversed order */
378   for (int i=MAX_RECENT_FILES;i>=0;i--)
379   {
380     QString entry = m_settings.value(QString().sprintf("recent/config%d",i)).toString();
381     if (!entry.isEmpty() && QFileInfo(entry).exists())
382     {
383       addRecentFileList(entry);
384     }
385   }
386   updateRecentFile();
387
388 }
389
390 void MainWindow::saveSettings()
391 {
392   QSettings settings(QString::fromLatin1("Doxygen.org"), QString::fromLatin1("Doxywizard"));
393
394   m_settings.setValue(QString::fromLatin1("main/geometry"), saveGeometry());
395   m_settings.setValue(QString::fromLatin1("main/state"),    saveState());
396   m_settings.setValue(QString::fromLatin1("wizard/state"),  m_wizard->saveState());
397   m_settings.setValue(QString::fromLatin1("wizard/workingdir"), m_workingDir->text());
398 }
399
400 void MainWindow::selectTab(int id)
401 {
402   if (id==0) m_wizard->refresh();
403   else if (id==1) m_expert->refresh();
404 }
405
406 void MainWindow::selectRunTab()
407 {
408   m_tabs->setCurrentIndex(2);
409 }
410
411 void MainWindow::addRecentFile(const QString &fileName)
412 {
413   addRecentFileList(fileName);
414   updateRecentFile();
415 }
416 void MainWindow::addRecentFileList(const QString &fileName)
417 {
418   int i=m_recentFiles.indexOf(fileName);
419   if (i!=-1) m_recentFiles.removeAt(i);
420   
421   // not found
422   if (m_recentFiles.count() < MAX_RECENT_FILES) // append
423   {
424     m_recentFiles.prepend(fileName);
425   }
426   else // add + drop last item
427   {
428     m_recentFiles.removeLast();
429     m_recentFiles.prepend(fileName);
430   }
431 }
432 void MainWindow::updateRecentFile(void)
433 {
434   m_recentMenu->clear();
435   int i=0;
436   foreach( QString str, m_recentFiles ) 
437   {
438     m_recentMenu->addAction(str);
439     m_settings.setValue(QString().sprintf("recent/config%d",i++),str);
440   }
441   for (;i<MAX_RECENT_FILES;i++)
442   {
443     m_settings.setValue(QString().sprintf("recent/config%d",i++),QString::fromLatin1(""));
444   }
445 }
446
447 void MainWindow::openRecent(QAction *action)
448 {
449   if (discardUnsavedChanges(false))
450   {
451     loadConfigFromFile(action->text());
452   }
453 }
454
455 void MainWindow::runDoxygen()
456 {
457   if (!m_running)
458   {
459     QString doxygenPath; 
460 #if defined(Q_OS_MACX)
461     doxygenPath = qApp->applicationDirPath()+QString::fromLatin1("/../Resources/");
462     qDebug() << tr("Doxygen path: ") << doxygenPath;
463     if ( !QFile(doxygenPath + QString::fromLatin1("doxygen")).exists() ) 
464     {
465       // No Doxygen binary in the resources, if there is a system Doxygen binary, use that instead
466       if ( QFile(QString::fromLatin1("/usr/local/bin/doxygen")).exists() )
467       {
468         doxygenPath = QString::fromLatin1("/usr/local/bin/");
469       }
470       else 
471       {
472         qDebug() << tr("Can't find the doxygen command, make sure it's in your $$PATH");
473         doxygenPath = QString::fromLatin1("");
474       }
475     }
476     qDebug() << tr("Getting doxygen from: ") << doxygenPath;
477 #endif
478
479     m_runProcess->setReadChannel(QProcess::StandardOutput);
480     m_runProcess->setProcessChannelMode(QProcess::MergedChannels);
481     m_runProcess->setWorkingDirectory(m_workingDir->text());
482     QStringList env=QProcess::systemEnvironment();
483     // set PWD environment variable to m_workingDir
484     env.replaceInStrings(QRegExp(QString::fromLatin1("^PWD=(.*)"),Qt::CaseInsensitive), 
485                          QString::fromLatin1("PWD=")+m_workingDir->text());
486     m_runProcess->setEnvironment(env);
487
488     QStringList args;
489     args << QString::fromLatin1("-b"); // make stdout unbuffered
490     args << QString::fromLatin1("-");  // read config from stdin
491
492     m_outputLog->clear();
493     text1  = QString::fromLatin1("");
494     m_runProcess->start(doxygenPath + QString::fromLatin1("doxygen"), args);
495
496     if (!m_runProcess->waitForStarted())
497     {
498       m_outputLog->append(APPQT(QString::fromLatin1("*** Failed to run doxygen\n")));
499       return;
500     }
501     QTextStream t(m_runProcess);
502     m_expert->writeConfig(t,false);
503     m_runProcess->closeWriteChannel();
504
505     if (m_runProcess->state() == QProcess::NotRunning)
506     {
507       m_outputLog->append(APPQT(QString::fromLatin1("*** Failed to run doxygen\n")));
508     }
509     else
510     {
511       m_saveLog->setEnabled(false);
512       m_running=true;
513       m_run->setText(tr("Stop doxygen"));
514       m_runStatus->setText(tr("Status: running"));
515       m_timer->start(1000);
516     }
517   }
518   else
519   {
520     m_running=false;
521     m_run->setText(tr("Run doxygen"));
522     m_runStatus->setText(tr("Status: not running"));
523     m_runProcess->kill();
524     m_timer->stop();
525     //updateRunnable(m_workingDir->text());
526   }
527 }
528
529 void MainWindow::readStdout()
530 {
531   if (m_running)
532   {
533     QByteArray data = m_runProcess->readAllStandardOutput();
534     QString text = QString::fromUtf8(data);
535     if (!text.isEmpty())
536     {
537       text1 += text;
538       m_outputLog->clear();
539       m_outputLog->append(APPQT(text1.trimmed()));
540     }
541   }
542 }
543
544 void MainWindow::runComplete()
545 {
546   if (m_running)
547   {
548     m_outputLog->append(APPQT(tr("*** Doxygen has finished\n")));
549   }
550   else
551   {
552     m_outputLog->append(APPQT(tr("*** Cancelled by user\n")));
553   }
554   m_outputLog->ensureCursorVisible();
555   m_run->setText(tr("Run doxygen"));
556   m_runStatus->setText(tr("Status: not running"));
557   m_running=false;
558   updateLaunchButtonState();
559   //updateRunnable(m_workingDir->text());
560   m_saveLog->setEnabled(true);
561 }
562
563 void MainWindow::updateLaunchButtonState()
564 {
565   m_launchHtml->setEnabled(m_expert->htmlOutputPresent(m_workingDir->text()));
566 #if 0
567   m_launchPdf->setEnabled(m_expert->pdfOutputPresent(m_workingDir->text()));
568 #endif
569 }
570
571 void MainWindow::showHtmlOutput()
572 {
573   QString indexFile = m_expert->getHtmlOutputIndex(m_workingDir->text());
574   QFileInfo fi(indexFile);
575   // TODO: the following doesn't seem to work with IE
576 #ifdef WIN32
577   //QString indexUrl(QString::fromLatin1("file:///"));
578   ShellExecute(NULL, L"open", (LPCWSTR)fi.absoluteFilePath().utf16(), NULL, NULL, SW_SHOWNORMAL);
579 #else
580   QString indexUrl(QString::fromLatin1("file://"));
581   indexUrl+=fi.absoluteFilePath();
582   QDesktopServices::openUrl(QUrl(indexUrl));
583 #endif
584 }
585
586 void MainWindow::saveLog()
587 {
588   QString fn = QFileDialog::getSaveFileName(this, tr("Save log file"), 
589         m_workingDir->text()+
590         QString::fromLatin1("/doxygen_log.txt"));
591   if (!fn.isEmpty())
592   {
593     QFile f(fn);
594     if (f.open(QIODevice::WriteOnly))
595     {
596       QTextStream t(&f);
597       t << m_outputLog->toPlainText();
598       statusBar()->showMessage(tr("Output log saved"),messageTimeout);
599     }
600     else
601     {
602       QMessageBox::warning(0,tr("Warning"),
603           tr("Cannot open file ")+fn+tr(" for writing. Nothing saved!"),tr("ok"));
604     }
605   }
606 }
607
608 void MainWindow::showSettings()
609 {
610   QString text;
611   QTextStream t(&text);
612   m_expert->writeConfig(t,true);
613   m_outputLog->clear();
614   m_outputLog->append(APPQT(text));
615   m_outputLog->ensureCursorVisible();
616   m_saveLog->setEnabled(true);
617 }
618
619 void MainWindow::configChanged()
620 {
621   m_modified = true;
622   updateTitle();
623 }
624
625 void MainWindow::updateTitle()
626 {
627   QString title = tr("Doxygen GUI frontend");
628   if (m_modified)
629   {
630     title+=QString::fromLatin1(" +");
631   }
632   if (!m_fileName.isEmpty())
633   {
634     title+=QString::fromLatin1(" (")+m_fileName+QString::fromLatin1(")");
635   }
636   setWindowTitle(title);
637 }
638
639 bool MainWindow::discardUnsavedChanges(bool saveOption)
640 {
641   if (m_modified)
642   {
643     QMessageBox::StandardButton button;
644     if (saveOption)
645     {
646       button = QMessageBox::question(this,
647           tr("Unsaved changes"),
648           tr("Unsaved changes will be lost! Do you want to save the configuration file?"),
649           QMessageBox::Save    |
650           QMessageBox::Discard |
651           QMessageBox::Cancel
652           );
653       if (button==QMessageBox::Save)
654       {
655         return saveConfig();
656       }
657     }
658     else
659     {
660       button = QMessageBox::question(this,
661           tr("Unsaved changes"),
662           tr("Unsaved changes will be lost! Do you want to continue?"),
663           QMessageBox::Discard |
664           QMessageBox::Cancel
665           );
666     }
667     return button==QMessageBox::Discard;
668   }
669   return true;
670 }
671
672 //-----------------------------------------------------------------------
673 int main(int argc,char **argv)
674 {
675   QApplication a(argc,argv);
676   if (argc == 2)
677   {
678     if (!qstrcmp(argv[1],"--help"))
679     {
680       QMessageBox msgBox;
681       msgBox.setText(QString().sprintf("Usage: %s [config file]",argv[0]));
682       msgBox.exec();
683       exit(0);
684     }
685   }
686   if (argc > 2)
687   {
688     QMessageBox msgBox;
689     msgBox.setText(QString().sprintf("Too many arguments specified\n\nUsage: %s [config file]",argv[0]));
690     msgBox.exec();
691     exit(1);
692   }
693   else
694   {
695     MainWindow &main = MainWindow::instance();
696     if (argc==2 && argv[1][0]!='-') // name of config file as an argument
697     {
698       main.loadConfigFromFile(QString::fromLocal8Bit(argv[1]));
699     }
700     main.show();
701     return a.exec();
702   }
703 }