fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_File_Browser.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_File_Browser.cxx 8063 2010-12-19 21:20:10Z matt $"
00003 //
00004 // Fl_File_Browser routines.
00005 //
00006 // Copyright 1999-2010 by Michael Sweet.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 // Contents:
00028 //
00029 //   Fl_File_Browser::full_height()     - Return the height of the list.
00030 //   Fl_File_Browser::item_height()     - Return the height of a list item.
00031 //   Fl_File_Browser::item_width()      - Return the width of a list item.
00032 //   Fl_File_Browser::item_draw()       - Draw a list item.
00033 //   Fl_File_Browser::Fl_File_Browser() - Create a Fl_File_Browser widget.
00034 //   Fl_File_Browser::load()            - Load a directory into the browser.
00035 //   Fl_File_Browser::filter()          - Set the filename filter.
00036 //
00037 
00038 //
00039 // Include necessary header files...
00040 //
00041 
00042 #include <FL/Fl_File_Browser.H>
00043 #include <FL/fl_draw.H>
00044 #include <FL/filename.H>
00045 #include <FL/Fl_Image.H>        // icon
00046 #include <stdio.h>
00047 #include <stdlib.h>
00048 #include "flstring.h"
00049 
00050 #ifdef __CYGWIN__
00051 #  include <mntent.h>
00052 #elif defined(WIN32)
00053 #  include <windows.h>
00054 #  include <direct.h>
00055 // Apparently Borland C++ defines DIRECTORY in <direct.h>, which
00056 // interfers with the Fl_File_Icon enumeration of the same name.
00057 #  ifdef DIRECTORY
00058 #    undef DIRECTORY
00059 #  endif // DIRECTORY
00060 #endif // __CYGWIN__
00061 
00062 #ifdef __EMX__
00063 #  define  INCL_DOS
00064 #  define  INCL_DOSMISC
00065 #  include <os2.h>
00066 #endif // __EMX__
00067 
00068 #if defined(__APPLE__)
00069 #  include <sys/param.h>
00070 #  include <sys/ucred.h>
00071 #  include <sys/mount.h>
00072 #endif // __APPLE__
00073 
00074 //
00075 // FL_BLINE definition from "Fl_Browser.cxx"...
00076 //
00077 
00078 #define SELECTED 1
00079 #define NOTDISPLAYED 2
00080 
00081 // TODO -- Warning: The definition of FL_BLINE here is a hack.
00082 //    Fl_File_Browser should not do this. PLEASE FIX.
00083 //    FL_BLINE should be private to Fl_Browser, and not re-defined here.
00084 //    For now, make sure this struct is precisely consistent with Fl_Browser.cxx.
00085 //
00086 struct FL_BLINE                 // data is in a linked list of these
00087 {
00088   FL_BLINE      *prev;          // Previous item in list
00089   FL_BLINE      *next;          // Next item in list
00090   void          *data;          // Pointer to data (function)
00091   Fl_Image      *icon;          // Pointer to optional icon
00092   short         length;         // sizeof(txt)-1, may be longer than string
00093   char          flags;          // selected, displayed
00094   char          txt[1];         // start of allocated array
00095 };
00096 
00097 
00098 //
00099 // 'Fl_File_Browser::full_height()' - Return the height of the list.
00100 //
00101 
00102 int                                     // O - Height in pixels
00103 Fl_File_Browser::full_height() const
00104 {
00105   int   i,                              // Looping var
00106         th;                             // Total height of list.
00107 
00108 
00109   for (i = 0, th = 0; i < size(); i ++)
00110     th += item_height(find_line(i));
00111 
00112   return (th);
00113 }
00114 
00115 
00116 //
00117 // 'Fl_File_Browser::item_height()' - Return the height of a list item.
00118 //
00119 
00120 int                                     // O - Height in pixels
00121 Fl_File_Browser::item_height(void *p) const     // I - List item data
00122 {
00123   FL_BLINE      *line;                  // Pointer to line
00124   char          *t;                     // Pointer into text
00125   int           height;                 // Width of line
00126   int           textheight;             // Height of text
00127 
00128 
00129   // Figure out the standard text height...
00130   fl_font(textfont(), textsize());
00131   textheight = fl_height();
00132 
00133   // We always have at least 1 line...
00134   height = textheight;
00135 
00136   // Scan for newlines...
00137   line = (FL_BLINE *)p;
00138 
00139   if (line != NULL)
00140     for (t = line->txt; *t != '\0'; t ++)
00141       if (*t == '\n')
00142         height += textheight;
00143 
00144   // If we have enabled icons then add space for them...
00145   if (Fl_File_Icon::first() != NULL && height < iconsize_)
00146     height = iconsize_;
00147 
00148   // Add space for the selection border..
00149   height += 2;
00150 
00151   // Return the height
00152   return (height);
00153 }
00154 
00155 
00156 //
00157 // 'Fl_File_Browser::item_width()' - Return the width of a list item.
00158 //
00159 
00160 int                                     // O - Width in pixels
00161 Fl_File_Browser::item_width(void *p) const      // I - List item data
00162 {
00163   int           i;                      // Looping var
00164   FL_BLINE      *line;                  // Pointer to line
00165   char          *t,                     // Pointer into text
00166                 *ptr,                   // Pointer into fragment
00167                 fragment[10240];        // Fragment of text
00168   int           width,                  // Width of line
00169                 tempwidth;              // Width of fragment
00170   int           column;                 // Current column
00171   const int     *columns;               // Columns
00172 
00173 
00174   // Scan for newlines...
00175   line    = (FL_BLINE *)p;
00176   columns = column_widths();
00177 
00178   // Set the font and size...
00179   if (line->txt[strlen(line->txt) - 1] == '/')
00180     fl_font(textfont() | FL_BOLD, textsize());
00181   else
00182     fl_font(textfont(), textsize());
00183 
00184   if (strchr(line->txt, '\n') == NULL &&
00185       strchr(line->txt, column_char()) == NULL)
00186   {
00187     // Do a fast width calculation...
00188     width = (int)fl_width(line->txt);
00189   }
00190   else
00191   {
00192     // More than 1 line or have columns; find the maximum width...
00193     width     = 0;
00194     tempwidth = 0;
00195     column    = 0;
00196 
00197     for (t = line->txt, ptr = fragment; *t != '\0'; t ++)
00198       if (*t == '\n')
00199       {
00200         // Newline - nul terminate this fragment and get the width...
00201         *ptr = '\0';
00202 
00203         tempwidth += (int)fl_width(fragment);
00204 
00205         // Update the max width as needed...
00206         if (tempwidth > width)
00207           width = tempwidth;
00208 
00209         // Point back to the start of the fragment...
00210         ptr       = fragment;
00211         tempwidth = 0;
00212         column    = 0;
00213       }
00214       else if (*t == column_char())
00215       {
00216         // Advance to the next column...
00217         column ++;
00218         if (columns)
00219         {
00220           for (i = 0, tempwidth = 0; i < column && columns[i]; i ++)
00221             tempwidth += columns[i];
00222         }
00223         else
00224           tempwidth = column * (int)(fl_height() * 0.6 * 8.0);
00225 
00226         if (tempwidth > width)
00227           width = tempwidth;
00228 
00229         ptr = fragment;
00230       }
00231       else
00232         *ptr++ = *t;
00233 
00234     if (ptr > fragment)
00235     {
00236       // Nul terminate this fragment and get the width...
00237       *ptr = '\0';
00238 
00239       tempwidth += (int)fl_width(fragment);
00240 
00241       // Update the max width as needed...
00242       if (tempwidth > width)
00243         width = tempwidth;
00244     }
00245   }
00246 
00247   // If we have enabled icons then add space for them...
00248   if (Fl_File_Icon::first() != NULL)
00249     width += iconsize_ + 8;
00250 
00251   // Add space for the selection border..
00252   width += 2;
00253 
00254   // Return the width
00255   return (width);
00256 }
00257 
00258 
00259 //
00260 // 'Fl_File_Browser::item_draw()' - Draw a list item.
00261 //
00262 
00263 void
00264 Fl_File_Browser::item_draw(void *p,     // I - List item data
00265                            int  X,      // I - Upper-lefthand X coordinate
00266                            int  Y,      // I - Upper-lefthand Y coordinate
00267                            int  W,      // I - Width of item
00268                            int) const   // I - Height of item
00269 {
00270   int           i;                      // Looping var
00271   FL_BLINE      *line;                  // Pointer to line
00272   Fl_Color      c;                      // Text color
00273   char          *t,                     // Pointer into text
00274                 *ptr,                   // Pointer into fragment
00275                 fragment[10240];        // Fragment of text
00276   int           width,                  // Width of line
00277                 height;                 // Height of line
00278   int           column;                 // Current column
00279   const int     *columns;               // Columns
00280 
00281 
00282   // Draw the list item text...
00283   line = (FL_BLINE *)p;
00284 
00285   if (line->txt[strlen(line->txt) - 1] == '/')
00286     fl_font(textfont() | FL_BOLD, textsize());
00287   else
00288     fl_font(textfont(), textsize());
00289 
00290   if (line->flags & SELECTED)
00291     c = fl_contrast(textcolor(), selection_color());
00292   else
00293     c = textcolor();
00294 
00295   if (Fl_File_Icon::first() == NULL)
00296   {
00297     // No icons, just draw the text...
00298     X ++;
00299     W -= 2;
00300   }
00301   else
00302   {
00303     // Draw the icon if it is set...
00304     if (line->data)
00305       ((Fl_File_Icon *)line->data)->draw(X, Y, iconsize_, iconsize_,
00306                                         (line->flags & SELECTED) ? FL_YELLOW :
00307                                                                    FL_LIGHT2,
00308                                         active_r());
00309 
00310     // Draw the text offset to the right...
00311     X += iconsize_ + 9;
00312     W -= iconsize_ - 10;
00313 
00314     // Center the text vertically...
00315     height = fl_height();
00316 
00317     for (t = line->txt; *t != '\0'; t ++)
00318       if (*t == '\n')
00319         height += fl_height();
00320 
00321     if (height < iconsize_)
00322       Y += (iconsize_ - height) / 2;
00323   }
00324 
00325   // Draw the text...
00326   line    = (FL_BLINE *)p;
00327   columns = column_widths();
00328   width   = 0;
00329   column  = 0;
00330 
00331   if (active_r())
00332     fl_color(c);
00333   else
00334     fl_color(fl_inactive(c));
00335 
00336   for (t = line->txt, ptr = fragment; *t != '\0'; t ++)
00337     if (*t == '\n')
00338     {
00339       // Newline - nul terminate this fragment and draw it...
00340       *ptr = '\0';
00341 
00342       fl_draw(fragment, X + width, Y, W - width, fl_height(),
00343               (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP), 0, 0);
00344 
00345       // Point back to the start of the fragment...
00346       ptr    = fragment;
00347       width  = 0;
00348       Y      += fl_height();
00349       column = 0;
00350     }
00351     else if (*t == column_char())
00352     {
00353       // Tab - nul terminate this fragment and draw it...
00354       *ptr = '\0';
00355 
00356       int cW = W - width; // Clip width...
00357 
00358       if (columns)
00359       {
00360         // Try clipping inside this column...
00361         for (i = 0; i < column && columns[i]; i ++);
00362 
00363         if (columns[i])
00364           cW = columns[i];
00365       }
00366 
00367       fl_draw(fragment, X + width, Y, cW, fl_height(),
00368               (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP), 0, 0);
00369 
00370       // Advance to the next column...
00371       column ++;
00372       if (columns)
00373       {
00374         for (i = 0, width = 0; i < column && columns[i]; i ++)
00375           width += columns[i];
00376       }
00377       else
00378         width = column * (int)(fl_height() * 0.6 * 8.0);
00379 
00380       ptr = fragment;
00381     }
00382     else
00383       *ptr++ = *t;
00384 
00385   if (ptr > fragment)
00386   {
00387     // Nul terminate this fragment and draw it...
00388     *ptr = '\0';
00389 
00390     fl_draw(fragment, X + width, Y, W - width, fl_height(),
00391             (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP), 0, 0);
00392   }
00393 }
00394 
00395 
00396 //
00397 // 'Fl_File_Browser::Fl_File_Browser()' - Create a Fl_File_Browser widget.
00398 //
00399 
00400 Fl_File_Browser::Fl_File_Browser(int        X,  // I - Upper-lefthand X coordinate
00401                                  int        Y,  // I - Upper-lefthand Y coordinate
00402                                  int        W,  // I - Width in pixels
00403                                  int        H,  // I - Height in pixels
00404                                  const char *l) // I - Label text
00405     : Fl_Browser(X, Y, W, H, l)
00406 {
00407   // Initialize the filter pattern, current directory, and icon size...
00408   pattern_   = "*";
00409   directory_ = "";
00410   iconsize_  = (uchar)(3 * textsize() / 2);
00411   filetype_  = FILES;
00412 }
00413 
00414 
00415 //
00416 // 'Fl_File_Browser::load()' - Load a directory into the browser.
00417 //
00418 
00419 int                                             // O - Number of files loaded
00420 Fl_File_Browser::load(const char     *directory,// I - Directory to load
00421                       Fl_File_Sort_F *sort)     // I - Sort function to use
00422 {
00423   int           i;                              // Looping var
00424   int           num_files;                      // Number of files in directory
00425   int           num_dirs;                       // Number of directories in list
00426   char          filename[4096];                 // Current file
00427   Fl_File_Icon  *icon;                          // Icon to use
00428 
00429 
00430 //  printf("Fl_File_Browser::load(\"%s\")\n", directory);
00431 
00432   clear();
00433 
00434   directory_ = directory;
00435 
00436   if (!directory)
00437     return (0);
00438 
00439   if (directory_[0] == '\0')
00440   {
00441     //
00442     // No directory specified; for UNIX list all mount points.  For DOS
00443     // list all valid drive letters...
00444     //
00445 
00446     num_files = 0;
00447     if ((icon = Fl_File_Icon::find("any", Fl_File_Icon::DEVICE)) == NULL)
00448       icon = Fl_File_Icon::find("any", Fl_File_Icon::DIRECTORY);
00449 
00450 #ifdef WIN32
00451 #  ifdef __CYGWIN__
00452     //
00453     // Cygwin provides an implementation of setmntent() to get the list
00454     // of available drives...
00455     //
00456     FILE          *m = setmntent("/-not-used-", "r");
00457     struct mntent *p;
00458 
00459     while ((p = getmntent (m)) != NULL) {
00460       add(p->mnt_dir, icon);
00461       num_files ++;
00462     }
00463 
00464     endmntent(m);
00465 #  else
00466     //
00467     // Normal WIN32 code uses drive bits...
00468     //
00469     DWORD       drives;         // Drive available bits
00470 
00471     drives = GetLogicalDrives();
00472     for (i = 'A'; i <= 'Z'; i ++, drives >>= 1)
00473       if (drives & 1)
00474       {
00475         sprintf(filename, "%c:/", i);
00476 
00477         if (i < 'C') // see also: GetDriveType and GetVolumeInformation in WIN32
00478           add(filename, icon);
00479         else
00480           add(filename, icon);
00481 
00482         num_files ++;
00483       }
00484 #  endif // __CYGWIN__
00485 #elif defined(__EMX__)
00486     //
00487     // OS/2 code uses drive bits...
00488     //
00489     ULONG       curdrive;       // Current drive
00490     ULONG       drives;         // Drive available bits
00491     int         start = 3;      // 'C' (MRS - dunno if this is correct!)
00492 
00493 
00494     DosQueryCurrentDisk(&curdrive, &drives);
00495     drives >>= start - 1;
00496     for (i = 'A'; i <= 'Z'; i ++, drives >>= 1)
00497       if (drives & 1)
00498       {
00499         sprintf(filename, "%c:/", i);
00500         add(filename, icon);
00501 
00502         num_files ++;
00503       }
00504 #elif defined(__APPLE__)
00505     // MacOS X and Darwin use getfsstat() system call...
00506     int                 numfs;  // Number of file systems
00507     struct statfs       *fs;    // Buffer for file system info
00508 
00509 
00510     // We always have the root filesystem.
00511     add("/", icon);
00512 
00513     // Get the mounted filesystems...
00514     numfs = getfsstat(NULL, 0, MNT_NOWAIT);
00515     if (numfs > 0) {
00516       // We have file systems, get them...
00517       fs = new struct statfs[numfs];
00518       getfsstat(fs, sizeof(struct statfs) * numfs, MNT_NOWAIT);
00519 
00520       // Add filesystems to the list...
00521       for (i = 0; i < numfs; i ++) {
00522         // Ignore "/", "/dev", and "/.vol"...
00523         if (fs[i].f_mntonname[1] && strcmp(fs[i].f_mntonname, "/dev") &&
00524             strcmp(fs[i].f_mntonname, "/.vol")) {
00525           snprintf(filename, sizeof(filename), "%s/", fs[i].f_mntonname);
00526           add(filename, icon);
00527         }
00528         num_files ++;
00529       }
00530 
00531       // Free the memory used for the file system info array...
00532       delete[] fs;
00533     }
00534 #else
00535     //
00536     // UNIX code uses /etc/fstab or similar...
00537     //
00538     FILE        *mtab;          // /etc/mtab or /etc/mnttab file
00539     char        line[FL_PATH_MAX];      // Input line
00540 
00541     //
00542     // Open the file that contains a list of mounted filesystems...
00543     //
00544 
00545     mtab = fl_fopen("/etc/mnttab", "r");        // Fairly standard
00546     if (mtab == NULL)
00547       mtab = fl_fopen("/etc/mtab", "r");        // More standard
00548     if (mtab == NULL)
00549       mtab = fl_fopen("/etc/fstab", "r");       // Otherwise fallback to full list
00550     if (mtab == NULL)
00551       mtab = fl_fopen("/etc/vfstab", "r");      // Alternate full list file
00552 
00553     if (mtab != NULL)
00554     {
00555       while (fgets(line, sizeof(line), mtab) != NULL)
00556       {
00557         if (line[0] == '#' || line[0] == '\n')
00558           continue;
00559         if (sscanf(line, "%*s%4095s", filename) != 1)
00560           continue;
00561 
00562         strlcat(filename, "/", sizeof(filename));
00563 
00564 //        printf("Fl_File_Browser::load() - adding \"%s\" to list...\n", filename);
00565         add(filename, icon);
00566         num_files ++;
00567       }
00568 
00569       fclose(mtab);
00570     }
00571 #endif // WIN32 || __EMX__
00572   }
00573   else
00574   {
00575     dirent      **files;        // Files in in directory
00576 
00577 
00578     //
00579     // Build the file list...
00580     //
00581 
00582 #if (defined(WIN32) && !defined(__CYGWIN__)) || defined(__EMX__)
00583     strlcpy(filename, directory_, sizeof(filename));
00584     i = strlen(filename) - 1;
00585 
00586     if (i == 2 && filename[1] == ':' &&
00587         (filename[2] == '/' || filename[2] == '\\'))
00588       filename[2] = '/';
00589     else if (filename[i] != '/' && filename[i] != '\\')
00590       strlcat(filename, "/", sizeof(filename));
00591 
00592     num_files = fl_filename_list(filename, &files, sort);
00593 #else
00594     num_files = fl_filename_list(directory_, &files, sort);
00595 #endif /* WIN32 || __EMX__ */
00596 
00597     if (num_files <= 0)
00598       return (0);
00599 
00600     for (i = 0, num_dirs = 0; i < num_files; i ++) {
00601       if (strcmp(files[i]->d_name, "./")) {
00602         snprintf(filename, sizeof(filename), "%s/%s", directory_,
00603                  files[i]->d_name);
00604 
00605         icon = Fl_File_Icon::find(filename);
00606         if ((icon && icon->type() == Fl_File_Icon::DIRECTORY) ||
00607              _fl_filename_isdir_quick(filename)) {
00608           num_dirs ++;
00609           insert(num_dirs, files[i]->d_name, icon);
00610         } else if (filetype_ == FILES &&
00611                    fl_filename_match(files[i]->d_name, pattern_)) {
00612           add(files[i]->d_name, icon);
00613         }
00614       }
00615 
00616       free(files[i]);
00617     }
00618 
00619     free(files);
00620   }
00621 
00622   return (num_files);
00623 }
00624 
00625 
00626 //
00627 // 'Fl_File_Browser::filter()' - Set the filename filter.
00628 //
00629 
00630 void
00631 Fl_File_Browser::filter(const char *pattern)    // I - Pattern string
00632 {
00633   // If pattern is NULL set the pattern to "*"...
00634   if (pattern)
00635     pattern_ = pattern;
00636   else
00637     pattern_ = "*";
00638 }
00639 
00640 
00641 //
00642 // End of "$Id: Fl_File_Browser.cxx 8063 2010-12-19 21:20:10Z matt $".
00643 //