home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Examples / LazyScrollDir / DirWindow.m < prev    next >
Encoding:
Text File  |  1996-02-08  |  30.2 KB  |  1,116 lines

  1. //=============================================================================
  2. //
  3. //        Copyright (C) 1995,1996 by Paul S. McCarthy and Eric Sunshine.
  4. //                Written by Paul S. McCarthy and Eric Sunshine.
  5. //                            All Rights Reserved.
  6. //
  7. //        This notice may not be removed from this source code.
  8. //
  9. //        This object is included in the MiscKit by permission from the authors
  10. //        and its use is governed by the MiscKit license, found in the file
  11. //        "License.rtf" in the MiscKit distribution.    Please refer to that file
  12. //        for a list of all applicable permissions and restrictions.
  13. //
  14. //=============================================================================
  15. //-----------------------------------------------------------------------------
  16. // DirWindow.m
  17. //
  18. //        Manages window which displays directory listing.
  19. //
  20. //-----------------------------------------------------------------------------
  21. //-----------------------------------------------------------------------------
  22. // $Id$
  23. // $Log$
  24. //-----------------------------------------------------------------------------
  25. #import "DirWindow.h"
  26. #import "Defaults.h"
  27. #import "NameCache.h"
  28. #import <misckit/MiscTableScroll.h>
  29. #import <misckit/MiscTableCell.h>
  30. #import <errno.h>
  31. #import <appkit/NXImage.h>
  32. #import <appkit/workspaceRequest.h>
  33. #import <assert.h>
  34.  
  35. #define USE_PRIVATE_ZONE        1
  36.  
  37. #ifdef _POSIX_SOURCE
  38. # define GET_CURR_DIR(_BF_,_SZ_)        getcwd(_BF_,_SZ_)
  39. #else
  40. # define GET_CURR_DIR(_BF_,_SZ_)        getwd(_BF_)
  41. #endif
  42.  
  43. #define CASCADE_MAX 10
  44. static int cascadeCounter = 0;
  45. static NXCoord cascadeOriginX;
  46. static NXCoord cascadeOriginY;
  47. static NXCoord cascadeDeltaX;
  48. static NXCoord cascadeDeltaY;
  49.  
  50. static BOOL defaultAutoSort;
  51. static BOOL defaultShowHidden;
  52. static BOOL defaultHighlightDirs;
  53. static NXColor defaultColor;
  54. static NXSize defaultWinSize;
  55. static Font* defaultFont;
  56. static List* openDirs = 0;
  57. static OwnerCache* owners = 0;
  58. static GroupCache* groups = 0;
  59.  
  60. static char const COLOR_DEF[]            = "DirColor";
  61. static char const SIZE_DEF[]            = "DirSize";
  62. static char const FONT_DEF[]            = "DirFont";
  63. static char const SORT_DEF[]            = "AutoSort";
  64. static char const HIDDEN_DEF[]            = "ShowHidden";
  65. static char const HLIGHT_DEF[]            = "HighlightDirs";
  66. static char const COL_SIZES_DEF[]        = "ColSizes";
  67. static char const COL_ORDER_DEF[]        = "ColOrder";
  68.  
  69.  
  70. //-----------------------------------------------------------------------------
  71. // normalize_path
  72. //-----------------------------------------------------------------------------
  73. static void normalize_path( char *buff, size_t sz )
  74.     {
  75.     char save_dir[ FILENAME_MAX + 1 ];
  76.     char tmp[ FILENAME_MAX + 1 ];
  77.  
  78.     if (buff != 0 && sz > 0)
  79.         {
  80.         if (GET_CURR_DIR( save_dir, sizeof(save_dir) ) != 0)
  81.             {
  82.             if (chdir( buff ) == 0)
  83.                 {
  84.                 if (GET_CURR_DIR( tmp, sizeof(tmp) ) != 0)
  85.                     {
  86.                     int const tmp_len = strlen( tmp );
  87.                     if (tmp_len < sz)
  88.                         strcpy( buff, tmp );
  89.                     else
  90.                         {
  91.                         strncpy( buff, tmp, sz );
  92.                         buff[ sz - 1 ] = '\0';
  93.                         }
  94.                     }
  95.                 chdir( save_dir );
  96.                 }
  97.             }
  98.         }
  99.     }
  100.  
  101.  
  102. //-----------------------------------------------------------------------------
  103. // str_int
  104. //-----------------------------------------------------------------------------
  105. static char const* str_int( int n )
  106.     {
  107.     static char buff[ 32 ];
  108.     sprintf( buff, "%d", n );
  109.     return buff;
  110.     }
  111.  
  112.  
  113. //-----------------------------------------------------------------------------
  114. // str_date
  115. //-----------------------------------------------------------------------------
  116. static char const* str_date( time_t t )
  117.     {
  118.     #define BUFF_SIZE 64
  119.     static char buff[ BUFF_SIZE ];
  120.     strftime( buff, BUFF_SIZE, "%m/%d/%y %H:%M", localtime(&t) );
  121.     return buff;
  122.     }
  123.  
  124.  
  125. //-----------------------------------------------------------------------------
  126. // str_perms
  127. //-----------------------------------------------------------------------------
  128. static char const* str_perms( unsigned int mode )
  129.     {
  130.     static char buff[ 16 ];
  131.     char* s;
  132.     int ftype;
  133.     int c;
  134.  
  135.     s = buff;
  136.  
  137.     ftype = (mode & S_IFMT);
  138.     switch (ftype)
  139.         {
  140.         case S_IFDIR:    c = 'd'; break;
  141.         case S_IFCHR:    c = 'c'; break;
  142.         case S_IFBLK:    c = 'b'; break;
  143.         case S_IFREG:    c = '-'; break;
  144.         case S_IFLNK:    c = 'l'; break;
  145.         case S_IFSOCK:    c = 's'; break;
  146.         default:        c = '-'; break;
  147.         }
  148.     *s++ = c;
  149.     *s++ = (mode & 0400) ? 'r' : '-';
  150.     *s++ = (mode & 0200) ? 'w' : '-';
  151.     *s++ = (mode & S_ISUID) ? 's' : (mode & 0100) ? 'x' : '-';
  152.     *s++ = (mode & 0040) ? 'r' : '-';
  153.     *s++ = (mode & 0020) ? 'w' : '-';
  154.     *s++ = (mode & S_ISGID) ? 's' : (mode & 0010) ? 'x' : '-';
  155.     *s++ = (mode & 0004) ? 'r' : '-';
  156.     *s++ = (mode & 0002) ? 'w' : '-';
  157.     *s++ = (mode & S_ISVTX) ? 't' : (mode & 0001) ? 'x' : '-';
  158.     *s = '\0';
  159.  
  160.     return buff;
  161.     }
  162.  
  163.  
  164. //-----------------------------------------------------------------------------
  165. // fmt_icon
  166. //-----------------------------------------------------------------------------
  167. static void fmt_icon( MiscTableScroll* ts, DirEntry const* de, id cell )
  168.     {
  169.     NXCoord h,w,s;
  170.     NXSize sz;
  171.     NXImage* img;
  172.  
  173.     w = [ts colSize:ICON_SLOT]; if (w == 0) w = 18;
  174.     h = [ts uniformSizeRows];    if (h == 0) h = 18;
  175.     s = (w < h ? w : h) - 1.0;
  176.     sz.width = s;
  177.     sz.height = s;
  178.  
  179.     img = [de->dir getImage:de];
  180.     [img setSize: &sz];
  181.     [cell setImage: img];
  182.     }
  183.  
  184.  
  185. //-----------------------------------------------------------------------------
  186. // fmt_name
  187. //-----------------------------------------------------------------------------
  188. static void fmt_name( MiscTableScroll* ts, DirEntry const* de, id cell )
  189.     {
  190.     [cell setStringValueNoCopy: de->name];
  191.     }
  192.  
  193.  
  194. //-----------------------------------------------------------------------------
  195. // fmt_size
  196. //-----------------------------------------------------------------------------
  197. static void fmt_size( MiscTableScroll* ts, DirEntry const* de, id cell )
  198.     {
  199.     [[cell setAlignment: NX_RIGHTALIGNED] setIntValue: de->st.st_size ];
  200.     }
  201.  
  202.  
  203. //-----------------------------------------------------------------------------
  204. // fmt_modified
  205. //-----------------------------------------------------------------------------
  206. static void fmt_modified( MiscTableScroll* ts, DirEntry const* de, id cell )
  207.     {
  208.     int const t = (int) de->st.st_mtime;
  209.     [cell setStringValue: str_date( t )];
  210.     [cell setTag: t];
  211.     }
  212.  
  213.  
  214. //-----------------------------------------------------------------------------
  215. // fmt_perms
  216. //-----------------------------------------------------------------------------
  217. static void fmt_perms( MiscTableScroll* ts, DirEntry const* de, id cell )
  218.     {
  219.     unsigned int const mode = de->st.st_mode;
  220.     [cell setStringValue: str_perms(mode)];
  221.     [cell setTag: mode];
  222.     }
  223.  
  224.  
  225. //-----------------------------------------------------------------------------
  226. // fmt_owner
  227. //-----------------------------------------------------------------------------
  228. static void fmt_owner( MiscTableScroll* ts, DirEntry const* de, id cell )
  229.     {
  230.     [cell setStringValueNoCopy: [owners lookup:de->st.st_uid] ];
  231.     }
  232.  
  233.  
  234. //-----------------------------------------------------------------------------
  235. // fmt_group
  236. //-----------------------------------------------------------------------------
  237. static void fmt_group( MiscTableScroll* ts, DirEntry const* de, id cell )
  238.     {
  239.     [cell setStringValueNoCopy: [groups lookup:de->st.st_gid] ];
  240.     }
  241.  
  242.  
  243. //-----------------------------------------------------------------------------
  244. // fmt_hardlinks
  245. //-----------------------------------------------------------------------------
  246. static void fmt_hardlinks( MiscTableScroll* ts, DirEntry const* de, id cell )
  247.     {
  248.     [cell setIntValue: de->st.st_nlink];
  249.     }
  250.  
  251.  
  252. //-----------------------------------------------------------------------------
  253. // fmt_softlink
  254. //-----------------------------------------------------------------------------
  255. static void fmt_softlink( MiscTableScroll* ts, DirEntry const* de, id cell )
  256.     {
  257.     char const* s = de->soft_link;
  258.     [cell setStringValue: s ? s : "" ];
  259.     }
  260.  
  261.  
  262. //-----------------------------------------------------------------------------
  263. // fmt_message
  264. //-----------------------------------------------------------------------------
  265. static void fmt_message( MiscTableScroll* ts, DirEntry const* de, id cell )
  266.     {
  267.     [cell setStringValue: strerror(de->err) ];
  268.     }
  269.  
  270.  
  271. //-----------------------------------------------------------------------------
  272. // fmt_blank
  273. //-----------------------------------------------------------------------------
  274. static void fmt_blank( MiscTableScroll* ts, DirEntry const* de, id cell )
  275.     {
  276.     [cell setStringValueNoCopy:""];
  277.     }
  278.  
  279.  
  280. //-----------------------------------------------------------------------------
  281. // fmt_unknown
  282. //-----------------------------------------------------------------------------
  283. static void fmt_unknown( MiscTableScroll* ts, DirEntry const* de, id cell )
  284.     {
  285.     [cell setStringValueNoCopy:"?"];
  286.     }
  287.  
  288.  
  289.  
  290. //-----------------------------------------------------------------------------
  291. // FORMAT_FUNC
  292. //-----------------------------------------------------------------------------
  293.  
  294. typedef void (*FormatFunc)( MiscTableScroll* ts, DirEntry const* de, id cell );
  295.  
  296. static FormatFunc FORMAT_FUNC[ MAX_SLOT ] =
  297.         {
  298.         fmt_icon,                // ICON_SLOT,
  299.         fmt_name,                // NAME_SLOT,
  300.         fmt_size,                // SIZE_SLOT,
  301.         fmt_modified,            // MODIFIED_SLOT,
  302.         fmt_perms,                // PERMS_SLOT,
  303.         fmt_owner,                // OWNER_SLOT,
  304.         fmt_group,                // GROUP_SLOT,
  305.         fmt_hardlinks,            // HARDLINKS_SLOT,
  306.         fmt_softlink,            // SOFTLINK_SLOT,
  307.         fmt_blank,                // MESSAGE_SLOT
  308.         };
  309.  
  310. static FormatFunc FORMAT_ERR_FUNC[ MAX_SLOT ] =
  311.         {
  312.         fmt_icon,                // ICON_SLOT,
  313.         fmt_name,                // NAME_SLOT,
  314.         fmt_unknown,            // SIZE_SLOT,
  315.         fmt_unknown,            // MODIFIED_SLOT,
  316.         fmt_unknown,            // PERMS_SLOT,
  317.         fmt_unknown,            // OWNER_SLOT,
  318.         fmt_unknown,            // GROUP_SLOT,
  319.         fmt_unknown,            // HARDLINKS_SLOT,
  320.         fmt_softlink,            // SOFTLINK_SLOT,
  321.         fmt_message,            // MESSAGE_SLOT
  322.         };
  323.  
  324.  
  325. //-----------------------------------------------------------------------------
  326. // format_cell
  327. //-----------------------------------------------------------------------------
  328. static inline void format_cell(
  329.         MiscTableScroll* ts,
  330.         DirEntry const* de,
  331.         id cell,
  332.         unsigned int col )
  333.     {
  334.     if (de->err == 0)
  335.         (*(FORMAT_FUNC[col]))( ts, de, cell );
  336.     else
  337.         (*(FORMAT_ERR_FUNC[col]))( ts, de, cell );
  338.     }
  339.  
  340.  
  341. //=============================================================================
  342. // IMPLEMENTATION
  343. //=============================================================================
  344. @implementation DirWindow
  345.  
  346. //-----------------------------------------------------------------------------
  347. // + initCascader
  348. //-----------------------------------------------------------------------------
  349. + (void) initCascader
  350.     {
  351.     NXSize screenSize;
  352.     [NXApp getScreenSize: &screenSize];
  353.     cascadeOriginX = screenSize.width / 4;
  354.     cascadeOriginY = screenSize.height - 20;
  355.     cascadeDeltaX = 20;
  356.     cascadeDeltaY = 20;
  357.     }
  358.  
  359.  
  360. //-----------------------------------------------------------------------------
  361. // + initialize
  362. //-----------------------------------------------------------------------------
  363. + initialize
  364.     {
  365.     if (self == [DirWindow class])
  366.         {
  367.         [self initCascader];
  368.         openDirs = [[List alloc] init];
  369.         defaultColor = [Defaults getColor:COLOR_DEF fallback:NX_COLORLTGRAY];
  370.         defaultAutoSort = [Defaults getBool:SORT_DEF fallback:NO];
  371.         defaultShowHidden = [Defaults getBool:HIDDEN_DEF fallback:NO];
  372.         defaultHighlightDirs = [Defaults getBool:HLIGHT_DEF fallback:NO];
  373.         owners = [OwnerCache commonInstance];
  374.         groups = [GroupCache commonInstance];
  375.         }
  376.     return self;
  377.     }
  378.  
  379.  
  380. //-----------------------------------------------------------------------------
  381. // - cascade
  382. //-----------------------------------------------------------------------------
  383. - (void) cascade
  384.     {
  385.     NXCoord top,left;
  386.     left = cascadeOriginX + (cascadeDeltaX * cascadeCounter);
  387.     top     = cascadeOriginY - (cascadeDeltaY * cascadeCounter);
  388.     [window moveTopLeftTo: left : top ];
  389.     if (++cascadeCounter >= CASCADE_MAX)
  390.         cascadeCounter = 0;
  391.     }
  392.  
  393.  
  394. //-----------------------------------------------------------------------------
  395. // - updateButtons
  396. //-----------------------------------------------------------------------------
  397. - (void) updateButtons
  398.     {
  399.     BOOL enable = NO;
  400.     if ([scroll numSelectedRows] == 1)
  401.         {
  402.         MiscCoord_P const row = [scroll selectedRow];
  403.         enable = [dir_array isDirAt:row];
  404.         }
  405.     if (enable != [cdButton isEnabled])
  406.         [cdButton setEnabled: enable];
  407.     }
  408.  
  409.  
  410. //-----------------------------------------------------------------------------
  411. // - tableScroll:cellAt::
  412. //-----------------------------------------------------------------------------
  413. - tableScroll:(MiscTableScroll*)ts cellAt: (int)row : (int)col
  414.     {
  415.     id cell = lazy_row[col];
  416.     DirEntry const* const de = [dir_array entryAt:row];
  417.     format_cell( ts, de, cell, col );
  418.     if ([cell respondsTo:@selector(setBackgroundColor:)])
  419.         {
  420.         if (highlightDirs && [dir_array isDir:de])
  421.             [cell setBackgroundColor:NX_COLORCYAN];
  422.         else
  423.             [cell setBackgroundColor:[ts backgroundColor]];
  424.         }
  425.     return cell;
  426.     }
  427.  
  428.  
  429. //-----------------------------------------------------------------------------
  430. // - tableScroll:stringValueAt::
  431. //-----------------------------------------------------------------------------
  432. - (char const*) tableScroll:(MiscTableScroll*)ts stringValueAt:(int)r :(int)c
  433.     {
  434.     char const* rc = 0;
  435.     if (r < [dir_array count])
  436.         {
  437.         DirEntry const* const de = [dir_array entryAt:r];
  438.         if (de->err == 0)
  439.             {
  440.             switch (c)
  441.                 {
  442.             case SIZE_SLOT:        rc = str_int(de->st.st_size);            break;
  443.             case MODIFIED_SLOT: rc = str_date(de->st.st_mtime);            break;
  444.             case PERMS_SLOT:    rc = str_perms(de->st.st_mode);            break;
  445.             case OWNER_SLOT:    rc = [owners lookup:de->st.st_uid];        break;
  446.             case GROUP_SLOT:    rc = [groups lookup:de->st.st_gid];        break;
  447.             case HARDLINKS_SLOT:rc = str_int(de->st.st_nlink);            break;
  448.             case NAME_SLOT:        rc = de->name;                            break;
  449.             case SOFTLINK_SLOT: rc = de->soft_link;                        break;
  450.             case MESSAGE_SLOT:
  451.             case ICON_SLOT:
  452.             default:            rc = "";                                break;
  453.                 }
  454.             }
  455.         else
  456.             {
  457.             switch (c)
  458.                 {
  459.             case NAME_SLOT:        rc = de->name;                            break;
  460.             case SOFTLINK_SLOT: rc = de->soft_link;                        break;
  461.             case MESSAGE_SLOT:    rc = strerror(de->err);                    break;
  462.             case SIZE_SLOT:
  463.             case MODIFIED_SLOT:
  464.             case PERMS_SLOT:
  465.             case OWNER_SLOT:
  466.             case GROUP_SLOT:
  467.             case HARDLINKS_SLOT:
  468.             case ICON_SLOT:
  469.             default:            rc = "?";                                break;
  470.                 }
  471.             }
  472.         }
  473.     return (rc ? rc : "");
  474.     }
  475.  
  476.  
  477. //-----------------------------------------------------------------------------
  478. // -intValueAt::
  479. //-----------------------------------------------------------------------------
  480. - (int) intValueAt:(int)r :(int)c
  481.     {
  482.     int rc = 0;
  483.     if (r < [dir_array count])
  484.         {
  485.         DirEntry const* const de = [dir_array entryAt:r];
  486.         if (de->err == 0)
  487.             {
  488.             switch (c)
  489.                 {
  490.             case SIZE_SLOT:                rc = de->st.st_size;    break;
  491.             case MODIFIED_SLOT:            rc = de->st.st_mtime;    break;
  492.             case PERMS_SLOT:            rc = de->st.st_mode;    break;
  493.             case OWNER_SLOT:            rc = de->st.st_uid;        break;
  494.             case GROUP_SLOT:            rc = de->st.st_gid;        break;
  495.             case HARDLINKS_SLOT:        rc = de->st.st_nlink;    break;
  496.             case ICON_SLOT:
  497.             case NAME_SLOT:
  498.             case SOFTLINK_SLOT:
  499.             case MESSAGE_SLOT:
  500.             default:                                            break;
  501.                 }
  502.             }
  503.         }
  504.     return rc;
  505.     }
  506.  
  507. //-----------------------------------------------------------------------------
  508. // - tableScroll:intValueAt::
  509. //-----------------------------------------------------------------------------
  510. - (int) tableScroll:(MiscTableScroll*)ts intValueAt:(int)r :(int)c
  511.     {
  512.     return [self intValueAt:r:c];
  513.     }
  514.  
  515.  
  516. //-----------------------------------------------------------------------------
  517. // - tableScroll:tagAt::
  518. //-----------------------------------------------------------------------------
  519. - (int) tableScroll:(MiscTableScroll*)ts tagAt:(int)r :(int)c
  520.     {
  521.     return [self intValueAt:r:c];
  522.     }
  523.  
  524.  
  525. //-----------------------------------------------------------------------------
  526. // - tableScroll:fontChangedFrom:to:
  527. //-----------------------------------------------------------------------------
  528. - tableScroll:(MiscTableScroll*)ts
  529.         fontChangedFrom:(Font*)oldFont
  530.         to:(Font*)newFont
  531.     {
  532.     int col;
  533.     for (col = 0; col < MAX_SLOT; col++)
  534.         [lazy_row[col] setFont:newFont];
  535.  
  536.     defaultFont = newFont;
  537.     [Defaults set:FONT_DEF font:defaultFont];
  538.     return self;
  539.     }
  540.  
  541.  
  542. //-----------------------------------------------------------------------------
  543. // - tableScroll:border:slotResized:
  544. //-----------------------------------------------------------------------------
  545. - tableScroll:(MiscTableScroll*)ts
  546.         border:(MiscBorderType)b
  547.         slotResized:(int)n
  548.     {
  549.     char* s;
  550.     assert( b == MISC_COL_BORDER );
  551.     s = [ts colSizesAsString:0 size:0 canExpand:YES];
  552.     [Defaults set:COL_SIZES_DEF str:s];
  553.     free( s );
  554.     return self;
  555.     }
  556.  
  557.  
  558. //-----------------------------------------------------------------------------
  559. // - tableScroll:border:slotDraggedFrom:to:
  560. //-----------------------------------------------------------------------------
  561. - tableScroll:(MiscTableScroll*)ts
  562.         border:(MiscBorderType)b
  563.         slotDraggedFrom:(int)fromPos
  564.         to:(int)toPos;
  565.     {
  566.     char* s;
  567.     assert( b == MISC_COL_BORDER );
  568.     s = [ts colOrderAsString:0 size:0 canExpand:YES];
  569.     [Defaults set:COL_ORDER_DEF str:s];
  570.     free( s );
  571.     return self;
  572.     }
  573.  
  574.  
  575. //-----------------------------------------------------------------------------
  576. // - fillScroll
  577. //-----------------------------------------------------------------------------
  578. - (void) fillScroll
  579.     {
  580.     char buff[ 128 ];
  581.  
  582.     [window disableDisplay];
  583.  
  584.     [scroll renewRows: [dir_array count]];
  585.  
  586.     if ([scroll autoSortRows])
  587.         [scroll sortRows];
  588.  
  589.     sprintf( buff, "%d files   %d bytes",
  590.                 [dir_array count], [dir_array totalBytes] );
  591.     [countField setStringValue:buff];
  592.  
  593.     [self updateButtons];
  594.     [[window reenableDisplay] display];
  595.     }
  596.  
  597.  
  598. //-----------------------------------------------------------------------------
  599. // - setPath:
  600. //-----------------------------------------------------------------------------
  601. - (void) setPath:(char const*)dirname
  602.     {
  603.     NXZone* const z = [self zone];
  604.     int dirlen;
  605.     if (path != 0) NXZoneFree( z, path );
  606.     if (dirname == 0) dirname = NXHomeDirectory();
  607.     if (dirname == 0) dirname = "/";
  608.     dirlen = strlen( dirname ) + 1;
  609.     path = (char*) NXZoneMalloc( z, dirlen );
  610.     memcpy( path, dirname, dirlen );
  611.     [window setTitle: path];
  612.     }
  613.  
  614.  
  615. //-----------------------------------------------------------------------------
  616. // - loadDirectory:
  617. //-----------------------------------------------------------------------------
  618. - (void) loadDirectory:(char const*)dirname
  619.     {
  620.     int rc = [dir_array loadPath:dirname showHidden:showHidden];
  621.     if (rc != 0)
  622.         {
  623.         NXRunAlertPanel( "Can't Open",
  624.                 "Cannot open directory, %s\n%d:%s", "OK",0,0,
  625.                 path, rc, strerror(rc) );
  626.         }
  627.     }
  628.  
  629.  
  630. //-----------------------------------------------------------------------------
  631. // - reload
  632. //-----------------------------------------------------------------------------
  633. - (void) reload
  634.     {
  635.     [self loadDirectory:path];
  636.     [self fillScroll];
  637.     }
  638.  
  639.  
  640. //-----------------------------------------------------------------------------
  641. // - load:
  642. //-----------------------------------------------------------------------------
  643. - (void) load:(char const*)dirname
  644.     {
  645.     [self setPath:dirname];
  646.     [self reload];
  647.     }
  648.  
  649.  
  650. //-----------------------------------------------------------------------------
  651. // - open:
  652. //-----------------------------------------------------------------------------
  653. - open:sender
  654.     {
  655.     if ([scroll hasRowSelection])
  656.         {
  657.         int i;
  658.         int path_len;
  659.         char buff[ FILENAME_MAX + 1 ];
  660.         MiscIntList* list = [[MiscIntList allocFromZone:[self zone]] init];
  661.  
  662.         strcpy( buff, path );
  663.         path_len = strlen( buff );
  664.         if (path_len == 0 || buff[path_len - 1] != '/')
  665.             {
  666.             buff[ path_len++ ] = '/';
  667.             buff[ path_len ] = '\0';
  668.             }
  669.             
  670.         [scroll selectedRows: list];
  671.         for (i = [list count]; i-- > 0; )
  672.             {
  673.             int row = [list intAt:i];
  674.             DirEntry const* de = [dir_array entryAt:row];
  675.  
  676.             strcpy( buff + path_len, de->name );
  677.             if ([dir_array isDir:de])
  678.                 [[self class] launchDir: buff];
  679.             else
  680.                 [[Application workspace] openFile: buff];
  681.             }
  682.         [list free];
  683.         }
  684.     return self;
  685.     }
  686.  
  687.  
  688. //-----------------------------------------------------------------------------
  689. // - destroy:
  690. //-----------------------------------------------------------------------------
  691. - destroy:sender
  692.     {
  693.     if ([scroll hasRowSelection])
  694.         {
  695.         size_t total_len = 0;
  696.         char* file_list;
  697.         int i;
  698.         NXZone* const z = [self zone];
  699.         MiscIntList* list = [[MiscIntList allocFromZone:z] init];
  700.  
  701.         [scroll selectedRows: list];
  702.  
  703.         for (i = [list count]; i-- > 0; )
  704.             {
  705.             DirEntry const* de = [dir_array entryAt:[list intAt:i]];
  706.             if (de->name != 0)
  707.                 total_len += strlen( de->name ) + 1;
  708.             }
  709.  
  710.         file_list = (char*) NXZoneMalloc( z, total_len + 1 );
  711.         
  712.         total_len = 0;
  713.         for (i = [list count]; i-- > 0; )
  714.             {
  715.             DirEntry const* de = [dir_array entryAt:[list intAt:i]];
  716.             char const* const s = de->name;
  717.             if (s != 0)
  718.                 {
  719.                 int const len = strlen( s );
  720.                 strcpy( file_list + total_len, s );
  721.                 total_len += len;
  722.                 file_list[ total_len++ ] = '\t';
  723.                 }
  724.             }
  725.         file_list[ total_len ] = '\0';
  726.  
  727.         [[Application workspace]
  728.                 performFileOperation: WSM_DESTROY_OPERATION
  729.                         source: path
  730.                         destination: ""
  731.                         files: file_list
  732.                         options: ""];
  733.  
  734.         NXZoneFree( z, file_list );
  735.         [list free];
  736.         [self reload];
  737.         }
  738.     return self;
  739.     }
  740.  
  741.  
  742. //-----------------------------------------------------------------------------
  743. // - updatePressed:
  744. //-----------------------------------------------------------------------------
  745. - updatePressed:sender
  746.     {
  747.     [self reload];
  748.     return self;
  749.     }
  750.  
  751.  
  752. //-----------------------------------------------------------------------------
  753. // - cdPressed:
  754. //-----------------------------------------------------------------------------
  755. - cdPressed:sender
  756.     {
  757.     if ([scroll numSelectedRows] == 1)
  758.         {
  759.         DirEntry const* const de = [dir_array entryAt:[scroll selectedRow]];
  760.         if ([dir_array isDir:de])
  761.             {
  762.             char buff[ FILENAME_MAX * 2 + 1 ];
  763.             strcat( strcat( strcpy( buff, path ), "/" ), de->name );
  764.             normalize_path( buff, sizeof(buff) );
  765.             [self load:buff];
  766.             }
  767.         }
  768.     return self;
  769.     }
  770.  
  771.  
  772. //-----------------------------------------------------------------------------
  773. // - autoSortClick:
  774. //-----------------------------------------------------------------------------
  775. - autoSortClick:sender
  776.     {
  777.     BOOL const switchState = [autoSortSwitch state];
  778.     if (autoSort != switchState)
  779.         {
  780.         defaultAutoSort = autoSort = switchState;
  781.         [Defaults set:SORT_DEF bool:defaultAutoSort];
  782.         [scroll setAutoSortRows:switchState];
  783.         if (switchState)
  784.             [scroll sortRows];
  785.         }
  786.     return self;
  787.     }
  788.  
  789.  
  790. //-----------------------------------------------------------------------------
  791. // - hiddenFilesClick:
  792. //
  793. //        FIXME: Should not have to rescan the whole directory just to show/hide
  794. //        hidden files.  A more careful implementation would not be this sloppy.
  795. //-----------------------------------------------------------------------------
  796. - hiddenFilesClick:sender
  797.     {
  798.     BOOL const switchState = [hiddenFilesSwitch state];
  799.     if (showHidden != switchState)
  800.         {
  801.         defaultShowHidden = showHidden = switchState;
  802.         [Defaults set:HIDDEN_DEF bool:defaultShowHidden];
  803.         [self reload];
  804.         }
  805.     return self;
  806.     }
  807.  
  808.  
  809. //-----------------------------------------------------------------------------
  810. // - highlightClick:
  811. //-----------------------------------------------------------------------------
  812. - highlightClick:sender
  813.     {
  814.     BOOL const switchState = [highlightSwitch state];
  815.     if (highlightDirs != switchState)
  816.         {
  817.         defaultHighlightDirs = highlightDirs = switchState;
  818.         [Defaults set:HLIGHT_DEF bool:defaultHighlightDirs];
  819.         [scroll display];
  820.         }
  821.     return self;
  822.     }
  823.  
  824.  
  825. //-----------------------------------------------------------------------------
  826. // - didClick:
  827. //-----------------------------------------------------------------------------
  828. - didClick:sender
  829.     {
  830.     [self updateButtons];
  831.     return self;
  832.     }
  833.  
  834.  
  835. //-----------------------------------------------------------------------------
  836. // - didDoubleClick:
  837. //-----------------------------------------------------------------------------
  838. - didDoubleClick:sender
  839.     {
  840.     [self open:sender];
  841.     return self;
  842.     }
  843.  
  844.  
  845. //-----------------------------------------------------------------------------
  846. // - makeKeyAndOrderFront:
  847. //-----------------------------------------------------------------------------
  848. - makeKeyAndOrderFront:sender
  849.     {
  850.     [window makeKeyAndOrderFront:sender];
  851.     return self;
  852.     }
  853.  
  854.  
  855. //-----------------------------------------------------------------------------
  856. // - windowWillClose:
  857. //-----------------------------------------------------------------------------
  858. - windowWillClose:sender
  859.     {
  860.     [openDirs removeObject:self];
  861.     [NXApp delayedFree: self];
  862.     return self;
  863.     }
  864.  
  865.  
  866. //-----------------------------------------------------------------------------
  867. // - windowDidResize:
  868. //-----------------------------------------------------------------------------
  869. - windowDidResize:sender
  870.     {
  871.     NXRect r; [sender getFrame:&r];
  872.     if (r.size.width  != defaultWinSize.width ||
  873.         r.size.height != defaultWinSize.height)
  874.         {
  875.         defaultWinSize = r.size;
  876.         [Defaults set:SIZE_DEF size:defaultWinSize];
  877.         }
  878.     return self;
  879.     }
  880.  
  881.  
  882. //-----------------------------------------------------------------------------
  883. // - setDefaultColor
  884. //-----------------------------------------------------------------------------
  885. - (void) setDefaultColor: (NXColor)c
  886.     {
  887.     defaultColor = c;
  888.     [Defaults set:COLOR_DEF color:c];
  889.     }
  890.  
  891.  
  892. //-----------------------------------------------------------------------------
  893. // - setDaColors:
  894. //-----------------------------------------------------------------------------
  895. - (void) setDaColors: (NXColor)c
  896.     {
  897.     [window disableDisplay];
  898.     [window setBackgroundColor:c];
  899.     [scroll setColor:c];
  900.     [window reenableDisplay];
  901.     }
  902.  
  903.  
  904. //-----------------------------------------------------------------------------
  905. // - draggingEntered:
  906. //-----------------------------------------------------------------------------
  907. - (NXDragOperation) draggingEntered:(id<NXDraggingInfo>)sender
  908.     {
  909.     return ([sender draggingSourceOperationMask] & NX_DragOperationGeneric);
  910.     }
  911.  
  912.  
  913. //-----------------------------------------------------------------------------
  914. // - performDragOperation:
  915. //-----------------------------------------------------------------------------
  916. - (BOOL) performDragOperation:(id<NXDraggingInfo>)sender
  917.     {
  918.     [self setDefaultColor:
  919.                 NXReadColorFromPasteboard( [sender draggingPasteboard] )];
  920.     [self setDaColors: defaultColor];
  921.     [window display];
  922.     return YES;
  923.     }
  924.  
  925.  
  926. //-----------------------------------------------------------------------------
  927. // - initLazyRow
  928. //-----------------------------------------------------------------------------
  929. - (void) initLazyRow
  930.     {
  931.     Font* font = [scroll font];
  932.     NXZone* const z = [self zone];
  933.     int i;
  934.     for (i = 0; i < MAX_SLOT; i++)
  935.         {
  936.         id cell = [[scroll colCellPrototype:i] copyFromZone:z];
  937.         if ([cell respondsTo:@selector(setFont:)])
  938.             [cell setFont:font];
  939.         lazy_row[i] = cell;
  940.         }
  941.     }
  942.  
  943.  
  944. //-----------------------------------------------------------------------------
  945. // - initDefaults
  946. //-----------------------------------------------------------------------------
  947. - (void) initDefaults
  948.     {
  949.     static BOOL initialized = NO;
  950.     if (!initialized)
  951.         {
  952.         NXRect r; [window getFrame:&r];
  953.         defaultWinSize = r.size;
  954.  
  955.         defaultFont = [Defaults getFont:FONT_DEF fallback:[scroll font]];
  956.     
  957.         initialized = YES;
  958.         }
  959.     }
  960.  
  961.  
  962. //-----------------------------------------------------------------------------
  963. // - loadDefaults
  964. //-----------------------------------------------------------------------------
  965. - (void) loadDefaults
  966.     {
  967.     NXRect r;
  968.     char const* s;
  969.  
  970.     [window getFrame:&r];
  971.     r.size = [Defaults getSize:SIZE_DEF fallback:defaultWinSize];
  972.     [window placeWindow:&r];
  973.  
  974.     autoSort = defaultAutoSort;
  975.     showHidden = defaultShowHidden;
  976.     highlightDirs = defaultHighlightDirs;
  977.  
  978.     [autoSortSwitch setState:autoSort];
  979.     [hiddenFilesSwitch setState:showHidden];
  980.     [highlightSwitch setState:highlightDirs];
  981.  
  982.     [scroll setAutoSortRows:autoSort];
  983.     [scroll setFont:defaultFont];
  984.     [self setDaColors:defaultColor];
  985.  
  986.     s = [Defaults getStr:COL_SIZES_DEF fallback:0];
  987.     if (s)
  988.         [scroll setColSizesFromString:s];
  989.  
  990.     s = [Defaults getStr:COL_ORDER_DEF fallback:0];
  991.     if (s)
  992.         [scroll setColOrderFromString:s];
  993.     }
  994.  
  995.  
  996. //-----------------------------------------------------------------------------
  997. // - initDir:
  998. //-----------------------------------------------------------------------------
  999. - initDir:(char const*)dirname
  1000.     {
  1001.     char buff[ FILENAME_MAX + 1 ];
  1002.     NXZone* const z = [self zone];
  1003.  
  1004.     [super init];
  1005.     [[NXBundle bundleForClass:[self class]]
  1006.         getPath:buff forResource:[[self class] name] ofType:"nib"];
  1007.     [NXApp loadNibFile:buff owner:self withNames:NO fromZone:z];
  1008.     [window registerForDraggedTypes:&NXColorPboardType count:1];
  1009.     path = 0;
  1010.     [scroll setDoubleAction: @selector(didDoubleClick:)];
  1011.     dir_array = [[DirArray allocFromZone:z] init];
  1012.     [self initDefaults];
  1013.     [self loadDefaults];
  1014.     [self initLazyRow];
  1015.     [self load:dirname];
  1016.     [openDirs addObject:self];
  1017.     [self cascade];
  1018.     [window makeKeyAndOrderFront:self];
  1019.     return self;
  1020.     }
  1021.  
  1022.  
  1023. //-----------------------------------------------------------------------------
  1024. // - init
  1025. //-----------------------------------------------------------------------------
  1026. - init
  1027.     {
  1028.     return [self initDir: NXHomeDirectory()];
  1029.     }
  1030.  
  1031.  
  1032. //-----------------------------------------------------------------------------
  1033. // - free
  1034. //-----------------------------------------------------------------------------
  1035. - free
  1036.     {
  1037.     int i;
  1038. #if(USE_PRIVATE_ZONE)
  1039.     NXZone* const z = [self zone];
  1040. #endif
  1041.     [window close];
  1042.     [window free];
  1043.     if (path != 0)
  1044.         free( path );
  1045.     [dir_array free];
  1046.     for (i = 0; i < MAX_SLOT; i++)
  1047.         [lazy_row[i] free];
  1048.     [super free];
  1049. #if(USE_PRIVATE_ZONE)
  1050.     NXDestroyZone( z );
  1051. #endif
  1052.     return 0;
  1053.     }
  1054.  
  1055.  
  1056. //-----------------------------------------------------------------------------
  1057. // - path
  1058. //-----------------------------------------------------------------------------
  1059. - (char const*) path
  1060.     {
  1061.     return path;
  1062.     }
  1063.  
  1064.  
  1065. //-----------------------------------------------------------------------------
  1066. // + findDir:
  1067. //-----------------------------------------------------------------------------
  1068. + (DirWindow*) findDir:(char const*) normalized_path
  1069.     {
  1070.     DirWindow* p = 0;
  1071.     if (normalized_path != 0)
  1072.         {
  1073.         char const* s;
  1074.         unsigned int i;
  1075.         unsigned int const lim = [openDirs count];
  1076.         for (i = 0;     i < lim;  i++)
  1077.             {
  1078.             p = (DirWindow*) [openDirs objectAt:i];
  1079.             s = [p path];
  1080.             if (s != 0 && strcmp( s, normalized_path ) == 0)
  1081.                 return p;
  1082.             }
  1083.         }
  1084.     return 0;
  1085.     }
  1086.  
  1087.  
  1088. //-----------------------------------------------------------------------------
  1089. // + launchDir:
  1090. //-----------------------------------------------------------------------------
  1091. + launchDir: (char const*) dirname
  1092.     {
  1093.     DirWindow* p = 0;
  1094.     char buff[ FILENAME_MAX + 1 ];
  1095.     if (dirname == 0) dirname = NXHomeDirectory();
  1096.     if (dirname == 0) dirname = "/";
  1097.     strncpy( buff, dirname, sizeof(buff) );
  1098.     buff[ sizeof(buff) - 1 ] = '\0';
  1099.     normalize_path( buff, sizeof(buff) );
  1100.     if ((p = [self findDir:buff]) != 0)
  1101.         [p makeKeyAndOrderFront:self];
  1102.     else
  1103.         {
  1104. #if(USE_PRIVATE_ZONE)
  1105.         NXZone* z = NXCreateZone( vm_page_size, vm_page_size, YES );
  1106.         p = [[self allocFromZone:z] initDir:buff];
  1107. #else
  1108.         p = [[self alloc] initDir:buff];
  1109. #endif
  1110.         }
  1111.     return p;
  1112.     }
  1113.  
  1114.  
  1115. @end
  1116.