1 
2 ///////////////////////////////////////////////////////////
3 //                                                       //
4 //                         SAGA                          //
5 //                                                       //
6 //      System for Automated Geoscientific Analyses      //
7 //                                                       //
8 //                    User Interface                     //
9 //                                                       //
10 //                    Program: SAGA                      //
11 //                                                       //
12 //-------------------------------------------------------//
13 //                                                       //
14 //                      Helper.cpp                       //
15 //                                                       //
16 //          Copyright (C) 2005 by Olaf Conrad            //
17 //                                                       //
18 //-------------------------------------------------------//
19 //                                                       //
20 // This file is part of 'SAGA - System for Automated     //
21 // Geoscientific Analyses'. SAGA is free software; you   //
22 // can redistribute it and/or modify it under the terms  //
23 // of the GNU General Public License as published by the //
24 // Free Software Foundation, either version 2 of the     //
25 // License, or (at your option) any later version.       //
26 //                                                       //
27 // SAGA is distributed in the hope that it will be       //
28 // useful, but WITHOUT ANY WARRANTY; without even the    //
29 // implied warranty of MERCHANTABILITY or FITNESS FOR A  //
30 // PARTICULAR PURPOSE. See the GNU General Public        //
31 // License for more details.                             //
32 //                                                       //
33 // You should have received a copy of the GNU General    //
34 // Public License along with this program; if not, see   //
35 // <http://www.gnu.org/licenses/>.                       //
36 //                                                       //
37 //-------------------------------------------------------//
38 //                                                       //
39 //    contact:    Olaf Conrad                            //
40 //                Institute of Geography                 //
41 //                University of Goettingen               //
42 //                Goldschmidtstr. 5                      //
43 //                37077 Goettingen                       //
44 //                Germany                                //
45 //                                                       //
46 //    e-mail:     oconrad@saga-gis.org                   //
47 //                                                       //
48 ///////////////////////////////////////////////////////////
49 
50 //---------------------------------------------------------
51 #include <wx/config.h>
52 #include <wx/cursor.h>
53 #include <wx/utils.h>
54 #include <wx/mimetype.h>
55 #include <wx/filename.h>
56 #include <wx/protocol/http.h>
57 #include <wx/gdicmn.h>
58 #include <wx/colour.h>
59 #include <wx/settings.h>
60 
61 #include "helper.h"
62 
63 #include "res_dialogs.h"
64 
65 #include "saga.h"
66 #include "saga_frame.h"
67 
68 #include "info.h"
69 #include "info_messages.h"
70 
71 #include "wksp_tool.h"
72 
73 
74 ///////////////////////////////////////////////////////////
75 //														 //
76 //														 //
77 //														 //
78 ///////////////////////////////////////////////////////////
79 
80 //---------------------------------------------------------
Get_SignificantDecimals_String(double Value,int maxDecimals)81 wxString	Get_SignificantDecimals_String(double Value, int maxDecimals)
82 {
83 	return( wxString::Format("%.*f", SG_Get_Significant_Decimals(Value, maxDecimals), Value) );
84 }
85 
86 //---------------------------------------------------------
Get_nBytes_asString(double nBytes,int Precision)87 wxString	Get_nBytes_asString(double nBytes, int Precision)
88 {
89 	if( nBytes < 1024 )
90 	{
91 		return( wxString::Format("%.0f %s", nBytes, _TL("bytes")) );
92 	}
93 
94 	double	dSize	= nBytes / 1024.0;
95 
96 	if( dSize < 1024 )
97 	{
98 		return( wxString::Format("%.*f %s", Precision < 0 ? SG_Get_Significant_Decimals(dSize, 20) : Precision, dSize, _TL("kB")) );
99 	}
100 
101 	dSize	/= 1024.0;
102 
103 	if( dSize < 1024 )
104 	{
105 		return( wxString::Format("%.*f %s", Precision < 0 ? SG_Get_Significant_Decimals(dSize, 20) : Precision, dSize, _TL("MB")) );
106 	}
107 
108 	dSize	/= 1024.0;
109 
110 	return( wxString::Format("%.*f %s", Precision < 0 ? SG_Get_Significant_Decimals(dSize, 20) : Precision, dSize, _TL("GB")) );
111 }
112 
113 
114 ///////////////////////////////////////////////////////////
115 //														 //
116 //														 //
117 //														 //
118 ///////////////////////////////////////////////////////////
119 
120 //---------------------------------------------------------
Get_FilePath_Relative(const wxString & Directory,const wxString & FileName)121 wxString	Get_FilePath_Relative(const wxString &Directory, const wxString &FileName)
122 {
123 	if( FileName.Find(Directory) != 0 )
124 	{
125 		return( FileName );
126 	}
127 
128 	wxFileName	fn(FileName);
129 
130 	fn.MakeRelativeTo(Directory);
131 
132 	return( fn.GetFullPath() );
133 }
134 
135 //---------------------------------------------------------
Get_FilePath_Absolute(const wxString & Directory,const wxString & FileName)136 wxString	Get_FilePath_Absolute(const wxString &Directory, const wxString &FileName)
137 {
138 	wxFileName	fn(FileName);
139 
140 	if( !fn.IsAbsolute() )
141 	{
142 		fn.MakeAbsolute(Directory);
143 	}
144 
145 	return( fn.GetFullPath() );
146 }
147 
148 
149 ///////////////////////////////////////////////////////////
150 //														 //
151 //														 //
152 //														 //
153 ///////////////////////////////////////////////////////////
154 
155 //---------------------------------------------------------
Get_TableInfo_asHTML(const CSG_Table * pTable)156 wxString		Get_TableInfo_asHTML(const CSG_Table *pTable)
157 {
158 	wxString	s;
159 
160 	if( pTable && pTable->is_Valid() )
161 	{
162 		s	+= wxString::Format("<hr><h4>%s</h4>", _TL("Table Description"));
163 
164 		s	+= wxString::Format("<table border=\"1\"><tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th>",
165 			_TL("Field"),
166 			_TL("Name"),
167 			_TL("Type"),
168 			_TL("Minimum"),
169 			_TL("Maximum"),
170 			_TL("Mean"),
171 			_TL("Standard Deviation")
172 		);
173 
174 		for(int i=0; i<pTable->Get_Field_Count(); i++)
175 		{
176 			s	+= wxString::Format("<tr><td>%d</td><td>%s</td><td>%s</td>",
177 				i + 1,
178 				pTable->Get_Field_Name(i),
179 				SG_Data_Type_Get_Name(pTable->Get_Field_Type(i)).c_str()
180 			);
181 
182 			if( SG_Data_Type_is_Numeric(pTable->Get_Field_Type(i)) )
183 			{
184 				s	+= wxString::Format("<td align=\"right\">%s</td><td align=\"right\">%s</td><td align=\"right\">%s</td><td align=\"right\">%s</td></tr>",
185 					SG_Get_String(pTable->Get_Minimum(i), -6).c_str(),
186 					SG_Get_String(pTable->Get_Maximum(i), -6).c_str(),
187 					SG_Get_String(pTable->Get_Mean   (i), -6).c_str(),
188 					SG_Get_String(pTable->Get_StdDev (i), -6).c_str()
189 				);
190 			}
191 			else
192 			{
193 				s	+= wxString::Format("<td></td><td></td><td></td><td></td></tr>");
194 			}
195 		}
196 
197 		s	+= "</table>";
198 	}
199 
200 	return( s );
201 }
202 
203 
204 ///////////////////////////////////////////////////////////
205 //														 //
206 //														 //
207 //														 //
208 ///////////////////////////////////////////////////////////
209 
210 //---------------------------------------------------------
Get_Rect_Scaled(const wxRect & Rect,double Scale)211 wxRect				Get_Rect_Scaled					(const wxRect &Rect, double Scale)
212 {
213 	wxRect	r;
214 
215 	r.x      = (int)(0.5 + Scale * Rect.x     );
216 	r.y      = (int)(0.5 + Scale * Rect.y     );
217 	r.width  = (int)(0.5 + Scale * Rect.width );
218 	r.height = (int)(0.5 + Scale * Rect.height);
219 
220 	return( r );
221 }
222 
223 
224 ///////////////////////////////////////////////////////////
225 //														 //
226 //														 //
227 //														 //
228 ///////////////////////////////////////////////////////////
229 
230 //---------------------------------------------------------
Set_Font(CSG_Parameter * pFont,wxFont & Font,wxColour & Colour)231 bool	Set_Font(CSG_Parameter *pFont, wxFont &Font, wxColour &Colour)
232 {
233 	if( !pFont || pFont->Get_Type() != PARAMETER_TYPE_Font )
234 	{
235 		return( false );
236 	}
237 
238 	Colour.Set(
239 		SG_GET_R(pFont->asColor()),
240 		SG_GET_G(pFont->asColor()),
241 		SG_GET_B(pFont->asColor())
242 	);
243 
244 	Font.SetNativeFontInfo(pFont->asFont());
245 
246 	return( true );
247 }
248 
249 //---------------------------------------------------------
Set_Font(const wxFont & Font,wxColour Colour,CSG_Parameter * pFont)250 bool	Set_Font(const wxFont &Font, wxColour Colour, CSG_Parameter *pFont)
251 {
252 	if( !pFont || pFont->Get_Type() != PARAMETER_TYPE_Font )
253 	{
254 		return( false );
255 	}
256 
257 	pFont->Set_Value((int)SG_GET_RGB(Colour.Red(), Colour.Green(), Colour.Blue()));
258 	pFont->Set_Value(Font.GetNativeFontInfoDesc().wx_str());
259 
260 	return( true );
261 }
262 
263 //---------------------------------------------------------
Get_Font(CSG_Parameter * pFont)264 wxFont	Get_Font(CSG_Parameter *pFont)
265 {
266 	wxColour	Colour;
267 	wxFont		Font;
268 
269 	Set_Font(pFont, Font, Colour);
270 
271 	return( Font );
272 }
273 
274 
275 ///////////////////////////////////////////////////////////
276 //														 //
277 //														 //
278 //														 //
279 ///////////////////////////////////////////////////////////
280 
281 //---------------------------------------------------------
Get_Color_asWX(int Color)282 wxColour	Get_Color_asWX(int Color)
283 {
284 	return( wxColour(SG_GET_R(Color), SG_GET_G(Color), SG_GET_B(Color)) );
285 }
286 
287 //---------------------------------------------------------
Get_Color_asInt(wxColour Color)288 int			Get_Color_asInt(wxColour Color)
289 {
290 	return( SG_GET_RGB(Color.Red(), Color.Green(), Color.Blue()) );
291 }
292 
293 //---------------------------------------------------------
SYS_Get_Color(wxSystemColour index)294 wxColour	SYS_Get_Color(wxSystemColour index)
295 {
296 	return( wxSystemSettings::GetColour(index) );
297 }
298 
299 //---------------------------------------------------------
SYS_Set_Color_BG(wxWindow * pWindow,wxSystemColour index)300 void		SYS_Set_Color_BG(wxWindow *pWindow, wxSystemColour index)
301 {
302 	if( pWindow )
303 	{
304 		pWindow->SetBackgroundColour(SYS_Get_Color(index));
305 	}
306 }
307 
308 //---------------------------------------------------------
SYS_Set_Color_BG_Window(wxWindow * pWindow)309 void		SYS_Set_Color_BG_Window(wxWindow *pWindow)
310 {
311 	if( pWindow )
312 	{
313 #if defined(__WXMSW__)
314 		pWindow->SetBackgroundColour(SYS_Get_Color(wxSYS_COLOUR_WINDOW));
315 #else
316 		pWindow->SetBackgroundColour(*wxWHITE);
317 #endif
318 	}
319 }
320 
321 
322 ///////////////////////////////////////////////////////////
323 //														 //
324 //														 //
325 //														 //
326 ///////////////////////////////////////////////////////////
327 
328 //---------------------------------------------------------
MDI_Get_Frame(void)329 wxWindow *	MDI_Get_Frame(void)
330 {
331 	return( g_pSAGA_Frame );
332 }
333 
334 //---------------------------------------------------------
MDI_Get_Def_Position(void)335 wxPoint		MDI_Get_Def_Position(void)
336 {
337 	static int	n	= 0;
338 
339 	int		Height	= wxSystemSettings::GetMetric(wxSYS_CAPTION_Y);
340 
341 	wxPoint	p(n * Height, n * Height);
342 
343 	n	= n < 10 ? n + 1 : 0;
344 
345 	return( p );
346 }
347 
348 //---------------------------------------------------------
MDI_Get_Def_Size(void)349 wxSize		MDI_Get_Def_Size(void)
350 {
351 	return( wxSize(400, 300) );
352 }
353 
354 //---------------------------------------------------------
MDI_Top_Window_Push(wxWindow * pWindow)355 void		MDI_Top_Window_Push(wxWindow *pWindow)
356 {
357 	if( g_pSAGA_Frame )
358 	{
359 		g_pSAGA_Frame->Top_Window_Push(pWindow);
360 	}
361 }
362 
363 //---------------------------------------------------------
MDI_Top_Window_Pop(wxWindow * pWindow)364 void		MDI_Top_Window_Pop(wxWindow *pWindow)
365 {
366 	if( g_pSAGA_Frame )
367 	{
368 		g_pSAGA_Frame->Top_Window_Pop(pWindow);
369 	}
370 }
371 
372 //---------------------------------------------------------
MDI_Get_Top_Window(void)373 wxWindow *	MDI_Get_Top_Window(void)
374 {
375 	return( g_pSAGA_Frame ? g_pSAGA_Frame->Top_Window_Get() : NULL );
376 }
377 
378 
379 ///////////////////////////////////////////////////////////
380 //														 //
381 //														 //
382 //														 //
383 ///////////////////////////////////////////////////////////
384 
385 //---------------------------------------------------------
Set_Buisy_Cursor(bool bOn)386 void		Set_Buisy_Cursor(bool bOn)
387 {
388 	if( g_pSAGA_Frame )
389 	{
390 		g_pSAGA_Frame->SetCursor(bOn ? *wxHOURGLASS_CURSOR : *wxSTANDARD_CURSOR);
391 	}
392 }
393 
394 //---------------------------------------------------------
Do_Beep(int Style)395 void		Do_Beep(int Style)
396 {
397 	switch( Style )
398 	{
399 	case -1:	// no noise...
400 		break;
401 
402 	case 0:	default:
403 #if defined(__WXMSW__)
404 		Beep(330, 100);
405 		Beep(440, 100);
406 		Beep(550, 100);
407 #else
408 //		wxBell();
409 #endif
410 		break;
411 	}
412 }
413 
414 
415 ///////////////////////////////////////////////////////////
416 //														 //
417 //														 //
418 //														 //
419 ///////////////////////////////////////////////////////////
420 
421 //---------------------------------------------------------
MSG_General_Add_Line(void)422 void		MSG_General_Add_Line(void)
423 {
424 	if( g_pINFO )
425 	{
426 		g_pINFO->Get_General()->Add_Line();
427 	}
428 }
429 
430 //---------------------------------------------------------
MSG_General_Add(const wxString & Message,bool bNewLine,bool bTime,TSG_UI_MSG_STYLE Style)431 void		MSG_General_Add(const wxString &Message, bool bNewLine, bool bTime, TSG_UI_MSG_STYLE Style)
432 {
433 	if( g_pINFO )
434 	{
435 		g_pINFO->Get_General()->Add_String(Message, bNewLine, bTime, Style);
436 	}
437 }
438 
439 //---------------------------------------------------------
MSG_Error_Add_Line(void)440 void		MSG_Error_Add_Line(void)
441 {
442 	if( g_pINFO )
443 	{
444 		g_pINFO->Get_Errors()->Add_Line();
445 	}
446 }
447 
448 //---------------------------------------------------------
MSG_Error_Add(const wxString & Message,bool bNewLine,bool bTime,TSG_UI_MSG_STYLE Style)449 void		MSG_Error_Add(const wxString &Message, bool bNewLine, bool bTime, TSG_UI_MSG_STYLE Style)
450 {
451 	if( g_pINFO )
452 	{
453 		g_pINFO->Get_Errors()->Add_String(Message, bNewLine, bTime, Style);
454 	}
455 }
456 
457 //---------------------------------------------------------
MSG_Execution_Add_Line(void)458 void		MSG_Execution_Add_Line(void)
459 {
460 	if( g_pINFO )
461 	{
462 		g_pINFO->Get_Execution()->Add_Line();
463 	}
464 }
465 
466 //---------------------------------------------------------
MSG_Execution_Add(const wxString & Message,bool bNewLine,bool bTime,TSG_UI_MSG_STYLE Style)467 void		MSG_Execution_Add(const wxString &Message, bool bNewLine, bool bTime, TSG_UI_MSG_STYLE Style)
468 {
469 	if( g_pINFO )
470 	{
471 		g_pINFO->Get_Execution()->Add_String(Message, bNewLine, bTime, Style);
472 	}
473 }
474 
475 
476 ///////////////////////////////////////////////////////////
477 //														 //
478 //														 //
479 //														 //
480 ///////////////////////////////////////////////////////////
481 
482 //---------------------------------------------------------
483 bool		g_CONFIG_bSave	= true;
484 
485 //---------------------------------------------------------
CONFIG_Do_Save(bool bOn)486 bool		CONFIG_Do_Save(bool bOn)
487 {
488 	if( g_CONFIG_bSave != bOn )
489 	{
490 		g_CONFIG_bSave	= bOn;
491 
492 		if( g_CONFIG_bSave )
493 		{
494 			wxConfigBase::Get()->Flush();
495 		}
496 	}
497 
498 	return( g_CONFIG_bSave );
499 }
500 
501 //---------------------------------------------------------
CONFIG_Read(const wxString & Group,const wxString & Entry,wxString & Value)502 bool		CONFIG_Read(const wxString &Group, const wxString &Entry, wxString &Value)
503 {
504 	wxConfigBase	*pConfig	= wxConfigBase::Get();
505 
506 	pConfig->SetPath(wxString::Format("/%s", Group));
507 
508 	return( pConfig->Read(Entry, &Value) );
509 }
510 
511 //---------------------------------------------------------
CONFIG_Read(const wxString & Group,const wxString & Entry,long & Value)512 bool		CONFIG_Read(const wxString &Group, const wxString &Entry, long &Value)
513 {
514 	wxConfigBase	*pConfig	= wxConfigBase::Get();
515 
516 	pConfig->SetPath(wxString::Format("/%s", Group));
517 
518 	return( pConfig->Read(Entry, &Value) );
519 }
520 
521 //---------------------------------------------------------
CONFIG_Read(const wxString & Group,const wxString & Entry,double & Value)522 bool		CONFIG_Read(const wxString &Group, const wxString &Entry, double &Value)
523 {
524 	wxConfigBase	*pConfig	= wxConfigBase::Get();
525 
526 	pConfig->SetPath(wxString::Format("/%s", Group));
527 
528 	return( pConfig->Read(Entry, &Value) );
529 }
530 
531 //---------------------------------------------------------
CONFIG_Read(const wxString & Group,const wxString & Entry,bool & Value)532 bool		CONFIG_Read(const wxString &Group, const wxString &Entry, bool &Value)
533 {
534 	wxConfigBase	*pConfig	= wxConfigBase::Get();
535 
536 	pConfig->SetPath(wxString::Format("/%s", Group));
537 
538 	return( pConfig->Read(Entry, &Value) );
539 }
540 
541 //---------------------------------------------------------
CONFIG_Write(const wxString & Group,const wxString & Entry,const wxString & Value)542 bool		CONFIG_Write(const wxString &Group, const wxString &Entry, const wxString &Value)
543 {
544 	if( g_CONFIG_bSave )
545 	{
546 		wxConfigBase	*pConfig	= wxConfigBase::Get();
547 
548 		pConfig->SetPath(wxString::Format("/%s", Group));
549 
550 		return( pConfig->Write(Entry, Value) ? pConfig->Flush() : false );
551 	}
552 
553 	return( true );
554 }
555 
CONFIG_Write(const wxString & Group,const wxString & Entry,const char * Value)556 bool		CONFIG_Write(const wxString &Group, const wxString &Entry, const char *Value)
557 {
558 	return( CONFIG_Write(Group, Entry, wxString(Value)) );
559 }
560 
CONFIG_Write(const wxString & Group,const wxString & Entry,const wchar_t * Value)561 bool		CONFIG_Write(const wxString &Group, const wxString &Entry, const wchar_t *Value)
562 {
563 	return( CONFIG_Write(Group, Entry, wxString(Value)) );
564 }
565 
566 //---------------------------------------------------------
CONFIG_Write(const wxString & Group,const wxString & Entry,long Value)567 bool		CONFIG_Write(const wxString &Group, const wxString &Entry, long Value)
568 {
569 	if( g_CONFIG_bSave )
570 	{
571 		wxConfigBase	*pConfig	= wxConfigBase::Get();
572 
573 		pConfig->SetPath(wxString::Format("/%s", Group));
574 
575 		return( pConfig->Write(Entry, Value) ? pConfig->Flush() : false );
576 	}
577 
578 	return( true );
579 }
580 
581 //---------------------------------------------------------
CONFIG_Write(const wxString & Group,const wxString & Entry,double Value)582 bool		CONFIG_Write(const wxString &Group, const wxString &Entry, double Value)
583 {
584 	if( g_CONFIG_bSave )
585 	{
586 		wxConfigBase	*pConfig	= wxConfigBase::Get();
587 
588 		pConfig->SetPath(wxString::Format("/%s", Group));
589 
590 		return( pConfig->Write(Entry, Value) ? pConfig->Flush() : false );
591 	}
592 
593 	return( true );
594 }
595 
596 //---------------------------------------------------------
CONFIG_Write(const wxString & Group,const wxString & Entry,bool Value)597 bool		CONFIG_Write(const wxString &Group, const wxString &Entry, bool Value)
598 {
599 	if( g_CONFIG_bSave )
600 	{
601 		wxConfigBase	*pConfig	= wxConfigBase::Get();
602 
603 		pConfig->SetPath(wxString::Format("/%s", Group));
604 
605 		return( pConfig->Write(Entry, Value) ? pConfig->Flush() : false );
606 	}
607 
608 	return( true );
609 }
610 
611 //---------------------------------------------------------
CONFIG_Delete(const wxString & Group)612 bool		CONFIG_Delete(const wxString &Group)
613 {
614 	if( g_CONFIG_bSave )
615 	{
616 		wxConfigBase	*pConfig	= wxConfigBase::Get();
617 
618 		return( pConfig->DeleteGroup(Group) ? pConfig->Flush() : false );
619 	}
620 
621 	return( true );
622 }
623 
CONFIG_Delete(const wxString & Group,const wxString & Entry)624 bool		CONFIG_Delete(const wxString &Group, const wxString &Entry)
625 {
626 	if( g_CONFIG_bSave )
627 	{
628 		wxConfigBase	*pConfig	= wxConfigBase::Get();
629 
630 		pConfig->SetPath(wxString::Format("/%s", Group));
631 
632 		return( pConfig->DeleteEntry(Entry) ? pConfig->Flush() : false );
633 	}
634 
635 	return( true );
636 }
637 
638 //---------------------------------------------------------
CONFIG_Read(wxConfigBase * pConfig,CSG_Parameter * pParameter)639 bool		CONFIG_Read(wxConfigBase *pConfig, CSG_Parameter *pParameter)
640 {
641 	long		l;
642 	double		d;
643 	wxString	s, Entry(pParameter->Get_Identifier());
644 
645 	switch( pParameter->Get_Type() )
646 	{
647 	case PARAMETER_TYPE_Bool    :
648 	case PARAMETER_TYPE_Int     :
649 	case PARAMETER_TYPE_Choice  :
650 	case PARAMETER_TYPE_Color   :
651 		return( pConfig->Read(Entry, &l) && pParameter->Set_Value((int)l) );
652 
653 	case PARAMETER_TYPE_Double  :
654 	case PARAMETER_TYPE_Degree  :
655 		return( pConfig->Read(Entry, &d) && pParameter->Set_Value(d) );
656 
657 	case PARAMETER_TYPE_Date    :
658 	case PARAMETER_TYPE_String  :
659 	case PARAMETER_TYPE_Text    :
660 	case PARAMETER_TYPE_FilePath:
661 	case PARAMETER_TYPE_Choices :
662 		return( pConfig->Read(Entry, &s) && pParameter->Set_Value((const SG_Char *)s) );
663 
664 	case PARAMETER_TYPE_Range   :
665 		return(
666 			pConfig->Read(Entry + "_LO", &d) && pParameter->asRange()->Set_Min(d)
667 		&&	pConfig->Read(Entry + "_HI", &d) && pParameter->asRange()->Set_Max(d)
668 		);
669 
670 	case PARAMETER_TYPE_Font    :
671 		return(
672 			pConfig->Read(Entry + "_FONT" , &s) && pParameter->Set_Value((const SG_Char *)s)
673 		&&	pConfig->Read(Entry + "_COLOR", &l) && pParameter->Set_Value((int)l)
674 		);
675 
676 	case PARAMETER_TYPE_Colors  :
677 		return( pConfig->Read(Entry, &s) && pParameter->asColors()->from_Text(&s) );
678 
679 	case PARAMETER_TYPE_Parameters:
680 		return( CONFIG_Read(Entry + "/" + pParameter->Get_Identifier(), pParameter->asParameters()) );
681 
682 	default:
683 		return( false );
684 	}
685 }
686 
687 //---------------------------------------------------------
CONFIG_Read(const wxString & Group,CSG_Parameters * pParameters)688 bool		CONFIG_Read(const wxString &Group, CSG_Parameters *pParameters)
689 {
690 	wxConfigBase	*pConfig	= wxConfigBase::Get();
691 
692 	pConfig->SetPath(wxString::Format("/%s", Group));
693 
694 	for(int i=0; i<pParameters->Get_Count(); i++)
695 	{
696 		CONFIG_Read(pConfig, pParameters->Get_Parameter(i));
697 	}
698 
699 	return( pConfig->Flush() );
700 }
701 
702 //---------------------------------------------------------
CONFIG_Write(wxConfigBase * pConfig,CSG_Parameter * pParameter)703 bool		CONFIG_Write(wxConfigBase *pConfig, CSG_Parameter *pParameter)
704 {
705 	if( g_CONFIG_bSave )
706 	{
707 		wxString	Entry(pParameter->Get_Identifier());
708 
709 		switch( pParameter->Get_Type() )
710 		{
711 		case PARAMETER_TYPE_Bool    :
712 		case PARAMETER_TYPE_Int     :
713 		case PARAMETER_TYPE_Choice  :
714 		case PARAMETER_TYPE_Color   :
715 			return( pConfig->Write(Entry, pParameter->asInt()) );
716 
717 		case PARAMETER_TYPE_Double  :
718 		case PARAMETER_TYPE_Degree  :
719 			return( pConfig->Write(Entry, pParameter->asDouble()) );
720 
721 		case PARAMETER_TYPE_Date    :
722 		case PARAMETER_TYPE_String  :
723 		case PARAMETER_TYPE_Text    :
724 		case PARAMETER_TYPE_FilePath:
725 		case PARAMETER_TYPE_Choices :
726 			return( pConfig->Write(Entry, pParameter->asString()) );
727 
728 		case PARAMETER_TYPE_Range   :
729 			return(
730 				pConfig->Write(Entry + "_LO", pParameter->asRange()->Get_Min())
731 			&&	pConfig->Write(Entry + "_HI", pParameter->asRange()->Get_Max())
732 			);
733 
734 		case PARAMETER_TYPE_Font    :
735 			return(
736 				pConfig->Write(Entry + "_FONT" , (const SG_Char *)pParameter->asPointer())
737 			&&	pConfig->Write(Entry + "_COLOR", pParameter->asInt())
738 			);
739 
740 		case PARAMETER_TYPE_Colors  :
741 			{
742 				CSG_String	s;
743 
744 				return( pParameter->asColors()->to_Text(s) && pConfig->Write(Entry, s.c_str()) );
745 			}
746 
747 		case PARAMETER_TYPE_Parameters:
748 			return( CONFIG_Write(Entry + "/" + pParameter->Get_Identifier(), pParameter->asParameters()) );
749 
750 		default:
751 			return( false );
752 		}
753 	}
754 
755 	return( true );
756 }
757 
758 //---------------------------------------------------------
CONFIG_Write(const wxString & Group,CSG_Parameters * pParameters)759 bool		CONFIG_Write(const wxString &Group, CSG_Parameters *pParameters)
760 {
761 	if( g_CONFIG_bSave )
762 	{
763 		wxConfigBase	*pConfig	= wxConfigBase::Get();
764 
765 		pConfig->SetPath(wxString::Format("/%s", Group));
766 
767 		for(int i=0; i<pParameters->Get_Count(); i++)
768 		{
769 			CONFIG_Write(pConfig, pParameters->Get_Parameter(i));
770 		}
771 
772 		return( pConfig->Flush() );
773 	}
774 
775 	return( true );
776 }
777 
778 
779 ///////////////////////////////////////////////////////////
780 //														 //
781 //														 //
782 //														 //
783 ///////////////////////////////////////////////////////////
784 
785 //---------------------------------------------------------
PROCESS_is_Executing(void)786 bool		PROCESS_is_Executing(void)
787 {
788 	return( g_pTool != NULL );
789 }
790 
791 //---------------------------------------------------------
PROCESS_Wait(void)792 bool		PROCESS_Wait(void)
793 {
794 	if( g_pSAGA )
795 	{
796 		return( g_pSAGA->Process_Wait() );
797 	}
798 
799 	return( true );
800 }
801 
802 //---------------------------------------------------------
PROCESS_Get_Okay(bool bBlink)803 bool		PROCESS_Get_Okay(bool bBlink)
804 {
805 	if( g_pSAGA_Frame )
806 	{
807 		return( g_pSAGA_Frame->Process_Get_Okay(bBlink) );
808 	}
809 
810 	return( true );
811 }
812 
813 //---------------------------------------------------------
PROCESS_Set_Okay(bool bOkay)814 bool		PROCESS_Set_Okay(bool bOkay)
815 {
816 	if( g_pSAGA_Frame )
817 	{
818 		return( g_pSAGA_Frame->Process_Set_Okay(bOkay) );
819 	}
820 
821 	return( true );
822 }
823 
824 //---------------------------------------------------------
PROGRESSBAR_Set_Position(int Position)825 bool		PROGRESSBAR_Set_Position(int Position)
826 {
827 	if( g_pSAGA_Frame )
828 	{
829 		return( g_pSAGA_Frame->ProgressBar_Set_Position(Position) );
830 	}
831 
832 	return( true );
833 }
834 
835 //---------------------------------------------------------
PROGRESSBAR_Set_Position(double Position,double Range)836 bool		PROGRESSBAR_Set_Position(double Position, double Range)
837 {
838 	if( g_pSAGA_Frame )
839 	{
840 		return( g_pSAGA_Frame->ProgressBar_Set_Position(Position, Range) );
841 	}
842 
843 	return( true );
844 }
845 
846 //---------------------------------------------------------
STATUSBAR_Set_Text(const wxString & Text,int iPane)847 void		STATUSBAR_Set_Text(const wxString &Text, int iPane)
848 {
849 	if( g_pSAGA_Frame )
850 	{
851 		g_pSAGA_Frame->StatusBar_Set_Text(Text, iPane);
852 	}
853 }
854 
855 
856 ///////////////////////////////////////////////////////////
857 //														 //
858 //														 //
859 //														 //
860 ///////////////////////////////////////////////////////////
861 
862 //---------------------------------------------------------
Open_Application(const wxString & Reference,const wxString & Mime_Extension)863 bool		Open_Application(const wxString &Reference, const wxString &Mime_Extension)
864 {
865 	if( Reference.IsEmpty() )
866 	{
867 		return( false );
868 	}
869 
870 	if(0&& Reference.Find("ftp:"   ) == 0 )
871 	{
872 		wxString	Directory;
873 
874 		if( DLG_Directory(Directory, _TL("Save to Directory...")) )
875 		{
876 			wxBusyCursor	BusyCursor;
877 
878 			if( SG_FTP_Download(&Directory, &Reference) )
879 			{
880 				DLG_Message_Show_Error(Reference, _TL("FTP download finished..."));
881 
882 				return( true );
883 			}
884 
885 			DLG_Message_Show_Error(Reference, _TL("FTP download failed..."));
886 
887 			return( false );
888 		}
889 	}
890 
891 	if( Reference.Find("ftp:"   ) == 0
892 	||  Reference.Find("file:"  ) == 0
893 	||  Reference.Find("http:"  ) == 0
894 	||  Reference.Find("https:" ) == 0
895 	||  Reference.Find("mailto:") == 0 )
896 	{
897 		return( wxLaunchDefaultBrowser(Reference) );
898 	}
899 
900 	//-----------------------------------------------------
901 	bool	bResult	= false;
902 
903 	wxFileName	FileName(Reference);
904 
905 	if( FileName.IsRelative() )	// very likely that this will not work
906 	{
907 		FileName.MakeAbsolute(g_pSAGA->Get_App_Path());	// this might not work either, but give it a try
908 	}
909 
910 	//-----------------------------------------------------
911 	if( Mime_Extension.IsEmpty() )
912 	{
913 		if( (bResult = wxLaunchDefaultApplication(FileName.GetFullPath())) == false )
914 		{
915 			MSG_Error_Add(wxString::Format("%s:\n%s\n", _TL("failed to launch default application"), FileName.GetFullPath().c_str()));
916 		}
917 	}
918 
919 	//-----------------------------------------------------
920 	else
921 	{
922 		wxFileType	*pFileType	= wxTheMimeTypesManager->GetFileTypeFromExtension(Mime_Extension);
923 
924 		if( pFileType )
925 		{
926 			wxString	Command;
927 
928 			if( !pFileType->GetOpenCommand(&Command, wxFileType::MessageParameters(FileName.GetFullPath(), ""))
929 			||  !(bResult = wxExecute(Command) == 0) )
930 			{
931 				MSG_Error_Add(wxString::Format("%s:\n%s\n", _TL("command execution failed"), Command.c_str()));
932 			}
933 
934 			delete(pFileType);
935 		}
936 	}
937 
938 	return( bResult );
939 }
940 
941 //---------------------------------------------------------
Open_WebBrowser(const wxString & Reference)942 bool		Open_WebBrowser(const wxString &Reference)
943 {
944 	return( wxLaunchDefaultBrowser(Reference) );
945 }
946 
947 
948 ///////////////////////////////////////////////////////////
949 //														 //
950 //														 //
951 //														 //
952 ///////////////////////////////////////////////////////////
953 
954 //---------------------------------------------------------
Get_Online_Tool_Description(const wxString & Library,const wxString & ID)955 wxString Get_Online_Tool_Description(const wxString &Library, const wxString &ID)
956 {
957 	static bool	bBuisy	= false;
958 
959 	wxString	Description;
960 
961 	if( !bBuisy )
962 	{
963 		bBuisy	= true;
964 
965 		wxInputStream	*pStream;
966 		wxHTTP			Server;
967 
968 		wxString	sServer	= "sourceforge.net";
969 		wxString	sPath	= SG_File_Get_Name(&Library, false).c_str();
970 
971 		if( sPath.Find("lib") == 0 )	// remove linux prefix 'lib'
972 		{
973 			sPath.Remove(0, 3);
974 		}
975 
976 		if( !ID.IsEmpty() )
977 		{
978 			sPath	+= "_" + ID;
979 		}
980 
981 		sPath	= "/p/saga-gis/wiki/" + sPath + "/";
982 
983 		if( Server.Connect(sServer) && (pStream = Server.GetInputStream(sPath)) != NULL )
984 		{
985 			while( !pStream->Eof() )
986 			{
987 				Description	+= pStream->GetC();
988 			}
989 
990 			int		n;
991 
992 			if( (n = Description.Find("<div class=\"markdown_content\">")) < 0 )
993 			{
994 				Description.Clear();
995 			}
996 			else
997 			{
998 				Description.Remove(0, n);
999 
1000 				if( (n = Description.Find("</div>")) > 0 )
1001 				{
1002 					Description.Truncate(n + 6);
1003 				}
1004 
1005 				Description.Replace("./attachment"      ,        "http://" + sServer + sPath + "attachment");
1006 				Description.Replace("href=\"/p/saga-gis", "href=\"http://" + sServer + "/p/saga-gis");
1007 				Description.Replace("\n", "");
1008 			}
1009 
1010 			delete(pStream);
1011 		}
1012 
1013 		bBuisy	= false;
1014 	}
1015 
1016 	return( Description );
1017 }
1018 
1019 
1020 ///////////////////////////////////////////////////////////
1021 //														 //
1022 //														 //
1023 //														 //
1024 ///////////////////////////////////////////////////////////
1025 
1026 //---------------------------------------------------------
QGIS_Styles_Import(const CSG_String & File,CSG_Table & Classes)1027 bool QGIS_Styles_Import(const CSG_String &File, CSG_Table &Classes)
1028 {
1029 	CSG_String	Attribute;
1030 
1031 	return( QGIS_Styles_Import(File, Classes, Attribute) );
1032 }
1033 
QGIS_Styles_Import(const CSG_String & File,CSG_Table & Classes,CSG_String & Attribute)1034 bool QGIS_Styles_Import(const CSG_String &File, CSG_Table &Classes, CSG_String &Attribute)
1035 {
1036 	CSG_MetaData	QML;
1037 
1038 	if( !QML.Load(File) || !QML.Cmp_Name("QGIS") )
1039 	{
1040 		SG_UI_Dlg_Error(CSG_String::Format("[%s]: %s", SG_File_Get_Name(File, true).c_str(), _TL("failed to load file")), _TL("QGIS Styles Import"));
1041 
1042 		return( false );
1043 	}
1044 
1045 	//-----------------------------------------------------
1046 	if( QML("renderer-v2")
1047 	&&  QML["renderer-v2"]("categories")
1048 	&&  QML["renderer-v2"]("symbols"   ) )
1049 	{
1050 		QML["renderer-v2"].Get_Property("attr", Attribute);
1051 
1052 		//-----------------------------------------------------
1053 		Classes.Destroy();
1054 
1055 		Classes.Add_Field(_TL("COLOR"      ), SG_DATATYPE_Color );
1056 		Classes.Add_Field(_TL("NAME"       ), SG_DATATYPE_String);
1057 		Classes.Add_Field(_TL("DESCRIPTION"), SG_DATATYPE_String);
1058 		Classes.Add_Field(_TL("MINIMUM"    ), SG_DATATYPE_String);
1059 		Classes.Add_Field(_TL("MAXIMUM"    ), SG_DATATYPE_String);
1060 
1061 		//-----------------------------------------------------
1062 		const CSG_MetaData	&Categories	= QML["renderer-v2"]["categories"];
1063 		const CSG_MetaData	&Symbols	= QML["renderer-v2"]["symbols"   ];
1064 
1065 		for(int i=0; i<Categories.Get_Children_Count(); i++)
1066 		{
1067 			CSG_String	Value, Label, Symbol;
1068 
1069 			if( Categories[i].Get_Property("value" , Value )
1070 			&&  Categories[i].Get_Property("label" , Label )
1071 			&&  Categories[i].Get_Property("symbol", Symbol) )
1072 			{
1073 				CSG_Table_Record	&Class	= *Classes.Add_Record();
1074 
1075 				int	Color	= SG_Color_Get_Random();
1076 
1077 				for(int j=0; j<Symbols.Get_Children_Count(); j++)
1078 				{
1079 					if( Symbols[j].Cmp_Property("name", Symbol) && Symbols[j]("layer") )
1080 					{
1081 						const CSG_MetaData	&Props	= Symbols[j]["layer"];
1082 
1083 						for(int k=0; k<Props.Get_Children_Count(); k++)
1084 						{
1085 							if( Props[k].Cmp_Property("k", "color") )
1086 							{
1087 								CSG_String	Value	= Props[k].Get_Property("v");
1088 
1089 								int	r	= Value.asInt(); Value = Value.AfterFirst(',');
1090 								int	g	= Value.asInt(); Value = Value.AfterFirst(',');
1091 								int	b	= Value.asInt(); Value = Value.AfterFirst(',');
1092 
1093 								Color	= SG_GET_RGB(r, g, b);
1094 							}
1095 						}
1096 
1097 						break;
1098 					}
1099 				}
1100 
1101 				Class.Set_Value(0, Color);	// Color
1102 				Class.Set_Value(1, Label);	// Name
1103 				Class.Set_Value(2, Label);	// Description
1104 				Class.Set_Value(3, Value);	// Minimum
1105 				Class.Set_Value(4, Value);	// Maximum
1106 			}
1107 		}
1108 
1109 		return( Classes.Get_Count() > 0 );
1110 	}
1111 
1112 	//-----------------------------------------------------
1113 	if( QML("pipe")
1114 	&&  QML["pipe"]("rasterrenderer") )
1115 	{
1116 		const CSG_MetaData	&Renderer	= QML["pipe"]["rasterrenderer"];
1117 
1118 		if( Renderer("rastershader")
1119 		&&  Renderer["rastershader"]("colorrampshader")
1120 		&&  Renderer["rastershader"]["colorrampshader"].Get_Children_Count() > 0 )
1121 		{
1122 			const CSG_MetaData	&ColorRamp	= Renderer["rastershader"]["colorrampshader"];
1123 
1124 			bool	bExact	= ColorRamp.Cmp_Property("colorRampType", "EXACT");	// "DISCRETE"
1125 
1126 			Classes.Destroy();
1127 
1128 			Classes.Add_Field(_TL("COLOR"      ), SG_DATATYPE_Color );
1129 			Classes.Add_Field(_TL("NAME"       ), SG_DATATYPE_String);
1130 			Classes.Add_Field(_TL("DESCRIPTION"), SG_DATATYPE_String);
1131 			Classes.Add_Field(_TL("MINIMUM"    ), SG_DATATYPE_Double);
1132 			Classes.Add_Field(_TL("MAXIMUM"    ), SG_DATATYPE_Double);
1133 
1134 			CSG_String	Value("-99999");
1135 
1136 			//---------------------------------------------
1137 			for(int i=0; i<ColorRamp.Get_Children_Count(); i++)
1138 			{
1139 				CSG_String	minVal(Value); Value = ColorRamp[i].Get_Property("value");
1140 
1141 				wxColour	Color; Color.Set(ColorRamp[i].Get_Property("color"));
1142 
1143 				CSG_Table_Record	&Class	= *Classes.Add_Record();
1144 
1145 				Class.Set_Value(0, Get_Color_asInt(Color));	// Color
1146 				Class.Set_Value(1, ColorRamp[i].Get_Property("label"));	// Name
1147 				Class.Set_Value(3, bExact ? Value : minVal);	// Minimum
1148 				Class.Set_Value(4, Value);	// Maximum
1149 			}
1150 
1151 			return( Classes.Get_Count() > 0 );
1152 		}
1153 
1154 		//-------------------------------------------------
1155 		if( Renderer("colorPalette")
1156 		&&  Renderer["colorPalette"].Get_Children_Count() > 0 )
1157 		{
1158 			const CSG_MetaData	&colorPalette	= Renderer["colorPalette"];
1159 
1160 			bool	bExact	= true;	// "DISCRETE"
1161 
1162 			Classes.Destroy();
1163 
1164 			Classes.Add_Field(_TL("COLOR"      ), SG_DATATYPE_Color );
1165 			Classes.Add_Field(_TL("NAME"       ), SG_DATATYPE_String);
1166 			Classes.Add_Field(_TL("DESCRIPTION"), SG_DATATYPE_String);
1167 			Classes.Add_Field(_TL("MINIMUM"    ), SG_DATATYPE_Double);
1168 			Classes.Add_Field(_TL("MAXIMUM"    ), SG_DATATYPE_Double);
1169 
1170 			CSG_String	Value("-99999");
1171 
1172 			//---------------------------------------------
1173 			for(int i=0; i<colorPalette.Get_Children_Count(); i++)
1174 			{
1175 				CSG_String	minVal(Value); Value = colorPalette[i].Get_Property("value");
1176 
1177 				wxColour	Color; Color.Set(colorPalette[i].Get_Property("color"));
1178 
1179 				CSG_Table_Record	&Class	= *Classes.Add_Record();
1180 
1181 				Class.Set_Value(0, Get_Color_asInt(Color));	// Color
1182 				Class.Set_Value(1, colorPalette[i].Get_Property("label"));	// Name
1183 				Class.Set_Value(3, bExact ? Value : minVal);	// Minimum
1184 				Class.Set_Value(4, Value);	// Maximum
1185 			}
1186 
1187 			return( Classes.Get_Count() > 0 );
1188 		}
1189 	}
1190 
1191 	//-----------------------------------------------------
1192 	if( QML("rasterproperties")
1193 	&&  QML["rasterproperties"]("customColorRamp")
1194 	&&  QML["rasterproperties"]["customColorRamp"]("colorRampType")
1195 //	&&  QML["rasterproperties"]["customColorRamp"]["colorRampType"].Cmp_Content("DISCRETE")
1196 	&&  QML["rasterproperties"]["customColorRamp"].Get_Children_Count() > 1 )
1197 	{
1198 		//-------------------------------------------------
1199 		const CSG_MetaData	&ColorRamp	= QML["rasterproperties"]["customColorRamp"];
1200 
1201 		bool	bExact	= ColorRamp("colorRampType") && ColorRamp["colorRampType"].Cmp_Content("DISCRETE");
1202 
1203 		Classes.Destroy();
1204 
1205 		Classes.Add_Field(_TL("COLOR"      ), SG_DATATYPE_Color );
1206 		Classes.Add_Field(_TL("NAME"       ), SG_DATATYPE_String);
1207 		Classes.Add_Field(_TL("DESCRIPTION"), SG_DATATYPE_String);
1208 		Classes.Add_Field(_TL("MINIMUM"    ), SG_DATATYPE_Double);
1209 		Classes.Add_Field(_TL("MAXIMUM"    ), SG_DATATYPE_Double);
1210 
1211 		CSG_String	Value("-99999");
1212 
1213 		//-------------------------------------------------
1214 		for(int i=0; i<ColorRamp.Get_Children_Count(); i++)
1215 		{
1216 			if( ColorRamp[i].Cmp_Name("colorRampEntry") )
1217 			{
1218 				CSG_Table_Record &Class = *Classes.Add_Record();
1219 
1220 				CSG_String	minVal(Value); Value = ColorRamp[i].Get_Property("value");
1221 
1222 				Class.Set_Value(1, ColorRamp[i].Get_Property("label"));	// Name
1223 				Class.Set_Value(3, bExact ? Value : minVal);	// Minimum
1224 				Class.Set_Value(4, Value);	// Maximum
1225 
1226 				if( ColorRamp[i].Get_Property("color", Value) )
1227 				{
1228 					wxColour Color; Color.Set(ColorRamp[i].Get_Property("color"));
1229 
1230 					Class.Set_Value(0, Get_Color_asInt(Color));	// Color
1231 				}
1232 				else
1233 				{
1234 					int	r, g, b;
1235 
1236 					ColorRamp[i].Get_Property("red"  , r);
1237 					ColorRamp[i].Get_Property("green", g);
1238 					ColorRamp[i].Get_Property("blue" , b);
1239 
1240 					Class.Set_Value(0, SG_GET_RGB(r, g, b));	// Color
1241 				}
1242 			}
1243 		}
1244 
1245 		//-------------------------------------------------
1246 		return( Classes.Get_Count() > 0 );
1247 	}
1248 
1249 	//-----------------------------------------------------
1250 	SG_UI_Dlg_Error(CSG_String::Format("[%s]: %s", SG_File_Get_Name(File, true).c_str(), _TL("unsupported format")), _TL("QGIS Styles Import"));
1251 
1252 	return( false );
1253 }
1254 
1255 //---------------------------------------------------------
QGIS_Styles_Export(const CSG_String & File,const CSG_Table & Classes,const CSG_String & Attribute)1256 bool QGIS_Styles_Export(const CSG_String &File, const CSG_Table &Classes, const CSG_String &Attribute)
1257 {
1258 	if( Classes.Get_Count() < 1 )
1259 	{
1260 		return( false );
1261 	}
1262 
1263 	CSG_MetaData	QML; QML.Set_Name("qgis");
1264 
1265 	//-----------------------------------------------------
1266 	if( Attribute.is_Empty() )	// raster
1267 	{
1268 		CSG_MetaData	&RasterProp	= *QML.Add_Child("rasterproperties");
1269 
1270 		RasterProp.Add_Child("mDrawingStyle"         , "SingleBandPseudoColor");
1271 		RasterProp.Add_Child("mColorShadingAlgorithm", "ColorRampShader"      );
1272 		RasterProp.Add_Child("mGrayBandName"         , "Band 1"               );
1273 
1274 		CSG_MetaData	&ColorRamp	= *RasterProp.Add_Child("customColorRamp");
1275 
1276 		ColorRamp.Add_Child("colorRampType", "DISCRETE");
1277 
1278 		for(int i=0; i<Classes.Get_Count(); i++)
1279 		{
1280 			CSG_Table_Record &Class = Classes[i];
1281 
1282 			CSG_MetaData &Entry	= *ColorRamp.Add_Child("colorRampEntry");
1283 
1284 		//	Entry.Add_Property("color", SG_Color_To_Text(Class.asInt(0)));
1285 			Entry.Add_Property("red"  , SG_GET_R(Class.asInt(0)));
1286 			Entry.Add_Property("blue" , SG_GET_B(Class.asInt(0)));
1287 			Entry.Add_Property("green", SG_GET_G(Class.asInt(0)));
1288 			Entry.Add_Property("value", Class.asDouble(4));
1289 			Entry.Add_Property("label", Class.asString(1));
1290 		}
1291 	}
1292 
1293 	//-----------------------------------------------------
1294 	return( QML.Save(File) );	// return( QML.Save(File, SG_T("qml")) );
1295 }
1296 
1297 
1298 ///////////////////////////////////////////////////////////
1299 //														 //
1300 //														 //
1301 //														 //
1302 ///////////////////////////////////////////////////////////
1303 
1304 //---------------------------------------------------------
1305