1 /*
2  *  xnec2c - GTK2-based version of nec2c, the C translation of NEC2
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU Library General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 /* nec2_model.c
20  *
21  * Structure modelling functions for xnec2c
22  */
23 
24 #include "nec2_model.h"
25 #include "shared.h"
26 
27 /*------------------------------------------------------------------------*/
28 
29 /* Nec2_Input_File_Treeview()
30  *
31  * Reads a NEC2 input file and renders it in a tree view
32  */
33   void
Nec2_Input_File_Treeview(int action)34 Nec2_Input_File_Treeview( int action )
35 {
36   /* Abort if editor window is not opened */
37   if( nec2_edit_window == NULL ) return;
38 
39   /* Signal save of edited file */
40   SetFlag( NEC2_EDIT_SAVE );
41 
42   /* Implement user action */
43   switch( action )
44   {
45 	case NEC2_EDITOR_REVERT: /* Revert editor to file contents */
46 	  /* Clear all tree view list stores */
47 	  gtk_list_store_clear( cmnt_store );
48 	  gtk_list_store_clear( geom_store );
49 	  gtk_list_store_clear( cmnd_store );
50 	  break;
51 
52 	case NEC2_EDITOR_NEW: /* Create new default input file */
53 	  /* If tree view stores are already
54 	   * created, just make the new file */
55 	  Create_List_Stores(); /* Only done if needed */
56 	  Create_Default_File();
57 	  return;
58 
59 	case NEC2_EDITOR_RELOAD: /* Just reload input file */
60 	  Create_List_Stores();  /* Only done if needed */
61 	  break;
62 
63   } /* switch( action ) */
64 
65   /* Rewind NEC2 input file */
66   rewind( input_fp );
67 
68   /*** List Comment cards ***/
69   List_Comments();
70 
71   /*** List Geometry cards ***/
72   List_Geometry();
73 
74   /*** Read Command cards ***/
75   List_Commands();
76 
77   return;
78 } /* Nec2_Input_File_Treeview() */
79 
80 /*------------------------------------------------------------------------*/
81 
82 /* Create_List_Stores()
83  *
84  * Create stores needed for the treeview
85  */
86   void
Create_List_Stores(void)87 Create_List_Stores( void )
88 {
89   /* Comments column names */
90   char *cmnt_col_name[CMNT_NUM_COLS] =
91   { _("Card"), _("Comments") };
92 
93   /* Geometry column names */
94   char *geom_col_name[GEOM_NUM_COLS] =
95   { _("Card"), "I1", "I2", "F1", "F2", "F3", "F4", "F5", "F6", "F7" };
96 
97   /* Command column names */
98   char *cmnd_col_name[CMND_NUM_COLS] =
99   { _("Card"), "I1", "I2", "I3", "I4", "F1", "F2", "F3", "F4", "F5", "F6" };
100 
101 
102   /* Create list stores only if needed */
103   if( cmnt_store != NULL ) return;
104 
105   /* Create comments list store */
106   cmnt_store = gtk_list_store_new(
107 	  CMNT_NUM_COLS, G_TYPE_STRING, G_TYPE_STRING );
108 
109   /* Create geometry data list store */
110   geom_store = gtk_list_store_new(
111 	  GEOM_NUM_COLS, G_TYPE_STRING,
112 	  G_TYPE_STRING, G_TYPE_STRING,
113 	  G_TYPE_STRING, G_TYPE_STRING,
114 	  G_TYPE_STRING, G_TYPE_STRING,
115 	  G_TYPE_STRING, G_TYPE_STRING,
116 	  G_TYPE_STRING );
117 
118   /* Create control commands data list store */
119   cmnd_store = gtk_list_store_new(
120 	  CMND_NUM_COLS, G_TYPE_STRING,
121 	  G_TYPE_STRING, G_TYPE_STRING,
122 	  G_TYPE_STRING, G_TYPE_STRING,
123 	  G_TYPE_STRING, G_TYPE_STRING,
124 	  G_TYPE_STRING, G_TYPE_STRING,
125 	  G_TYPE_STRING, G_TYPE_STRING );
126 
127   /* Insert comment columns */
128   Insert_Columns(
129 	  nec2_edit_window, "nec2_cmnt_treeview",
130 	  cmnt_store, CMNT_NUM_COLS, cmnt_col_name );
131 
132   /* Insert geometry columns */
133   Insert_Columns(
134 	  nec2_edit_window, "nec2_geom_treeview",
135 	  geom_store, GEOM_NUM_COLS, geom_col_name );
136 
137   /* Insert command columns */
138   Insert_Columns(
139 	  nec2_edit_window, "nec2_cmnd_treeview",
140 	  cmnd_store, CMND_NUM_COLS, cmnd_col_name );
141 
142   /* Set models to treviews */
143   gtk_tree_view_set_model(
144 	  GTK_TREE_VIEW(lookup_widget(
145 		  nec2_edit_window, "nec2_cmnt_treeview")),
146 	  GTK_TREE_MODEL(cmnt_store) );
147   gtk_tree_view_set_model(
148 	  GTK_TREE_VIEW(lookup_widget(
149 		  nec2_edit_window, "nec2_geom_treeview")),
150 	  GTK_TREE_MODEL(geom_store) );
151   gtk_tree_view_set_model(
152 	  GTK_TREE_VIEW(lookup_widget(
153 		  nec2_edit_window, "nec2_cmnd_treeview")),
154 	  GTK_TREE_MODEL(cmnd_store) );
155 
156 } /* Create_List_Stores() */
157 
158 /*------------------------------------------------------------------------*/
159 
160 /* Create_Default_File()
161  *
162  * Creates a default NEC2 file if needed
163  */
164   void
Create_Default_File(void)165 Create_Default_File( void )
166 {
167   GtkTreeIter iter;
168   int idx, idi;
169   char str[64];
170   size_t s = sizeof( str );
171 
172 
173   /* Clear all tree views */
174   gtk_list_store_clear( cmnt_store );
175   gtk_list_store_clear( geom_store );
176   gtk_list_store_clear( cmnd_store );
177 
178   /* Append a default comment row */
179   Strlcpy( str, _("--- NEC2 Input File created or edited by "), s );
180   Strlcat( str, PACKAGE_STRING, s );
181   Strlcat( str, " ---", s );
182   gtk_list_store_append( cmnt_store, &iter );
183   gtk_list_store_set(
184 	  cmnt_store, &iter,
185 	  CMNT_COL_NAME, "CM",
186 	  CMNT_COL_COMMENT, str, -1 );
187 
188   /* Append a default CE card */
189   gtk_list_store_append( cmnt_store, &iter );
190   gtk_list_store_set(
191 	  cmnt_store, &iter,
192 	  CMNT_COL_NAME, "CE",
193 	  CMNT_COL_COMMENT,
194 	  _("--- End Comments ---"),
195 	  -1 );
196 
197   /* Append a dipole wire (GW) card */
198   gtk_list_store_append( geom_store, &iter );
199   gtk_list_store_set( geom_store, &iter,
200 	  GEOM_COL_NAME, "GW",
201 	  GEOM_COL_I1, "1",
202 	  GEOM_COL_I2, "15",
203 	  GEOM_COL_F1, "0.0",
204 	  GEOM_COL_F2, "0.0",
205 	  GEOM_COL_F3, "-1.0",
206 	  GEOM_COL_F4, "0.0",
207 	  GEOM_COL_F5, "0.0",
208 	  GEOM_COL_F6, "1.0",
209 	  GEOM_COL_F7, "0.015",
210 	  -1 );
211 
212   /* Append a geometry end (GE) card */
213   gtk_list_store_append( geom_store, &iter );
214   gtk_list_store_set( geom_store,
215 	  &iter, GEOM_COL_NAME, "GE", -1 );
216   for( idx = GEOM_COL_I1; idx < GEOM_NUM_COLS; idx++ )
217 	gtk_list_store_set( geom_store, &iter, idx, "0", -1 );
218 
219   /* Append an excitation (EX) card */
220   gtk_list_store_append( cmnd_store, &iter );
221   gtk_list_store_set( cmnd_store, &iter,
222 	  CMND_COL_NAME, "EX",
223 	  CMND_COL_I1, "0",
224 	  CMND_COL_I2, "1",
225 	  CMND_COL_I3, "8",
226 	  CMND_COL_I4, "0",
227 	  CMND_COL_F1, "1.0",
228 	  CMND_COL_F2, "0.0",
229 	  CMND_COL_F3, "0.0",
230 	  CMND_COL_F4, "0.0",
231 	  CMND_COL_F5, "0.0",
232 	  CMND_COL_F6, "0.0",
233 	  -1 );
234 
235   /* Append a frequency (FR) card */
236   gtk_list_store_append( cmnd_store, &iter );
237   gtk_list_store_set( cmnd_store, &iter,
238 	  CMND_COL_NAME, "FR",
239 	  CMND_COL_I1, "0",
240 	  CMND_COL_I2, "11",
241 	  CMND_COL_I3, "0",
242 	  CMND_COL_I4, "0",
243 	  CMND_COL_F1, "50.0",
244 	  CMND_COL_F2, "5.0",
245 	  CMND_COL_F3, "0.0",
246 	  CMND_COL_F4, "0.0",
247 	  CMND_COL_F5, "0.0",
248 	  CMND_COL_F6, "0.0",
249 	  -1 );
250 
251   /* Append a near H field (NH) card */
252   gtk_list_store_append( cmnd_store, &iter );
253   gtk_list_store_set( cmnd_store, &iter,
254 	  CMND_COL_NAME, "NH",
255 	  CMND_COL_I1, "0",
256 	  CMND_COL_I2, "0",
257 	  CMND_COL_I3, "0",
258 	  CMND_COL_I4, "0",
259 	  CMND_COL_F1, "0.0",
260 	  CMND_COL_F2, "0.0",
261 	  CMND_COL_F3, "0.0",
262 	  CMND_COL_F4, "0.0",
263 	  CMND_COL_F5, "0.0",
264 	  CMND_COL_F6, "0.0",
265 	  -1 );
266 
267   /* Append a near E field (NE) card */
268   gtk_list_store_append( cmnd_store, &iter );
269   gtk_list_store_set( cmnd_store, &iter,
270 	  CMND_COL_NAME, "NE",
271 	  CMND_COL_I1, "0",
272 	  CMND_COL_I2, "10",
273 	  CMND_COL_I3, "1",
274 	  CMND_COL_I4, "10",
275 	  CMND_COL_F1, "-1.35",
276 	  CMND_COL_F2, "0.0",
277 	  CMND_COL_F3, "-1.35",
278 	  CMND_COL_F4, "0.3",
279 	  CMND_COL_F5, "0.0",
280 	  CMND_COL_F6, "0.3",
281 	  -1 );
282 
283   /* Append a radiation pattern (RP) card */
284   gtk_list_store_append( cmnd_store, &iter );
285   gtk_list_store_set( cmnd_store, &iter,
286 	  CMND_COL_NAME, "RP",
287 	  CMND_COL_I1, "0",
288 	  CMND_COL_I2, "19",
289 	  CMND_COL_I3, "37",
290 	  CMND_COL_I4, "1000",
291 	  CMND_COL_F1, "0.0",
292 	  CMND_COL_F2, "0.0",
293 	  CMND_COL_F3, "10.0",
294 	  CMND_COL_F4, "10.0",
295 	  CMND_COL_F5, "0.0",
296 	  CMND_COL_F6, "0.0",
297 	  -1 );
298 
299   /* Append a file end (EN) card */
300   gtk_list_store_append( cmnd_store, &iter );
301   gtk_list_store_set( cmnd_store,
302 	  &iter, CMND_COL_NAME, "EN", -1 );
303   for( idi = CMND_COL_I1; idi < CMND_NUM_COLS; idi++ )
304 	gtk_list_store_set( cmnd_store, &iter, idi, "0", -1 );
305 
306 } /* Create_Default_File() */
307 
308 /*------------------------------------------------------------------------*/
309 
310 /* List_Comments()
311  *
312  * Reads comments from file and lists in tree view
313  */
314   void
List_Comments(void)315 List_Comments( void )
316 {
317   GtkTreeIter iter;
318   gboolean ret;
319 
320   /* "Card" mnemonic and line buffer */
321   char ain[3], line_buf[LINE_LEN];
322 
323   /* Check that store is empty */
324   ret = gtk_tree_model_get_iter_first(
325 	  GTK_TREE_MODEL(cmnt_store), &iter );
326 
327   /* Keep reading till the CE card */
328   do
329   {
330 	/* Read a line from input file */
331 	if( Load_Line(line_buf, input_fp) == EOF )
332 	  stop( _("List_Comments():\n"\
333 			"Error reading input file\n"\
334 			"Unexpected EOF (End of File)"), ERR_OK );
335 
336 	/* Check for short or missing CM or CE and fix */
337 	if( strlen(line_buf) < 2 )
338 	{
339 	  stop( _("List_Comments():\n"\
340 			"Error reading input file\n"\
341 			"Comment mnemonic short or missing"), ERR_OK );
342 	  Strlcpy( line_buf, "XX ", sizeof(line_buf) );
343 	}
344 
345 	/* If only mnemonic in card,
346 	 * "cut" the rest of line buffer */
347 	if( strlen(line_buf) == 2 ) line_buf[3] = '\0';
348 
349 	/* Separate card's id mnemonic */
350 	Strlcpy( ain, line_buf, sizeof(ain) );
351 
352 	/* Append a comment row and fill in text if opening call */
353 	if( !ret )
354 	  gtk_list_store_append( cmnt_store, &iter );
355 	gtk_list_store_set(
356 		cmnt_store, &iter,
357 		CMNT_COL_NAME, ain,
358 		CMNT_COL_COMMENT,
359 		&line_buf[3], -1 );
360 
361 	/* Get new row if available */
362 	ret = gtk_tree_model_iter_next(
363 		GTK_TREE_MODEL(cmnt_store), &iter);
364 
365   } /* do */
366   while( strcmp(ain, "CE") != 0 );
367 
368 } /* List_Comments() */
369 
370 /*------------------------------------------------------------------------*/
371 
372 /* List_Geometry()
373  *
374  * Reads geometry cards from file and lists in tree view
375  */
376   void
List_Geometry(void)377 List_Geometry( void )
378 {
379   GtkTreeIter iter;
380 
381   /* "Card" mnemonic */
382   char ain[3];
383 
384   /* int data from cards */
385   int iv[4];
386 
387   /* float data from cards */
388   double fv[7];
389 
390   /* For snprintf */
391   char si[4][7], sf[7][13];
392 
393   int idx;
394   gboolean ret;
395 
396   /* Check that store is empty */
397   ret = gtk_tree_model_get_iter_first(
398 	  GTK_TREE_MODEL(geom_store), &iter );
399   do
400   {
401 	/* Read a geometry card. Errors are handled in readgm() */
402 	if( !readgm( ain, &iv[0], &iv[1],
403 		&fv[0], &fv[1], &fv[2], &fv[3],
404 		&fv[4], &fv[5], &fv[6]) )
405 	  break;
406 
407 	/* Ignore in-data (NEC4 style) comments */
408 	if( strcmp(ain, "CM") == 0 ) continue;
409 
410 	/* Format card data and print to string */
411 	snprintf( si[0], 6, "%5d",  iv[0] );
412 	snprintf( si[1], 7, "%5d ", iv[1] );
413 	for( idx = GEOM_COL_F1; idx <= GEOM_COL_F7; idx++ )
414 	  snprintf( sf[idx-GEOM_COL_F1], 13,
415 		  "%12.5E", (double)fv[idx-GEOM_COL_F1] );
416 
417 	/* Append a comment row and fill in text if opening call */
418 	if( !ret )
419 	  gtk_list_store_append( geom_store, &iter );
420 
421 	/* Set data to list store */
422 	gtk_list_store_set(
423 		geom_store, &iter, GEOM_COL_NAME, ain, -1 );
424 	for( idx = GEOM_COL_I1; idx <= GEOM_COL_I2; idx++ )
425 	  gtk_list_store_set(
426 		  geom_store, &iter, idx, si[idx-GEOM_COL_I1], -1 );
427 	for( idx = GEOM_COL_F1; idx <= GEOM_COL_F7; idx++ )
428 	  gtk_list_store_set(
429 		  geom_store, &iter, idx, sf[idx-GEOM_COL_F1], -1 );
430 
431 	/* Get new row if available */
432 	ret = gtk_tree_model_iter_next(
433 		GTK_TREE_MODEL(geom_store), &iter);
434   }
435   while( strcmp(ain, "GE") != 0 );
436 
437 } /* List_Geometry() */
438 
439 /*------------------------------------------------------------------------*/
440 
441 /* List_Commands()
442  *
443  * Reads command cards from file and lists in tree view
444  */
445   void
List_Commands(void)446 List_Commands( void )
447 {
448   GtkTreeIter iter;
449 
450   /* "Card" mnemonic and line buffer */
451   char ain[3];
452 
453   /* int data from cards */
454   int iv[4];
455 
456   /* float data from cards */
457   double fv[7];
458 
459   /* For snprintf */
460   char si[4][7], sf[7][13];
461 
462   int idx;
463   gboolean ret;
464 
465   /* Check that store is empty */
466   ret = gtk_tree_model_get_iter_first(
467 	  GTK_TREE_MODEL(cmnd_store), &iter );
468   do
469   {
470 	/* Read a command card. Errors are handled in readmn() */
471 	readmn(
472 		ain, &iv[0], &iv[1], &iv[2], &iv[3], &fv[0],
473 		&fv[1], &fv[2], &fv[3], &fv[4], &fv[5] );
474 
475 	/* Ignore in-data (NEC4 style) comments */
476 	if( strcmp(ain, "CM") == 0 ) continue;
477 
478 	/* Format card data and print to string */
479 	for( idx = CMND_COL_I1; idx < CMND_COL_I4; idx++ )
480 	  snprintf( si[idx-CMND_COL_I1], 6, "%5d", iv[idx-CMND_COL_I1] );
481 
482 	/* For alignment of data printed to NEC2 file */
483 	snprintf( si[idx-CMND_COL_I1], 7, " %5d", iv[idx-CMND_COL_I1] );
484 	for( idx = CMND_COL_F1; idx <= CMND_COL_F6; idx++ )
485 	  snprintf( sf[idx-CMND_COL_F1], 13,
486 		  "%12.5E", (double)fv[idx-CMND_COL_F1] );
487 
488 	/* Append a command row and fill in text if opening call */
489 	if( !ret )
490 	  gtk_list_store_append( cmnd_store, &iter );
491 
492 	/* Set data to list store */
493 	gtk_list_store_set(
494 		cmnd_store, &iter, CMND_COL_NAME, ain, -1 );
495 	for( idx = CMND_COL_I1; idx <= CMND_COL_I4; idx++ )
496 	  gtk_list_store_set(
497 		  cmnd_store, &iter, idx, si[idx-CMND_COL_I1], -1 );
498 	for( idx = CMND_COL_F1; idx <= CMND_COL_F6; idx++ )
499 	  gtk_list_store_set(
500 		  cmnd_store, &iter, idx, sf[idx-CMND_COL_F1], -1 );
501 
502 	/* Get new row if available */
503 	ret = gtk_tree_model_iter_next(
504 		GTK_TREE_MODEL(cmnd_store), &iter);
505   }
506   while( strcmp(ain, "EN") != 0 );
507 
508 } /* List_Commands() */
509 
510 /*------------------------------------------------------------------------*/
511 
512 /* Insert_Columns()
513  *
514  * Inserts columns in a list store
515  */
516   void
Insert_Columns(GtkWidget * window,gchar * treeview,GtkListStore * store,int ncols,char * colname[])517 Insert_Columns(	GtkWidget *window, gchar *treeview,
518 	GtkListStore* store, int ncols, char *colname[] )
519 {
520   int idx;
521   GtkTreeModel *model;
522   GtkCellRenderer *renderer;
523 
524   static GtkWidget *view;
525   view = lookup_widget( window, treeview );
526   for( idx = 0; idx < ncols; idx++ )
527   {
528 	renderer = gtk_cell_renderer_text_new();
529 	g_object_set(renderer, "editable", TRUE, NULL);
530 	g_signal_connect( renderer, "edited",
531 		(GCallback)cell_edited_callback, view );
532 	g_object_set_data( G_OBJECT(renderer),
533 		"column", GUINT_TO_POINTER(idx) );
534 	gtk_tree_view_insert_column_with_attributes(
535 		GTK_TREE_VIEW(view), -1, colname[idx],
536 		renderer, "text", idx, NULL );
537   }
538   model = GTK_TREE_MODEL(store);
539   gtk_tree_view_set_model( GTK_TREE_VIEW (view), model );
540 
541   /* Destroy model automatically with view */
542   g_object_unref( model );
543 
544 } /* Insert_Columns() */
545 
546 /*------------------------------------------------------------------------*/
547 
548 /* cell_edited_callback()
549  *
550  * Text cell edited callback
551  */
552   void
cell_edited_callback(GtkCellRendererText * cell,gchar * path,gchar * new_text,gpointer user_data)553 cell_edited_callback(
554 	GtkCellRendererText *cell,
555 	gchar				*path,
556 	gchar               *new_text,
557 	gpointer             user_data )
558 {
559   GtkTreeSelection *selection;
560   GtkTreeModel     *model;
561   GtkTreeIter       iter;
562   guint column;
563 
564   column = GPOINTER_TO_UINT(
565 	  g_object_get_data(G_OBJECT(cell), "column") );
566   selection = gtk_tree_view_get_selection(
567 	  GTK_TREE_VIEW(user_data) );
568   gtk_tree_selection_get_selected(
569 	  selection, &model, &iter );
570 
571   /* Blank cells cause problems */
572   if( strcmp(new_text, "") == 0 )
573   {
574 	gchar *name;
575 
576 	gtk_tree_model_get( model, &iter, 0, &name, -1 );
577 	if( strcmp(name, "CE") == 0 )
578 	  gtk_list_store_set( GTK_LIST_STORE(model),
579 		  &iter, column, _("End Comments"), -1 );
580 	else
581 	  gtk_list_store_set( GTK_LIST_STORE(model),
582 		  &iter, column, "0", -1 );
583 	g_free(name);
584   }
585   else
586 	gtk_list_store_set( GTK_LIST_STORE(model),
587 	  &iter, column, new_text, -1 );
588 
589 } /* cell_edited_callback() */
590 
591 /*------------------------------------------------------------------------*/
592 
593 /* Save_Nec2_Input_File()
594  *
595  * Saves the data in a NEC2 input treeview to a given filename
596  */
597   void
Save_Nec2_Input_File(GtkWidget * treeview_window,char * nec2_file)598 Save_Nec2_Input_File( GtkWidget *treeview_window, char *nec2_file )
599 {
600   FILE *nec2_fp = NULL;
601   GtkTreeView *tree_view;
602 
603 
604   /* Abort if editor window is not opened */
605   if( nec2_edit_window == NULL ) return;
606 
607   /* Open NEC2 input file for writing */
608   if( !Open_File(&nec2_fp, nec2_file, "w") ) return;
609 
610   /* Save comments to file */
611   tree_view = GTK_TREE_VIEW( lookup_widget(
612 		treeview_window, "nec2_cmnt_treeview") );
613   Save_Treeview_Data( tree_view, CMNT_NUM_COLS, nec2_fp );
614 
615   /* Save geometry to file */
616   tree_view = GTK_TREE_VIEW( lookup_widget(
617 		treeview_window, "nec2_geom_treeview") );
618   Save_Treeview_Data( tree_view, GEOM_NUM_COLS, nec2_fp );
619 
620   /* Save commands to file */
621   tree_view = GTK_TREE_VIEW( lookup_widget(
622 		treeview_window, "nec2_cmnd_treeview") );
623   Save_Treeview_Data( tree_view, CMND_NUM_COLS, nec2_fp );
624 
625   /* Re-open file in read mode */
626   Close_File( &nec2_fp );
627 
628 } /* Save_Nec2_Input_File() */
629 
630 /*------------------------------------------------------------------------*/
631 
632 /* Save_Treeview_Data()
633  *
634  * Saves tree view data to an open NEC2 input file
635  */
636   void
Save_Treeview_Data(GtkTreeView * tree_view,int ncols,FILE * nec2_fp)637 Save_Treeview_Data( GtkTreeView *tree_view, int ncols, FILE *nec2_fp )
638 {
639   GtkTreeModel *list_store;
640   GtkTreeIter iter;
641   gboolean valid;
642   int idx;
643 
644   /* Abort if no open file to sane to */
645   if( nec2_fp == NULL )
646   {
647 	stop( _("Cannot save treeview data\n"\
648 		  "Please use the Save button\n"\
649 		  "to specify a file path"), ERR_STOP );
650   }
651 
652   /* Get the first iter in the list */
653   list_store = GTK_TREE_MODEL( gtk_tree_view_get_model(tree_view) );
654   valid = gtk_tree_model_get_iter_first( list_store, &iter );
655 
656   /* Walk through all rows and print data to file */
657   while( valid )
658   {
659 	gchar *str_data;
660 
661 	for( idx = 0; idx < ncols; idx++ )
662 	{
663 	  gtk_tree_model_get( list_store, &iter, idx, &str_data, -1 );
664 	  fprintf( nec2_fp, "%s ", str_data );
665 	  g_free( str_data );
666 	}
667 
668 	/* Overwrite last space with newline */
669 	if( fseek(nec2_fp, -1, SEEK_CUR) == 0 )
670 	  fprintf( nec2_fp, "\n" );
671 
672 	valid = gtk_tree_model_iter_next( list_store, &iter );
673   } /* while( valid ) */
674 
675 } /* Save_Treeview_Data() */
676 
677 /*------------------------------------------------------------------------*/
678 
679 /* Helper function */
680   gboolean
gtk_tree_model_iter_previous(GtkTreeModel * tree_model,GtkTreeIter * iter)681 gtk_tree_model_iter_previous(GtkTreeModel *tree_model, GtkTreeIter *iter)
682 {
683   GtkTreePath *path;
684   gboolean ret;
685 
686   path = gtk_tree_model_get_path (tree_model, iter);
687   ret = gtk_tree_path_prev (path);
688   if (ret == TRUE)
689 	gtk_tree_model_get_iter (tree_model, iter, path);
690   gtk_tree_path_free (path);
691   return ret;
692 }
693 
694 /*------------------------------------------------------------------------*/
695 
696