1 
2 ///////////////////////////////////////////////////////////
3 //                                                       //
4 //                         SAGA                          //
5 //                                                       //
6 //      System for Automated Geoscientific Analyses      //
7 //                                                       //
8 //                    User Interface                     //
9 //                                                       //
10 //                    Program: SAGA                      //
11 //                                                       //
12 //-------------------------------------------------------//
13 //                                                       //
14 //                  VIEW_Table_Data.cpp                  //
15 //                                                       //
16 //          Copyright (C) 2021 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 Hamburg                  //
42 //                Germany                                //
43 //                                                       //
44 //    e-mail:     oconrad@saga-gis.org                   //
45 //                                                       //
46 ///////////////////////////////////////////////////////////
47 
48 //---------------------------------------------------------
49 #include <wx/window.h>
50 #include <wx/filename.h>
51 #include <wx/clipbrd.h>
52 
53 #include <saga_api/saga_api.h>
54 
55 #include "res_commands.h"
56 #include "res_dialogs.h"
57 
58 #include "helper.h"
59 
60 #include "wksp_data_manager.h"
61 
62 #include "view_table_data.h"
63 
64 
65 ///////////////////////////////////////////////////////////
66 //														 //
67 //														 //
68 //														 //
69 ///////////////////////////////////////////////////////////
70 
71 //---------------------------------------------------------
CVIEW_Table_Data(CSG_Table * pTable)72 CVIEW_Table_Data::CVIEW_Table_Data(CSG_Table *pTable)
73 {
74 	m_pTable     = pTable;
75 
76 	m_bSelection = false;
77 	m_bRowLabels = false;
78 }
79 
80 //---------------------------------------------------------
~CVIEW_Table_Data(void)81 CVIEW_Table_Data::~CVIEW_Table_Data(void)
82 {
83 	// nop
84 }
85 
86 
87 ///////////////////////////////////////////////////////////
88 //														 //
89 ///////////////////////////////////////////////////////////
90 
91 //---------------------------------------------------------
InsertRows(size_t Position,size_t Number)92 bool CVIEW_Table_Data::InsertRows			(size_t Position, size_t Number)
93 {
94 	wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, Position, Number);
95 
96 	return( GetView()->ProcessTableMessage(msg) );
97 }
98 
99 //---------------------------------------------------------
AppendRows(size_t Number)100 bool CVIEW_Table_Data::AppendRows			(                 size_t Number)
101 {
102 	wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED,           Number);
103 
104 	return( GetView()->ProcessTableMessage(msg) );
105 }
106 
107 //---------------------------------------------------------
DeleteRows(size_t Position,size_t Number)108 bool CVIEW_Table_Data::DeleteRows			(size_t Position, size_t Number)
109 {
110 	wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_DELETED , Position, Number);
111 
112 	return( GetView()->ProcessTableMessage(msg) );
113 }
114 
115 //---------------------------------------------------------
InsertCols(size_t Position,size_t Number)116 bool CVIEW_Table_Data::InsertCols			(size_t Position, size_t Number)
117 {
118 	wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_COLS_INSERTED, Position, Number);
119 
120 	return( GetView()->ProcessTableMessage(msg) );
121 }
122 
123 //---------------------------------------------------------
AppendCols(size_t Number)124 bool CVIEW_Table_Data::AppendCols			(                 size_t Number)
125 {
126 	wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_COLS_APPENDED,           Number);
127 
128 	return( GetView()->ProcessTableMessage(msg) );
129 }
130 
131 //---------------------------------------------------------
DeleteCols(size_t Position,size_t Number)132 bool CVIEW_Table_Data::DeleteCols			(size_t Position, size_t Number)
133 {
134 	wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_COLS_DELETED , Position, Number);
135 
136 	return( GetView()->ProcessTableMessage(msg) );
137 }
138 
139 
140 ///////////////////////////////////////////////////////////
141 //														 //
142 ///////////////////////////////////////////////////////////
143 
144 //---------------------------------------------------------
SetValue(int iRecord,int iField,const wxString & Value)145 void CVIEW_Table_Data::SetValue(int iRecord, int iField, const wxString &Value)
146 {
147 	CSG_Table_Record *pRecord = Get_Field(iField) ? Get_Record(iRecord, iField) : NULL;
148 
149 	if( pRecord )
150 	{
151 		if( Value.IsEmpty() )
152 		{
153 			pRecord->Set_NoData(iField);
154 		}
155 		else switch( m_pTable->Get_Field_Type(iField) )
156 		{
157 		default:
158 			{
159 				pRecord->Set_Value(iField, &Value);
160 			}
161 			break;
162 
163 		case SG_DATATYPE_Color:
164 			{
165 				if( Value[0] == '#' )
166 				{
167 					wxColour Color; Color.Set(Value);
168 
169 					pRecord->Set_Value(iField, Get_Color_asInt(Color));
170 				}
171 				else
172 				{
173 					pRecord->Set_Value(iField, &Value);
174 				}
175 			}
176 			break;
177 		}
178 	}
179 }
180 
181 //---------------------------------------------------------
SetValueAsLong(int iRecord,int iField,long Value)182 void CVIEW_Table_Data::SetValueAsLong(int iRecord, int iField, long Value)
183 {
184 	CSG_Table_Record *pRecord = Get_Field(iField) ? Get_Record(iRecord, iField) : NULL;
185 
186 	if( pRecord ) { pRecord->Set_Value(iField, Value); }
187 }
188 
189 //---------------------------------------------------------
SetValueAsDouble(int iRecord,int iField,double Value)190 void CVIEW_Table_Data::SetValueAsDouble(int iRecord, int iField, double Value)
191 {
192 	CSG_Table_Record *pRecord = Get_Field(iField) ? Get_Record(iRecord, iField) : NULL;
193 
194 	if( pRecord ) { pRecord->Set_Value(iField, Value); }
195 }
196 
197 //---------------------------------------------------------
SetValueAsBool(int iRecord,int iField,bool Value)198 void CVIEW_Table_Data::SetValueAsBool(int iRecord, int iField, bool Value)
199 {
200 	CSG_Table_Record *pRecord = Get_Field(iField) ? Get_Record(iRecord, iField) : NULL;
201 
202 	if( pRecord ) { pRecord->Set_Value(iField, Value); }
203 }
204 
205 ///////////////////////////////////////////////////////////
206 //														 //
207 ///////////////////////////////////////////////////////////
208 
209 //---------------------------------------------------------
On_Changed(int iRecord,int iField)210 bool CVIEW_Table_Data::On_Changed(int iRecord, int iField)
211 {
212 	CSG_Table_Record *pRecord = Get_Field(iField) ? Get_Record(iRecord, iField) : NULL;
213 
214 	if( pRecord && GetView() )
215 	{
216 		switch( m_pTable->Get_Field_Type(iField) )
217 		{
218 		default:
219 			{
220 				// nop
221 			}
222 			break;
223 
224 		case SG_DATATYPE_Color:
225 			{
226 				wxColour Colour(Get_Color_asWX(pRecord->asInt(iField)));
227 
228 				GetView()->SetCellBackgroundColour(iRecord, iField, Colour);
229 				GetView()->SetCellTextColour      (iRecord, iField, Colour);
230 			}
231 			break;
232 		}
233 	}
234 
235 	return( true );
236 }
237 
238 //---------------------------------------------------------
Sort_Parameter_Changed(CSG_Parameter * pParameter,int Flags)239 int Sort_Parameter_Changed(CSG_Parameter *pParameter, int Flags)
240 {
241 	CSG_String ID(pParameter->Get_Identifier());
242 
243 	if( ID.Find("ORDER") == 0 )
244 	{
245 		pParameter->Set_Children_Enabled(pParameter->asInt() > 0);
246 	}
247 
248 	return( 1 );
249 }
250 
251 //---------------------------------------------------------
On_Sort(void)252 bool CVIEW_Table_Data::On_Sort(void)
253 {
254 	CSG_String	Fields, Order;
255 
256 	for(int i=0; i<m_pTable->Get_Field_Count(); i++)
257 	{
258 		Fields	+= m_pTable->Get_Field_Name(i) + CSG_String("|");
259 	}
260 
261 	Order.Printf("%s|%s|%s",
262 		_TL("do not sort"),
263 		_TL("ascending"),
264 		_TL("descending")
265 	);
266 
267 	//-----------------------------------------------------
268 	CSG_Parameters	P(_TL("Sort Table"));
269 
270 	P.Set_Callback_On_Parameter_Changed(Sort_Parameter_Changed);
271 
272 	P.Add_Choice(""       , "ORDER_1", _TL("Sorting Order"    ), _TL(""), Order , !m_pTable->is_Indexed() ? 1 : m_pTable->Get_Index_Order(0));
273 	P.Add_Choice("ORDER_1", "FIELD_1", _TL("Field"            ), _TL(""), Fields, !m_pTable->is_Indexed() ? 0 : m_pTable->Get_Index_Field(0));
274 
275 	P.Add_Choice("ORDER_1", "ORDER_2", _TL("2nd Sorting Order"), _TL(""), Order , !m_pTable->is_Indexed() ? 0 : m_pTable->Get_Index_Order(1));
276 	P.Add_Choice("ORDER_2", "FIELD_2", _TL("2nd Field"        ), _TL(""), Fields, !m_pTable->is_Indexed() ? 0 : m_pTable->Get_Index_Field(1));
277 
278 	P.Add_Choice("ORDER_2", "ORDER_3", _TL("3rd Sorting Order"), _TL(""), Order , !m_pTable->is_Indexed() ? 0 : m_pTable->Get_Index_Order(2));
279 	P.Add_Choice("ORDER_3", "FIELD_3", _TL("3rd Field"        ), _TL(""), Fields, !m_pTable->is_Indexed() ? 0 : m_pTable->Get_Index_Field(2));
280 
281 	//-----------------------------------------------------
282 	if( DLG_Parameters(&P) )
283 	{
284 		m_pTable->Set_Index(
285 			P("FIELD_1")->asInt(), P("ORDER_1")->asInt() == 1 ? TABLE_INDEX_Ascending : P("ORDER_1")->asInt() == 2 ? TABLE_INDEX_Descending : TABLE_INDEX_None,
286 			P("FIELD_2")->asInt(), P("ORDER_2")->asInt() == 1 ? TABLE_INDEX_Ascending : P("ORDER_2")->asInt() == 2 ? TABLE_INDEX_Descending : TABLE_INDEX_None,
287 			P("FIELD_3")->asInt(), P("ORDER_3")->asInt() == 1 ? TABLE_INDEX_Ascending : P("ORDER_3")->asInt() == 2 ? TABLE_INDEX_Descending : TABLE_INDEX_None
288 		);
289 
290 		return( true );
291 	}
292 
293 	return( false );
294 }
295 
296 
297 ///////////////////////////////////////////////////////////
298 //														 //
299 ///////////////////////////////////////////////////////////
300 
301 //---------------------------------------------------------
Sort(int iField,int Direction)302 bool CVIEW_Table_Data::Sort(int iField, int Direction)
303 {
304 	if( iField >= 0 && iField < GetNumberCols() )
305 	{
306 		switch( Direction )
307 		{
308 		default: m_pTable->Toggle_Index(iField                        ); break;
309 		case  0: m_pTable->   Set_Index(iField, TABLE_INDEX_None      ); break;
310 		case  1: m_pTable->   Set_Index(iField, TABLE_INDEX_Ascending ); break;
311 		case  2: m_pTable->   Set_Index(iField, TABLE_INDEX_Descending); break;
312 		}
313 
314 		return( true );
315 	}
316 
317 	return( false );
318 }
319 
320 //---------------------------------------------------------
To_Clipboard(void)321 bool CVIEW_Table_Data::To_Clipboard(void)
322 {
323 	if( wxTheClipboard->Open() )
324 	{
325 		wxString	Data;
326 
327 		for(int iField=0; iField<m_pTable->Get_Field_Count(); iField++)
328 		{
329 			Data	+= m_pTable->Get_Field_Name(iField);
330 			Data	+= 1 + iField < m_pTable->Get_Field_Count() ? '\t' : '\n';
331 		}
332 
333 		int nRecords = m_pTable->Get_Selection_Count()
334 			? (int)m_pTable->Get_Selection_Count() : m_pTable->Get_Count();
335 
336 		for(int iRecord=0; iRecord<nRecords; iRecord++)
337 		{
338 			CSG_Table_Record	*pRecord	= m_pTable->Get_Selection_Count()
339 				? m_pTable->Get_Selection(iRecord) : m_pTable->Get_Record_byIndex(iRecord);
340 
341 			for(int iField=0; iField<m_pTable->Get_Field_Count(); iField++)
342 			{
343 				Data	+= pRecord->asString(iField);
344 				Data	+= 1 + iField < m_pTable->Get_Field_Count() ? '\t' : '\n';
345 			}
346 		}
347 
348 		wxTheClipboard->SetData(new wxTextDataObject(Data));
349 		wxTheClipboard->Close();
350 
351 		return( true );
352 	}
353 
354 	return( false );
355 }
356 
357 //---------------------------------------------------------
is_DataSource(wxString & Source)358 bool CVIEW_Table_Data::is_DataSource(wxString &Source)
359 {
360 	if( Source.Find("PGSQL:"  ) == 0
361 	||	Source.Find("ftp://"  ) == 0
362 	||	Source.Find("http://" ) == 0
363 	||	Source.Find("https://") == 0
364 	||	Source.Find("file://" ) == 0
365 	||  wxFileExists(Source)  )
366 	{
367 		return( true );
368 	}
369 
370 	if( m_pTable->Get_File_Name(false) )
371 	{
372 		wxFileName	fn(Source), dir(m_pTable->Get_File_Name(false));
373 
374 		if( fn.MakeAbsolute(dir.GetPath()) && fn.Exists() )
375 		{
376 			Source	= fn.GetFullPath();
377 
378 			return( true );
379 		}
380 	}
381 
382 	return( false );
383 }
384 
385 
386 ///////////////////////////////////////////////////////////
387 //														 //
388 //														 //
389 //														 //
390 ///////////////////////////////////////////////////////////
391 
392 //---------------------------------------------------------
393