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