blob: 861f7399776385cd97d57aba5e6e50c025c9a0ab [file] [log] [blame]
DRC2ff39b82011-07-28 08:38:59 +00001//
2// "$Id: Fl_File_Chooser2.cxx 8785 2011-06-06 16:11:22Z manolo $"
3//
4// More Fl_File_Chooser routines.
5//
6// Copyright 1999-2011 by Michael Sweet.
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Library General Public
10// License as published by the Free Software Foundation; either
11// version 2 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// Library General Public License for more details.
17//
18// You should have received a copy of the GNU Library General Public
19// License along with this library; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21// USA.
22//
23// Please report all bugs and problems on the following page:
24//
25// http://www.fltk.org/str.php
26//
27
28// fabien: ATTENTION: Only Out Of Source Gen. because cxx/H files are autogenerated by fluid.
29/** \defgroup group_comdlg Common Dialogs classes and functions
30 @{
31*/
32/** \class Fl_File_Chooser
33 The Fl_File_Chooser widget displays a standard file selection
34 dialog that supports various selection modes.
35
36 \image html Fl_File_Chooser.jpg
37 \image latex Fl_File_Chooser.jpg "Fl_File_Chooser" width=12cm
38
39 The Fl_File_Chooser class also exports several static values
40 that may be used to localize or customize the appearance of all file chooser
41 dialogs:
42
43 <CENTER><TABLE BORDER="1">
44 <TR>
45 <TH>Member</TH>
46 <TH>Default value</TH>
47 </TR>
48 <TR>
49 <TD>add_favorites_label</TD>
50 <TD>"Add to Favorites"</TD>
51 </TR>
52 <TR>
53 <TD>all_files_label</TD>
54 <TD>"All Files (*)"</TD>
55 </TR>
56 <TR>
57 <TD>custom_filter_label</TD>
58 <TD>"Custom Filter"</TD>
59 </TR>
60 <TR>
61 <TD>existing_file_label</TD>
62 <TD>"Please choose an existing file!"</TD>
63 </TR>
64 <TR>
65 <TD>favorites_label</TD>
66 <TD>"Favorites"</TD>
67 </TR>
68 <TR>
69 <TD>filename_label</TD>
70 <TD>"Filename:"</TD>
71 </TR>
72 <TR>
73 <TD>filesystems_label</TD>
74 <TD>"My Computer" (WIN32)<BR>
75 "File Systems" (all others)</TD>
76 </TR>
77 <TR>
78 <TD>hidden_label</TD>
79 <TD>"Show hidden files:"</TD>
80 </TR>
81 <TR>
82 <TD>manage_favorites_label</TD>
83 <TD>"Manage Favorites"</TD>
84 </TR>
85 <TR>
86 <TD>new_directory_label</TD>
87 <TD>"New Directory?"</TD>
88 </TR>
89 <TR>
90 <TD>new_directory_tooltip</TD>
91 <TD>"Create a new directory."</TD>
92 </TR>
93 <TR>
94 <TD>preview_label</TD>
95 <TD>"Preview"</TD>
96 </TR>
97 <TR>
98 <TD>save_label</TD>
99 <TD>"Save"</TD>
100 </TR>
101 <TR>
102 <TD>show_label</TD>
103 <TD>"Show:"</TD>
104 </TR>
105 <TR>
106 <TD>sort</TD>
107 <TD>fl_numericsort</TD>
108 </TR>
109 </TABLE></CENTER>
110
111 The Fl_File_Chooser::sort member specifies the sort function that is
112 used when loading the contents of a directory and can be customized
113 at run-time.
114
115 The Fl_File_Chooser class also exports the Fl_File_Chooser::newButton
116 and Fl_File_Chooser::previewButton widgets so that application developers
117 can control their appearance and use. For more complex customization,
118 consider copying the FLTK file chooser code and changing it accordingly.
119*/
120/** @} */
121
122/** \fn Fl_File_Chooser::Fl_File_Chooser(const char *pathname, const char *pattern, int type, const char *title)
123 The constructor creates the Fl_File_Chooser dialog shown.
124 The pathname argument can be a directory name or a
125 complete file name (in which case the corresponding file is highlighted
126 in the list and in the filename input field.)
127
128 The pattern argument can be a NULL
129 string or "*" to list all files, or it can be a
130 series of descriptions and filter strings separated by tab
131 characters (\\t). The format of filters is either
132 "Description text (patterns)" or just "patterns". A file chooser
133 that provides filters for HTML and image files might look like:
134
135 \code
136 "HTML Files (*.html)\tImage Files (*.{bmp,gif,jpg,png})"
137 \endcode
138
139 The file chooser will automatically add the "All Files (*)"
140 pattern to the end of the string you pass if you do not provide
141 one. The first filter in the string is the default filter.
142
143 See the FLTK documentation on fl_filename_match()
144 for the kinds of pattern strings that are supported.
145
146 The type argument can be one of the following:
147
148 \li \c SINGLE - allows the user to select a single, existing file.
149 \li \c MULTI - allows the user to select one or more existing files.
150 \li \c CREATE - allows the user to select a single, existing file or
151 specify a new filename.
152 \li \c DIRECTORY - allows the user to select a single, existing directory.
153
154 The title argument is used to set the title bar text for the
155 Fl_File_Chooser window.
156*/
157
158/** \var Fl_File_Chooser::newButton
159 The "new directory" button is exported so that application developers
160 can control the appearance and use.
161*/
162
163/** \var Fl_File_Chooser::previewButton
164 The "preview" button is exported so that application developers can
165 control the appearance and use.
166*/
167
168/** \fn Fl_File_Chooser::~Fl_File_Chooser()
169 Destroys the widget and frees all memory used by it.*/
170
171/** \fn void Fl_File_Chooser::color(Fl_Color c)
172 Sets the background color of the Fl_File_Browser list.*/
173
174/** \fn Fl_Color Fl_File_Chooser::color()
175 Gets the background color of the Fl_File_Browser list.*/
176
177/** \fn int Fl_File_Chooser::count()
178 Returns the number of selected files.*/
179
180/** \fn void Fl_File_Chooser::directory(const char *pathname)
181 Sets the current directory.*/
182
183/** \fn const char *Fl_File_Chooser::directory()
184 Gets the current directory.*/
185
186/** \fn void Fl_File_Chooser::filter(const char *pattern)
187 Sets or gets the current filename filter patterns. The filter
188 patterns use fl_filename_match().
189 Multiple patterns can be used by separating them with tabs, like
190 <tt>"*.jpg\t*.png\t*.gif\t*"</tt>. In addition, you can provide
191 human-readable labels with the patterns inside parenthesis, like
192 <tt>"JPEG Files (*.jpg)\tPNG Files (*.png)\tGIF Files (*.gif)\tAll Files (*)"
193 </tt>.
194
195 Use filter(NULL) to show all files.
196*/
197
198/** \fn const char *Fl_File_Chooser::filter()
199 See void filter(const char *pattern)*/
200
201/** \fn void Fl_File_Chooser::filter_value(int f)
202 Sets the current filename filter selection.*/
203
204/** \fn int Fl_File_Chooser::filter_value()
205 Gets the current filename filter selection.*/
206
207/** \fn void Fl_File_Chooser::hide()
208 Hides the Fl_File_Chooser window.*/
209
210/** \fn void Fl_File_Chooser::iconsize(uchar s)
211 Sets the size of the icons in the Fl_File_Browser. By
212 default the icon size is set to 1.5 times the textsize().
213*/
214
215/** \fn uchar Fl_File_Chooser::iconsize()
216 Gets the size of the icons in the Fl_File_Browser. By
217 default the icon size is set to 1.5 times the textsize().
218*/
219
220/** \fn void Fl_File_Chooser::label(const char *l)
221 Sets the title bar text for the Fl_File_Chooser.*/
222
223/** \fn const char *Fl_File_Chooser::label()
224 Gets the title bar text for the Fl_File_Chooser.*/
225
226/** \fn void Fl_File_Chooser::ok_label(const char *l)
227 Sets the label for the "ok" button in the Fl_File_Chooser.
228*/
229
230/** \fn const char *Fl_File_Chooser::ok_label()
231 Gets the label for the "ok" button in the Fl_File_Chooser.
232*/
233
234/** \fn int Fl_File_Chooser::preview() const
235 Returns the current state of the preview box. */
236
237/** \fn void Fl_File_Chooser::rescan()
238 Reloads the current directory in the Fl_File_Browser.*/
239
240/** \fn void Fl_File_Chooser::show()
241 Shows the Fl_File_Chooser window.*/
242
243/** \fn void Fl_File_Chooser::textcolor(Fl_Color c)
244 Sets the current Fl_File_Browser text color.*/
245
246/** \fn Fl_Color Fl_File_Chooser::textcolor()
247 Gets the current Fl_File_Browser text color.*/
248
249/** \fn void Fl_File_Chooser::textfont(Fl_Font f)
250 Sets the current Fl_File_Browser text font.*/
251
252/** \fn Fl_Font Fl_File_Chooser::textfont()
253 Gets the current Fl_File_Browser text font.*/
254
255/** \fn void Fl_File_Chooser::textsize(Fl_Fontsize s)
256 Sets the current Fl_File_Browser text size.*/
257
258/** \fn Fl_Fontsize Fl_File_Chooser::textsize()
259 Gets the current Fl_File_Browser text size.*/
260
261/** \fn void Fl_File_Chooser::type(int t)
262 Sets the current type of Fl_File_Chooser.*/
263
264/** \fn int Fl_File_Chooser::type()
265 Gets the current type of Fl_File_Chooser.*/
266
267/** \fn void Fl_File_Chooser::value(const char *pathname)
268 Sets the current value of the selected file.
269*/
270
271/** \fn const char *Fl_File_Chooser::value(int f)
272 Gets the current value of the selected file(s).
273 \p f is a \c 1-based index into a list of
274 file names. The number of selected files is returned by
275 Fl_File_Chooser::count().
276
277 This sample code loops through all selected files:
278 \code
279 // Get list of filenames user selected from a MULTI chooser
280 for ( int t=1; t<=chooser->count(); t++ ) {
281 const char *filename = chooser->value(t);
282 ...
283 }
284 \endcode
285 */
286
287/** \fn int Fl_File_Chooser::visible()
288 Returns 1 if the Fl_File_Chooser window is visible.*/
289
290/** \fn Fl_Widget* Fl_File_Chooser::add_extra(Fl_Widget*)
291 Adds extra widget at the bottom of Fl_File_Chooser window.
292 Returns pointer for previous extra widget or NULL if not set previously.
293 If argument is NULL only remove previous extra widget.
294
295 \note Fl_File_Chooser does \b not delete extra widget in destructor!
296 To prevent memory leakage, don't forget to delete unused extra widgets
297*/
298 /** \fn int Fl_File_Chooser::shown()
299 Returns non-zero if the file chooser main window show() has been called (but not hide()
300 see Fl_Window::shown()
301 */
302
303 /** \fn void Fl_File_Chooser::callback(void (*cb)(Fl_File_Chooser *, void *), void *d = 0)
304 Sets the file chooser callback cb and associated data d */
305
306 /** \fn void Fl_File_Chooser::user_data(void *d)
307 Sets the file chooser user data d */
308
309 /** \fn void * Fl_File_Chooser::user_data() const
310 Gets the file chooser user data d */
311
312 /** \fn Fl_File_Browser* Fl_File_Chooser::browser()
313 returns a pointer to the underlying Fl_File_Browser object */
314// *** END OF OUT OF SOURCE DOC ***
315
316// Contents:
317//
318// Fl_File_Chooser::count() - Return the number of selected files.
319// Fl_File_Chooser::directory() - Set the directory in the file chooser.
320// Fl_File_Chooser::filter() - Set the filter(s) for the chooser.
321// Fl_File_Chooser::newdir() - Make a new directory.
322// Fl_File_Chooser::value() - Return a selected filename.
323// Fl_File_Chooser::rescan() - Rescan the current directory.
324// Fl_File_Chooser::favoritesButtonCB() - Handle favorites selections.
325// Fl_File_Chooser::fileListCB() - Handle clicks (and double-clicks)
326// in the Fl_File_Browser.
327// Fl_File_Chooser::fileNameCB() - Handle text entry in the FileBrowser.
328// Fl_File_Chooser::showChoiceCB() - Handle show selections.
329// compare_dirnames() - Compare two directory names.
330// quote_pathname() - Quote a pathname for a menu.
331// unquote_pathname() - Unquote a pathname from a menu.
332//
333// Fl_File_Chooser::add_extra() - add extra widget at the bottom, return pointer
334// to previous extra widget or NULL if none,
335// If argument is NULL extra widget removed.
336// NOTE! file chooser does't delete extra widget in
337// destructor! To prevent memory leakage don't forget
338// delete unused extra widgets by yourself.
339//
340
341//
342// Include necessary headers.
343//
344
345#include <FL/Fl_File_Chooser.H>
346#include <FL/filename.H>
347#include <FL/fl_ask.H>
348#include <FL/x.H>
349#include <FL/Fl_Shared_Image.H>
350#include <FL/fl_draw.H>
351
352#include <stdio.h>
353#include <stdlib.h>
354#include "flstring.h"
355#include <errno.h>
356#include <sys/types.h>
357#include <sys/stat.h>
358
359#if defined(WIN32) && ! defined (__CYGWIN__)
360# include <direct.h>
361# include <io.h>
362// Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs
363// on Windows, which is supposed to be POSIX compliant...
364# define access _access
365# define mkdir _mkdir
366// Apparently Borland C++ defines DIRECTORY in <direct.h>, which
367// interfers with the Fl_File_Icon enumeration of the same name.
368# ifdef DIRECTORY
369# undef DIRECTORY
370# endif // DIRECTORY
371#else
372# include <unistd.h>
373# include <pwd.h>
374#endif /* WIN32 */
375
376
377//
378// File chooser label strings and sort function...
379//
380
381Fl_Preferences Fl_File_Chooser::prefs_(Fl_Preferences::USER, "fltk.org", "filechooser");
382
383const char *Fl_File_Chooser::add_favorites_label = "Add to Favorites";
384const char *Fl_File_Chooser::all_files_label = "All Files (*)";
385const char *Fl_File_Chooser::custom_filter_label = "Custom Filter";
386const char *Fl_File_Chooser::existing_file_label = "Please choose an existing file!";
387const char *Fl_File_Chooser::favorites_label = "Favorites";
388const char *Fl_File_Chooser::filename_label = "Filename:";
389#ifdef WIN32
390const char *Fl_File_Chooser::filesystems_label = "My Computer";
391#else
392const char *Fl_File_Chooser::filesystems_label = "File Systems";
393#endif // WIN32
394const char *Fl_File_Chooser::manage_favorites_label = "Manage Favorites";
395const char *Fl_File_Chooser::new_directory_label = "New Directory?";
396const char *Fl_File_Chooser::new_directory_tooltip = "Create a new directory.";
397const char *Fl_File_Chooser::preview_label = "Preview";
398const char *Fl_File_Chooser::save_label = "Save";
399const char *Fl_File_Chooser::show_label = "Show:";
400const char *Fl_File_Chooser::hidden_label = "Show hidden files";
401Fl_File_Sort_F *Fl_File_Chooser::sort = fl_numericsort;
402
403
404//
405// Local functions...
406//
407
408static int compare_dirnames(const char *a, const char *b);
409static void quote_pathname(char *, const char *, int);
410static void unquote_pathname(char *, const char *, int);
411
412
413//
414// 'Fl_File_Chooser::count()' - Return the number of selected files.
415//
416
417int // O - Number of selected files
418Fl_File_Chooser::count() {
419 int i; // Looping var
420 int fcount; // Number of selected files
421 const char *filename; // Filename in input field or list
422
423
424 filename = fileName->value();
425
426 if (!(type_ & MULTI)) {
427 // Check to see if the file name input field is blank...
428 if (!filename || !filename[0]) return 0;
429 else return 1;
430 }
431
432 for (i = 1, fcount = 0; i <= fileList->size(); i ++)
433 if (fileList->selected(i)) {
434 // See if this file is a directory...
435 // matt: why would we do that? It is perfectly legal to select multiple
436 // directories in a DIR chooser. They are visually selected and value(i)
437 // returns all of them as expected
438 //filename = (char *)fileList->text(i);
439
440 //if (filename[strlen(filename) - 1] != '/')
441 fcount ++;
442 }
443
444 if (fcount) return fcount;
445 else if (!filename || !filename[0]) return 0;
446 else return 1;
447}
448
449
450//
451// 'Fl_File_Chooser::directory()' - Set the directory in the file chooser.
452//
453
454void
455Fl_File_Chooser::directory(const char *d)// I - Directory to change to
456{
457 char *dirptr; // Pointer into directory
458
459
460// printf("Fl_File_Chooser::directory(\"%s\")\n", d == NULL ? "(null)" : d);
461
462 // NULL == current directory
463 if (d == NULL)
464 d = ".";
465
466#ifdef WIN32
467 // See if the filename contains backslashes...
468 char *slash; // Pointer to slashes
469 char fixpath[FL_PATH_MAX]; // Path with slashes converted
470 if (strchr(d, '\\')) {
471 // Convert backslashes to slashes...
472 strlcpy(fixpath, d, sizeof(fixpath));
473
474 for (slash = strchr(fixpath, '\\'); slash; slash = strchr(slash + 1, '\\'))
475 *slash = '/';
476
477 d = fixpath;
478 }
479#endif // WIN32
480
481 if (d[0] != '\0')
482 {
483 // Make the directory absolute...
484#if (defined(WIN32) && ! defined(__CYGWIN__))|| defined(__EMX__)
485 if (d[0] != '/' && d[0] != '\\' && d[1] != ':')
486#else
487 if (d[0] != '/' && d[0] != '\\')
488#endif /* WIN32 || __EMX__ */
489 fl_filename_absolute(directory_, d);
490 else
491 strlcpy(directory_, d, sizeof(directory_));
492
493 // Strip any trailing slash...
494 dirptr = directory_ + strlen(directory_) - 1;
495 if ((*dirptr == '/' || *dirptr == '\\') && dirptr > directory_)
496 *dirptr = '\0';
497
498 // See if we have a trailing .. or . in the filename...
499 dirptr = directory_ + strlen(directory_) - 3;
500 if (dirptr >= directory_ && strcmp(dirptr, "/..") == 0) {
501 // Yes, we have "..", so strip the trailing path...
502 *dirptr = '\0';
503 while (dirptr > directory_) {
504 if (*dirptr == '/') break;
505 dirptr --;
506 }
507
508 if (dirptr >= directory_ && *dirptr == '/')
509 *dirptr = '\0';
510 } else if ((dirptr + 1) >= directory_ && strcmp(dirptr + 1, "/.") == 0) {
511 // Strip trailing "."...
512 dirptr[1] = '\0';
513 }
514 }
515 else
516 directory_[0] = '\0';
517
518 if (shown()) {
519 // Rescan the directory...
520 rescan();
521 }
522}
523
524
525//
526// 'Fl_File_Chooser::favoritesButtonCB()' - Handle favorites selections.
527//
528
529void
530Fl_File_Chooser::favoritesButtonCB()
531{
532 int v; // Current selection
533 char pathname[FL_PATH_MAX], // Pathname
534 menuname[FL_PATH_MAX]; // Menu name
535
536
537 v = favoritesButton->value();
538
539 if (!v) {
540 // Add current directory to favorites...
541 if (getenv("HOME")) v = favoritesButton->size() - 5;
542 else v = favoritesButton->size() - 4;
543
544 sprintf(menuname, "favorite%02d", v);
545
546 prefs_.set(menuname, directory_);
547 prefs_.flush();
548
549 quote_pathname(menuname, directory_, sizeof(menuname));
550 favoritesButton->add(menuname);
551
552 if (favoritesButton->size() > 104) {
553 ((Fl_Menu_Item *)favoritesButton->menu())[0].deactivate();
554 }
555 } else if (v == 1) {
556 // Manage favorites...
557 favoritesCB(0);
558 } else if (v == 2) {
559 // Filesystems/My Computer
560 directory("");
561 } else {
562 unquote_pathname(pathname, favoritesButton->text(v), sizeof(pathname));
563 directory(pathname);
564 }
565}
566
567
568//
569// 'Fl_File_Chooser::favoritesCB()' - Handle favorites dialog.
570//
571
572void
573Fl_File_Chooser::favoritesCB(Fl_Widget *w)
574 // I - Widget
575{
576 int i; // Looping var
577 char name[32], // Preference name
578 pathname[1024]; // Directory in list
579
580
581 if (!w) {
582 // Load the favorites list...
583 favList->clear();
584 favList->deselect();
585
586 for (i = 0; i < 100; i ++) {
587 // Get favorite directory 0 to 99...
588 sprintf(name, "favorite%02d", i);
589
590 prefs_.get(name, pathname, "", sizeof(pathname));
591
592 // Stop on the first empty favorite...
593 if (!pathname[0]) break;
594
595 // Add the favorite to the list...
596 favList->add(pathname,
597 Fl_File_Icon::find(pathname, Fl_File_Icon::DIRECTORY));
598 }
599
600 favUpButton->deactivate();
601 favDeleteButton->deactivate();
602 favDownButton->deactivate();
603 favOkButton->deactivate();
604
605 favWindow->hotspot(favList);
606 favWindow->show();
607 } else if (w == favList) {
608 i = favList->value();
609 if (i) {
610 if (i > 1) favUpButton->activate();
611 else favUpButton->deactivate();
612
613 favDeleteButton->activate();
614
615 if (i < favList->size()) favDownButton->activate();
616 else favDownButton->deactivate();
617 } else {
618 favUpButton->deactivate();
619 favDeleteButton->deactivate();
620 favDownButton->deactivate();
621 }
622 } else if (w == favUpButton) {
623 i = favList->value();
624
625 favList->insert(i - 1, favList->text(i), favList->data(i));
626 favList->remove(i + 1);
627 favList->select(i - 1);
628
629 if (i == 2) favUpButton->deactivate();
630
631 favDownButton->activate();
632
633 favOkButton->activate();
634 } else if (w == favDeleteButton) {
635 i = favList->value();
636
637 favList->remove(i);
638
639 if (i > favList->size()) i --;
640 favList->select(i);
641
642 if (i < favList->size()) favDownButton->activate();
643 else favDownButton->deactivate();
644
645 if (i > 1) favUpButton->activate();
646 else favUpButton->deactivate();
647
648 if (!i) favDeleteButton->deactivate();
649
650 favOkButton->activate();
651 } else if (w == favDownButton) {
652 i = favList->value();
653
654 favList->insert(i + 2, favList->text(i), favList->data(i));
655 favList->remove(i);
656 favList->select(i + 1);
657
658 if ((i + 1) == favList->size()) favDownButton->deactivate();
659
660 favUpButton->activate();
661
662 favOkButton->activate();
663 } else if (w == favOkButton) {
664 // Copy the new list over...
665 for (i = 0; i < favList->size(); i ++) {
666 // Set favorite directory 0 to 99...
667 sprintf(name, "favorite%02d", i);
668
669 prefs_.set(name, favList->text(i + 1));
670 }
671
672 // Clear old entries as necessary...
673 for (; i < 100; i ++) {
674 // Clear favorite directory 0 to 99...
675 sprintf(name, "favorite%02d", i);
676
677 prefs_.get(name, pathname, "", sizeof(pathname));
678
679 if (pathname[0]) prefs_.set(name, "");
680 else break;
681 }
682
683 update_favorites();
684 prefs_.flush();
685
686 favWindow->hide();
687 }
688}
689
690
691//
692// 'Fl_File_Chooser::fileListCB()' - Handle clicks (and double-clicks) in the
693// Fl_File_Browser.
694//
695
696void
697Fl_File_Chooser::fileListCB()
698{
699 char *filename, // New filename
700 pathname[FL_PATH_MAX]; // Full pathname to file
701
702
703 filename = (char *)fileList->text(fileList->value());
704 if (!filename)
705 return;
706
707 if (!directory_[0]) {
708 strlcpy(pathname, filename, sizeof(pathname));
709 } else if (strcmp(directory_, "/") == 0) {
710 snprintf(pathname, sizeof(pathname), "/%s", filename);
711 } else {
712 snprintf(pathname, sizeof(pathname), "%s/%s", directory_, filename);
713 }
714
715 if (Fl::event_clicks()) {
716#if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
717 if ((strlen(pathname) == 2 && pathname[1] == ':') ||
718 _fl_filename_isdir_quick(pathname))
719#else
720 if (_fl_filename_isdir_quick(pathname))
721#endif /* WIN32 || __EMX__ */
722 {
723 // Change directories...
724 directory(pathname);
725
726 // Reset the click count so that a click in the same spot won't
727 // be treated as a triple-click. We use a value of -1 because
728 // the next click will increment click count to 0, which is what
729 // we really want...
730 Fl::event_clicks(-1);
731 }
732 else
733 {
734 // Hide the window - picked the file...
735 window->hide();
736 if (callback_) (*callback_)(this, data_);
737 }
738 }
739 else
740 {
741 // Check if the user clicks on a directory when picking files;
742 // if so, make sure only that item is selected...
743 filename = pathname + strlen(pathname) - 1;
744
745 if ((type_ & MULTI) && !(type_ & DIRECTORY)) {
746 if (*filename == '/') {
747 // Clicked on a directory, deselect everything else...
748 int i = fileList->value();
749 fileList->deselect();
750 fileList->select(i);
751 } else {
752 // Clicked on a file - see if there are other directories selected...
753 int i;
754 const char *temp;
755 for (i = 1; i <= fileList->size(); i ++) {
756 if (i != fileList->value() && fileList->selected(i)) {
757 temp = fileList->text(i);
758 temp += strlen(temp) - 1;
759 if (*temp == '/') break; // Yes, selected directory
760 }
761 }
762
763 if (i <= fileList->size()) {
764 i = fileList->value();
765 fileList->deselect();
766 fileList->select(i);
767 }
768 }
769 }
770 // Strip any trailing slash from the directory name...
771 if (*filename == '/') *filename = '\0';
772
773// puts("Setting fileName from fileListCB...");
774 fileName->value(pathname);
775
776 // Update the preview box...
777 Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this);
778 Fl::add_timeout(1.0, (Fl_Timeout_Handler)previewCB, this);
779
780 // Do any callback that is registered...
781 if (callback_) (*callback_)(this, data_);
782
783 // Activate the OK button as needed...
784 if (!_fl_filename_isdir_quick(pathname) || (type_ & DIRECTORY))
785 okButton->activate();
786 else
787 okButton->deactivate();
788 }
789}
790
791
792//
793// 'Fl_File_Chooser::fileNameCB()' - Handle text entry in the FileBrowser.
794//
795
796void
797Fl_File_Chooser::fileNameCB()
798{
799 char *filename, // New filename
800 *slash, // Pointer to trailing slash
801 pathname[FL_PATH_MAX], // Full pathname to file
802 matchname[FL_PATH_MAX]; // Matching filename
803 int i, // Looping var
804 min_match, // Minimum number of matching chars
805 max_match, // Maximum number of matching chars
806 num_files, // Number of files in directory
807 first_line; // First matching line
808 const char *file; // File from directory
809
810// puts("fileNameCB()");
811// printf("Event: %s\n", fl_eventnames[Fl::event()]);
812
813 // Get the filename from the text field...
814 filename = (char *)fileName->value();
815
816 if (!filename || !filename[0]) {
817 okButton->deactivate();
818 return;
819 }
820
821 // Expand ~ and $ variables as needed...
822 if (strchr(filename, '~') || strchr(filename, '$')) {
823 fl_filename_expand(pathname, sizeof(pathname), filename);
824 filename = pathname;
825 value(pathname);
826 }
827
828 // Make sure we have an absolute path...
829#if (defined(WIN32) && !defined(__CYGWIN__)) || defined(__EMX__)
830 if (directory_[0] != '\0' && filename[0] != '/' &&
831 filename[0] != '\\' &&
832 !(isalpha(filename[0] & 255) && (!filename[1] || filename[1] == ':'))) {
833#else
834 if (directory_[0] != '\0' && filename[0] != '/') {
835#endif /* WIN32 || __EMX__ */
836 fl_filename_absolute(pathname, sizeof(pathname), filename);
837 value(pathname);
838 fileName->mark(fileName->position()); // no selection after expansion
839 } else if (filename != pathname) {
840 // Finally, make sure that we have a writable copy...
841 strlcpy(pathname, filename, sizeof(pathname));
842 }
843
844 filename = pathname;
845
846 // Now process things according to the key pressed...
847 if (Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter) {
848 // Enter pressed - select or change directory...
849#if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
850 if ((isalpha(pathname[0] & 255) && pathname[1] == ':' && !pathname[2]) ||
851 (_fl_filename_isdir_quick(pathname) &&
852 compare_dirnames(pathname, directory_))) {
853#else
854 if (_fl_filename_isdir_quick(pathname) &&
855 compare_dirnames(pathname, directory_)) {
856#endif /* WIN32 || __EMX__ */
857 directory(pathname);
858 } else if ((type_ & CREATE) || access(pathname, 0) == 0) {
859 if (!_fl_filename_isdir_quick(pathname) || (type_ & DIRECTORY)) {
860 // Update the preview box...
861 update_preview();
862
863 // Do any callback that is registered...
864 if (callback_) (*callback_)(this, data_);
865
866 // Hide the window to signal things are done...
867 window->hide();
868 }
869 } else {
870 // File doesn't exist, so beep at and alert the user...
871 fl_alert("%s",existing_file_label);
872 }
873 }
874 else if (Fl::event_key() != FL_Delete &&
875 Fl::event_key() != FL_BackSpace) {
876 // Check to see if the user has entered a directory...
877 if ((slash = strrchr(pathname, '/')) == NULL)
878 slash = strrchr(pathname, '\\');
879
880 if (!slash) return;
881
882 // Yes, change directories if necessary...
883 *slash++ = '\0';
884 filename = slash;
885
886#if defined(WIN32) || defined(__EMX__)
887 if (strcasecmp(pathname, directory_) &&
888 (pathname[0] || strcasecmp("/", directory_))) {
889#else
890 if (strcmp(pathname, directory_) &&
891 (pathname[0] || strcasecmp("/", directory_))) {
892#endif // WIN32 || __EMX__
893 int p = fileName->position();
894 int m = fileName->mark();
895
896 directory(pathname);
897
898 if (filename[0]) {
899 char tempname[FL_PATH_MAX];
900
901 snprintf(tempname, sizeof(tempname), "%s/%s", directory_, filename);
902 fileName->value(tempname);
903 strlcpy(pathname, tempname, sizeof(pathname));
904 }
905
906 fileName->position(p, m);
907 }
908
909 // Other key pressed - do filename completion as possible...
910 num_files = fileList->size();
911 min_match = strlen(filename);
912 max_match = min_match + 1;
913 first_line = 0;
914
915 for (i = 1; i <= num_files && max_match > min_match; i ++) {
916 file = fileList->text(i);
917
918#if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
919 if (strncasecmp(filename, file, min_match) == 0) {
920#else
921 if (strncmp(filename, file, min_match) == 0) {
922#endif // WIN32 || __EMX__
923 // OK, this one matches; check against the previous match
924 if (!first_line) {
925 // First match; copy stuff over...
926 strlcpy(matchname, file, sizeof(matchname));
927 max_match = strlen(matchname);
928
929 // Strip trailing /, if any...
930 if (matchname[max_match - 1] == '/') {
931 max_match --;
932 matchname[max_match] = '\0';
933 }
934
935 // And then make sure that the item is visible
936 fileList->topline(i);
937 first_line = i;
938 } else {
939 // Succeeding match; compare to find maximum string match...
940 while (max_match > min_match)
941#if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
942 if (strncasecmp(file, matchname, max_match) == 0)
943#else
944 if (strncmp(file, matchname, max_match) == 0)
945#endif // WIN32 || __EMX__
946 break;
947 else
948 max_match --;
949
950 // Truncate the string as needed...
951 matchname[max_match] = '\0';
952 }
953 }
954 }
955
956 // If we have any matches, add them to the input field...
957 if (first_line > 0 && min_match == max_match &&
958 max_match == (int)strlen(fileList->text(first_line))) {
959 // This is the only possible match...
960 fileList->deselect(0);
961 fileList->select(first_line);
962 fileList->redraw();
963 } else if (max_match > min_match && first_line) {
964 // Add the matching portion...
965 fileName->replace(filename - pathname, filename - pathname + min_match,
966 matchname);
967
968 // Highlight it with the cursor at the end of the selection so
969 // s/he can press the right arrow to accept the selection
970 // (Tab and End also do this for both cases.)
971 fileName->position(filename - pathname + max_match,
972 filename - pathname + min_match);
973 } else if (max_match == 0) {
974 fileList->deselect(0);
975 fileList->redraw();
976 }
977
978 // See if we need to enable the OK button...
979 if (((type_ & CREATE) || !access(fileName->value(), 0)) &&
980 (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) {
981 okButton->activate();
982 } else {
983 okButton->deactivate();
984 }
985 } else {
986 // FL_Delete or FL_BackSpace
987 fileList->deselect(0);
988 fileList->redraw();
989 if (((type_ & CREATE) || !access(fileName->value(), 0)) &&
990 (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) {
991 okButton->activate();
992 } else {
993 okButton->deactivate();
994 }
995 }
996}
997
998
999//
1000// 'Fl_File_Chooser::filter()' - Set the filter(s) for the chooser.
1001//
1002
1003void
1004Fl_File_Chooser::filter(const char *p) // I - Pattern(s)
1005{
1006 char *copyp, // Copy of pattern
1007 *start, // Start of pattern
1008 *end; // End of pattern
1009 int allfiles; // Do we have a "*" pattern?
1010 char temp[FL_PATH_MAX]; // Temporary pattern string
1011
1012
1013 // Make sure we have a pattern...
1014 if (!p || !*p) p = "*";
1015
1016 // Copy the pattern string...
1017 copyp = strdup(p);
1018
1019 // Separate the pattern string as necessary...
1020 showChoice->clear();
1021
1022 for (start = copyp, allfiles = 0; start && *start; start = end) {
1023 end = strchr(start, '\t');
1024 if (end) *end++ = '\0';
1025
1026 if (strcmp(start, "*") == 0) {
1027 showChoice->add(all_files_label);
1028 allfiles = 1;
1029 } else {
1030 quote_pathname(temp, start, sizeof(temp));
1031 showChoice->add(temp);
1032 if (strstr(start, "(*)") != NULL) allfiles = 1;
1033 }
1034 }
1035
1036 free(copyp);
1037
1038 if (!allfiles) showChoice->add(all_files_label);
1039
1040 showChoice->add(custom_filter_label);
1041
1042 showChoice->value(0);
1043 showChoiceCB();
1044}
1045
1046
1047//
1048// 'Fl_File_Chooser::newdir()' - Make a new directory.
1049//
1050
1051void
1052Fl_File_Chooser::newdir()
1053{
1054 const char *dir; // New directory name
1055 char pathname[FL_PATH_MAX]; // Full path of directory
1056
1057
1058 // Get a directory name from the user
1059 if ((dir = fl_input("%s", NULL, new_directory_label)) == NULL)
1060 return;
1061
1062 // Make it relative to the current directory as needed...
1063#if (defined(WIN32) && ! defined (__CYGWIN__)) || defined(__EMX__)
1064 if (dir[0] != '/' && dir[0] != '\\' && dir[1] != ':')
1065#else
1066 if (dir[0] != '/' && dir[0] != '\\')
1067#endif /* WIN32 || __EMX__ */
1068 snprintf(pathname, sizeof(pathname), "%s/%s", directory_, dir);
1069 else
1070 strlcpy(pathname, dir, sizeof(pathname));
1071
1072 // Create the directory; ignore EEXIST errors...
1073#if defined(WIN32) && ! defined (__CYGWIN__)
1074 if (mkdir(pathname))
1075#else
1076 if (mkdir(pathname, 0777))
1077#endif /* WIN32 */
1078 if (errno != EEXIST)
1079 {
1080 fl_alert("%s", strerror(errno));
1081 return;
1082 }
1083
1084 // Show the new directory...
1085 directory(pathname);
1086}
1087
1088
1089
1090/** Enable or disable the preview tile. 1 = enable preview, 0 = disable preview. */
1091void Fl_File_Chooser::preview(int e)
1092{
1093 previewButton->value(e);
1094 prefs_.set("preview", e);
1095 prefs_.flush();
1096
1097 Fl_Group *p = previewBox->parent();
1098 if (e) {
1099 int w = p->w() * 2 / 3;
1100 fileList->resize(fileList->x(), fileList->y(),
1101 w, fileList->h());
1102 previewBox->resize(fileList->x()+w, previewBox->y(),
1103 p->w()-w, previewBox->h());
1104 previewBox->show();
1105 update_preview();
1106 } else {
1107 fileList->resize(fileList->x(), fileList->y(),
1108 p->w(), fileList->h());
1109 previewBox->resize(p->x()+p->w(), previewBox->y(),
1110 0, previewBox->h());
1111 previewBox->hide();
1112 }
1113 p->init_sizes();
1114
1115 fileList->parent()->redraw();
1116}
1117
1118
1119//
1120// 'Fl_File_Chooser::previewCB()' - Timeout handler for the preview box.
1121//
1122
1123void
1124Fl_File_Chooser::previewCB(Fl_File_Chooser *fc) { // I - File chooser
1125 fc->update_preview();
1126}
1127
1128
1129//
1130// 'Fl_File_Chooser::rescan()' - Rescan the current directory.
1131//
1132
1133void
1134Fl_File_Chooser::rescan()
1135{
1136 char pathname[FL_PATH_MAX]; // New pathname for filename field
1137
1138
1139 // Clear the current filename
1140 strlcpy(pathname, directory_, sizeof(pathname));
1141 if (pathname[0] && pathname[strlen(pathname) - 1] != '/') {
1142 strlcat(pathname, "/", sizeof(pathname));
1143 }
1144// puts("Setting fileName in rescan()");
1145 fileName->value(pathname);
1146
1147 if (type_ & DIRECTORY)
1148 okButton->activate();
1149 else
1150 okButton->deactivate();
1151
1152 // Build the file list...
1153 fileList->load(directory_, sort);
1154#ifndef WIN32
1155 if (!showHiddenButton->value()) remove_hidden_files();
1156#endif
1157 // Update the preview box...
1158 update_preview();
1159}
1160
1161//
1162/**
1163 Rescan the current directory without clearing the filename,
1164 then select the file if it is in the list
1165*/
1166void Fl_File_Chooser::rescan_keep_filename()
1167{
1168 // if no filename was set, this is likely a diretory browser
1169 const char *fn = fileName->value();
1170 if (!fn || !*fn || fn[strlen(fn) - 1]=='/') {
1171 rescan();
1172 return;
1173 }
1174
1175 int i;
1176 char pathname[FL_PATH_MAX]; // New pathname for filename field
1177 strlcpy(pathname, fn, sizeof(pathname));
1178
1179 // Build the file list...
1180 fileList->load(directory_, sort);
1181#ifndef WIN32
1182 if (!showHiddenButton->value()) remove_hidden_files();
1183#endif
1184 // Update the preview box...
1185 update_preview();
1186
1187 // and select the chosen file
1188 char found = 0;
1189 char *slash = strrchr(pathname, '/');
1190 if (slash)
1191 slash++;
1192 else
1193 slash = pathname;
1194 for (i = 1; i <= fileList->size(); i ++)
1195#if defined(WIN32) || defined(__EMX__)
1196 if (strcasecmp(fileList->text(i), slash) == 0) {
1197#else
1198 if (strcmp(fileList->text(i), slash) == 0) {
1199#endif // WIN32 || __EMX__
1200 fileList->topline(i);
1201 fileList->select(i);
1202 found = 1;
1203 break;
1204 }
1205
1206 // update OK button activity
1207 if (found || type_ & CREATE)
1208 okButton->activate();
1209 else
1210 okButton->deactivate();
1211}
1212
1213
1214//
1215// 'Fl_File_Chooser::showChoiceCB()' - Handle show selections.
1216//
1217
1218void
1219Fl_File_Chooser::showChoiceCB()
1220{
1221 const char *item, // Selected item
1222 *patstart; // Start of pattern
1223 char *patend; // End of pattern
1224 char temp[FL_PATH_MAX]; // Temporary string for pattern
1225
1226
1227 item = showChoice->text(showChoice->value());
1228
1229 if (strcmp(item, custom_filter_label) == 0) {
1230 if ((item = fl_input("%s", pattern_, custom_filter_label)) != NULL) {
1231 strlcpy(pattern_, item, sizeof(pattern_));
1232
1233 quote_pathname(temp, item, sizeof(temp));
1234 showChoice->add(temp);
1235 showChoice->value(showChoice->size() - 2);
1236 }
1237 } else if ((patstart = strchr(item, '(')) == NULL) {
1238 strlcpy(pattern_, item, sizeof(pattern_));
1239 } else {
1240 strlcpy(pattern_, patstart + 1, sizeof(pattern_));
1241 if ((patend = strrchr(pattern_, ')')) != NULL) *patend = '\0';
1242 }
1243
1244 fileList->filter(pattern_);
1245
1246 if (shown()) {
1247 // Rescan the directory...
1248 rescan_keep_filename();
1249 }
1250}
1251
1252
1253//
1254// 'Fl_File_Chooser::update_favorites()' - Update the favorites menu.
1255//
1256
1257void
1258Fl_File_Chooser::update_favorites()
1259{
1260 int i; // Looping var
1261 char pathname[FL_PATH_MAX], // Pathname
1262 menuname[2048]; // Menu name
1263 const char *home; // Home directory
1264
1265
1266 favoritesButton->clear();
1267 favoritesButton->add("bla");
1268 favoritesButton->clear();
1269 favoritesButton->add(add_favorites_label, FL_ALT + 'a', 0);
1270 favoritesButton->add(manage_favorites_label, FL_ALT + 'm', 0, 0, FL_MENU_DIVIDER);
1271 favoritesButton->add(filesystems_label, FL_ALT + 'f', 0);
1272
1273 if ((home = getenv("HOME")) != NULL) {
1274 quote_pathname(menuname, home, sizeof(menuname));
1275 favoritesButton->add(menuname, FL_ALT + 'h', 0);
1276 }
1277
1278 for (i = 0; i < 100; i ++) {
1279 sprintf(menuname, "favorite%02d", i);
1280 prefs_.get(menuname, pathname, "", sizeof(pathname));
1281 if (!pathname[0]) break;
1282
1283 quote_pathname(menuname, pathname, sizeof(menuname));
1284
1285 if (i < 10) favoritesButton->add(menuname, FL_ALT + '0' + i, 0);
1286 else favoritesButton->add(menuname);
1287 }
1288
1289 if (i == 100) ((Fl_Menu_Item *)favoritesButton->menu())[0].deactivate();
1290}
1291
1292
1293//
1294// 'Fl_File_Chooser::update_preview()' - Update the preview box...
1295//
1296
1297void
1298Fl_File_Chooser::update_preview()
1299{
1300 const char *filename; // Current filename
1301 const char *newlabel = 0; // New label text
1302 Fl_Shared_Image *image = 0, // New image
1303 *oldimage; // Old image
1304 int pbw, pbh; // Width and height of preview box
1305 int w, h; // Width and height of preview image
1306 int set = 0; // Set this flag as soon as a decent preview is found
1307
1308 if (!previewButton->value()) return;
1309
1310 filename = value();
1311 if (filename == NULL) {
1312 // no file name at all, so we have an empty preview
1313 set = 1;
1314 } else if (fl_filename_isdir(filename)) {
1315 // filename is a directory, show a folder icon
1316 newlabel = "@fileopen";
1317 set = 1;
1318 } else {
1319 struct stat s;
1320 if (fl_stat(filename, &s)==0) {
1321 if ((s.st_mode&S_IFMT)!=S_IFREG) {
1322 // this is no regular file, probably some kind of device
1323 newlabel = "@-3refresh"; // a cross
1324 set = 1;
1325 } else if (s.st_size==0) {
1326 // this file is emty
1327 newlabel = "<empty file>";
1328 set = 1;
1329 } else {
1330 // if this file is an image, try to load it
1331 window->cursor(FL_CURSOR_WAIT);
1332 Fl::check();
1333
1334 image = Fl_Shared_Image::get(filename);
1335
1336 if (image) {
1337 window->cursor(FL_CURSOR_DEFAULT);
1338 Fl::check();
1339 set = 1;
1340 }
1341 }
1342 }
1343 }
1344
1345 oldimage = (Fl_Shared_Image *)previewBox->image();
1346
1347 if (oldimage) oldimage->release();
1348
1349 previewBox->image(0);
1350
1351 if (!set) {
1352 FILE *fp;
1353 int bytes;
1354 char *ptr;
1355
1356 if (filename) fp = fl_fopen(filename, "rb");
1357 else fp = NULL;
1358
1359 if (fp != NULL) {
1360 // Try reading the first 1k of data for a label...
1361 bytes = fread(preview_text_, 1, sizeof(preview_text_) - 1, fp);
1362 preview_text_[bytes] = '\0';
1363 fclose(fp);
1364 } else {
1365 // Assume we can't read any data...
1366 preview_text_[0] = '\0';
1367 }
1368
1369 window->cursor(FL_CURSOR_DEFAULT);
1370 Fl::check();
1371
1372 // Scan the buffer for printable UTF8 chars...
1373 for (ptr = preview_text_; *ptr; ptr++) {
1374 uchar c = uchar(*ptr);
1375 if ( (c&0x80)==0 ) {
1376 if (!isprint(c&255) && !isspace(c&255)) break;
1377 } else if ( (c&0xe0)==0xc0 ) {
1378 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1379 ptr++;
1380 } else if ( (c&0xf0)==0xe0 ) {
1381 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1382 ptr++;
1383 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1384 ptr++;
1385 } else if ( (c&0xf8)==0xf0 ) {
1386 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1387 ptr++;
1388 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1389 ptr++;
1390 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1391 ptr++;
1392 }
1393 }
1394// *ptr && (isprint(*ptr & 255) || isspace(*ptr & 255));
1395// ptr ++);
1396
1397 // Scan the buffer for printable characters in 8 bit
1398 if (*ptr || ptr == preview_text_) {
1399 for (ptr = preview_text_;
1400 *ptr && (isprint(*ptr & 255) || isspace(*ptr & 255));
1401 ptr ++);
1402 }
1403
1404 if (*ptr || ptr == preview_text_) {
1405 // Non-printable file, just show a big ?...
1406 previewBox->label(filename ? "?" : 0);
1407 previewBox->align(FL_ALIGN_CLIP);
1408 previewBox->labelsize(75);
1409 previewBox->labelfont(FL_HELVETICA);
1410 } else {
1411 // Show the first 1k of text...
1412 int size = previewBox->h() / 20;
1413 if (size < 6) size = 6;
1414 else if (size > FL_NORMAL_SIZE) size = FL_NORMAL_SIZE;
1415
1416 previewBox->label(preview_text_);
1417 previewBox->align((Fl_Align)(FL_ALIGN_CLIP | FL_ALIGN_INSIDE |
1418 FL_ALIGN_LEFT | FL_ALIGN_TOP));
1419 previewBox->labelsize(size);
1420 previewBox->labelfont(FL_COURIER);
1421 }
1422 } else if (image) {
1423 pbw = previewBox->w() - 20;
1424 pbh = previewBox->h() - 20;
1425
1426 if (image->w() > pbw || image->h() > pbh) {
1427 w = pbw;
1428 h = w * image->h() / image->w();
1429
1430 if (h > pbh) {
1431 h = pbh;
1432 w = h * image->w() / image->h();
1433 }
1434
1435 oldimage = (Fl_Shared_Image *)image->copy(w, h);
1436 previewBox->image((Fl_Image *)oldimage);
1437
1438 image->release();
1439 } else {
1440 previewBox->image((Fl_Image *)image);
1441 }
1442
1443 previewBox->align(FL_ALIGN_CLIP);
1444 previewBox->label(0);
1445 } else if (newlabel) {
1446 previewBox->label(newlabel);
1447 previewBox->align(FL_ALIGN_CLIP);
1448 previewBox->labelsize(newlabel[0]=='@'?75:12);
1449 previewBox->labelfont(FL_HELVETICA);
1450 }
1451
1452 previewBox->redraw();
1453}
1454
1455
1456//
1457// 'Fl_File_Chooser::value()' - Return a selected filename.
1458//
1459
1460const char * // O - Filename or NULL
1461Fl_File_Chooser::value(int f) // I - File number
1462{
1463 int i; // Looping var
1464 int fcount; // Number of selected files
1465 const char *name; // Current filename
1466 static char pathname[FL_PATH_MAX]; // Filename + directory
1467
1468
1469 name = fileName->value();
1470
1471 if (!(type_ & MULTI)) {
1472 // Return the filename in the filename field...
1473 if (!name || !name[0]) return NULL;
1474 else return name;
1475 }
1476
1477 // Return a filename from the list...
1478 for (i = 1, fcount = 0; i <= fileList->size(); i ++)
1479 if (fileList->selected(i)) {
1480 // See if this file is a selected file/directory...
1481 name = fileList->text(i);
1482
1483 fcount ++;
1484
1485 if (fcount == f) {
1486 if (directory_[0]) {
1487 snprintf(pathname, sizeof(pathname), "%s/%s", directory_, name);
1488 } else {
1489 strlcpy(pathname, name, sizeof(pathname));
1490 }
1491
1492 return pathname;
1493 }
1494 }
1495
1496 // If nothing is selected, use the filename field...
1497 if (!name || !name[0]) return NULL;
1498 else return name;
1499}
1500
1501
1502//
1503// 'Fl_File_Chooser::value()' - Set the current filename.
1504//
1505
1506void
1507Fl_File_Chooser::value(const char *filename)
1508 // I - Filename + directory
1509{
1510 int i, // Looping var
1511 fcount; // Number of items in list
1512 char *slash; // Directory separator
1513 char pathname[FL_PATH_MAX]; // Local copy of filename
1514
1515
1516// printf("Fl_File_Chooser::value(\"%s\")\n", filename == NULL ? "(null)" : filename);
1517
1518 // See if the filename is the "My System" directory...
1519 if (filename == NULL || !filename[0]) {
1520 // Yes, just change the current directory...
1521 directory(filename);
1522 fileName->value("");
1523 okButton->deactivate();
1524 return;
1525 }
1526
1527#ifdef WIN32
1528 // See if the filename contains backslashes...
1529 char fixpath[FL_PATH_MAX]; // Path with slashes converted
1530 if (strchr(filename, '\\')) {
1531 // Convert backslashes to slashes...
1532 strlcpy(fixpath, filename, sizeof(fixpath));
1533
1534 for (slash = strchr(fixpath, '\\'); slash; slash = strchr(slash + 1, '\\'))
1535 *slash = '/';
1536
1537 filename = fixpath;
1538 }
1539#endif // WIN32
1540
1541 // See if there is a directory in there...
1542 fl_filename_absolute(pathname, sizeof(pathname), filename);
1543
1544 if ((slash = strrchr(pathname, '/')) != NULL) {
1545 // Yes, change the display to the directory...
1546 if (!fl_filename_isdir(pathname)) *slash++ = '\0';
1547
1548 directory(pathname);
1549 if (*slash == '/') slash = pathname;
1550 } else {
1551 directory(".");
1552 slash = pathname;
1553 }
1554
1555 // Set the input field to the absolute path...
1556 if (slash > pathname) slash[-1] = '/';
1557
1558 fileName->value(pathname);
1559 fileName->position(0, strlen(pathname));
1560 okButton->activate();
1561
1562 // Then find the file in the file list and select it...
1563 fcount = fileList->size();
1564
1565 fileList->deselect(0);
1566 fileList->redraw();
1567
1568 for (i = 1; i <= fcount; i ++)
1569#if defined(WIN32) || defined(__EMX__)
1570 if (strcasecmp(fileList->text(i), slash) == 0) {
1571#else
1572 if (strcmp(fileList->text(i), slash) == 0) {
1573#endif // WIN32 || __EMX__
1574// printf("Selecting line %d...\n", i);
1575 fileList->topline(i);
1576 fileList->select(i);
1577 break;
1578 }
1579}
1580
1581void Fl_File_Chooser::show()
1582{
1583 window->hotspot(fileList);
1584 window->show();
1585 Fl::flush();
1586 fl_cursor(FL_CURSOR_WAIT);
1587 rescan_keep_filename();
1588 fl_cursor(FL_CURSOR_DEFAULT);
1589 fileName->take_focus();
1590#ifdef WIN32
1591 showHiddenButton->hide();
1592#endif
1593}
1594
1595void Fl_File_Chooser::showHidden(int value)
1596{
1597 if (value) {
1598 fileList->load(directory());
1599 } else {
1600 remove_hidden_files();
1601 fileList->redraw();
1602 }
1603}
1604
1605void Fl_File_Chooser::remove_hidden_files()
1606{
1607 int count = fileList->size();
1608 for(int num = count; num >= 1; num--) {
1609 const char *p = fileList->text(num);
1610 if (*p == '.' && strcmp(p, "../") != 0) fileList->remove(num);
1611 }
1612 fileList->topline(1);
1613}
1614
1615
1616//
1617// 'compare_dirnames()' - Compare two directory names.
1618//
1619
1620static int
1621compare_dirnames(const char *a, const char *b) {
1622 int alen, blen;
1623
1624 // Get length of each string...
1625 alen = strlen(a) - 1;
1626 blen = strlen(b) - 1;
1627
1628 if (alen < 0 || blen < 0) return alen - blen;
1629
1630 // Check for trailing slashes...
1631 if (a[alen] != '/') alen ++;
1632 if (b[blen] != '/') blen ++;
1633
1634 // If the lengths aren't the same, then return the difference...
1635 if (alen != blen) return alen - blen;
1636
1637 // Do a comparison of the first N chars (alen == blen at this point)...
1638#ifdef WIN32
1639 return strncasecmp(a, b, alen);
1640#else
1641 return strncmp(a, b, alen);
1642#endif // WIN32
1643}
1644
1645
1646//
1647// 'quote_pathname()' - Quote a pathname for a menu.
1648//
1649
1650static void
1651quote_pathname(char *dst, // O - Destination string
1652 const char *src, // I - Source string
1653 int dstsize) // I - Size of destination string
1654{
1655 dstsize --;
1656
1657 while (*src && dstsize > 1) {
1658 if (*src == '\\') {
1659 // Convert backslash to forward slash...
1660 *dst++ = '\\';
1661 *dst++ = '/';
1662 src ++;
1663 } else {
1664 if (*src == '/') *dst++ = '\\';
1665
1666 *dst++ = *src++;
1667 }
1668 }
1669
1670 *dst = '\0';
1671}
1672
1673
1674//
1675// 'unquote_pathname()' - Unquote a pathname from a menu.
1676//
1677
1678static void
1679unquote_pathname(char *dst, // O - Destination string
1680 const char *src, // I - Source string
1681 int dstsize) // I - Size of destination string
1682{
1683 dstsize --;
1684
1685 while (*src && dstsize > 1) {
1686 if (*src == '\\') src ++;
1687 *dst++ = *src++;
1688 }
1689
1690 *dst = '\0';
1691}
1692
1693
1694//
1695// End of "$Id: Fl_File_Chooser2.cxx 8785 2011-06-06 16:11:22Z manolo $".
1696//