1 /***************************************************************************
2  *   Copyright (C) 2008 by Alexey Balakin                                  *
3  *   mathgl.abalakin@gmail.com                                             *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #ifdef WIN32
21 #include <io.h>
22 #include <direct.h>
23 #else
24 #include <unistd.h>
25 #endif
26 #include <QMenuBar>
27 #include <QMessageBox>
28 #include <QApplication>
29 #include <QSettings>
30 #include <QSplitter>
31 #include <QFileDialog>
32 #include <QStatusBar>
33 #include <QDockWidget>
34 #include <QCloseEvent>
35 #include <QTextCodec>
36 #include <QTranslator>
37 #include <QMimeData>
38 #include <QUrl>
39 #include <QFileInfo>
40 //-----------------------------------------------------------------------------
41 #include <mgl2/qmathgl.h>
42 #include "udav_wnd.h"
43 #include "text_pnl.h"
44 #include "plot_pnl.h"
45 #include "prop_dlg.h"
46 #include "qmglsyntax.h"
47 //-----------------------------------------------------------------------------
48 extern bool mglAutoExecute;
49 PropDialog *propDlg=0;
50 int MainWindow::num_wnd=0;
51 QStringList recentFiles;
52 int MaxRecentFiles=5;
53 bool editPosBottom = false;
54 bool mglAutoSave = false;
55 bool mglHighlight = true;
56 bool mglDotsRefr = true;
57 // bool mglAutoPure = true;
58 bool mglCompleter = true;
59 bool loadInNewWnd = false;
60 bool mglWheelZoom = false;
61 QString pathHelp;
62 extern mglParse parser;
63 extern QColor mglColorScheme[10];
64 extern QString defFontFamily;
65 extern int defFontSize;
66 extern QString pathFont;
67 extern int defWidth, defHeight;
68 //-----------------------------------------------------------------------------
69 QWidget *createCalcDlg(QWidget *p, QTextEdit *e);
70 QDialog *createArgsDlg(QWidget *p);
71 QWidget *createMemPanel(QWidget *p);
72 QWidget *createHlpPanel(QWidget *p);
73 void showHelpMGL(QWidget *hlp, QString s);
addDataPanel(QWidget * p,QWidget * w,QString name)74 void addDataPanel(QWidget *p, QWidget *w, QString name)
75 {
76 	MainWindow *wnd = dynamic_cast<MainWindow *>(p);
77 	if(wnd)	wnd->addPanel(w, name);
78 }
79 //-----------------------------------------------------------------------------
80 #ifndef UDAV_DIR
81 #ifdef WIN32
82 #define UDAV_DIR ""
83 #else
84 #define UDAV_DIR "/usr/local/share/udav/"
85 #endif
86 #endif
87 //-----------------------------------------------------------------------------
88 int mgl_cmd_cmp(const void *a, const void *b);
89 void udavLoadDefCommands();
90 void udavShowHint(QWidget *);
91 void mgl_ask_qt(const wchar_t *quest, wchar_t *res);
92 //-----------------------------------------------------------------------------
main(int argc,char ** argv)93 int main(int argc, char **argv)
94 {
95 	QString lang="";
96 	QSettings settings("udav","UDAV");
97 	settings.setPath(QSettings::IniFormat, QSettings::UserScope, "UDAV");
98 	settings.beginGroup("/UDAV");
99 	pathHelp = settings.value("/helpPath", MGL_DOC_DIR).toString();
100 	pathFont = settings.value("/userFont", "").toString();
101 	lang = settings.value("/udavLang", "").toString();
102 
103 	const char *loc="";
104 	if(lang=="en")	loc = "C.UTF8";
105 #if WIN32
106 	if(lang=="ru")	loc = "ru_RU.cp1251";
107 #else
108 	if(lang=="ru")	loc = "ru_RU.utf8";
109 #endif
110 	if(lang=="es")	{	loc = "es_ES.utf8";	lang="en";	}	// TODO remove lang="en"; then Spanish translation is ready !
111 	mgl_textdomain(argv?argv[0]:NULL,loc);
112 
113 	bool showHint = settings.value("/showHint", true).toBool();
114 	mglCompleter = settings.value("/completer",  true).toBool();
115 	settings.endGroup();
116 
117 	mgl_suppress_warn(true);
118 	QCoreApplication::setAttribute(Qt::AA_X11InitThreads);
119 #ifdef WIN32
120 	QCoreApplication::addLibraryPath("c:/plugins/");
121 	QCoreApplication::addLibraryPath(QFileInfo(QString::fromLocal8Bit(argv[0])).absolutePath().append("/plugins/"));
122 #endif
123 	mgl_ask_func = mgl_ask_qt;
124 	QApplication a(argc, argv);
125 	QTranslator translator;
126 //QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
127 #if defined(WIN32)
128 	if(pathHelp.isEmpty())	pathHelp = a.applicationDirPath()+"\\";
129 #else
130 	if(pathHelp.isEmpty())	pathHelp=MGL_DOC_DIR;
131 #endif
132 
133 	if(!lang.isEmpty())
134 	{
135 		if(!translator.load("udav_"+lang, UDAV_DIR))
136 			translator.load("udav_"+lang, pathHelp);
137 		a.installTranslator(&translator);
138 	}
139 
140 	udavLoadDefCommands();
141 	parser.AllowSetSize(true);
142 	MainWindow *mw = new MainWindow();
143 	if(argc>1)
144 	{
145 		QTextCodec *codec = QTextCodec::codecForLocale();
146 		mw->load(codec->toUnicode(argv[1]), true);
147 	}
148 	mw->show();
149 	mw->edit->edit->setFocus();
150 	a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
151 	if(showHint)	udavShowHint(mw);
152 	return a.exec();
153 }
154 //-----------------------------------------------------------------------------
155 //
156 //		mgl addon
157 //
158 //-----------------------------------------------------------------------------
udavLoadDefCommands()159 void udavLoadDefCommands()	{}	//{	udavAddCommands(udav_base_cmd);	}
160 //-----------------------------------------------------------------------------
161 //
162 //	Class MainWindow
163 //
164 //-----------------------------------------------------------------------------
MainWindow(QWidget * wp)165 MainWindow::MainWindow(QWidget *wp) : QMainWindow(wp)
166 {
167 	QAction *a;
168 	setWindowTitle(_("untitled - UDAV"));
169 	setAttribute(Qt::WA_DeleteOnClose);
170 
171 	split = new QSplitter(this);
172 	ltab = new QTabWidget(split);
173 	ltab->setMovable(true);	ltab->setTabPosition(QTabWidget::South);
174 //	ltab->setTabsClosable(true);
175 	rtab = new QTabWidget(split);
176 	rtab->setMovable(true);	rtab->setTabPosition(QTabWidget::South);
177 
178 	messWnd = new QDockWidget(_("Messages and warnings"),this);
179 	mess = new QTextEdit(this);	messWnd->setWidget(mess);
180 	messWnd->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
181 	addDockWidget(Qt::BottomDockWidgetArea, messWnd);
182 	messWnd->resize(size().width(), 0);	new MessSyntax(mess);
183 //	connect(mess,SIGNAL(cursorPositionChanged()),this,SLOT(messClicked()));
184 	connect(mess,SIGNAL(selectionChanged()),this,SLOT(messClicked()));
185 
186 	hideWnd = new QDockWidget(_("Hidden plots"),this);
187 	hidden = new TextEdit(this);	hideWnd->setWidget(hidden);
188 	hideWnd->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
189 	addDockWidget(Qt::BottomDockWidgetArea, hideWnd);
190 	hideWnd->resize(size().width(), 0);	hidden->setReadOnly(true);
191 	connect(hidden,SIGNAL(selectionChanged()),this,SLOT(hiddenClicked()));	// TODO
192 //	connect(hidden,SIGNAL(cursorPositionChanged()),this,SLOT(hiddenClicked()));
193 
194 	calcWnd = new QDockWidget(_("Calculator"),this);
195 
196 	aload = a = new QAction(QPixmap(":/png/document-open.png"), _("Open file"), this);
197 	connect(a, SIGNAL(triggered()), this, SLOT(choose()));
198 	a->setToolTip(_("Open and execute/show script or data from file (Ctrl+O).\nYou may switch off automatic exection in UDAV properties."));
199 	a->setShortcut(Qt::CTRL+Qt::Key_O);
200 
201 	asave = a = new QAction(QPixmap(":/png/document-save.png"), _("Save script"), this);
202 	connect(a, SIGNAL(triggered()), this, SLOT(save()));
203 	a->setToolTip(_("Save script to a file (Ctrl+S)"));
204 	a->setShortcut(Qt::CTRL+Qt::Key_S);
205 
206 	acalc = a = new QAction(QPixmap(":/png/accessories-calculator.png"), _("Calculator"), this);
207 	a->setShortcut(Qt::Key_F4);	a->setCheckable(true);
208 	connect(a, SIGNAL(toggled(bool)), calcWnd, SLOT(setVisible(bool)));
209 	connect(calcWnd, SIGNAL(visibilityChanged(bool)), a, SLOT(setChecked(bool)));
210 	a->setToolTip(_("Show calculator which evaluate and help to type textual formulas.\nTextual formulas may contain data variables too."));
211 	a->setChecked(false);	calcWnd->setVisible(false);
212 
213 	ainfo = a = new QAction(_("Show info"), this);
214 	a->setShortcut(Qt::Key_F2);	a->setCheckable(true);
215 	connect(a, SIGNAL(toggled(bool)), messWnd, SLOT(setVisible(bool)));
216 	connect(messWnd, SIGNAL(visibilityChanged(bool)), a, SLOT(setChecked(bool)));
217 	a->setChecked(false);	messWnd->setVisible(false);
218 
219 	ahide = a = new QAction(QPixmap(":/png/layer-visible-on.png"), _("Show hidden plots"), this);
220 	a->setShortcut(Qt::Key_F8);	a->setCheckable(true);
221 	connect(a, SIGNAL(toggled(bool)), hideWnd, SLOT(setVisible(bool)));
222 	connect(hideWnd, SIGNAL(visibilityChanged(bool)), a, SLOT(setChecked(bool)));
223 	a->setChecked(false);	hideWnd->setVisible(false);
224 
225 	graph = new PlotPanel(this);
226 	rtab->addTab(graph,QPixmap(":/png/office-chart-line.png"),_("Canvas"));
227 	//	connect(info,SIGNAL(addPanel(QWidget*)),this,SLOT(addPanel(QWidget*)));
228 	info = createMemPanel(this);
229 	rtab->addTab(info,QPixmap(":/png/system-file-manager.png"),_("Info"));
230 	hlp = createHlpPanel(this);
231 	rtab->addTab(hlp,QPixmap(":/png/help-contents.png"),_("Help"));
232 	edit = new TextPanel(this);	edit->graph = graph;
233 	graph->textMGL = edit->edit;
234 	connect(graph->mgl,SIGNAL(showWarn(QString)),mess,SLOT(setText(QString)));
235 	connect(graph->mgl,SIGNAL(showWarn(QString)),edit->edit,SLOT(setErrMessage(QString)));
236 	connect(graph,SIGNAL(clearWarn()),mess,SLOT(clear()));
237 	ltab->addTab(edit,QPixmap(":/png/text-plain.png"),_("Script"));
238 
239 	calcWnd->setWidget(createCalcDlg(this, edit->edit));
240 	calcWnd->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
241 	addDockWidget(Qt::BottomDockWidgetArea, calcWnd);
242 	calcWnd->resize(size().width(), 200);
243 
244 	makeMenu();
245 	setCentralWidget(split);
246 	setWindowIcon(QIcon(":/udav.png"));
247 	readSettings();
248 	if(!propDlg)	propDlg = new PropDialog;
249 
250 	connect(graph, SIGNAL(save()), this, SLOT(save()));
251 	connect(graph, SIGNAL(setStatus(const QString &)), this, SLOT(setStatus(const QString &)));
252 	connect(graph, SIGNAL(animPutText(const QString &)), edit, SLOT(animPutText(const QString &)));
253 	connect(graph,SIGNAL(giveFocus()),edit->edit,SLOT(setFocus()));
254 	connect(graph->mgl, SIGNAL(objChanged(int)), edit, SLOT(setCursorPosition(int)));
255 //	connect(graph->mgl, SIGNAL(posChanged(QString)), statusBar(), SLOT(showMessage(QString)));
256 	connect(graph->mgl, SIGNAL(refreshData()), this, SLOT(refresh()));
257 	connect(graph->mgl, SIGNAL(refreshData()), edit, SLOT(refreshData()));
258 	connect(graph->mgl,SIGNAL(doubleClick(int)),edit,SLOT(newCmd(int)));
259 
260 	connect(edit->edit,SIGNAL(textChanged()),this,SLOT(updateHidden()));
261 	connect(mess, SIGNAL(textChanged()), this, SLOT(warnChanged()));
262 	connect(propDlg, SIGNAL(sizeChanged(int,int)), graph->mgl, SLOT(imgSize(int,int)));
263 	connect(edit->edit,SIGNAL(textChanged()), this, SLOT(setAsterix()));
264 	connect(edit->edit, SIGNAL(cursorPositionChanged()), this, SLOT(editPosChanged()));
265 	connect(edit,SIGNAL(setCurrentFile(QString)),this,SLOT(setCurrentFile(QString)));
266 	connect(edit,SIGNAL(setStatus(QString)),this,SLOT(setStatus(QString)));
267 
268 	setStatus(_("Ready"));
269 	num_wnd++;
270 	edit->setAcceptDrops(false);	// for disabling default action by 'edit'
271 	setAcceptDrops(true);
272 }
273 //-----------------------------------------------------------------------------
makeMenu()274 void MainWindow::makeMenu()
275 {
276 	QAction *a;
277 	QMenu *o;
278 
279 	// file menu
280 	{
281 	o = menuBar()->addMenu(_("File"));
282 	a = new QAction(QPixmap(":/png/document-new.png"), _("New script"), this);
283 	connect(a, SIGNAL(triggered()), this, SLOT(newDoc()));
284 	a->setToolTip(_("Create new empty script window (Ctrl+N)."));
285 	a->setShortcut(Qt::CTRL+Qt::Key_N);	o->addAction(a);
286 
287 	o->addAction(aload);
288 	o->addAction(asave);
289 
290 	a = new QAction(_("Save as ..."), this);
291 	connect(a, SIGNAL(triggered()), this, SLOT(saveAs()));
292 	o->addAction(a);
293 
294 	o->addSeparator();
295 	o->addAction(_("Print script"), edit, SLOT(printText()));
296 	a = new QAction(QPixmap(":/png/document-print.png"), _("Print graphics"), this);
297 	connect(a, SIGNAL(triggered()), graph->mgl, SLOT(print()));
298 	a->setToolTip(_("Open printer dialog and print graphics (Ctrl+P)"));
299 	a->setShortcut(Qt::CTRL+Qt::Key_P);	o->addAction(a);
300 	o->addSeparator();
301 	fileMenu = o->addMenu(_("Recent files"));
302 	o->addSeparator();
303 	o->addAction(_("Quit"), qApp, SLOT(closeAllWindows()));
304 	}
305 
306 	menuBar()->addMenu(edit->menu);
307 	menuBar()->addMenu(graph->menu);
308 
309 	// settings menu
310 	{
311 	o = menuBar()->addMenu(_("Settings"));
312 	a = new QAction(QPixmap(":/png/preferences-system.png"), _("Properties"), this);
313 	connect(a, SIGNAL(triggered()), this, SLOT(properties()));
314 	a->setToolTip(_("Show dialog for UDAV properties."));	o->addAction(a);
315 	o->addAction(_("Set arguments"), createArgsDlg(this), SLOT(exec()));
316 
317 	o->addAction(acalc);
318 	o->addAction(ainfo);
319 	o->addAction(ahide);
320 	}
321 
322 	menuBar()->addSeparator();
323 	o = menuBar()->addMenu(_("Help"));
324 	a = new QAction(QPixmap(":/png/help-contents.png"), _("MGL help"), this);
325 	connect(a, SIGNAL(triggered()), this, SLOT(showHelp()));
326 	a->setToolTip(_("Show help on MGL commands (F1)."));
327 	a->setShortcut(Qt::Key_F1);	o->addAction(a);
328 	a = new QAction(QPixmap(":/png/help-faq.png"), _("Hints"), this);
329 	connect(a, SIGNAL(triggered()), this, SLOT(showHint()));
330 	a->setToolTip(_("Show hints of MGL usage."));	o->addAction(a);
331 	o->addAction(_("About"), this, SLOT(about()));
332 	o->addAction(_("About Qt"), this, SLOT(aboutQt()));
333 }
334 //-----------------------------------------------------------------------------
closeEvent(QCloseEvent * ce)335 void MainWindow::closeEvent(QCloseEvent* ce)
336 {
337 	bool ok=true;
338 	writeSettings();
339 	if(edit->isModified())
340 		switch(QMessageBox::information(this, _("UDAV"),
341 				_("Do you want to save the changes to the document?"),
342 				QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel))
343 		{
344 			case QMessageBox::Yes:	save();	break;
345 			case QMessageBox::No:	break;
346 			default:	ok=false;	break;
347 		}
348 	if(ok)
349 	{
350 		num_wnd--;
351 		ce->accept();
352 		if(num_wnd==0)	QApplication::quit();
353 	}
354 	else	ce->ignore();
355 }
356 //-----------------------------------------------------------------------------
dropEvent(QDropEvent * de)357 void MainWindow::dropEvent(QDropEvent * de)
358 {
359 	// Linux Qt send "text/plain" mime data in drop event
360 	// Windows version send "text/uri-list"
361 	QTextCodec *codec = QTextCodec::codecForLocale();
362 	QString filename;
363 	if ( de->mimeData()->hasFormat("text/plain") )
364 	{
365 		// Under linux just convert the text from the local encodig to Qt's unicode
366 		filename = codec->toUnicode(de->mimeData()->data("text/plain"));
367 		if (filename.indexOf("file:") == 0)
368 			load(filename.remove("file://").trimmed(), false);
369 	}else
370 	if ( de->mimeData()->hasUrls() )
371 	{
372 		// Under win - parse the dropped data and find the path to local file
373 		QList<QUrl> UrlList;
374 		QFileInfo finfo;
375 		UrlList = de->mimeData()->urls();
376 		if ( UrlList.size() > 0) // if at least one QUrl is present in list
377 		{
378 			filename = UrlList[0].toLocalFile(); // convert first QUrl to local path
379 			finfo.setFile( filename );
380 			if ( finfo.isFile() )
381 			{
382 				load(filename, false);
383 			}
384 		}
385 	}
386 }
387 //-----------------------------------------------------------------------------
dragEnterEvent(QDragEnterEvent * event)388 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
389 {
390 	QTextCodec *codec = QTextCodec::codecForLocale();
391 	QString filename = codec->toUnicode(event->mimeData()->data("text/plain"));
392 	/*if ( event->provides("text/plain") )
393 	{
394 		QTextCodec *codec = QTextCodec::codecForLocale();
395 		QString instring = codec->toUnicode(event->mimeData()->data("text/plain"));
396 		if ( instring.indexOf("file://") >= 0)
397 		{
398 			event->acceptProposedAction();
399 			setStatus(instring);
400 		}
401 	}
402 	else */
403 	if(event->mimeData()->hasUrls())
404 	{
405 		QList<QUrl> UrlList;
406 		QFileInfo finfo;
407 		UrlList = event->mimeData()->urls();
408 		if ( UrlList.size() > 0) // if at least one QUrl is present in list
409 		{
410 			filename = UrlList[0].toLocalFile(); // convert first QUrl to local path
411 			finfo.setFile(filename);
412 			if ( finfo.isFile() )
413 			{
414 				event->acceptProposedAction();
415 				setStatus(filename);
416 			}
417 		}
418 	}
419 }
420 //-----------------------------------------------------------------------------
showHelp()421 void MainWindow::showHelp()
422 {
423 	QString s = edit->selection(), dlm(" #;:\t");
424 	int i, n = s.length();
425 	for(i=0;i<n;i++)	if(dlm.contains(s[i]))	break;
426 	s.truncate(i);
427 //	s = s.section(' ',0);
428 	showHelpMGL(hlp,s);
429 }
430 //-----------------------------------------------------------------------------
431 int mgl_cmd_cmp(const void *a, const void *b);
editPosChanged()432 void MainWindow::editPosChanged()
433 {
434 	QString text = edit->selection(), dlm(" #;:\t");
435 	int n = text.length(), i;
436 	for(i=0;i<n;i++)	if(dlm.contains(text[i]))	break;
437 	text.truncate(i);
438 
439 	QByteArray qxtext = text.toLatin1();
440 	const char *ctext = qxtext.constData();
441 	const char *desc = parser.CmdDesc(ctext);
442 	const char *form = parser.CmdFormat(ctext);
443 	if(form)	setStatus(QString(desc)+": "+QString(form));
444 	else	setStatus(_("Not recognized"));
445 }
446 //-----------------------------------------------------------------------------
setEditPos(bool bottom)447 void MainWindow::setEditPos(bool bottom)
448 {	split->setOrientation(bottom ? Qt::Vertical : Qt::Horizontal);	}
449 //-----------------------------------------------------------------------------
properties()450 void MainWindow::properties()	{	propDlg->exec();	}
451 //-----------------------------------------------------------------------------
about()452 void MainWindow::about()
453 {
454 	QString s = "<a href='http://mathgl.sourceforge.net/doc_en/UDAV-overview.html'>UDAV</a> v. 2."+QString::number(MGL_VER2)+
455 	_("<br>(c) Alexey Balakin, 2007-present<br><br><a href='http://www.gnu.org/copyleft/gpl.html'>License is GPL v.2 or later.</a>");
456 	QMessageBox::about(this, _("UDAV - about"), s);
457 }
458 //-----------------------------------------------------------------------------
aboutQt()459 void MainWindow::aboutQt()
460 {	QMessageBox::aboutQt(this, _("About Qt"));	}
461 //-----------------------------------------------------------------------------
writeSettings()462 void MainWindow::writeSettings()
463 {
464 	QSettings settings("udav","UDAV");
465 	settings.setPath(QSettings::IniFormat, QSettings::UserScope, "UDAV");
466 	settings.beginGroup("/UDAV");
467 	settings.setValue("/animDelay", animDelay);
468 	settings.setValue("/geometry/size", size());
469 //	settings.setValue("/geometry/dock", messWnd->size());
470 	settings.setValue("/geometry/split_e/w1", split->sizes().at(0));
471 	settings.setValue("/geometry/split_e/w2", split->sizes().at(1));
472 
473 	settings.setValue("/recentFiles", recentFiles);
474 	settings.setValue("/recentFilesMax", MaxRecentFiles);
475 	settings.setValue("/helpPath", pathHelp);
476 	settings.setValue("/userFont", pathFont);
477 	settings.setValue("/colComment",mglColorScheme[0].name());
478 	settings.setValue("/colString", mglColorScheme[1].name());
479 	settings.setValue("/colKeyword",mglColorScheme[2].name());
480 	settings.setValue("/colOption", mglColorScheme[3].name());
481 	settings.setValue("/colSuffix", mglColorScheme[4].name());
482 	settings.setValue("/colNumber", mglColorScheme[5].name());
483 	settings.setValue("/colACKeyword", mglColorScheme[6].name());
484 	settings.setValue("/colFCKeyword", mglColorScheme[7].name());
485 	settings.setValue("/colReserved", mglColorScheme[8].name());
486 	settings.setValue("/colCurrLine", mglColorScheme[9].name());
487 	settings.setValue("/autoExec",  mglAutoExecute);
488 	settings.setValue("/autoSave",  mglAutoSave);
489 	settings.setValue("/highlight",  mglHighlight);
490 	settings.setValue("/dotsRefresh", mglDotsRefr);
491 // 	settings.setValue("/autoPure",  mglAutoPure);
492 	settings.setValue("/editAtTop", editPosBottom);
493 	settings.setValue("/fontFamily", defFontFamily);
494 	settings.setValue("/fontSize", defFontSize);
495 	settings.setValue("/loadInNewWnd", loadInNewWnd);
496 	settings.setValue("/completer",  mglCompleter);
497 	settings.setValue("/wheelZoom",  mglWheelZoom);
498 	settings.endGroup();
499 }
500 //-----------------------------------------------------------------------------
readSettings()501 void MainWindow::readSettings()
502 {
503 	QSettings settings("udav","UDAV");
504 	settings.setPath(QSettings::IniFormat, QSettings::UserScope, "UDAV");
505 	settings.beginGroup("/UDAV");
506 	pathHelp = settings.value("/helpPath", MGL_DOC_DIR).toString();
507 	if(pathHelp.isEmpty())	pathHelp=MGL_DOC_DIR;
508 	MaxRecentFiles = settings.value("/recentFilesMax", 5).toInt();
509 	animDelay = settings.value("/animDelay", 500).toInt();
510 	resize(settings.value("/geometry/size", QSize(880,720)).toSize());
511 	QList<int> le;
512 	le.append(settings.value("/geometry/split_e/w1", 230).toInt());
513 	le.append(settings.value("/geometry/split_e/w2", 604).toInt());
514 	split->setSizes(le);
515 
516 	pathFont = settings.value("/userFont", "").toString();
517 	mglColorScheme[0] = QColor(settings.value("/colComment","#007F00").toString());
518 	mglColorScheme[1] = QColor(settings.value("/colString", "#FF0000").toString());
519 	mglColorScheme[2] = QColor(settings.value("/colKeyword","#00007F").toString());
520 	mglColorScheme[3] = QColor(settings.value("/colOption", "#7F0000").toString());
521 	mglColorScheme[4] = QColor(settings.value("/colSuffix", "#7F0000").toString());
522 	mglColorScheme[5] = QColor(settings.value("/colNumber", "#0000FF").toString());
523 	mglColorScheme[6] = QColor(settings.value("/colACKeyword","#7F007F").toString());
524 	mglColorScheme[7] = QColor(settings.value("/colFCKeyword","#007F7F").toString());
525 	mglColorScheme[8] = QColor(settings.value("/colReserved", "#0000FF").toString());
526 	mglColorScheme[9] = QColor(settings.value("/colCurrLine", "#FFFFCC").toString());
527 	mglAutoSave = settings.value("/autoSave", false).toBool();
528 	mglHighlight = settings.value("/highlight", true).toBool();
529 // 	mglAutoPure = settings.value("/autoPure", true).toBool();
530 	mglAutoExecute = settings.value("/autoExec", true).toBool();
531 	editPosBottom = settings.value("/editAtTop", false).toBool();
532 	mglCompleter = settings.value("/completer", true).toBool();
533 	mglWheelZoom = settings.value("/wheelZoom", false).toBool();
534 	loadInNewWnd = settings.value("/loadInNewWnd", false).toBool();
535 	mglDotsRefr = settings.value("/dotsRefresh", true).toBool();
536 	defFontFamily = settings.value("/fontFamily", "Georgia").toString();
537 	defFontSize = settings.value("/fontSize", 10).toInt();
538 	edit->setEditorFont();	setEditPos(editPosBottom);
539 	graph->setMGLFont(pathFont);
540 	graph->mgl->enableWheel = mglWheelZoom;
541 
542 	defWidth = settings.value("/defWidth", 640).toInt();
543 	defHeight = settings.value("/defHeight", 480).toInt();
544 	graph->mgl->setSize(defWidth, defHeight);
545 
546 	recentFiles = settings.value("/recentFiles").toStringList();
547 	settings.endGroup();
548 	updateRecentFileItems();
549 }
550 //-----------------------------------------------------------------------------
setStatus(const QString & txt)551 void MainWindow::setStatus(const QString &txt)
552 {	statusBar()->showMessage(txt, 5000);	}
553 //-----------------------------------------------------------------------------
setCurrentFile(const QString & fileName)554 void MainWindow::setCurrentFile(const QString &fileName)
555 {
556 	filename = fileName;
557 	mgl_set_plotid(graph->mgl->getGraph(), fileName.toLocal8Bit().constData());
558 	edit->setModified(false);
559 	if(filename.isEmpty())
560 		setWindowTitle(_("untitled - UDAV"));
561 	else
562 	{
563 		setWindowTitle(QFileInfo(filename).fileName()+" - UDAV");
564 		int i = recentFiles.indexOf(filename);
565 		if(i>=0)	recentFiles.removeAt(i);
566 		recentFiles.push_front(filename);
567 		updateRecentFileItems();
568 		if(chdir(qPrintable(QFileInfo(filename).path())))
569 			QMessageBox::warning(this, _("UDAV - save current"),
570 				_("Couldn't change to folder ")+QFileInfo(filename).path());
571 	}
572 }
573 //-----------------------------------------------------------------------------
openRecentFile()574 void MainWindow::openRecentFile()
575 {
576 	QAction *a = qobject_cast<QAction *>(sender());
577 	if(!a)	return;
578 	if(edit->isModified())
579 		switch(QMessageBox::information(this, _("UDAV - save current"),
580 				_("Do you want to save the changes to the document?"),
581 				QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel))
582 		{
583 			case QMessageBox::Yes:	save();	break;
584 			case QMessageBox::No:	break;
585 			default:	return;
586 		}
587 	QString fn = recentFiles[a->data().toInt()];
588 	if(!fn.isEmpty())	load(fn);
589 }
590 //-----------------------------------------------------------------------------
updateRecentFileItems()591 void MainWindow::updateRecentFileItems()
592 {
593 	foreach(QWidget *w, QApplication::topLevelWidgets())
594 	{
595 		MainWindow *wnd = qobject_cast<MainWindow *>(w);
596 		if(wnd)	wnd->updateRecent();
597 	}
598 }
599 //-----------------------------------------------------------------------------
updateRecent()600 void MainWindow::updateRecent()
601 {
602 	QAction *a;
603 	fileMenu->clear();	qApp->processEvents();
604 	for(int i=0; i<recentFiles.size() && i<MaxRecentFiles; i++)
605 	{
606 		QString text="&"+QString::number(i+1)+" "+QFileInfo(recentFiles[i]).fileName();
607 		a = fileMenu->addAction(text, this, SLOT(openRecentFile()));
608 		a->setData(i);
609 	}
610 }
611 //-----------------------------------------------------------------------------
newDoc()612 void MainWindow::newDoc()
613 {
614 	MainWindow *ed = new MainWindow;
615 	ed->show();	ed->activateWindow();
616 }
617 //-----------------------------------------------------------------------------
choose()618 void MainWindow::choose()
619 {
620 	if(edit->isModified())
621 		switch(QMessageBox::information(this, _("UDAV - save current"),
622 				_("Do you want to save the changes to the document?"),
623 				QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel))
624 		{
625 			case QMessageBox::Yes:	save();	break;
626 			case QMessageBox::No:	break;
627 			default:	return;
628 		}
629 	QSettings settings("udav","UDAV");
630 	settings.setPath(QSettings::IniFormat, QSettings::UserScope, "UDAV");
631 	settings.beginGroup("/UDAV");
632 	QString fn = QFileDialog::getOpenFileName(this,
633 			_("UDAV - Open file"),
634 			settings.value("/filePath", MGL_DOC_DIR).toString(),
635 			_("MGL scripts (*.mgl)\nHDF5 files (*.hdf *.h5)\nText files (*.txt)\nData files (*.dat)\nAll files (*.*)"));
636 	settings.endGroup();
637 	if(!fn.isEmpty())	load(fn);
638 	else	setStatus(_("Loading aborted"));
639 }
640 //-----------------------------------------------------------------------------
load(const QString & fileName,bool noNewWnd)641 void MainWindow::load(const QString &fileName, bool noNewWnd)
642 {
643 	// save current path
644 	QFileInfo fi(fileName);		filename = fileName;
645 	QSettings settings("udav","UDAV");
646 	settings.setPath(QSettings::IniFormat, QSettings::UserScope, "UDAV");
647 	settings.beginGroup("/UDAV");
648 	settings.setValue("/filePath", fi.absolutePath());
649 	settings.endGroup();
650 	// open new window if it is required
651 	if(loadInNewWnd && !noNewWnd)
652 	{
653 		MainWindow *mw = new MainWindow;
654 		mw->edit->load(fileName);
655 		mw->show();	//ed->activateWindow();
656 	}
657 	else	edit->load(fileName);
658 }
659 //-----------------------------------------------------------------------------
save()660 void MainWindow::save()
661 {
662 	if(filename.isEmpty())	saveAs();
663 	else	edit->save(filename);
664 }
665 //-----------------------------------------------------------------------------
saveAs()666 void MainWindow::saveAs()
667 {
668 	QString fn;
669 	fn = QFileDialog::getSaveFileName(this, _("UDAV - save file"), "",
670 			_("MGL scripts (*.mgl)\nHDF5 files (*.hdf *.h5)\nAll files (*.*)"));
671 	if(fn.isEmpty())
672 	{	setStatus(_("Saving aborted"));	return;	}
673 	else
674 	{
675 		int nn=fn.length();
676 		if(fn[nn-4]!='.' && fn[nn-3]!='.')	fn = fn + ".mgl";
677 		filename = fn;		save();
678 	}
679 }
680 //-----------------------------------------------------------------------------
setAsterix()681 void MainWindow::setAsterix()
682 {
683 	if(edit->isModified())
684 	{
685 		if(filename.isEmpty())
686 			setWindowTitle(_("untitled* - UDAV"));
687 		else
688 			setWindowTitle(QFileInfo(filename).fileName()+"* - UDAV");
689 	}
690 	else
691 	{
692 		if(filename.isEmpty())
693 			setWindowTitle(_("untitled - UDAV"));
694 		else
695 			setWindowTitle(QFileInfo(filename).fileName()+" - UDAV");
696 	}
697 }
698 //-----------------------------------------------------------------------------
updateDataItems()699 void updateDataItems()
700 {
701 	foreach (QWidget *w, QApplication::topLevelWidgets())
702 		if(w->inherits("MainWindow"))	((MainWindow *)w)->refresh();
703 }
704 //-----------------------------------------------------------------------------
addPanel(QWidget * w,QString name)705 void MainWindow::addPanel(QWidget *w, QString name)
706 {
707 	ltab->addTab(w,QPixmap(":/png/text-csv.png"),name);
708 	ltab->setCurrentWidget(w);
709 }
710 //-----------------------------------------------------------------------------
findMain(QWidget * wnd)711 MGL_LOCAL_PURE MainWindow *findMain(QWidget *wnd)
712 {
713 	MainWindow *mw=0;
714 	QObject *w=wnd;
715 
716 	while(w && !mw)
717 	{
718 		mw = dynamic_cast<MainWindow *>(w);
719 		w = w->parent();
720 	}
721 	return mw;
722 }
723 //-----------------------------------------------------------------------------
raisePanel(QWidget * w)724 void raisePanel(QWidget *w)
725 {
726 	MainWindow *mw=findMain(w);
727 	if(mw)	mw->rtab->setCurrentWidget(w);
728 }
729 //-----------------------------------------------------------------------------
updateHidden()730 void MainWindow::updateHidden()
731 {
732 	QTextCursor tc = edit->edit->textCursor();
733 	long pos = tc.position(), i=0;
734 	hidden->clear();
735 	tc.movePosition(QTextCursor::Start);
736 	do {
737 		i++;
738 		if(tc.block().text().startsWith("#h "))
739 			hidden->append("Line "+QString::number(i)+QString::fromWCharArray(L" \u2192 ")+tc.block().text().mid(3)+"\n");
740 	} while(tc.movePosition(QTextCursor::NextBlock));
741 	tc.setPosition(pos);
742 }
743 //-----------------------------------------------------------------------------
hiddenClicked()744 void MainWindow::hiddenClicked()
745 {
746 	QString q = hidden->textCursor().block().text();
747 	if(q.contains("Line "))
748 	{
749 		int n = q.section(' ',1,1).toInt()-1;
750 		edit->edit->moveCursor(QTextCursor::Start);
751 		for(int i=0;i<n;i++)	edit->edit->moveCursor(QTextCursor::NextBlock);
752 		edit->edit->textCursor().deleteChar();
753 		edit->edit->textCursor().deleteChar();
754 		edit->edit->textCursor().deleteChar();
755 	}
756 	graph->execute();
757 }
758 //-----------------------------------------------------------------------------
messClicked()759 void MainWindow::messClicked()
760 {
761 	QString q = mess->textCursor().block().text();
762 	if(q.contains("in line "))
763 	{
764 		int n = q.section(' ',-1).toInt()-1;	if(n<0)	return;
765 		edit->moveCursor(QTextCursor::Start);
766 		for(int i=0;i<n;i++)	edit->moveCursor(QTextCursor::NextBlock);
767 	}
768 	edit->setFocus();
769 }
770 //-----------------------------------------------------------------------------
warnChanged()771 void MainWindow::warnChanged()
772 {
773 	if(mess->toPlainText().isEmpty())
774 	{	messWnd->hide();	ainfo->setChecked(false);	}
775 	else
776 	{	messWnd->show();	ainfo->setChecked(true);	}
777 }
778 //-----------------------------------------------------------------------------
779