fixes and upgrades to guicast
[goodguy/history.git] / cinelerra-5.0 / guicast / bcfilebox.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdelete.h"
23 #include "bcfilebox.h"
24 #include "bclistboxitem.h"
25 #include "bcnewfolder.h"
26 #include "bcpixmap.h"
27 #include "bcrename.h"
28 #include "bcresources.h"
29 #include "bcsignals.h"
30 #include "bctitle.h"
31 #include "clip.h"
32 #include "condition.h"
33 #include "filesystem.h"
34 #include "format.inc"
35 #include "keys.h"
36 #include "language.h"
37 #include "mutex.h"
38 #include <string.h>
39 #include <sys/stat.h>
40
41
42
43
44
45
46
47 BC_FileBoxRecent::BC_FileBoxRecent(BC_FileBox *filebox, int x, int y)
48  : BC_ListBox(x, y, 250,
49                 filebox->get_text_height(MEDIUMFONT) * FILEBOX_HISTORY_SIZE +
50                 BC_ScrollBar::get_span(SCROLL_HORIZ) +
51                 LISTBOX_MARGIN * 2, LISTBOX_TEXT, &filebox->recent_dirs,
52                 0, 0, 1, 0, 1)
53 {
54         this->filebox = filebox;
55 }
56
57 int BC_FileBoxRecent::handle_event()
58 {
59         BC_ListBoxItem *selection = get_selection(0, 0);
60         if( selection != 0 ) {
61                 char *path = selection->get_text();
62                 filebox->submit_dir(path);
63         }
64         return 1;
65 }
66
67
68
69
70
71
72
73
74
75
76
77 BC_FileBoxListBox::BC_FileBoxListBox(int x, int y, BC_FileBox *filebox)
78  : BC_ListBox(x, y, filebox->get_listbox_w(), filebox->get_listbox_h(y),
79                 filebox->get_display_mode(), filebox->list_column,
80                 filebox->column_titles, filebox->column_width,
81                 filebox->columns, 0, 0,
82                 filebox->select_multiple ? LISTBOX_MULTIPLE : LISTBOX_SINGLE,
83                 ICON_LEFT, 0)
84 {
85         this->filebox = filebox;
86         set_sort_column(filebox->sort_column);
87         set_sort_order(filebox->sort_order);
88         set_allow_drag_column(1);
89 }
90
91 BC_FileBoxListBox::~BC_FileBoxListBox()
92 {
93 }
94
95 int BC_FileBoxListBox::handle_event()
96 {
97         filebox->submit_file(filebox->textbox->get_text());
98         return 1;
99 }
100
101 int BC_FileBoxListBox::selection_changed()
102 {
103         BC_ListBoxItem *item = get_selection(
104                 filebox->column_of_type(FILEBOX_NAME), 0);
105
106         if(item) {
107                 char path[BCTEXTLEN];
108                 strcpy(path, item->get_text());
109                 filebox->textbox->update(path);
110                 filebox->fs->extract_dir(filebox->directory, path);
111                 filebox->fs->extract_name(filebox->filename, path);
112                 filebox->fs->complete_path(path);
113                 strcpy(filebox->current_path, path);
114                 strcpy(filebox->submitted_path, path);
115         }
116         return 1;
117 }
118
119 int BC_FileBoxListBox::column_resize_event()
120 {
121         for(int i = 0; i < filebox->columns; i++)
122                 BC_WindowBase::get_resources()->filebox_columnwidth[i] =
123                         filebox->column_width[i] =
124                         get_column_width(i);
125         return 1;
126 }
127
128 int BC_FileBoxListBox::sort_order_event()
129 {
130         get_resources()->filebox_sortcolumn = filebox->sort_column = get_sort_column();
131         get_resources()->filebox_sortorder = filebox->sort_order = get_sort_order();
132         filebox->refresh();
133         return 1;
134 }
135
136 int BC_FileBoxListBox::move_column_event()
137 {
138         filebox->move_column(get_from_column(), get_to_column());
139         return 1;
140 }
141
142 int BC_FileBoxListBox::evaluate_query(char *string)
143 {
144 // Search name column
145         ArrayList<BC_ListBoxItem*> *column =
146                 &filebox->list_column[filebox->column_of_type(FILEBOX_NAME)];
147 // Get current selection
148         int current_selection = get_selection_number(0, 0);
149
150 // Get best score in remaining items
151         int lowest_score = 0x7fffffff;
152         int best_item = -1;
153         if(current_selection < 0) current_selection = 0;
154 //      for(int i = current_selection + 1; i < column->size(); i++)
155         for(int i = current_selection; i < column->size(); i++)
156         {
157                 int len1 = strlen(string);
158                 int len2 = strlen(column->get(i)->get_text());
159                 int current_score = strncasecmp(string,
160                         column->get(i)->get_text(),
161                         MIN(len1, len2));
162 //printf(" %d i=%d %d %s %s\n", __LINE__, i, current_score, string, column->get(i)->get_text());
163
164                 if(abs(current_score) < lowest_score)
165                 {
166                         lowest_score = abs(current_score);
167                         best_item = i;
168                 }
169         }
170
171
172         return best_item;
173 }
174
175
176
177
178 BC_FileBoxTextBox::BC_FileBoxTextBox(int x, int y, BC_FileBox *filebox)
179  : BC_TextBox(x, y, filebox->get_w() - 20, 1,
180         filebox->want_directory ?  filebox->directory : filebox->filename)
181 {
182         this->filebox = filebox;
183 }
184
185 BC_FileBoxTextBox::~BC_FileBoxTextBox()
186 {
187 }
188
189
190
191
192 int BC_FileBoxTextBox::handle_event()
193 {
194         int result = 0;
195         if(get_keypress() != RETURN)
196         {
197                 result = calculate_suggestions(&filebox->list_column[0]);
198         }
199         return result;
200 }
201
202
203
204
205 BC_FileBoxDirectoryText::BC_FileBoxDirectoryText(int x, int y, BC_FileBox *filebox)
206  : BC_TextBox(x, y, filebox->get_w() - 40, 1, filebox->fs->get_current_dir())
207 {
208         this->filebox = filebox;
209 }
210
211 int BC_FileBoxDirectoryText::handle_event()
212 {
213         const char *path = get_text();
214         if( !filebox->fs->is_dir(path) ) return 0;
215         const char *cp = path;
216         while( *cp ) ++cp;
217         if( cp > path && *--cp != '/' ) return 0;
218         char *file_path = FileSystem::basepath(path);
219         char *dir_path = FileSystem::basepath(filebox->fs->get_current_dir());
220         int ret = !strcmp(file_path, dir_path) ? 0 : 1;
221         if( ret ) {
222                 strcpy(filebox->directory, file_path);
223                 filebox->update_history();
224                 filebox->fs->change_dir(file_path);
225                 filebox->refresh(1);
226         }
227         delete [] dir_path;
228         delete [] file_path;
229         return ret;
230 }
231
232
233
234
235
236 BC_FileBoxFilterText::BC_FileBoxFilterText(int x, int y, BC_FileBox *filebox)
237  : BC_TextBox(x, y, filebox->get_w() - 50, 1, filebox->get_resources()->filebox_filter)
238 {
239         this->filebox = filebox;
240 }
241
242 int BC_FileBoxFilterText::handle_event()
243 {
244         filebox->update_filter(get_text());
245         return 1;
246 }
247
248
249
250
251 BC_FileBoxFilterMenu::BC_FileBoxFilterMenu(int x, int y, BC_FileBox *filebox)
252  : BC_ListBox(x,
253         y,
254         filebox->get_w() - 30,
255         120,
256         LISTBOX_TEXT,
257         &filebox->filter_list,
258         0,
259         0,
260         1,
261         0,
262         1)
263 {
264         this->filebox = filebox;
265         set_tooltip(_("Change the filter"));
266 }
267
268 int BC_FileBoxFilterMenu::handle_event()
269 {
270         filebox->filter_text->update(
271                 get_selection(filebox->column_of_type(FILEBOX_NAME), 0)->get_text());
272         filebox->update_filter(
273                 get_selection(filebox->column_of_type(FILEBOX_NAME), 0)->get_text());
274         return 1;
275 }
276
277
278
279
280
281
282
283
284
285
286 BC_FileBoxCancel::BC_FileBoxCancel(BC_FileBox *filebox)
287  : BC_CancelButton(filebox)
288 {
289         this->filebox = filebox;
290         set_tooltip(_("Cancel the operation"));
291 }
292
293 BC_FileBoxCancel::~BC_FileBoxCancel()
294 {
295 }
296
297 int BC_FileBoxCancel::handle_event()
298 {
299 //      filebox->submit_file(filebox->textbox->get_text());
300         filebox->newfolder_thread->interrupt();
301         filebox->set_done(1);
302         return 1;
303 }
304
305
306
307
308
309
310
311 BC_FileBoxUseThis::BC_FileBoxUseThis(BC_FileBox *filebox)
312  : BC_Button(filebox->get_w() / 2 -
313                 BC_WindowBase::get_resources()->usethis_button_images[0]->get_w() / 2,
314         filebox->ok_button->get_y(),
315         BC_WindowBase::get_resources()->usethis_button_images)
316 {
317         this->filebox = filebox;
318         set_tooltip(_("Submit the directory"));
319 }
320
321 BC_FileBoxUseThis::~BC_FileBoxUseThis()
322 {
323 }
324
325 int BC_FileBoxUseThis::handle_event()
326 {
327 // printf("BC_FileBoxUseThis::handle_event %d '%s'\n",
328 // __LINE__,
329 // filebox->textbox->get_text());
330         filebox->submit_file(filebox->textbox->get_text(), 1);
331         return 1;
332 }
333
334
335
336
337
338 BC_FileBoxOK::BC_FileBoxOK(BC_FileBox *filebox)
339  : BC_OKButton(filebox,
340         !filebox->want_directory ?
341                 BC_WindowBase::get_resources()->ok_images :
342                 BC_WindowBase::get_resources()->filebox_descend_images)
343 {
344         this->filebox = filebox;
345         if(filebox->want_directory)
346                 set_tooltip(_("Descend directory"));
347         else
348                 set_tooltip(_("Submit the file"));
349 }
350
351 BC_FileBoxOK::~BC_FileBoxOK()
352 {
353 }
354
355 int BC_FileBoxOK::handle_event()
356 {
357 //printf("BC_FileBoxOK::handle_event %d\n", __LINE__);
358         filebox->submit_file(filebox->textbox->get_text());
359         return 1;
360 }
361
362
363
364
365
366
367 BC_FileBoxText::BC_FileBoxText(int x, int y, BC_FileBox *filebox)
368  : BC_Button(x, y, BC_WindowBase::get_resources()->filebox_text_images)
369 {
370         this->filebox = filebox;
371         set_tooltip(_("Display text"));
372 }
373 int BC_FileBoxText::handle_event()
374 {
375         filebox->create_listbox(filebox->listbox->get_x(), filebox->listbox->get_y(), LISTBOX_TEXT);
376         filebox->listbox->show_window(1);
377         return 1;
378 }
379
380
381 BC_FileBoxIcons::BC_FileBoxIcons(int x, int y, BC_FileBox *filebox)
382  : BC_Button(x, y, BC_WindowBase::get_resources()->filebox_icons_images)
383 {
384         this->filebox = filebox;
385         set_tooltip(_("Display icons"));
386 }
387 int BC_FileBoxIcons::handle_event()
388 {
389         filebox->create_listbox(filebox->listbox->get_x(), filebox->listbox->get_y(), LISTBOX_ICONS);
390         filebox->listbox->show_window(1);
391         return 1;
392 }
393
394
395 BC_FileBoxNewfolder::BC_FileBoxNewfolder(int x, int y, BC_FileBox *filebox)
396  : BC_Button(x, y, BC_WindowBase::get_resources()->filebox_newfolder_images)
397 {
398         this->filebox = filebox;
399         set_tooltip(_("Create new folder"));
400 }
401 int BC_FileBoxNewfolder::handle_event()
402 {
403         filebox->newfolder_thread->start_new_folder();
404         return 1;
405 }
406
407
408 BC_FileBoxRename::BC_FileBoxRename(int x, int y, BC_FileBox *filebox)
409  : BC_Button(x, y, BC_WindowBase::get_resources()->filebox_rename_images)
410 {
411         this->filebox = filebox;
412         set_tooltip(_("Rename file"));
413 }
414 int BC_FileBoxRename::handle_event()
415 {
416         filebox->rename_thread->start_rename();
417         return 1;
418 }
419
420 BC_FileBoxUpdir::BC_FileBoxUpdir(int x, int y, BC_FileBox *filebox)
421  : BC_Button(x, y, BC_WindowBase::get_resources()->filebox_updir_images)
422 {
423         this->filebox = filebox;
424         set_tooltip(_("Up a directory"));
425 }
426 int BC_FileBoxUpdir::handle_event()
427 {
428 // Need a temp so submit_file can expand it
429         sprintf(string, "..");
430         filebox->submit_file(string);
431         return 1;
432 }
433
434 BC_FileBoxDelete::BC_FileBoxDelete(int x, int y, BC_FileBox *filebox)
435  : BC_Button(x, y, BC_WindowBase::get_resources()->filebox_delete_images)
436 {
437         this->filebox = filebox;
438         set_tooltip(_("Delete files"));
439 }
440 int BC_FileBoxDelete::handle_event()
441 {
442         filebox->unlock_window();
443         filebox->delete_thread->start();
444         filebox->lock_window("BC_FileBoxDelete::handle_event");
445         return 1;
446 }
447
448 BC_FileBoxReload::BC_FileBoxReload(int x, int y, BC_FileBox *filebox)
449  : BC_Button(x, y, BC_WindowBase::get_resources()->filebox_reload_images)
450 {
451         this->filebox = filebox;
452         set_tooltip(_("Refresh"));
453 }
454 int BC_FileBoxReload::handle_event()
455 {
456         filebox->refresh();
457         return 1;
458 }
459
460
461
462
463
464
465
466
467
468
469 BC_FileBox::BC_FileBox(int x, int y, const char *init_path,
470                 const char *title, const char *caption, int show_all_files,
471                 int want_directory, int multiple_files, int h_padding)
472  : BC_Window(title, x, y,
473         BC_WindowBase::get_resources()->filebox_w,
474         BC_WindowBase::get_resources()->filebox_h,
475         400, 300, 1, 0, 1)
476 {
477         fs = new FileSystem;
478 //      if(want_directory)
479 //      {
480 //              fs->set_want_directory();
481 //              columns = DIRBOX_COLUMNS;
482 //              columns = FILEBOX_COLUMNS;
483 //      }
484 //      else
485         {
486                 columns = FILEBOX_COLUMNS;
487         }
488
489         list_column = new ArrayList<BC_ListBoxItem*>[columns];
490         column_type = new int[columns];
491         column_width = new int[columns];
492
493         filter_text = 0;
494         filter_popup = 0;
495         usethis_button = 0;
496
497         strcpy(this->caption, caption);
498         strcpy(this->current_path, init_path);
499         strcpy(this->submitted_path, init_path);
500         select_multiple = multiple_files;
501         this->want_directory = want_directory;
502         if(show_all_files) fs->set_show_all();
503         fs->complete_path(this->current_path);
504         fs->complete_path(this->submitted_path);
505         fs->extract_dir(directory, this->current_path);
506         fs->extract_name(filename, this->current_path);
507
508 // printf("BC_FileBox::BC_FileBox %d '%s' '%s' '%s'\n",
509 // __LINE__,
510 // this->submitted_path,
511 // directory,
512 // filename);
513
514 //      if(want_directory)
515 //      {
516 //              for(int i = 0; i < columns; i++)
517 //              {
518 //                      column_type[i] = get_resources()->dirbox_columntype[i];
519 //                      column_width[i] = get_resources()->dirbox_columnwidth[i];
520 //                      column_titles[i] = BC_FileBox::columntype_to_text(column_type[i]);
521 //              }
522 //              sort_column = get_resources()->dirbox_sortcolumn;
523 //              sort_order = get_resources()->dirbox_sortorder;
524 //      }
525 //      else
526         {
527                 for(int i = 0; i < columns; i++)
528                 {
529                         column_type[i] = get_resources()->filebox_columntype[i];
530                         column_width[i] = get_resources()->filebox_columnwidth[i];
531                         column_titles[i] = (char*)BC_FileBox::columntype_to_text(column_type[i]);
532                 }
533                 sort_column = get_resources()->filebox_sortcolumn;
534                 sort_order = get_resources()->filebox_sortorder;
535         }
536
537
538
539 // Test if current directory exists
540         if(!fs->is_dir(directory))
541         {
542                 sprintf(this->current_path, "~");
543                 fs->complete_path(this->current_path);
544                 fs->set_current_dir(this->current_path);
545 //              fs->update(this->current_path);
546                 strcpy(directory, fs->get_current_dir());
547                 filename[0] = 0;
548         }
549         else
550                 fs->set_current_dir(this->directory);
551
552
553         if(h_padding == -1)
554         {
555                 h_padding = BC_WindowBase::get_resources()->ok_images[0]->get_h() -
556                         20;
557         }
558         this->h_padding = h_padding;
559         delete_thread = new BC_DeleteThread(this);
560         rename_thread = 0;
561 }
562
563 BC_FileBox::~BC_FileBox()
564 {
565 // this has to be destroyed before tables, because it can call for an update!
566         delete newfolder_thread;
567         delete fs;
568         delete_tables();
569         for(int i = 0; i < TOTAL_ICONS; i++)
570                 delete icons[i];
571         filter_list.remove_all_objects();
572         delete [] list_column;
573         delete [] column_type;
574         delete [] column_width;
575         delete delete_thread;
576         delete rename_thread;
577         recent_dirs.remove_all_objects();
578 }
579
580 void BC_FileBox::create_objects()
581 {
582         int x = 10, y = 10;
583         BC_Resources *resources = BC_WindowBase::get_resources();
584         int directory_title_margin = MAX(20,
585                 resources->filebox_text_images[0]->get_h());
586
587 // Create recent dir list
588         create_history();
589
590 // Directories aren't filtered in FileSystem so skip this
591         if(!want_directory)
592         {
593                 filter_list.append(new BC_ListBoxItem("*"));
594                 filter_list.append(new BC_ListBoxItem("[*.ifo][*.vob]"));
595                 filter_list.append(new BC_ListBoxItem("[*.mp2][*.mp3][*.wav]"));
596                 filter_list.append(new BC_ListBoxItem("[*.avi][*.mpg][*.m2v][*.m1v][*.mov]"));
597                 filter_list.append(new BC_ListBoxItem("heroine*"));
598                 filter_list.append(new BC_ListBoxItem("*.xml"));
599                 fs->set_filter(get_resources()->filebox_filter);
600         }
601
602 //      fs->update(directory);
603         create_icons();
604         create_tables();
605
606         add_subwindow(ok_button = new BC_FileBoxOK(this));
607         if(want_directory)
608                 add_subwindow(usethis_button = new BC_FileBoxUseThis(this));
609         add_subwindow(cancel_button = new BC_FileBoxCancel(this));
610
611         add_subwindow(new BC_Title(x, y, caption));
612
613         x = get_w() - resources->filebox_icons_images[0]->get_w() - 10;
614
615         add_subwindow(icon_button = new BC_FileBoxIcons(x, y, this));
616         x -= resources->filebox_text_images[0]->get_w() + 5;
617
618         add_subwindow(text_button = new BC_FileBoxText(x, y, this));
619         x -= resources->filebox_newfolder_images[0]->get_w() + 5;
620
621         add_subwindow(folder_button = new BC_FileBoxNewfolder(x, y, this));
622         x -= resources->filebox_delete_images[0]->get_w() + 5;
623
624         add_subwindow(rename_button = new BC_FileBoxRename(x, y, this));
625         x -= resources->filebox_delete_images[0]->get_w() + 5;
626
627         add_subwindow(delete_button = new BC_FileBoxDelete(x, y, this));
628         x -= resources->filebox_reload_images[0]->get_w() + 5;
629
630         add_subwindow(reload_button = new BC_FileBoxReload(x, y, this));
631         x -= resources->filebox_updir_images[0]->get_w() + 5;
632
633         add_subwindow(updir_button = new BC_FileBoxUpdir(x, y, this));
634
635         x = 10;
636         y += directory_title_margin + 3;
637
638         add_subwindow(recent_popup = new BC_FileBoxRecent(this, x, y));
639         add_subwindow(directory_title = new BC_FileBoxDirectoryText(x, y, this));
640         directory_title->reposition_window(x, y,
641                 get_w() - recent_popup->get_w() -  20, 1);
642         recent_popup->reposition_window(
643                 x + directory_title->get_w(), y,
644                 directory_title->get_w(), 200);
645
646         x = 10;
647         y += directory_title->get_h() + 5;
648
649         int newest_id = 0, newest = -1;
650         for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++) {
651                 if( !resources->filebox_history[i].path[0] ) continue;
652                 if( resources->filebox_history[i].id > newest_id ) {
653                         newest_id = resources->filebox_history[i].id;
654                         newest = i;
655                 }
656         }
657         if( newest >= 0 ) {
658                 strcpy(directory, resources->filebox_history[newest].path);
659                 fs->change_dir(directory, 0);
660                 directory_title->update(fs->get_current_dir());
661         }
662
663         listbox = 0;
664         create_listbox(x, y, get_display_mode());
665         y += listbox->get_h() + 10;
666         add_subwindow(textbox = new BC_FileBoxTextBox(x, y, this));
667         y += textbox->get_h() + 10;
668
669         if(!want_directory) {
670                 add_subwindow(filter_text = new BC_FileBoxFilterText(x, y, this));
671                 add_subwindow(filter_popup =
672                         new BC_FileBoxFilterMenu(x + filter_text->get_w(), y, this));;
673         }
674
675 // listbox has to be active because refresh might be called from newfolder_thread
676         listbox->activate();
677         newfolder_thread = new BC_NewFolderThread(this);
678
679         rename_thread = new BC_RenameThread(this);
680
681
682         show_window();
683 }
684
685 int BC_FileBox::get_listbox_w()
686 {
687         return get_w() - 20;
688 }
689
690 int BC_FileBox::get_listbox_h(int y)
691 {
692         int result = get_h() -
693                 y -
694                 h_padding;
695         if(want_directory)
696                 result -= BC_WindowBase::get_resources()->dirbox_margin;
697         else
698                 result -= BC_WindowBase::get_resources()->filebox_margin;
699
700         return result;
701 }
702
703 int BC_FileBox::create_icons()
704 {
705         for(int i = 0; i < TOTAL_ICONS; i++)
706         {
707                 icons[i] = new BC_Pixmap(this,
708                         BC_WindowBase::get_resources()->type_to_icon[i],
709                         PIXMAP_ALPHA);
710         }
711         return 0;
712 }
713
714 int BC_FileBox::resize_event(int w, int h)
715 {
716         draw_background(0, 0, w, h);
717         flash(0);
718
719 // OK button handles resize event itself
720 //      ok_button->reposition_window(ok_button->get_x(),
721 //              h - (get_h() - ok_button->get_y()));
722 //      cancel_button->reposition_window(w - (get_w() - cancel_button->get_x()),
723 //              h - (get_h() - cancel_button->get_y()));
724         if(usethis_button)
725                 usethis_button->reposition_window(w / 2 - 50,
726                         h - (get_h() - usethis_button->get_y()));
727
728
729         if(filter_popup) filter_popup->reposition_window(w - (get_w() - filter_popup->get_x()),
730                 h - (get_h() - filter_popup->get_y()),
731                 w - 30,
732                 0);
733
734
735         if(filter_text) filter_text->reposition_window(filter_text->get_x(),
736                 h - (get_h() - filter_text->get_y()),
737                 w - (get_w() - filter_text->get_w()),
738                 1);
739         directory_title->reposition_window(
740                 directory_title->get_x(),
741                 directory_title->get_y(),
742                 get_w() - recent_popup->get_w() -  20,
743                 1);
744         recent_popup->reposition_window(
745                 directory_title->get_x() + directory_title->get_w(),
746                 directory_title->get_y(),
747                 directory_title->get_w() + recent_popup->get_w(),
748                 recent_popup->get_h());
749         textbox->reposition_window(textbox->get_x(),
750                 h - (get_h() - textbox->get_y()),
751                 w - (get_w() - textbox->get_w()),
752                 1);
753         listbox->reposition_window(listbox->get_x(),
754                 listbox->get_y(),
755                 w - (get_w() - listbox->get_w()),
756                 h - (get_h() - listbox->get_h()),
757                 0);
758         icon_button->reposition_window(w - (get_w() - icon_button->get_x()),
759                 icon_button->get_y());
760         text_button->reposition_window(w - (get_w() - text_button->get_x()),
761                 text_button->get_y());
762         folder_button->reposition_window(w - (get_w() - folder_button->get_x()),
763                 folder_button->get_y());
764         rename_button->reposition_window(w - (get_w() - rename_button->get_x()),
765                 rename_button->get_y());
766         reload_button->reposition_window(w - (get_w() - reload_button->get_x()),
767                 reload_button->get_y());
768         delete_button->reposition_window(w - (get_w() - delete_button->get_x()),
769                 delete_button->get_y());
770         updir_button->reposition_window(w - (get_w() - updir_button->get_x()),
771                 updir_button->get_y());
772         set_w(w);
773         set_h(h);
774         get_resources()->filebox_w = get_w();
775         get_resources()->filebox_h = get_h();
776         flush();
777         return 1;
778 }
779
780 int BC_FileBox::keypress_event()
781 {
782         switch(get_keypress())
783         {
784                 case 'w':
785                         if(ctrl_down()) set_done(1);
786                         return 1;
787                         break;
788         }
789         return 0;
790 }
791
792 int BC_FileBox::close_event()
793 {
794         set_done(1);
795         return 1;
796 }
797
798 int BC_FileBox::handle_event()
799 {
800         return 0;
801 }
802
803 int BC_FileBox::extract_extension(char *out, const char *in)
804 {
805         *out = 0;
806         int i = strlen(in);
807         while( --i>=0 && in[i]!='.' );
808         if( i >= 0 ) strcpy(out, &in[++i]);
809         return 0;
810 }
811
812 int BC_FileBox::create_tables()
813 {
814         delete_tables();
815         char string[BCTEXTLEN];
816         BC_ListBoxItem *new_item;
817
818         fs->set_sort_order(sort_order);
819         fs->set_sort_field(column_type[sort_column]);
820
821 // Directory is entered before this from a random source
822         fs->update(0);
823         for(int i = 0; i < fs->total_files(); i++)
824         {
825                 FileItem *file_item = fs->get_entry(i);
826                 int is_dir = file_item->is_dir;
827                 BC_Pixmap* icon = get_icon(file_item->name, is_dir);
828
829 // Name entry
830                 new_item = new BC_ListBoxItem(file_item->name,
831                         icon,
832                         is_dir ? get_resources()->directory_color : get_resources()->file_color);
833                 if(is_dir) new_item->set_searchable(0);
834                 list_column[column_of_type(FILEBOX_NAME)].append(new_item);
835
836 // Size entry
837 //              if(!want_directory)
838 //              {
839                         if(!is_dir)
840                         {
841                                 sprintf(string, "%jd", file_item->size);
842                                 new_item = new BC_ListBoxItem(string, get_resources()->file_color);
843                         }
844                         else
845                         {
846                                 new_item = new BC_ListBoxItem("", get_resources()->directory_color);
847                         }
848
849                         list_column[column_of_type(FILEBOX_SIZE)].append(new_item);
850 //              }
851
852 // Date entry
853                 if(!is_dir || 1)
854                 {
855                         static const char *month_text[13] = { "Nul",
856                                 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
857                                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
858                         };
859                         sprintf(string,
860                                 "%s %d, %d",
861                                 month_text[file_item->month],
862                                 file_item->day,
863                                 file_item->year);
864                         new_item = new BC_ListBoxItem(string, get_resources()->file_color);
865                 }
866                 else
867                 {
868                         new_item = new BC_ListBoxItem("", get_resources()->directory_color);
869                 }
870
871                 list_column[column_of_type(FILEBOX_DATE)].append(new_item);
872
873 // Extension entry
874 //              if(!want_directory)
875 //              {
876                         if(!is_dir) {
877                                 extract_extension(string, file_item->name);
878                                 new_item = new BC_ListBoxItem(string, get_resources()->file_color);
879                         }
880                         else {
881                                 new_item = new BC_ListBoxItem("", get_resources()->directory_color);
882                         }
883                         list_column[column_of_type(FILEBOX_EXTENSION)].append(new_item);
884 //              }
885         }
886
887         return 0;
888 }
889
890 int BC_FileBox::delete_tables()
891 {
892         for(int j = 0; j < columns; j++)
893         {
894                 list_column[j].remove_all_objects();
895         }
896         return 0;
897 }
898
899 BC_Pixmap* BC_FileBox::get_icon(char *path, int is_dir)
900 {
901         char *suffix = strrchr(path, '.');
902         int icon_type = ICON_UNKNOWN;
903
904         if(is_dir) return icons[ICON_FOLDER];
905
906         if(suffix)
907         {
908                 suffix++;
909                 if(*suffix != 0)
910                 {
911                         for(int i = 0; i < TOTAL_SUFFIXES; i++)
912                         {
913                                 if(!strcasecmp(suffix, BC_WindowBase::get_resources()->suffix_to_type[i].suffix))
914                                 {
915                                         icon_type = BC_WindowBase::get_resources()->suffix_to_type[i].icon_type;
916                                         break;
917                                 }
918                         }
919                 }
920         }
921
922         return icons[icon_type];
923 }
924
925 const char* BC_FileBox::columntype_to_text(int type)
926 {
927         switch(type)
928         {
929                 case FILEBOX_NAME:
930                         return FILEBOX_NAME_TEXT;
931                         break;
932                 case FILEBOX_SIZE:
933                         return FILEBOX_SIZE_TEXT;
934                         break;
935                 case FILEBOX_DATE:
936                         return FILEBOX_DATE_TEXT;
937                         break;
938                 case FILEBOX_EXTENSION:
939                         return FILEBOX_EXTENSION_TEXT;
940                         break;
941         }
942         return "";
943 }
944
945 int BC_FileBox::column_of_type(int type)
946 {
947         for(int i = 0; i < columns; i++)
948                 if(column_type[i] == type) return i;
949         return 0;
950 }
951
952
953
954 int BC_FileBox::refresh(int zscroll)
955 {
956         create_tables();
957         listbox->set_master_column(column_of_type(FILEBOX_NAME), 0);
958         listbox->update(list_column, column_titles, column_width, columns,
959                 !zscroll ? listbox->get_xposition() : 0,
960                 !zscroll ? listbox->get_yposition() : 0,
961                 -1, 1);
962         return 0;
963 }
964
965 int BC_FileBox::update_filter(const char *filter)
966 {
967         fs->set_filter(filter);
968 //      fs->update(0);
969         refresh();
970         strcpy(get_resources()->filebox_filter, filter);
971
972         return 0;
973 }
974
975
976 void BC_FileBox::move_column(int src, int dst)
977 {
978         if(src != dst)
979         {
980
981                 ArrayList<BC_ListBoxItem*> *new_columns =
982                         new ArrayList<BC_ListBoxItem*>[columns];
983                 int *new_types = new int[columns];
984                 int *new_widths = new int[columns];
985
986         // Fill in remaining columns with consecutive data
987                 for(int out_column = 0, in_column = 0;
988                         out_column < columns;
989                         out_column++,
990                         in_column++)
991                 {
992         // Copy destination column from src column
993                         if(out_column == dst)
994                         {
995                                 for(int i = 0; i < list_column[src].total; i++)
996                                 {
997                                         new_columns[out_column].append(list_column[src].values[i]);
998                                 }
999                                 new_types[out_column] = column_type[src];
1000                                 new_widths[out_column] = column_width[src];
1001                                 in_column--;
1002                         }
1003                         else
1004                         {
1005         // Skip source column
1006                                 if(in_column == src) in_column++;
1007                                 for(int i = 0; i < list_column[src].total; i++)
1008                                 {
1009                                         new_columns[out_column].append(list_column[in_column].values[i]);
1010                                 }
1011                                 new_types[out_column] = column_type[in_column];
1012                                 new_widths[out_column] = column_width[in_column];
1013                         }
1014                 }
1015
1016         // Swap tables
1017                 delete [] list_column;
1018                 delete [] column_type;
1019                 delete [] column_width;
1020                 list_column = new_columns;
1021                 column_type = new_types;
1022                 column_width = new_widths;
1023
1024                 for(int i = 0; i < columns; i++)
1025                 {
1026                         get_resources()->filebox_columntype[i] = column_type[i];
1027                         get_resources()->filebox_columnwidth[i] = column_width[i];
1028                         column_titles[i] = (char*)BC_FileBox::columntype_to_text(column_type[i]);
1029                 }
1030         }
1031
1032         refresh();
1033 }
1034
1035
1036 int BC_FileBox::submit_dir(char *dir)
1037 {
1038         strcpy(directory, dir);
1039         fs->join_names(current_path, directory, filename);
1040
1041 // printf("BC_FileBox::submit_dir %d '%s' '%s' '%s'\n",
1042 // __LINE__,
1043 // current_path,
1044 // directory,
1045 // filename);
1046         strcpy(submitted_path, current_path);
1047         fs->change_dir(dir, 0);
1048         refresh(1);
1049         directory_title->update(fs->get_current_dir());
1050         if(want_directory)
1051                 textbox->update(fs->get_current_dir());
1052         else
1053                 textbox->update(filename);
1054         listbox->reset_query();
1055         return 0;
1056 }
1057
1058 int BC_FileBox::submit_file(const char *path, int use_this)
1059 {
1060 // Deactivate textbox to hide suggestions
1061         textbox->deactivate();
1062
1063 // If file wanted, take the current directory as the desired file.
1064 // If directory wanted, ignore it.
1065         if(!path[0] && !want_directory)
1066         {
1067 // save complete path
1068                 strcpy(this->current_path, directory);
1069 // save complete path
1070                 strcpy(this->submitted_path, directory);
1071                 update_history();
1072 // Zero out filename
1073                 filename[0] = 0;
1074                 set_done(0);
1075                 return 0;
1076         }
1077
1078 // is a directory, change directories
1079         if(fs->is_dir(path) && !use_this)
1080         {
1081                 fs->change_dir(path, 0);
1082                 refresh(1);
1083                 directory_title->update(fs->get_current_dir());
1084                 strcpy(this->current_path, fs->get_current_dir());
1085                 strcpy(this->submitted_path, fs->get_current_dir());
1086                 strcpy(this->directory, fs->get_current_dir());
1087                 filename[0] = 0;
1088                 if(want_directory)
1089                         textbox->update(fs->get_current_dir());
1090                 else
1091                         textbox->update("");
1092                 listbox->reset_query();
1093                 return 1;
1094         }
1095         else
1096 // Is a file or desired directory.  Quit the operation.
1097         {
1098                 char path2[BCTEXTLEN];
1099                 strcpy(path2, path);
1100
1101 // save directory for defaults
1102                 fs->extract_dir(directory, path2);
1103
1104 // Just take the directory
1105                 if(want_directory)
1106                 {
1107                         filename[0] = 0;
1108                         strcpy(path2, directory);
1109                 }
1110                 else
1111 // Take the complete path
1112                 {
1113                         fs->extract_name(filename, path2);     // save filename
1114                 }
1115
1116                 fs->complete_path(path2);
1117                 strcpy(this->current_path, path2);          // save complete path
1118                 strcpy(this->submitted_path, path2);          // save complete path
1119                 update_history();
1120                 newfolder_thread->interrupt();
1121                 set_done(0);
1122                 return 0;
1123         }
1124         return 0;
1125 }
1126
1127 void BC_FileBox::update_history()
1128 {
1129 // Look for path already in history
1130         BC_Resources *resources = get_resources();
1131 //      int new_slot = FILEBOX_HISTORY_SIZE - 1;
1132
1133         for(int i = FILEBOX_HISTORY_SIZE - 1; i >= 0; i--)
1134         {
1135                 if(resources->filebox_history[i].path[0] &&
1136                         !strcmp(resources->filebox_history[i].path, directory))
1137                 {
1138 // Got matching path.
1139 // Update ID.
1140                         resources->filebox_history[i].id = resources->get_filebox_id();
1141                         return;
1142                 }
1143 // // Shift down from this point.
1144 //                      while(i > 0)
1145 //                      {
1146 //                              strcpy(resources->filebox_history[i],
1147 //                                      resources->filebox_history[i - 1]);
1148 //                              if(resources->filebox_history[i][0]) new_slot--;
1149 //                              i--;
1150 //                      }
1151 //                      break;
1152 //              }
1153 //              else
1154 //                      if(resources->filebox_history[i][0])
1155 //                              new_slot--;
1156 //              else
1157 //                      break;
1158         }
1159
1160 // Remove oldest entry if full
1161         if(resources->filebox_history[FILEBOX_HISTORY_SIZE - 1].path[0])
1162         {
1163                 int oldest_id = 0x7fffffff;
1164                 int oldest = 0;
1165                 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
1166                 {
1167                         if(resources->filebox_history[i].path[0] &&
1168                                 resources->filebox_history[i].id < oldest_id)
1169                         {
1170                                 oldest_id = resources->filebox_history[i].id;
1171                                 oldest = i;
1172                         }
1173                 }
1174
1175                 for(int i = oldest; i < FILEBOX_HISTORY_SIZE - 1; i++)
1176                 {
1177                         strcpy(resources->filebox_history[i].path,
1178                                 resources->filebox_history[i + 1].path);
1179                         resources->filebox_history[i].id =
1180                                 resources->filebox_history[i + 1].id;
1181                 }
1182         }
1183
1184 // Create new entry
1185         strcpy(resources->filebox_history[FILEBOX_HISTORY_SIZE - 1].path,
1186                 directory);
1187         resources->filebox_history[FILEBOX_HISTORY_SIZE - 1].id = resources->get_filebox_id();
1188
1189 // Alphabetize
1190         int done = 0;
1191         while(!done)
1192         {
1193                 done = 1;
1194                 for(int i = 1; i < FILEBOX_HISTORY_SIZE; i++)
1195                 {
1196                         if( (resources->filebox_history[i - 1].path[0] &&
1197                                 resources->filebox_history[i].path[0] &&
1198                                 strcasecmp(resources->filebox_history[i - 1].path,
1199                                         resources->filebox_history[i].path) > 0) ||
1200                                 (resources->filebox_history[i - 1].path[0] == 0 &&
1201                                         resources->filebox_history[i].path[0]) )
1202                         {
1203                                 done = 0;
1204                                 char temp[BCTEXTLEN];
1205                                 int id_temp;
1206                                 strcpy(temp, resources->filebox_history[i - 1].path);
1207                                 id_temp = resources->filebox_history[i - 1].id;
1208                                 strcpy(resources->filebox_history[i - 1].path,
1209                                         resources->filebox_history[i].path);
1210                                 resources->filebox_history[i - 1].id =
1211                                         resources->filebox_history[i].id;
1212                                 strcpy(resources->filebox_history[i].path, temp);
1213                                 resources->filebox_history[i].id = id_temp;
1214                         }
1215                 }
1216         }
1217
1218 //      if(new_slot < 0)
1219 //      {
1220 //              for(int i = FILEBOX_HISTORY_SIZE - 1; i > 0; i--)
1221 //              {
1222 //                      strcpy(resources->filebox_history[i],
1223 //                                      resources->filebox_history[i - 1]);
1224 //              }
1225 //              new_slot = 0;
1226 //      }
1227 //
1228 //      strcpy(resources->filebox_history[new_slot], directory);
1229
1230         create_history();
1231         recent_popup->update(&recent_dirs, 0, 0, 1);
1232 }
1233
1234 void BC_FileBox::create_history()
1235 {
1236         BC_Resources *resources = get_resources();
1237         recent_dirs.remove_all_objects();
1238         for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++) {
1239                 if(resources->filebox_history[i].path[0]) {
1240                         recent_dirs.append(new BC_ListBoxItem(resources->filebox_history[i].path));
1241                 }
1242         }
1243 }
1244
1245
1246 int BC_FileBox::get_display_mode()
1247 {
1248         return top_level->get_resources()->filebox_mode;
1249 }
1250
1251 void BC_FileBox::create_listbox(int x, int y, int mode)
1252 {
1253         if(listbox && listbox->get_display_mode() != mode)
1254         {
1255                 delete listbox;
1256                 listbox = 0;
1257                 top_level->get_resources()->filebox_mode = mode;
1258         }
1259
1260         if(!listbox)
1261                 add_subwindow(listbox = new BC_FileBoxListBox(x, y, this));
1262 }
1263
1264 char* BC_FileBox::get_path(int selection)
1265 {
1266         if(selection == 0)
1267         {
1268                 return get_submitted_path();
1269         }
1270         else
1271         {
1272                 BC_ListBoxItem *item = listbox->get_selection(
1273                         column_of_type(FILEBOX_NAME), selection - 1);
1274                 if(item)
1275                 {
1276                         fs->join_names(string, directory, item->get_text());
1277                         return string;
1278                 }
1279         }
1280         return 0;
1281 }
1282
1283 char* BC_FileBox::get_submitted_path()
1284 {
1285         return submitted_path;
1286 }
1287
1288 char* BC_FileBox::get_current_path()
1289 {
1290 //printf("BC_FileBox::get_current_path 1 %s\n", current_path);
1291         return current_path;
1292 }
1293
1294 char* BC_FileBox::get_newfolder_title()
1295 {
1296         char *letter2 = strchr(title, ':');
1297         new_folder_title[0] = 0;
1298         if(letter2)
1299         {
1300                 memcpy(new_folder_title, title, letter2 - title);
1301                 new_folder_title[letter2 - title] = 0;
1302         }
1303
1304         strcat(new_folder_title, _(": New folder"));
1305
1306         return new_folder_title;
1307 }
1308
1309 char* BC_FileBox::get_rename_title()
1310 {
1311         char *letter2 = strchr(title, ':');
1312         new_folder_title[0] = 0;
1313         if(letter2)
1314         {
1315                 memcpy(new_folder_title, title, letter2 - title);
1316                 new_folder_title[letter2 - title] = 0;
1317         }
1318
1319         strcat(new_folder_title, _(": Rename"));
1320
1321         return new_folder_title;
1322 }
1323
1324 char* BC_FileBox::get_delete_title()
1325 {
1326         char *letter2 = strchr(title, ':');
1327         new_folder_title[0] = 0;
1328         if(letter2)
1329         {
1330                 memcpy(new_folder_title, title, letter2 - title);
1331                 new_folder_title[letter2 - title] = 0;
1332         }
1333
1334         strcat(new_folder_title, _(": Delete"));
1335
1336         return new_folder_title;
1337 }
1338
1339 void BC_FileBox::delete_files()
1340 {
1341 // Starting at 1 causes it to ignore what's in the textbox.
1342         int i = 1;
1343         char *path;
1344         FileSystem fs;
1345         while((path = get_path(i)))
1346         {
1347 // Not directory.  Remove it.
1348                 if(!fs.is_dir(path))
1349                 {
1350 //printf("BC_FileBox::delete_files: removing \"%s\"\n", path);
1351                         remove(path);
1352                 }
1353                 i++;
1354         }
1355         refresh();
1356 }
1357
1358 BC_Button* BC_FileBox::get_ok_button()
1359 {
1360         return ok_button;
1361 }
1362
1363 BC_Button* BC_FileBox::get_cancel_button()
1364 {
1365         return cancel_button;
1366 }
1367