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 #include <QTableWidget>
21 #include <QLabel>
22 #include <QAction>
23 #include <QLayout>
24 #include <QMenuBar>
25 #include <QLineEdit>
26 #include <QMenu>
27 #include <QClipboard>
28 #include <QStatusBar>
29 #include <QFileDialog>
30 #include <QPushButton>
31 #include <QApplication>
32 #include <QInputDialog>
33 #include <QToolButton>
34 #include <QSpinBox>
35 #include <QComboBox>
36 #include <QCheckBox>
37 #include <QMessageBox>
38 #include <mgl2/mgl.h>
39 //-----------------------------------------------------------------------------
40 #include "dat_pnl.h"
41 #include "info_dlg.h"
42 #include "xpm/table.xpm"
43 #undef sprintf	// fix libintl bug of defining sprintf
44 //-----------------------------------------------------------------------------
45 extern mglParse parser;
46 void updateDataItems();
47 void addDataPanel(QWidget *wnd, QWidget *w, QString name);
deleteDat(void * o)48 void deleteDat(void *o)		{	if(o)	delete ((DatPanel *)o);	}
refreshData(QWidget * w)49 void refreshData(QWidget *w)	{	((DatPanel *)w)->refresh();	}
50 //-----------------------------------------------------------------------------
newDataWnd(InfoDialog * inf,QWidget * wnd,mglDataA * v)51 QWidget *newDataWnd(InfoDialog *inf, QWidget *wnd, mglDataA *v)
52 {
53 	DatPanel *t = new DatPanel(inf);
54 	if(v)	t->setVar(v);
55 	addDataPanel(wnd,t,t->dataName());
56 	return t;
57 }
58 //-----------------------------------------------------------------------------
DatPanel(InfoDialog * inf,QWidget * parent)59 DatPanel::DatPanel(InfoDialog *inf, QWidget *parent) : QWidget(parent)
60 {
61 	setAttribute(Qt::WA_DeleteOnClose);
62 	kz = nx = ny = nz = 0;	var = 0;
63 	ready = false;	infoDlg = inf;
64 	QBoxLayout *v,*h,*m;
65 
66 	menu = new QMenu(_("Data"),this);
67 	v = new QVBoxLayout(this);
68 	h = new QHBoxLayout();	v->addLayout(h);	toolTop(h);
69 	h = new QHBoxLayout();	v->addLayout(h);
70 	m = new QVBoxLayout();	h->addLayout(m);	toolLeft(m);
71 	tab = new QTableWidget(this);	h->addWidget(tab);
72 	connect(tab, SIGNAL(cellChanged(int,int)), this, SLOT(putValue(int, int)));
73 
74 	setWindowIcon(QPixmap(table_xpm));
75 }
76 //-----------------------------------------------------------------------------
~DatPanel()77 DatPanel::~DatPanel()	{	if(var && var->o==this)	var->o = 0;	}
78 //-----------------------------------------------------------------------------
refresh()79 void DatPanel::refresh()
80 {
81 	bool rc = false;
82 	if(!var)	return;
83 	infoDlg->allowRefresh=false;
84 	if(nx!=var->GetNx())	{	nx = var->GetNx();	tab->setColumnCount(nx);	rc=true;	}
85 	if(ny!=var->GetNy())	{	ny = var->GetNy();	tab->setRowCount(ny);	rc=true;	}
86 	if(kz>=var->GetNz())	{	kz = 0;	emit sliceChanged(0);	}
87 	if(nz!=var->GetNz())	{	nz = var->GetNz();	emit nzChanged(nz);		}
88 	id = QString(var->GetColumnId());
89 	if(nz==1 && ny>1 && !id.isEmpty())
90 	{
91 		QStringList head;
92 		QString s;
93 		for(int i=0;i<ny;i++)
94 		{
95 			s = QString("%1").arg(i);
96 			if(id[i]>='a' && id[i]<='z')	s=s+" ("+id[i]+")";
97 			head<<s;
98 		}
99 		tab->setHorizontalHeaderLabels(head);
100 	}
101 	QString s,d;
102 	if(rc)
103 	{
104 		QStringList sh,sv;
105 		for(long i=0;i<nx;i++)	sh<<QString::number(i);
106 		tab->setHorizontalHeaderLabels(sh);
107 		for(long i=0;i<ny;i++)	sv<<QString::number(i);
108 		tab->setVerticalHeaderLabels(sv);
109 		for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)
110 			tab->setItem(j,i,new QTableWidgetItem);
111 	}
112 	mglDataC *cc = dynamic_cast<mglDataC*>(var);
113 	if(cc)	for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)
114 	{
115 		dual f = cc->a[i+nx*(j+ny*kz)];
116 		if(mgl_isnan(f))	s = "nan";
117 		else if(mgl_isbad(f))	s="inf";
118 		else if(imag(f)>0)	s.asprintf("%.15g+%.15gi",real(f),imag(f));
119 		else if(imag(f)<0)	s.asprintf("%.15g-%.15gi",real(f),-imag(f));
120 		else	s.asprintf("%15g",real(f));
121 		tab->item(j,i)->setText(s);
122 	}
123 	else	for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)
124 	{
125 		double f = var->v(i,j,kz);
126 		if(mgl_isnan(f))	s = "nan";
127 		else if(mgl_isbad(f))	s=f>0?"inf":"-inf";
128 		else	s.asprintf("%.15g",f);
129 		tab->item(j,i)->setText(s);
130 	}
131 	infoDlg->allowRefresh=true;	infoDlg->refresh();
132 	const wchar_t *vs = var->Name();
133 	long m=wcslen(vs);
134 	QChar *ss = new QChar[m+1];
135 	for(long i=0;i<m;i++)	ss[i] = vs[i];
136 	s = QString(ss, m);	delete []ss;
137 	d.asprintf("%d * %d * %d", nx, ny, nz);
138 	ready = true;
139 }
140 //-----------------------------------------------------------------------------
setVar(mglDataA * v)141 void DatPanel::setVar(mglDataA *v)
142 {
143 	ready = false;
144 	if(var)	var->o = 0;
145 	var = v;	infoDlg->setVar(v);
146 	nx = ny = nz = kz = 0;
147 	if(v)
148 	{
149 		QString s = QString::fromWCharArray(v->Name());
150 		v->o = this;	v->func = deleteDat;
151 		refresh();
152 		setWindowTitle(s + _(" - UDAV variable"));
153 		infoDlg->setWindowTitle(s + _(" - UDAV preview"));
154 	}
155 	else
156 	{	tab->setColumnCount(0);	tab->setRowCount(0);	emit nzChanged(nz);	}
157 	emit sliceChanged(0);
158 }
159 //-----------------------------------------------------------------------------
setSlice(int k)160 void DatPanel::setSlice(int k)
161 {
162 	if(k>=nz)	k=nz-1;
163 	if(k<0)	k=0;
164 	if(k!=kz)
165 	{
166 		infoDlg->setSlice(k);
167 		emit sliceChanged(k);
168 		kz = k;		refresh();
169 	}
170 }
171 //-----------------------------------------------------------------------------
mgl_str2dual(const char * s)172 dual mgl_str2dual(const char *s)
173 {
174 	setlocale(LC_NUMERIC, "C");
175 	double re=0,im=0;	size_t ll=strlen(s);
176 	while(s[ll]<=' ')	ll--;
177 	if(*s=='(')		sscanf(s,"(%lg,%lg)",&re,&im);
178 	else if(*s=='i')	{	re=0;	im=atof(s+1);	}
179 	else if(*s=='[')	sscanf(s,"[%lg,%lg]",&re,&im);
180 	else if(*s=='{')	sscanf(s,"{%lg,%lg}",&re,&im);
181 	else if(s[ll]=='i')
182 	{
183 		double a,b;
184 		int s1=sscanf(s,"%lg+%lgi",&re,&im);
185 		int s2=sscanf(s,"%lg-%lgi",&a,&b);
186 		if(s1<2)
187 		{
188 		if(s2==2)	{	re=a;	im=-b;	}
189 		else	{	im=atof(s);	re=0;	}
190 		}
191 	}
192 	else
193 	{
194 		double a,b;
195 		int s1=sscanf(s,"%lg+i%lg",&re,&im);
196 		int s2=sscanf(s,"%lg-i%lg",&a,&b);
197 		if(s1<2)
198 		{
199 		if(s2==2)	{	re=a;	im=-b;	}
200 		else	{	re=atof(s);	im=0;	}
201 		}
202 	}
203 	setlocale(LC_NUMERIC, "");
204 	return dual(re,im);
205 }
206 //-----------------------------------------------------------------------------
putValue(int r,int c)207 void DatPanel::putValue(int r, int c)
208 {
209 	if(!var || r<0 || c<0 || r>=ny || c>=nx || !ready)	return;
210 	QString s = tab->item(r,c)->text().toLower();
211 	mreal f;
212 	dual g;
213 	if(s=="nan")	f=NAN;
214 	else if(s=="inf")	f=INFINITY;
215 	else if(s=="-inf")	f=-INFINITY;
216 	else
217 	{	g = mgl_str2dual(s.toLocal8Bit().constData());	f = real(g);	}
218 	mglDataC *cc = dynamic_cast<mglDataC*>(var);
219 	if(cc)
220 	{
221 		if(g!=cc->a[c+nx*(r+ny*kz)])
222 		{
223 			if(mgl_isnan(g))	s="nan";
224 			else if(mgl_isbad(g))	s="inf";
225 			else if(imag(g)>0)	s.asprintf("%g+%gi",real(g),imag(g));
226 			else if(imag(g)<0)	s.asprintf("%g-%gi",real(g),-imag(g));
227 			else	s.asprintf("%g",real(g));
228 			tab->item(r,c)->setText(s);
229 		}
230 		cc->a[c+nx*(r+ny*kz)] = g;
231 	}
232 	else
233 	{
234 		if(f!=var->v(c,r,kz))
235 		{
236 			if(mgl_isnan(f))	s="nan";
237 			else if(mgl_isbad(f))	s=f>0?"inf":"-inf";
238 			else	s.asprintf("%g", f);
239 			tab->item(r,c)->setText(s);
240 		}
241 		var->set_v(f,c,r,kz);
242 	}
243 	infoDlg->refresh();
244 }
245 //-----------------------------------------------------------------------------
save()246 void DatPanel::save()
247 {
248 	QString fn = QFileDialog::getSaveFileName(this, _("UDAV - Save/export data"), "",
249 				_("Data files (*.dat)\nHDF5 files (*.h5 *.hdf)\nPNG files (*.png)\nAll files (*.*)"));
250 	if(fn.isEmpty())	return;
251 	QString ext = fn.section(".",-1);
252 	if(ext=="png")
253 	{
254 		bool ok;
255 		QString s = QInputDialog::getText(this, _("UDAV - Export to PNG"), _("Enter color scheme"), QLineEdit::Normal, MGL_DEF_SCH, &ok);
256 		if(ok)	var->Export(fn.toLocal8Bit().constData(), s.toLocal8Bit().constData());
257 	}
258 	else if(ext=="h5" || ext=="hdf")
259 	{
260 		bool ok;
261 		QString s = QInputDialog::getText(this, _("UDAV - Save to HDF"), _("Enter data name"), QLineEdit::Normal, QString::fromWCharArray(var->Name()), &ok);
262 		if(ok)	var->SaveHDF(fn.toLocal8Bit().constData(), s.toLocal8Bit().constData());
263 	}
264 	else 	var->Save(fn.toLocal8Bit().constData());
265 }
266 //-----------------------------------------------------------------------------
load()267 void DatPanel::load()
268 {
269 	mglData *d = dynamic_cast<mglData *>(var);	if(!d)	return;
270 	QString fn = QFileDialog::getOpenFileName(this, _("UDAV - Load data"), "",
271 				_("Data files (*.dat)\nHDF5 files (*.h5 *.hdf)\nPNG files (*.png)\nAll files (*.*)"));
272 	if(fn.isEmpty())	return;
273 	QString ext = fn.section(".",-1);
274 	if(ext=="png")
275 	{
276 		bool ok;
277 		QString s = QInputDialog::getText(this, _("UDAV - Import PNG"), _("Enter color scheme"), QLineEdit::Normal, MGL_DEF_SCH, &ok);
278 		if(ok)	d->Import(fn.toLocal8Bit().constData(), s.toLocal8Bit().constData());
279 	}
280 	else if(ext=="h5" || ext=="hdf")
281 	{
282 		bool ok;
283 		QString s = QInputDialog::getText(this, _("UDAV - Read from HDF"), _("Enter data name"), QLineEdit::Normal, QString::fromWCharArray(var->Name()), &ok);
284 		if(ok)	d->ReadHDF(fn.toLocal8Bit().constData(), s.toLocal8Bit().constData());
285 	}
286 	else 	d->Read(fn.toLocal8Bit().constData());
287 	refresh();
288 }
289 //-----------------------------------------------------------------------------
copy()290 void DatPanel::copy()
291 {
292 	QTableWidgetSelectionRange ts = tab->selectedRanges().first();
293 	QString res;
294 	for(long j=ts.topRow();j<=ts.bottomRow();j++)
295 	{
296 		for(long i=ts.leftColumn();i<=ts.rightColumn();i++)
297 		{
298 			res = res + tab->item(j,i)->text();
299 			if(i<ts.rightColumn())	res = res + "\t";
300 		}
301 		res = res + "\n";
302 	}
303 	QApplication::clipboard()->setText(res, QClipboard::Clipboard);
304 }
305 //-----------------------------------------------------------------------------
paste()306 void DatPanel::paste()
307 {
308 	QString txt = QApplication::clipboard()->text(QClipboard::Clipboard);
309 	QString s, t;
310 	int r = tab->currentRow(), c = tab->currentColumn(), i, j;
311 	for(i=0;i<ny-r;i++)
312 	{
313 		s = txt.section('\n',i,i,QString::SectionSkipEmpty);
314 		if(s.isEmpty())	break;
315 		for(j=0;j<nx-c;j++)
316 		{
317 			t = s.section('\t',j,j,QString::SectionSkipEmpty);
318 			if(t.isEmpty())	{	j=nx;	continue;	}
319 			var->set_v(t.toDouble(),j+c,i+r,kz);
320 		}
321 	}
322 	refresh();
323 }
324 //-----------------------------------------------------------------------------
plot()325 void DatPanel::plot()	// TODO: plot dialog
326 {
327 
328 }
329 //-----------------------------------------------------------------------------
list()330 void DatPanel::list()	// TODO: in which script insert ???
331 {
332 /*	if(nx*ny+ny > 1020)
333 	{	QMessageBox::warning(this, _("UDAV - To list conversion"), _("Too many numbers (>1000) on slice"), QMessageBox::Ok, 0, 0);	return;	}
334 	if(nz > 1)
335 		QMessageBox::information(this, _("UDAV - To list conversion"), _("Only current slice will be inserted"), QMessageBox::Ok, 0, 0);
336 	QString res = "list\t", s;
337 	for(long j=0;j<ny;j++)
338 	{
339 	for(long i=0;i<nx;i++)
340 		{
341 			s.asprintf("%g\t",d->a[i+nx*(j+kz*ny)]);
342 			res += s;
343 		}
344 		if(j<ny-1)	res = res + "|\t";
345 	}*/
346 }
347 //-----------------------------------------------------------------------------
inrange()348 void DatPanel::inrange()
349 {
350 	QString v1("-1"), v2("1"), dir("x");
351 	if(sizesDialog(_("UDAV - Fill data"), _("Enter range for data and direction of filling"), _("From"), _("To"), _("Direction"), v1, v2, dir))
352 	{
353 		mglData *d = dynamic_cast<mglData *>(var);
354 		if(d)	d->Fill(v1.toDouble(), v2.toDouble(), dir[0].toLatin1());
355 		mglDataC *dc = dynamic_cast<mglDataC *>(var);
356 		if(dc)	dc->Fill(v1.toDouble(), v2.toDouble(), dir[0].toLatin1());
357 		mglDataV *dv = dynamic_cast<mglDataV *>(var);
358 		if(dv)	dv->Fill(v1.toDouble(), v2.toDouble(), dir[0].toLatin1());
359 		refresh();
360 	}
361 }
362 //-----------------------------------------------------------------------------
norm()363 void DatPanel::norm()
364 {
365 	QString v1("0"), v2("1"), how;
366 	if(sizesDialog(_("UDAV - Normalize data"), _("Enter range for final data"), _("From"), _("To"), _("Symmetrical?"), v1, v2, how))
367 	{
368 		mglData *d = dynamic_cast<mglData *>(var);
369 		if(d)	d->Norm(v1.toDouble(), v2.toDouble(), (how=="on" || how.contains('s')));
370 		refresh();
371 	}
372 }
373 //-----------------------------------------------------------------------------
normsl()374 void DatPanel::normsl()
375 {
376 	QString v1("0"), v2("1"), dir("z");
377 	if(sizesDialog(_("UDAV - Normalize by slice"), _("Enter range for final data"), _("From"), _("To"), _("Direction"), v1, v2, dir))
378 	{
379 		mglData *d = dynamic_cast<mglData *>(var);
380 		if(d)	d->NormSl(v1.toDouble(), v2.toDouble(), dir[0].toLatin1());
381 		refresh();
382 	}
383 }
384 //-----------------------------------------------------------------------------
create()385 void DatPanel::create()
386 {
387 	QString mx, my("1"), mz("1");
388 	if(sizesDialog(_("UDAV - Clear data"), _("Enter new data sizes"), _("X-size"), _("Y-size"), _("Z-size"), mx, my, mz))
389 	{
390 		mglData *d = dynamic_cast<mglData *>(var);
391 		if(d)	d->Create(mx.toInt(), my.toInt(), mz.toInt());
392 		mglDataC *c = dynamic_cast<mglDataC *>(var);
393 		if(c)	c->Create(mx.toInt(), my.toInt(), mz.toInt());
394 		refresh();	updateDataItems();
395 	}
396 }
397 //-----------------------------------------------------------------------------
reSize()398 void DatPanel::reSize()
399 {
400 	QString mx, my, mz;
401 	mx.asprintf("%d",nx);	my.asprintf("%d",ny);	mz.asprintf("%d",nz);
402 	if(sizesDialog(_("UDAV - Resize data"), _("Enter new data sizes"), _("X-size"), _("Y-size"), _("Z-size"), mx, my, mz))
403 	{
404 		mglData *d = dynamic_cast<mglData *>(var);
405 		if(d)	d->Set(d->Resize(mx.toInt(), my.toInt(), mz.toInt()));
406 		refresh();	updateDataItems();
407 	}
408 }
409 //-----------------------------------------------------------------------------
squize()410 void DatPanel::squize()
411 {
412 	QString mx("1"), my("1"), mz("1");
413 	if(sizesDialog(_("UDAV - Squeeze data"), _("Enter step of saved points. For example, '1' save all, '2' save each 2nd point, '3' save each 3rd and so on."), _("X-direction"), _("Y-direction"), _("Z-direction"), mx, my, mz))
414 	{
415 		mglData *d = dynamic_cast<mglData *>(var);
416 		if(d)	d->Squeeze(mx.toInt(), my.toInt(), mz.toInt());
417 		refresh();	updateDataItems();
418 	}
419 }
420 //-----------------------------------------------------------------------------
crop()421 void DatPanel::crop()
422 {
423 	QString n1("1"), n2("1"), dir;
424 	if(sizesDialog(_("UDAV - Crop data"), _("Enter range of saved date."), _("From"), _("To"), _("Direction"), n1, n2, dir))
425 	{
426 		mglData *d = dynamic_cast<mglData *>(var);
427 		if(d)	d->Squeeze(n1.toInt(), n2.toInt(), dir[0].toLatin1());
428 		refresh();	updateDataItems();
429 	}
430 }
431 //-----------------------------------------------------------------------------
rearrange()432 void DatPanel::rearrange()
433 {
434 	QString mx, my, mz;
435 	mx.asprintf("%d",nx);	my.asprintf("%d",ny);	mz.asprintf("%d",nz);
436 	if(sizesDialog(_("UDAV - Rearrange data"), _("Enter new data sizes"), _("X-size"), _("Y-size"), _("Z-size"), mx, my, mz))
437 	{
438 		mglData *d = dynamic_cast<mglData *>(var);
439 		if(d)	d->Rearrange(mx.toInt(), my.toInt(), mz.toInt());
440 		refresh();	updateDataItems();
441 	}
442 }
443 //-----------------------------------------------------------------------------
hist()444 void DatPanel::hist()
445 {
446 	QLabel *l;
447 	QLineEdit *id, *v1, *v2;
448 	QSpinBox *nm;
449 	QPushButton *b;
450 	QDialog *d = new QDialog(this);	d->setWindowTitle(_("UDAV - Make histogram"));
451 	QGridLayout *g = new QGridLayout(d);
452 	l = new QLabel(_("From"), d);	g->addWidget(l,0,0);
453 	l = new QLabel(_("To"), d);	g->addWidget(l,0,1);
454 	v1 = new QLineEdit(d);	g->addWidget(v1,1,0);
455 	v2 = new QLineEdit(d);	g->addWidget(v2,1,1);
456 	l = new QLabel(_("Number of points"), d);	g->addWidget(l,2,0);
457 	l = new QLabel(_("Put in variable"), d);	g->addWidget(l,2,1);
458 	nm = new QSpinBox(d);	nm->setRange(2,8192);	g->addWidget(nm,3,0);
459 	id = new QLineEdit(d);	nm->setSingleStep(10);	g->addWidget(id,3,1);
460 	b = new QPushButton(_("Cancel"), d);	g->addWidget(b,4,0);
461 	connect(b, SIGNAL(clicked()), d, SLOT(reject()));
462 	b = new QPushButton(_("OK"), d);		g->addWidget(b,4,1);
463 	connect(b, SIGNAL(clicked()), d, SLOT(accept()));	b->setDefault(true);
464 	// now execute dialog and get values
465 	bool res = d->exec();
466 	if(res && !v1->text().isEmpty() && !v2->text().isEmpty() && !id->text().isEmpty())
467 	{
468 		mglData *vv = dynamic_cast<mglData*>(parser.AddVar(id->text().toLocal8Bit().constData()));
469 		if(vv)	vv->Set(mgl_data_hist(var, nm->value(), v1->text().toDouble(), v2->text().toDouble(),0));
470 		updateDataItems();
471 	}
472 }
473 //-----------------------------------------------------------------------------
first()474 void DatPanel::first()	{	setSlice(0);	}
475 //-----------------------------------------------------------------------------
last()476 void DatPanel::last()	{	setSlice(nz-1);	}
477 //-----------------------------------------------------------------------------
next()478 void DatPanel::next()	{	setSlice(kz+1);	}
479 //-----------------------------------------------------------------------------
prev()480 void DatPanel::prev()	{	setSlice(kz-1);	}
481 //-----------------------------------------------------------------------------
gosl()482 void DatPanel::gosl()
483 {
484 	bool ok;
485 	QString s = QInputDialog::getText(this, _("UDAV - Go to slice"), _("Enter slice id:"), QLineEdit::Normal, "0", &ok);
486 	if(ok)	setSlice(s.toInt());
487 }
488 //-----------------------------------------------------------------------------
setNz(int nz)489 void DatPanel::setNz(int nz)	{	sb->setMaximum(nz-1);	}
490 //-----------------------------------------------------------------------------
sizesDialog(const QString & cap,const QString & lab,const QString & desc1,const QString & desc2,const QString & desc3,QString & val1,QString & val2,QString & val3)491 bool DatPanel::sizesDialog(const QString &cap, const QString &lab, const QString &desc1, const QString &desc2, const QString &desc3, QString &val1, QString &val2, QString &val3)
492 {
493 	QLabel *l;
494 	QLineEdit *f1, *f2, *f3;
495 	QPushButton *b;
496 	QDialog *d = new QDialog(this);
497 	d->setWindowTitle(cap);
498 	QVBoxLayout *v = new QVBoxLayout(d);
499 	l = new QLabel(lab, d);	v->addWidget(l);
500 	l = new QLabel(_("NOTE: All fields must be filled!"), d);	v->addWidget(l);
501 	QGridLayout *g = new QGridLayout();	v->addLayout(g);
502 	l = new QLabel(desc1, d);		g->addWidget(l, 0, 0);
503 	l = new QLabel(desc2, d);		g->addWidget(l, 0, 1);
504 	l = new QLabel(desc3, d);		g->addWidget(l, 0, 2);
505 	f1 = new QLineEdit(val1, d);	g->addWidget(f1, 1, 0);
506 	f2 = new QLineEdit(val2, d);	g->addWidget(f2, 1, 1);
507 	f3 = new QLineEdit(val3, d);	g->addWidget(f3, 1, 2);
508 	QHBoxLayout *h = new QHBoxLayout();	v->addLayout(h);
509 	h->addStretch(1);
510 	b = new QPushButton(_("Cancel"), d);	h->addWidget(b);
511 	connect(b, SIGNAL(clicked()), d, SLOT(reject()));
512 	b = new QPushButton(_("OK"), d);		h->addWidget(b);
513 	connect(b, SIGNAL(clicked()), d, SLOT(accept()));
514 	b->setDefault(true);
515 	// now execute dialog and get values
516 	bool res = d->exec();
517 	val1 = f1->text();	val2 = f2->text();	val3 = f3->text();
518 	if(val1.isEmpty() || val2.isEmpty() || val3.isEmpty())	res = false;
519 	delete d;
520 	return res;
521 }
522 //-----------------------------------------------------------------------------
523 #include "xpm/size.xpm"
524 #include "xpm/crop.xpm"
525 #include "xpm/squize.xpm"
526 #include "xpm/hist.xpm"
527 #include "xpm/oper_dir.xpm"
528 #include "xpm/oper_of.xpm"
529 //-----------------------------------------------------------------------------
newdat()530 void DatPanel::newdat()
531 {
532 	QLabel *l;
533 	QLineEdit *f1, *f2;
534 	QPushButton *b;
535 	QDialog *d = new QDialog(this);
536 	d->setWindowTitle(_("UDAV - make new data"));
537 	QVBoxLayout *v = new QVBoxLayout(d);
538 	QComboBox *c = new QComboBox(d);	v->addWidget(c);
539 	c->addItem(_("Sum along direction(s)"));
540 	c->addItem(_("Min along direction(s)"));
541 	c->addItem(_("Max along direction(s)"));
542 	c->addItem(_("Momentum along 'x' for function"));
543 	c->addItem(_("Momentum along 'y' for function"));
544 	c->addItem(_("Momentum along 'z' for function"));
545 	c->setCurrentIndex(0);
546 
547 	f1 = new QLineEdit("z",d);	v->addWidget(f1);
548 	QCheckBox *cb = new QCheckBox(_("Put into this data array"), d);	v->addWidget(cb);
549 	l = new QLabel(_("or enter name for new variable"), d);	v->addWidget(l);
550 	f2 = new QLineEdit(d);		v->addWidget(f2);
551 	QHBoxLayout *h = new QHBoxLayout();	v->addLayout(h);	h->addStretch(1);
552 	b = new QPushButton(_("Cancel"), d);	h->addWidget(b);
553 	connect(b, SIGNAL(clicked()), d, SLOT(reject()));
554 	b = new QPushButton(_("OK"), d);		h->addWidget(b);
555 	connect(b, SIGNAL(clicked()), d, SLOT(accept()));
556 	b->setDefault(true);
557 	// now execute dialog and get values
558 	bool res = d->exec();
559 	QString 	val = f1->text(), mgl;
560 	int k = c->currentIndex();
561 	QString self = QString::fromWCharArray(var->Name());
562 	if(res)
563 	{
564 		if(k<0)
565 		{
566 			QMessageBox::warning(d, _("UDAV - make new data"),
567 				_("No action is selected. Do nothing."));
568 			return;
569 		}
570 		if(val.isEmpty())
571 		{
572 			QMessageBox::warning(d, _("UDAV - make new data"),
573 				_("No direction/formula is entered. Do nothing."));
574 			return;
575 		}
576 		if(cb->isChecked())	k += 6;
577 		QString name = f2->text();
578 		switch(k)
579 		{
580 		case 0:	mgl = "sum "+name+" "+self+" '"+val+"'";	break;
581 		case 1:	mgl = "min "+name+" "+self+" '"+val+"'";	break;
582 		case 2:	mgl = "max "+name+" "+self+" '"+val+"'";	break;
583 		case 3:	mgl = "momentum "+name+" "+self+" 'x' '"+val+"'";	break;
584 		case 4:	mgl = "momentum "+name+" "+self+" 'y' '"+val+"'";	break;
585 		case 5:	mgl = "momentum "+name+" "+self+" 'z' '"+val+"'";	break;
586 		case 6:	mgl = "copy "+self+" {sum "+self+" '"+val+"'}";	break;
587 		case 7:	mgl = "copy "+self+" {min "+self+" '"+val+"'}";	break;
588 		case 8:	mgl = "copy "+self+" {max "+self+" '"+val+"'}";	break;
589 		case 9:	mgl = "copy "+self+" {momentum "+self+" 'x' '"+val+"'}";	break;
590 		case 10:	mgl = "copy "+self+" {momentum "+self+" 'y' '"+val+"'}";	break;
591 		case 11:	mgl = "copy "+self+" {momentum "+self+" 'z' '"+val+"'}";	break;
592 		}
593 	}
594 	if(!mgl.isEmpty())
595 	{
596 		mglGraph gr;
597 		parser.Execute(&gr,mgl.toLocal8Bit().constData());
598 		if(k>=6)	opers += mgl+"\n";
599 		updateDataItems();
600 	}
601 }
602 //-----------------------------------------------------------------------------
oper()603 void DatPanel::oper()
604 {
605 	QLineEdit *f1;
606 	QPushButton *b;
607 	QDialog *d = new QDialog(this);
608 	d->setWindowTitle(_("UDAV - change data"));
609 	QVBoxLayout *v = new QVBoxLayout(d);
610 	QComboBox *c = new QComboBox(d);	v->addWidget(c);
611 	c->addItem(_("Fill data by formula"));
612 	c->addItem(_("Transpose data with new dimensions"));
613 	c->addItem(_("Smooth data along direction(s)"));
614 	c->addItem(_("Summarize data along direction(s)"));
615 	c->addItem(_("Integrate data along direction(s)"));
616 	c->addItem(_("Differentiate data along direction(s)"));
617 	c->addItem(_("Laplace transform along direction(s)"));
618 	c->addItem(_("Swap data along direction(s)"));
619 	c->addItem(_("Mirror data along direction(s)"));
620 	c->addItem(_("Sin-Fourier transform along direction(s)"));
621 	c->addItem(_("Cos-Fourier transform along direction(s)"));
622 	c->addItem(_("Hankel transform along direction(s)"));
623 	c->addItem(_("Sew data along direction(s)"));
624 	c->addItem(_("Find envelope along direction(s)"));
625 	c->setCurrentIndex(0);
626 
627 	f1 = new QLineEdit("z",d);	v->addWidget(f1);
628 	QHBoxLayout *h = new QHBoxLayout();	v->addLayout(h);	h->addStretch(1);
629 	b = new QPushButton(_("Cancel"), d);	h->addWidget(b);
630 	connect(b, SIGNAL(clicked()), d, SLOT(reject()));
631 	b = new QPushButton(_("OK"), d);		h->addWidget(b);
632 	connect(b, SIGNAL(clicked()), d, SLOT(accept()));
633 	b->setDefault(true);
634 	// now execute dialog and get values
635 	bool res = d->exec();
636 	QString 	val = f1->text(), mgl;
637 	int k = c->currentIndex();
638 	QString self = QString::fromWCharArray(var->Name());
639 	if(res)
640 	{
641 		if(k<0)
642 		{
643 			QMessageBox::warning(d, _("UDAV - make new data"),
644 				_("No action is selected. Do nothing."));
645 			return;
646 		}
647 		switch(k)
648 		{
649 		case 0:	mgl = "modify "+self+" '"+val+"'";	break;
650 		case 1:	mgl = "transpose "+self+" '"+val+"'";	break;
651 		case 2:	mgl = "smooth "+self+" '"+val+"'";	break;
652 		case 3:	mgl = "cumsum "+self+" '"+val+"'";	break;
653 		case 4:	mgl = "integrate "+self+" '"+val+"'";	break;
654 		case 5:	mgl = "diff "+self+" '"+val+"'";	break;
655 		case 6:	mgl = "diff2 "+self+" '"+val+"'";	break;
656 		case 7:	mgl = "swap "+self+" '"+val+"'";	break;
657 		case 8:	mgl = "mirror "+self+" '"+val+"'";	break;
658 		case 9:	mgl = "sinfft "+self+" '"+val+"'";	break;
659 		case 10:	mgl = "cosfft "+self+" '"+val+"'";	break;
660 		case 11:	mgl = "hankel "+self+" '"+val+"'";	break;
661 		case 12:	mgl = "sew "+self+" '"+val+"'";	break;
662 		case 13:	mgl = "envelop "+self+" '"+val+"'";	break;
663 		}
664 	}
665 	if(!mgl.isEmpty())
666 	{
667 		mglGraph gr;
668 		parser.Execute(&gr,mgl.toLocal8Bit().constData());
669 		opers += mgl+"\n";
670 		updateDataItems();
671 	}
672 }
673 //-----------------------------------------------------------------------------
toolTop(QBoxLayout * l)674 void DatPanel::toolTop(QBoxLayout *l)
675 {
676 	QAction *a;
677 	QMenu *o;
678 	QToolButton *bb;
679 
680 	// file menu
681 	o = menu->addMenu(_("File"));
682 	a = new QAction(QPixmap(":/png/document-open.png"), _("Load data"), this);
683 	connect(a, SIGNAL(triggered()), this, SLOT(load()));
684 	a->setToolTip(_("Load data from file. Data will be deleted only\nat exit but UDAV will not ask to save it (Ctrl+Shift+O)."));
685 	a->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_O);	o->addAction(a);
686 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
687 
688 	a = new QAction(QPixmap(":/png/document-save.png"), _("Save data"), this);
689 	connect(a, SIGNAL(triggered()), this, SLOT(save()));
690 	a->setToolTip(_("Save data to a file (Ctrl+Shift+S)."));
691 	a->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_S);	o->addAction(a);
692 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
693 
694 //	o->addSeparator();	bb->addSeparator();
695 //	a = new QAction(QPixmap(insert_xpm), _("Insert as list"), this);
696 //	connect(a, SIGNAL(triggered()), this, SLOT(list()));
697 //	o->addAction(a);
698 //	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
699 
700 
701 	a = new QAction(QPixmap(":/png/office-chart-line.png"), _("Plot data"), this);
702 	connect(a, SIGNAL(triggered()), this, SLOT(plot()));
703 	a->setToolTip(_("Plot data in new script window. You may select the kind\nof plot, its style and so on."));
704 	o->addAction(a);
705 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
706 
707 	a = new QAction(QPixmap(":/png/edit-copy.png"), _("Copy data"), this);
708 	connect(a, SIGNAL(triggered()), this, SLOT(copy()));
709 	a->setToolTip(_("Copy range of numbers to clipboard (Ctrl+Shift+C)."));
710 	a->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_C);	o->addAction(a);
711 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
712 
713 	a = new QAction(QPixmap(":/png/edit-paste.png"), _("Paste data"), this);
714 	connect(a, SIGNAL(triggered()), this, SLOT(copy()));
715 	a->setToolTip(_("Paste range of numbers from clipboard (Ctrl+Shift+P)."));
716 	a->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_V);	o->addAction(a);
717 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
718 
719 	// navigation menu
720 	o = menu->addMenu(_("Navigation"));
721 	a = new QAction(QPixmap(":/png/go-first.png"), _("First slice"), this);
722 	connect(a, SIGNAL(triggered()), this, SLOT(first()));
723 	a->setToolTip(_("Go to first slice for 3D data (Ctrl-F1)."));
724 	a->setShortcut(Qt::CTRL+Qt::Key_F1);	o->addAction(a);
725 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
726 
727 	a = new QAction(QPixmap(":/png/go-previous.png"), _("Prev slice"), this);
728 	connect(a, SIGNAL(triggered()), this, SLOT(prev()));
729 	a->setToolTip(_("Go to the previous slice for 3D data."));
730 	o->addAction(a);
731 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
732 
733 	sb = new QSpinBox(this);
734 	l->addWidget(sb);	sb->setRange(0,0);
735 	sb->setToolTip(_("Go to the specified slice for 3D data."));
736 	connect(sb, SIGNAL(valueChanged(int)), this, SLOT(setSlice(int)));
737 	connect(this, SIGNAL(sliceChanged(int)), sb, SLOT(setValue(int)));
738 	connect(this, SIGNAL(nzChanged(int)), this, SLOT(setNz(int)));
739 
740 	a = new QAction(_("Go to slice"), this);
741 	connect(a, SIGNAL(triggered()), this, SLOT(gosl()));
742 	a->setToolTip(_("Go to the specified slice for 3D data."));
743 	o->addAction(a);
744 
745 	a = new QAction(QPixmap(":/png/go-next.png"), _("Next slice"), this);
746 	connect(a, SIGNAL(triggered()), this, SLOT(next()));
747 	a->setToolTip(_("Go to the next slice for 3D data."));
748 	o->addAction(a);
749 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
750 
751 	a = new QAction(QPixmap(":/png/go-last.png"), _("Last slice"), this);
752 	connect(a, SIGNAL(triggered()), this, SLOT(last()));
753 	a->setToolTip(_("Go to last slice for 3D data (Ctrl-F4)."));
754 	a->setShortcut(Qt::CTRL+Qt::Key_F4);	o->addAction(a);
755 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
756 }
757 //-----------------------------------------------------------------------------
toolLeft(QBoxLayout * l)758 void DatPanel::toolLeft(QBoxLayout *l)
759 {
760 	QAction *a;
761 	QMenu *o;
762 	QToolButton *bb;
763 
764 	// size menu
765 	o = menu->addMenu(_("Sizes"));
766 	a = new QAction(QPixmap(":/png/document-new.png"), _("Create new"), this);
767 	connect(a, SIGNAL(triggered()), this, SLOT(create()));
768 	a->setToolTip(_("Recreate the data with new sizes and fill it by zeros (Ctrl+Shift+N)."));
769 	a->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_N);	o->addAction(a);
770 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
771 
772 	a = new QAction(QPixmap(size_xpm), _("Resize"), this);
773 	connect(a, SIGNAL(triggered()), this, SLOT(reSize()));
774 	a->setToolTip(_("Resize (interpolate) the data to specified sizes (Ctrl+Shift+R)."));
775 	a->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_R);	o->addAction(a);
776 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
777 
778 	a = new QAction(QPixmap(squize_xpm), _("Squeeze"), this);
779 	connect(a, SIGNAL(triggered()), this, SLOT(squize()));
780 	a->setToolTip(_("Keep only each n-th element of the data array."));
781 	o->addAction(a);
782 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
783 
784 	a = new QAction(QPixmap(crop_xpm), _("Crop"), this);
785 	connect(a, SIGNAL(triggered()), this, SLOT(crop()));
786 	a->setToolTip(_("Crop the data edges. Useful to cut off the zero-filled area."));
787 	o->addAction(a);
788 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
789 
790 	a = new QAction(QPixmap(oper_of_xpm), _("Transform"), this);
791 	connect(a, SIGNAL(triggered()), this, SLOT(newdat()));
792 	a->setToolTip(_("Transform data along dimension(s) (Ctrl+Shift+T)."));
793 	a->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_T);	o->addAction(a);
794 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
795 
796 	a = new QAction(QPixmap(oper_dir_xpm), _("Make new (Ctrl+Shift+M)"), this);
797 	connect(a, SIGNAL(triggered()), this, SLOT(oper()));
798 	a->setToolTip(_("Make another data."));
799 	a->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_M);	o->addAction(a);
800 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
801 
802 	a = new QAction(QPixmap(hist_xpm), _("Histogram (Ctrl+Shift+H)"), this);
803 	connect(a, SIGNAL(triggered()), this, SLOT(hist()));
804 	a->setToolTip(_("Find histogram of data."));
805 	a->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_H);	o->addAction(a);
806 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
807 
808 /*	a = new QAction(QPixmap(":/png/view-refresh.png"), _("Refresh"), this);
809 	connect(a, SIGNAL(triggered()), this, SLOT(refresh()));
810 	a->setToolTip(_("Refresh data values."));
811 	o->addAction(a);
812 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);*/
813 
814 /*	a = new QAction(_("Rearrange"), this);	// TODO: move in generalized dialog
815 	connect(a, SIGNAL(triggered()), this, SLOT(rearrange()));
816 	a->setToolTip(_("Rearrange data sizes without changing data values."));
817 	o->addAction(a);
818 	a = new QAction(_("Fill in range"), this);
819 	connect(a, SIGNAL(triggered()), this, SLOT(inrange()));
820 	a->setToolTip(_("Fill data equidistantly from one value to another."));
821 	o->addAction(a);
822 	a = new QAction(_("Normalize"), this);
823 	connect(a, SIGNAL(triggered()), this, SLOT(norm()));
824 	a->setToolTip(_("Normalize data so that its minimal\nand maximal values be in specified range."));
825 	o->addAction(a);
826 	a = new QAction(_("Norm. slices"), this);
827 	connect(a, SIGNAL(triggered()), this, SLOT(normsl()));
828 	a->setToolTip(_("Normalize each data slice perpendicular to some direction\nso that its minimal and maximal values be in specified range."));
829 	o->addAction(a);*/
830 
831 	l->addStretch(1);
832 
833 	a = new QAction(QPixmap(":/png/tab-close.png"), _("Close tab"), this);
834 	connect(a, SIGNAL(triggered()), this, SLOT(close()));
835 	a->setToolTip(_("Close this data tab."));
836 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
837 }
838 //-----------------------------------------------------------------------------
dataName()839 QString DatPanel::dataName()	{	return QString::fromWCharArray(var->Name());	}
840 //-----------------------------------------------------------------------------
841