1 // fgadmin_funcs.cxx -- FG Admin UI functions.
3 // Written by Curtis Olson, started February 2004.
5 // Copyright (c) 2004 Curtis L. Olson - curt@flightgear.org
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 #include <FL/Fl_File_Chooser.H>
35 #include <simgear/misc/sg_path.hxx>
45 static const float min_progress = 0.0;
46 static const float max_progress = 5000.0;
49 FGAdminUI::~FGAdminUI() {
54 // initialize additional class elements
55 void FGAdminUI::init() {
56 prefs = new Fl_Preferences( Fl_Preferences::USER,
59 char buf[FL_PATH_MAX];
60 prefs->get( "install-source", buf, "", FL_PATH_MAX );
61 source_text->value( buf );
64 prefs->get( "scenery-dest", buf, "", FL_PATH_MAX );
65 dest_text->value( buf );
70 progress->minimum( min_progress );
71 progress->maximum( max_progress );
75 void FGAdminUI::show() {
80 // refresh the check box lists
81 void FGAdminUI::refresh_lists() {
87 // scan the source directory and update the install_box contents
89 void FGAdminUI::quit() {
94 // select the install source
95 void FGAdminUI::select_install_source() {
96 char* p = fl_dir_chooser( "Select Scenery Source Directory",
101 source_text->value( p );
102 prefs->set( "install-source", p );
108 // select the install source
109 void FGAdminUI::select_install_dest() {
110 char* p = fl_dir_chooser( "Select Scenery Install Directory",
115 dest_text->value( p );
116 prefs->set( "scenery-dest", p );
122 // Like strcmp, but for strings
123 static int stringCompare(const void *string1, const void *string2)
125 const string *s1 = (const string *)string1;
126 const string *s2 = (const string *)string2;
128 // Compare name first, and then index.
129 return strcmp(s1->c_str(), s2->c_str());
133 void FGAdminUI::update_install_box() {
135 vector<string> file_list;
138 install_box->clear();
140 if ( source.length() ) {
141 ulDir *dir = ulOpenDir( source.c_str() ) ;
143 while ( ent = ulReadDir( dir ) ) {
144 // find base name of archive file
145 char base[FL_PATH_MAX];
146 strncpy( base, ent->d_name, FL_PATH_MAX );
147 const char *p = fl_filename_ext( base );
149 if ( strcmp( p, ".gz" ) == 0 ) {
152 p = fl_filename_ext( base );
153 if ( strcmp( p, ".tar" ) == 0 ) {
157 } else if ( strcmp( p, ".zip" ) == 0 ) {
162 // add to list if not installed
163 SGPath install( dest );
164 install.append( base );
165 if ( ! fl_filename_isdir( install.c_str() ) ) {
166 // cout << install.str() << " install candidate." << endl;
167 file_list.push_back( ent->d_name );
169 // cout << install.str() << " exists." << endl;
174 // convert to a qsort()'able array
175 string *sort_list = new string[file_list.size()];
176 for ( i = 0; i < file_list.size(); ++i ) {
177 sort_list[i] = fl_filename_name( file_list[i].c_str() );
180 // Sort the file list into display order
181 qsort(sort_list, file_list.size(), sizeof(string), stringCompare);
183 for ( int i = 0; i < file_list.size(); ++i ) {
184 install_box->add( sort_list[i].c_str() );
189 install_box->redraw();
194 // scan the source directory and update the install_box contents
195 void FGAdminUI::update_remove_box() {
197 vector<string> dir_list;
202 if ( dest.length() ) {
203 ulDir *dir = ulOpenDir( dest.c_str() ) ;
205 while ( ent = ulReadDir( dir ) ) {
206 if ( strlen(ent->d_name) != 7 ) {
207 // simple heuristic to ingore non-scenery directories
208 } else if ( ent->d_name[0] != 'e' && ent->d_name[0] != 'w' ) {
209 // further sanity checks on name
210 } else if ( ent->d_name[4] != 'n' && ent->d_name[4] != 's' ) {
211 // further sanity checks on name
213 dir_list.push_back( ent->d_name );
218 // convert to a qsort()'able array
219 string *sort_list = new string[dir_list.size()];
220 for ( i = 0; i < dir_list.size(); ++i ) {
221 sort_list[i] = fl_filename_name( dir_list[i].c_str() );
224 // Sort the file list into display order
225 qsort(sort_list, dir_list.size(), sizeof(string), stringCompare);
227 for ( int i = 0; i < dir_list.size(); ++i ) {
228 remove_box->add( sort_list[i].c_str() );
233 remove_box->redraw();
238 // install selected files
239 void FGAdminUI::install_selected() {
242 install_b->deactivate();
243 remove_b->deactivate();
245 // traverse install box and install each item
246 for ( int i = 0; i <= install_box->nitems(); ++i ) {
247 if ( install_box->checked( i ) ) {
248 f = install_box->text( i );
249 SGPath file( source );
251 cout << "installing " << file.str() << endl;
252 progress->value( min_progress );
253 main_window->cursor( FL_CURSOR_WAIT );
254 tarextract( (char *)file.c_str(), (char *)dest.c_str(), true, &FGAdminUI::step, this );
255 progress->value( min_progress );
256 main_window->cursor( FL_CURSOR_DEFAULT );
259 install_b->activate();
260 remove_b->activate();
266 static void remove_dir( const char *dir_name, void (*step)(void*), void *data ) {
267 ulDir *dir = ulOpenDir( dir_name ) ;
269 while ( ent = ulReadDir( dir ) ) {
270 if ( strcmp( ent->d_name, "." ) == 0 ) {
272 } else if ( strcmp( ent->d_name, ".." ) == 0 ) {
274 } else if ( ent->d_isdir ) {
275 SGPath child( dir_name );
276 child.append( ent->d_name );
277 remove_dir( child.c_str(), step, data );
279 SGPath child( dir_name );
280 child.append( ent->d_name );
281 unlink( child.c_str() );
282 if (step) step( data );
290 // remove selected files
291 void FGAdminUI::remove_selected() {
294 install_b->deactivate();
295 remove_b->deactivate();
296 // traverse remove box and recursively remove each item
297 for ( int i = 0; i <= remove_box->nitems(); ++i ) {
298 if ( remove_box->checked( i ) ) {
299 f = remove_box->text( i );
302 progress->value( min_progress );
303 main_window->cursor( FL_CURSOR_WAIT );
304 cout << "removing " << dir.str() << endl;
305 remove_dir( dir.c_str(), &FGAdminUI::step, this );
306 progress->value( min_progress );
307 main_window->cursor( FL_CURSOR_DEFAULT );
310 install_b->activate();
311 remove_b->activate();
318 void FGAdminUI::step(void *data)
320 Fl_Progress *p = ((FGAdminUI*)data)->progress;
322 // we don't actually know the total work in advanced due to the
323 // nature of tar archives, and it would be inefficient to prescan
324 // the files, so just cycle the progress bar until we are done.
325 float tmp = p->value() + 1;
326 if ( tmp > max_progress ) {