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