Engauge Digitizer  2
main.cpp
1 /******************************************************************************************************
2  * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3  * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4  * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5  ******************************************************************************************************/
6 
7 #include "ColorFilterMode.h"
8 #include "FittingCurveCoefficients.h"
9 #include <iostream>
10 #include "Logger.h"
11 #include "MainWindow.h"
12 #include <QApplication>
13 #include <QCoreApplication>
14 #include <QDebug>
15 #include <QDir>
16 #include <QFileInfo>
17 #include <QMessageBox>
18 #include <QObject>
19 #include <QProcessEnvironment>
20 #include <QStyleFactory>
21 #include "TranslatorContainer.h"
22 #include "ZoomFactor.h"
23 
24 using namespace std;
25 
26 const QString CMD_DEBUG ("debug");
27 const QString CMD_ERROR_REPORT ("errorreport");
28 const QString CMD_EXPORT_ONLY ("exportonly");
29 const QString CMD_FILE_CMD_SCRIPT ("filecmdscript");
30 const QString CMD_GNUPLOT ("gnuplot");
31 const QString CMD_HELP ("help");
32 const QString CMD_REGRESSION ("regression");
33 const QString CMD_RESET ("reset");
34 const QString CMD_STYLES ("styles"); // Not to be confused with -style option that qt handles
35 const QString DASH ("-");
36 const QString DASH_DEBUG ("-" + CMD_DEBUG);
37 const QString DASH_ERROR_REPORT ("-" + CMD_ERROR_REPORT);
38 const QString DASH_EXPORT_ONLY ("-" + CMD_EXPORT_ONLY);
39 const QString DASH_FILE_CMD_SCRIPT ("-" + CMD_FILE_CMD_SCRIPT);
40 const QString DASH_GNUPLOT ("-" + CMD_GNUPLOT);
41 const QString DASH_HELP ("-" + CMD_HELP);
42 const QString DASH_REGRESSION ("-" + CMD_REGRESSION);
43 const QString DASH_RESET ("-" + CMD_RESET);
44 const QString DASH_STYLES ("-" + CMD_STYLES);
45 const QString ENGAUGE_LOG_FILE (".engauge.log");
46 
47 // Prototypes
48 bool checkFileExists (const QString &file);
49 QString engaugeLogFilename ();
50 bool engaugeLogFilenameAttempt (const QString &path,
51  QString &pathAndFile);
52 void parseCmdLine (int argc,
53  char **argv,
54  bool &isDebug,
55  bool &isReset,
56  QString &errorReportFile,
57  QString &fileCmdScriptFile,
58  bool &isErrorReportRegressionTest,
59  bool &isGnuplot,
60  bool &isExportOnly,
61  QStringList &loadStartupFiles);
62 void showStylesAndExit ();
63 
64 // Functions
65 bool checkFileExists (const QString &file)
66 {
67  QFileInfo check (file);
68  return check.exists() && check.isFile();
69 }
70 
71 QString engaugeLogFilename()
72 {
73  QString pathAndFile; // Return empty value in OSX which is unused
74 
75 #if !defined(OSX_RELEASE) && !defined(WIN_RELEASE) && !defined(APPIMAGE_RELEASE)
76  QProcessEnvironment env;
77 
78  // Make multiple attempts until a directory is found where the log file can be written
79  if (!engaugeLogFilenameAttempt (QCoreApplication::applicationDirPath(), pathAndFile)) {
80  if (!engaugeLogFilenameAttempt (env.value ("HOME"), pathAndFile)) {
81  if (!engaugeLogFilenameAttempt (env.value ("TEMP"), pathAndFile)) {
82  pathAndFile = ENGAUGE_LOG_FILE; // Current directory will have to do
83  }
84  }
85  }
86 #endif
87 
88  return pathAndFile;
89 }
90 
91 bool engaugeLogFilenameAttempt (const QString &path,
92  QString &pathAndFile)
93 {
94  bool success = false;
95 
96  // Test if file can be opened. Checking permissions on directory is unreliable in Windows/OSX
97  pathAndFile = QString ("%1%2%3")
98  .arg (path)
99  .arg (QDir::separator())
100  .arg (ENGAUGE_LOG_FILE);
101  QFile file (pathAndFile);
102  if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
103  // Success
104  file.close();
105  file.remove(); // Cleanup
106  success = true;
107  }
108 
109  return success;
110 }
111 
112 int main(int argc, char *argv[])
113 {
114  qRegisterMetaType<ColorFilterMode> ("ColorFilterMode");
115  qRegisterMetaType<FittingCurveCoefficients> ("FilterCurveCoefficients");
116  qRegisterMetaType<ZoomFactor> ("ZoomFactor");
117 
118  QApplication app(argc, argv);
119 
120  // Translations
121  TranslatorContainer translatorContainer (app); // Must exist until execution terminates
122 
123  // Command line
124  bool isDebug, isReset, isGnuplot, isErrorReportRegressionTest, isExportOnly;
125  QString errorReportFile, fileCmdScriptFile;
126  QStringList loadStartupFiles;
127  parseCmdLine (argc,
128  argv,
129  isDebug,
130  isReset,
131  errorReportFile,
132  fileCmdScriptFile,
133  isErrorReportRegressionTest,
134  isGnuplot,
135  isExportOnly,
136  loadStartupFiles);
137 
138  // Logging
139  initializeLogging ("engauge",
140  engaugeLogFilename(),
141  isDebug);
142  LOG4CPP_INFO_S ((*mainCat)) << "main args=" << QApplication::arguments().join (" ").toLatin1().data();
143 
144  // Create and show main window
145  MainWindow w (errorReportFile,
146  fileCmdScriptFile,
147  isErrorReportRegressionTest,
148  isGnuplot,
149  isReset,
150  isExportOnly,
151  loadStartupFiles);
152  w.show();
153 
154  // Event loop
155  return app.exec();
156 }
157 
158 void parseCmdLine (int argc,
159  char **argv,
160  bool &isDebug,
161  bool &isReset,
162  QString &errorReportFile,
163  QString &fileCmdScriptFile,
164  bool &isErrorReportRegressionTest,
165  bool &isGnuplot,
166  bool &isExportOnly,
167  QStringList &loadStartupFiles)
168 {
169  bool showUsage = false;
170 
171  // State
172  bool nextIsErrorReportFile = false;
173  bool nextIsFileCmdScript = false;
174 
175  // Defaults
176  isDebug = false;
177  isReset = false;
178  errorReportFile = "";
179  fileCmdScriptFile = "";
180  isErrorReportRegressionTest = false;
181  isGnuplot = false;
182  isExportOnly = false;
183 
184  for (int i = 1; i < argc; i++) {
185 
186  if (nextIsErrorReportFile) {
187  errorReportFile = argv [i];
188  showUsage |= !checkFileExists (errorReportFile);
189  nextIsErrorReportFile = false;
190  } else if (nextIsFileCmdScript) {
191  fileCmdScriptFile = argv [i];
192  showUsage |= !checkFileExists (fileCmdScriptFile);
193  nextIsFileCmdScript = false;
194  } else if (strcmp (argv [i], DASH_DEBUG.toLatin1().data()) == 0) {
195  isDebug = true;
196  } else if (strcmp (argv [i], DASH_ERROR_REPORT.toLatin1().data()) == 0) {
197  nextIsErrorReportFile = true;
198  } else if (strcmp (argv [i], DASH_EXPORT_ONLY.toLatin1().data()) == 0) {
199  isExportOnly = true;
200  } else if (strcmp (argv [i], DASH_FILE_CMD_SCRIPT.toLatin1().data()) == 0) {
201  nextIsFileCmdScript = true;
202  } else if (strcmp (argv [i], DASH_GNUPLOT.toLatin1().data()) == 0) {
203  isGnuplot = true;
204  } else if (strcmp (argv [i], DASH_HELP.toLatin1().data()) == 0) {
205  showUsage = true; // User requested help
206  } else if (strcmp (argv [i], DASH_REGRESSION.toLatin1().data()) == 0) {
207  isErrorReportRegressionTest = true;
208  } else if (strcmp (argv [i], DASH_RESET.toLatin1().data()) == 0) {
209  isReset = true;
210  } else if (strcmp (argv [i], DASH_STYLES.toLatin1().data()) == 0) {
211  showStylesAndExit ();
212  } else if (strncmp (argv [i], DASH.toLatin1().data(), 1) == 0) {
213  showUsage = true; // User entered an unrecognized token
214  } else {
215  // MainWindow will change current directory (which is often some obscure application directory),
216  // so relative paths must be changed in advance to absolute so the files can still be found
217  QString fileName = argv [i];
218  QFileInfo fInfo (fileName);
219  if (fInfo.isRelative()) {
220  fileName = fInfo.absoluteFilePath();
221  }
222  loadStartupFiles << fileName; // Save file name
223  }
224  }
225 
226  // Sanity checks
227  if (isExportOnly && (!errorReportFile.isEmpty() ||
228  !fileCmdScriptFile.isEmpty() ||
229  loadStartupFiles.size() != 1)) {
230  QString msg;
231  QTextStream str (&msg);
232  str << DASH_EXPORT_ONLY.toLatin1().data() << " " << QObject::tr (" is used only with one document file specified");
233  QMessageBox::critical (0,
234  QObject::tr ("Engauge Digitizer"),
235  msg);
236  exit (0);
237  }
238 
239  // Usage
240  if (showUsage || nextIsErrorReportFile) {
241 
242  QString msg;
243  QTextStream str (&msg);
244  str << "<html>Usage: engauge "
245  << "[" << DASH_DEBUG.toLatin1().data() << "] "
246  << "[" << DASH_ERROR_REPORT.toLatin1().data() << " <file>] "
247  << "[" << DASH_EXPORT_ONLY.toLatin1().data() << "] "
248  << "[" << DASH_FILE_CMD_SCRIPT.toLatin1().data() << " <file> "
249  << "[" << DASH_GNUPLOT.toLatin1().data() << "] "
250  << "[" << DASH_HELP.toLatin1().data() << "] "
251  << "[" << DASH_REGRESSION.toLatin1().data() << "] "
252  << "[" << DASH_RESET.toLatin1().data () << "] "
253  << "[" << DASH_STYLES.toLatin1().data () << "] "
254  << "[&lt;load_file1&gt;] [&lt;load_file2&gt;] ..." << endl
255  << "<table>"
256  << "<tr>"
257  << "<td>" << DASH_DEBUG.toLatin1().data() << "</td>"
258  << "<td>" << QObject::tr ("Enables extra debug information. Used for debugging").toLatin1().data() << "</td>"
259  << "</tr>"
260  << "<tr>"
261  << "<td>" << DASH_ERROR_REPORT.toLatin1().data() << "</td>"
262  << "<td>" << QObject::tr ("Specifies an error report file as input. Used for debugging and testing").toLatin1().data() << "</td>"
263  << "</tr>"
264  << "<tr>"
265  << "<td>" << DASH_EXPORT_ONLY.toLatin1().data() << "</td>"
266  << "<td>" << QObject::tr ("Export the loaded startup file, which must have all axis points defined, then stop").toLatin1().data() << "</td>"
267  << "</tr>"
268  << "<tr>"
269  << "<td>" << DASH_FILE_CMD_SCRIPT.toLatin1().data() << "</td>"
270  << "<td>" << QObject::tr ("Specifies a file command script file as input. Used for debugging and testing").toLatin1().data() << "</td>"
271  << "</tr>"
272  << "<tr>"
273  << "<td>" << DASH_GNUPLOT.toLatin1().data() << "</td>"
274  << "<td>" << QObject::tr ("Output diagnostic gnuplot input files. Used for debugging").toLatin1().data() << "</td>"
275  << "</tr>"
276  << "<tr>"
277  << "<td>" << DASH_HELP.toLatin1().data() << "</td>"
278  << "<td>" << QObject::tr ("Show this help information").toLatin1().data() << "</td>"
279  << "</tr>"
280  << "<tr>"
281  << "<td>" << DASH_REGRESSION.toLatin1().data() << "</td>"
282  << "<td>" << QObject::tr ("Executes the error report file or file command script. Used for regression testing").toLatin1().data() << "</td>"
283  << "</tr>"
284  << "<tr>"
285  << "<td>" << DASH_RESET.toLatin1().data() << "</td>"
286  << "<td>" << QObject::tr ("Removes all stored settings, including window positions. Used when windows start up offscreen").toLatin1().data() << "</td>"
287  << "</tr>"
288  << "<tr>"
289  << "<td>" << DASH_STYLES.toLatin1().data() << "</td>"
290  << "<td>" << QObject::tr ("Show a list of available styles that can be used with the -style command").toLatin1().data() << "</td>"
291  << "</tr>"
292  << "<tr>"
293  << "<td>" << QString ("&lt;load file&gt; ").toLatin1().data() << "</td>"
294  << "<td>" << QObject::tr ("File(s) to be imported or opened at startup").toLatin1().data() << "</td>"
295  << "</tr>"
296  << "</table></html>";
297 
298  // Show error in QMessageBox instead of cerr since console output is disabled in Microsoft Windows
299  QMessageBox::critical (0,
300  QObject::tr ("Engauge Digitizer"),
301  msg);
302  exit (0);
303  }
304 }
305 
306 void showStylesAndExit ()
307 {
308  cout << "Available styles: " << QStyleFactory::keys ().join (", ").toLatin1().data() << endl;
309  exit (0);
310 }
Class that stores QTranslator objects for the duration of application execution.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:89