2006-08-20 22:43:09 +04:00
/*
* $ Id $
*
* EFiler - EDE File Manager
* Part of Equinox Desktop Environment ( EDE ) .
* Copyright ( c ) 2000 - 2006 EDE Authors .
*
* This program is licenced under terms of the
* GNU General Public Licence version 2 or newer .
* See COPYING for details .
*/
2006-08-21 23:27:22 +04:00
2007-07-16 11:35:32 +04:00
# include <string.h>
# include <dirent.h>
# include <sys/stat.h>
2007-07-17 23:16:39 +04:00
# include <sys/time.h> // timer
# include <unistd.h> // edelib/Run needs it :(
# include <sys/resource.h> // for core
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
# include <Fl/Fl.H>
2007-07-17 23:16:39 +04:00
# include <Fl/Fl_Double_Window.H>
# include <Fl/Fl_Menu_Bar.H>
# include <Fl/Fl_File_Chooser.H> // for fl_dir_chooser, used in "Open location"
# include <Fl/Fl_Progress.H>
# include <Fl/Fl_Button.H>
2007-07-16 11:35:32 +04:00
# include <Fl/filename.H>
# include <Fl/fl_ask.H>
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
# include <edelib/Nls.h>
# include <edelib/MimeType.h>
# include <edelib/String.h>
2007-07-17 23:16:39 +04:00
# include <edelib/Run.h>
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
# include "EDE_FileView.h"
# include "Util.h"
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
# define DEFAULT_ICON "misc-vedran"
2006-08-30 13:20:54 +04:00
2007-07-17 23:16:39 +04:00
Fl_Window * win ;
2007-07-16 11:35:32 +04:00
FileDetailsView * view ;
2007-07-17 23:16:39 +04:00
Fl_Menu_Bar * main_menu ;
Fl_Box * statusbar ;
char current_dir [ FL_PATH_MAX ] ;
2007-07-16 11:35:32 +04:00
bool showhidden ;
bool semaphore ;
bool dirsfirst ;
bool ignorecase ;
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
// These variables are global to save time on construction/destruction
edelib : : MimeType mime_resolver ;
struct stat buf ;
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
// constants
const int default_window_width = 600 ;
const int default_window_height = 400 ;
const int menubar_height = 30 ;
const int statusbar_height = 24 ;
const int statusbar_width = 400 ;
// This is just a temporary fix so that efiler works atm.
struct sopeners {
char * type ;
char * opener ;
sopeners * next ;
} * openers = 0 ;
char * simpleopener ( const char * mimetype ) {
sopeners * p ;
if ( ! openers ) {
FILE * fp = fopen ( " openers.txt " , " r " ) ;
if ( ! fp ) { fl_alert ( _ ( " File openers.txt not found " ) ) ; return 0 ; }
char buf [ FL_PATH_MAX * 2 ] ;
while ( ! feof ( fp ) ) {
fgets ( ( char * ) & buf , FL_PATH_MAX * 2 , fp ) ;
if ( buf [ 0 ] = = ' \0 ' | | buf [ 1 ] = = ' \0 ' | | buf [ 0 ] = = ' # ' ) continue ;
buf [ strlen ( buf ) - 1 ] = ' \0 ' ;
char * tmp = strstr ( buf , " || " ) ;
* tmp = ' \0 ' ;
sopeners * q = new sopeners ;
q - > type = strdup ( buf ) ;
q - > opener = strdup ( tmp + 2 ) ;
//fprintf (stderr, "Found type: '%s' opener: '%s'\n",q->type,q->opener);
q - > next = 0 ;
if ( ! openers ) openers = q ;
else p - > next = q ;
p = q ;
}
fclose ( fp ) ;
}
p = openers ;
char * result = 0 ; int topscore = 0 ;
while ( p ! = 0 ) {
int score = strlen ( p - > type ) ;
if ( strncmp ( p - > type , mimetype , score ) = = 0 & & score > topscore ) {
topscore = score ;
result = p - > opener ;
}
p = p - > next ;
}
return result ;
}
2007-07-16 11:35:32 +04:00
// modification of versionsort which ignores case
void lowercase ( char * s ) {
for ( int i = 0 ; i < strlen ( s ) ; i + + )
if ( s [ i ] > = ' A ' & & s [ i ] < = ' Z ' ) s [ i ] + = ' a ' - ' A ' ;
}
int myversionsort ( const void * a , const void * b ) {
struct dirent * * ka = ( struct dirent * * ) a ;
struct dirent * * kb = ( struct dirent * * ) b ;
char * ma = strdup ( ( * ka ) - > d_name ) ;
char * mb = strdup ( ( * kb ) - > d_name ) ;
lowercase ( ma ) ; lowercase ( mb ) ;
int k = strverscmp ( ma , mb ) ;
free ( ma ) ; free ( mb ) ;
return k ;
2006-08-20 22:43:09 +04:00
}
2006-08-30 13:20:54 +04:00
2006-08-20 22:43:09 +04:00
void loaddir ( const char * path ) {
2007-07-17 23:16:39 +04:00
if ( semaphore ) return ; // Prevent loaddir to interrupt previous loaddir - that can result in crash
semaphore = true ;
2007-07-16 11:35:32 +04:00
char old_dir [ FL_PATH_MAX ] ;
2007-07-17 23:16:39 +04:00
strncpy ( old_dir , current_dir , strlen ( current_dir ) ) ; // Restore olddir in case of error
2006-08-20 22:43:09 +04:00
// Set current_dir
2007-07-16 11:35:32 +04:00
if ( fl_filename_isdir ( path ) ) {
2006-08-20 22:43:09 +04:00
if ( path [ 0 ] = = ' ~ ' ) // Expand tilde
2006-08-21 23:27:22 +04:00
snprintf ( current_dir , PATH_MAX , " %s/%s " , getenv ( " HOME " ) , path + 1 ) ;
2006-08-20 22:43:09 +04:00
else
strcpy ( current_dir , path ) ;
} else
strcpy ( current_dir , getenv ( " HOME " ) ) ;
2007-07-16 11:35:32 +04:00
2006-08-20 22:43:09 +04:00
// Trailing slash should always be there
if ( current_dir [ strlen ( current_dir ) - 1 ] ! = ' / ' ) strcat ( current_dir , " / " ) ;
2007-07-16 11:35:32 +04:00
// Compact dotdot (..)
if ( char * tmp = strstr ( current_dir , " /../ " ) ) {
char * tmp2 = tmp + 4 ;
tmp - - ;
while ( tmp ! = current_dir & & * tmp ! = ' / ' ) tmp - - ;
tmp + + ;
while ( * tmp2 ! = ' \0 ' ) * tmp + + = * tmp2 + + ;
* tmp = ' \0 ' ;
}
2006-08-20 22:43:09 +04:00
fprintf ( stderr , " loaddir(%s) = (%s) \n " , path , current_dir ) ;
2006-08-26 13:06:13 +04:00
// Update directory tree
2007-07-16 11:35:32 +04:00
// dirtree->set_current(current_dir);
2006-08-26 13:06:13 +04:00
2007-07-16 11:35:32 +04:00
// variables used later
int size = 0 ;
dirent * * files ;
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
// List all files in directory
if ( ignorecase )
size = scandir ( current_dir , & files , 0 , myversionsort ) ;
else
size = scandir ( current_dir , & files , 0 , versionsort ) ;
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
if ( size < 1 ) { // there should always be . and ..
2007-07-16 11:35:32 +04:00
fl_alert ( _ ( " Permission denied! " ) ) ;
strncpy ( current_dir , old_dir , strlen ( current_dir ) ) ;
2007-07-17 23:16:39 +04:00
semaphore = false ;
2007-07-16 11:35:32 +04:00
return ;
}
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
// set window label
win - > label ( tasprintf ( _ ( " %s - File manager " ) , current_dir ) ) ;
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
view - > clear ( ) ;
2006-08-30 13:20:54 +04:00
2007-07-16 11:35:32 +04:00
FileItem * * item_list = new FileItem * [ size ] ;
int fsize = 0 ;
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
for ( int i = 0 ; i < size ; i + + ) {
2006-08-20 22:43:09 +04:00
char * n = files [ i ] - > d_name ; //shortcut
2007-07-17 23:16:39 +04:00
// don't show . (current directory)
2007-07-16 11:35:32 +04:00
if ( strcmp ( n , " . " ) = = 0 ) continue ;
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
// hide files with dot except .. (up directory)
2007-07-16 11:35:32 +04:00
if ( ! showhidden & & ( n [ 0 ] = = ' . ' ) & & ( strcmp ( n , " .. " ) ! = 0 ) ) continue ;
2006-08-20 22:43:09 +04:00
// hide files ending with tilde (backup) - NOTE
if ( ! showhidden & & ( n [ strlen ( n ) - 1 ] = = ' ~ ' ) ) continue ;
2007-07-16 11:35:32 +04:00
char fullpath [ FL_PATH_MAX ] ;
2007-07-17 23:16:39 +04:00
snprintf ( fullpath , FL_PATH_MAX - 1 , " %s%s " , current_dir , n ) ;
2007-07-16 11:35:32 +04:00
if ( stat ( fullpath , & buf ) ) continue ; // error
FileItem * item = new FileItem ;
item - > name = n ;
item - > realpath = fullpath ;
2007-07-17 23:16:39 +04:00
item - > date = nice_time ( buf . st_mtime ) ;
item - > permissions = " " ; // todo
2007-07-16 11:35:32 +04:00
if ( strcmp ( n , " .. " ) = = 0 ) {
item - > icon = " undo " ;
item - > description = " Go up " ;
item - > size = " " ;
} else if ( S_ISDIR ( buf . st_mode ) ) { // directory
item - > icon = " folder " ;
item - > description = " Directory " ;
// item->name += "/";
item - > size = " " ;
} else {
item - > icon = " unknown " ;
item - > description = " Unknown " ;
2007-07-17 23:16:39 +04:00
item - > size = nice_size ( buf . st_size ) ;
2006-08-30 13:20:54 +04:00
}
2007-07-16 11:35:32 +04:00
item_list [ fsize + + ] = item ;
2006-08-30 13:20:54 +04:00
}
2007-07-17 23:16:39 +04:00
// Populate view
2007-07-16 11:35:32 +04:00
if ( dirsfirst ) {
for ( int i = 0 ; i < fsize ; i + + ) {
if ( item_list [ i ] - > description = = " Directory " | | item_list [ i ] - > description = = " Go up " )
view - > add ( item_list [ i ] ) ;
2006-08-30 13:20:54 +04:00
}
2007-07-16 11:35:32 +04:00
for ( int i = 0 ; i < fsize ; i + + )
if ( item_list [ i ] - > description ! = " Directory " & & item_list [ i ] - > description ! = " Go up " )
view - > add ( item_list [ i ] ) ;
2006-08-30 13:20:54 +04:00
} else {
2007-07-16 11:35:32 +04:00
for ( int i = 0 ; i < fsize ; i + + )
view - > add ( item_list [ i ] ) ;
}
view - > redraw ( ) ;
Fl : : check ( ) ;
2006-08-30 13:20:54 +04:00
2007-07-16 11:35:32 +04:00
// Update mime types - can be slow...
for ( int i = 0 ; i < fsize ; i + + ) {
if ( item_list [ i ] - > description ! = " Directory " & & item_list [ i ] - > description ! = " Go up " ) {
mime_resolver . set ( item_list [ i ] - > realpath . c_str ( ) ) ;
edelib : : String desc , icon ;
desc = mime_resolver . comment ( ) ;
icon = mime_resolver . icon_name ( ) ;
if ( desc ! = " " | | icon ! = " " ) {
if ( desc ! = " " ) item_list [ i ] - > description = desc ;
if ( icon ! = " " ) item_list [ i ] - > icon = icon ;
fprintf ( stderr , " ICON: %s !!!!! \n " , icon . c_str ( ) ) ;
view - > update ( item_list [ i ] ) ;
2006-08-30 13:20:54 +04:00
}
2007-07-16 11:35:32 +04:00
Fl : : check ( ) ;
2006-08-30 13:20:54 +04:00
}
}
2007-07-16 11:35:32 +04:00
// Cleanup
for ( int i = 0 ; i < fsize ; i + + ) delete item_list [ i ] ;
delete [ ] item_list ;
2007-07-17 23:16:39 +04:00
semaphore = false ;
// TODO Get free space for statusbar
statusbar - > label ( _ ( " Ready. " ) ) ;
}
/*-----------------------------------------------------------------
File moving and copying operations
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
Fl_Progress * cut_copy_progress ;
bool stop_now ;
bool overwrite_all , skip_all ;
char * * cut_copy_buffer = 0 ;
bool operation_is_copy = false ;
// Yada n'exist cest pas
bool fl_filename_exist ( const char * file ) { return ( stat ( file , & buf ) = = 0 ) ; }
// Execute cut or copy operation when List View is active
void do_cut_copy ( bool m_copy ) {
// Count selected icons, for malloc
int num = view - > size ( ) ;
int nselected = 0 ;
for ( int i = 1 ; i < = num ; i + + )
if ( view - > selected ( i ) ) {
nselected + + ;
// Can not cut/copy the up directory button (..)
const char * tmp = view - > text ( i ) ;
if ( tmp [ 0 ] = = ' . ' & & tmp [ 1 ] = = ' . ' & & ( tmp [ 2 ] = = ' \0 ' | | tmp [ 2 ] = = view - > column_char ( ) ) ) return ;
}
// Clear cut/copy buffer and optionally ungray the previously cutted icons
if ( cut_copy_buffer ) {
for ( int i = 0 ; cut_copy_buffer [ i ] ; i + + )
free ( cut_copy_buffer [ i ] ) ;
free ( cut_copy_buffer ) ;
if ( ! operation_is_copy ) {
for ( int i = 1 ; i < = num ; i + + )
view - > ungray ( i ) ;
}
}
// Allocate buffer
cut_copy_buffer = ( char * * ) malloc ( sizeof ( char * ) * ( nselected + 2 ) ) ;
// Add selected files to buffer and optionally grey icons (for cut effect)
int buf = 0 ;
for ( int i = 1 ; i < = num ; i + + ) {
if ( view - > selected ( i ) = = 1 ) {
cut_copy_buffer [ buf ] = strdup ( ( char * ) view - > data ( i ) ) ;
if ( ! m_copy ) view - > gray ( i ) ;
buf + + ;
}
}
if ( buf = = 0 ) { //nothing selected, use the focused item
int i = view - > get_focus ( ) ;
cut_copy_buffer [ buf ] = strdup ( ( char * ) view - > data ( i ) ) ;
if ( ! m_copy ) view - > gray ( i ) ;
buf + + ;
nselected = 1 ;
}
cut_copy_buffer [ buf ] = 0 ;
operation_is_copy = m_copy ;
// Deselect all
int focused = view - > get_focus ( ) ;
for ( int i = 1 ; i < = num ; i + + )
if ( view - > selected ( i ) ) view - > select ( i , 0 ) ;
view - > set_focus ( focused ) ;
// Update statusbar
if ( m_copy )
statusbar - > label ( tasprintf ( _ ( " Selected %d items for copying " ) , nselected ) ) ;
else
statusbar - > label ( tasprintf ( _ ( " Selected %d items for moving " ) , nselected ) ) ;
}
// Helper functions for paste:
// Tests if two files are on the same filesystem
bool is_on_same_fs ( const char * file1 , const char * file2 ) {
FILE * mtab ; // /etc/mtab or /etc/mnttab file
static char filesystems [ 50 ] [ PATH_MAX ] ;
static int fs_number = 0 ;
// On first access read filesystems
if ( fs_number = = 0 ) {
mtab = fopen ( " /etc/mnttab " , " r " ) ; // Fairly standard
if ( mtab = = NULL )
mtab = fopen ( " /etc/mtab " , " r " ) ; // More standard
if ( mtab = = NULL )
mtab = fopen ( " /etc/fstab " , " r " ) ; // Otherwise fallback to full list
if ( mtab = = NULL )
mtab = fopen ( " /etc/vfstab " , " r " ) ; // Alternate full list file
char line [ PATH_MAX ] ; // Input line
char device [ PATH_MAX ] , mountpoint [ PATH_MAX ] , fs [ PATH_MAX ] ;
while ( mtab ! = NULL & & fgets ( line , sizeof ( line ) , mtab ) ! = NULL ) {
if ( line [ 0 ] = = ' # ' | | line [ 0 ] = = ' \n ' )
continue ;
if ( sscanf ( line , " %s%s%s " , device , mountpoint , fs ) ! = 3 )
continue ;
strcpy ( filesystems [ fs_number ] , mountpoint ) ;
fs_number + + ;
}
fclose ( mtab ) ;
if ( fs_number = = 0 ) return false ; // some kind of error
}
// Find filesystem for file1 (largest mount point match)
char * max ;
int maxlen = 0 ;
for ( int i = 0 ; i < fs_number ; i + + ) {
int mylen = strlen ( filesystems [ i ] ) ;
if ( ( strncmp ( file1 , filesystems [ i ] , mylen ) = = 0 ) & & ( mylen > maxlen ) ) {
maxlen = mylen ;
max = filesystems [ i ] ;
}
}
if ( maxlen = = 0 ) return false ; // some kind of error
// See if file2 matches the same filesystem
return ( strncmp ( file2 , max , maxlen ) = = 0 ) ;
}
// Copy single file. Returns true if operation should continue
bool my_copy ( const char * src , const char * dest ) {
FILE * fold , * fnew ;
int c ;
if ( strcmp ( src , dest ) = = 0 )
// this shouldn't happen
return true ;
if ( fl_filename_exist ( dest ) ) {
// if both src and dest are directories, do nothing
if ( fl_filename_isdir ( src ) & & fl_filename_isdir ( dest ) )
return true ;
int c = - 1 ;
if ( ! overwrite_all & & ! skip_all ) {
// here was choice_alert
c = fl_choice ( tsprintf ( _ ( " File already exists: %s. What to do? " ) , dest ) , _ ( " &Overwrite " ) , _ ( " Over&write all " ) , _ ( " *&Skip " ) , _ ( " Skip &all " ) , 0 ) ; // asterisk (*) means default
}
if ( c = = 1 ) overwrite_all = true ;
if ( c = = 3 ) skip_all = true ;
if ( c = = 2 | | skip_all ) {
return true ;
}
// At this point either c==0 (overwrite) or overwrite_all == true
// copy directory over file
if ( fl_filename_isdir ( src ) )
unlink ( dest ) ;
// copy file over directory
// TODO: we will just skip this case, but ideally there should be
// another warning
if ( fl_filename_isdir ( dest ) )
return true ;
}
if ( fl_filename_isdir ( src ) ) {
if ( mkdir ( dest , umask ( 0 ) ) = = 0 )
return true ; // success
// here was choice_alert
int q = fl_choice ( tsprintf ( _ ( " Cannot create directory %s " ) , dest ) , _ ( " *&Continue " ) , _ ( " &Stop " ) , 0 ) ;
if ( q = = 0 ) return true ; else return false ;
}
if ( ( fold = fopen ( src , " rb " ) ) = = NULL ) {
// here was choice_alert
int q = fl_choice ( tsprintf ( _ ( " Cannot read file %s " ) , src ) , _ ( " *&Continue " ) , _ ( " &Stop " ) , 0 ) ;
if ( q = = 0 ) return true ; else return false ;
}
if ( ( fnew = fopen ( dest , " wb " ) ) = = NULL )
{
fclose ( fold ) ;
// here was choice_alert
int q = fl_choice ( tsprintf ( _ ( " Cannot create file %s " ) , dest ) , _ ( " *&Continue " ) , _ ( " &Stop " ) , 0 ) ;
if ( q = = 0 ) return true ; else return false ;
}
while ( ! feof ( fold ) ) {
c = fgetc ( fold ) ;
fputc ( c , fnew ) ;
}
// TODO: Add more error handling using ferror()
fclose ( fold ) ;
fclose ( fnew ) ;
return true ;
}
// Recursive function that creates a list of all files to be
// copied, expanding directories etc. The total number of elements
// will be stored in listsize. Returns false if user decided to
// interrupt copying.
bool create_list ( const char * src , char * * & list , int & list_size , int & list_capacity ) {
// Grow list if neccessary
if ( list_size > = list_capacity - 1 ) {
list_capacity + = 1000 ;
list = ( char * * ) realloc ( list , sizeof ( char * * ) * list_capacity ) ;
}
// We add both files and diretories to list
list [ list_size + + ] = strdup ( src ) ;
if ( fl_filename_isdir ( src ) ) {
char new_src [ PATH_MAX ] ;
dirent * * files ;
// FIXME: use same sort as currently used
// FIXME: detect errors on accessing folder
int num_files = fl_filename_list ( src , & files , fl_casenumericsort ) ;
for ( int i = 0 ; i < num_files ; i + + ) {
if ( strcmp ( files [ i ] - > d_name , " ./ " ) = = 0 | | strcmp ( files [ i ] - > d_name , " ../ " ) = = 0 ) continue ;
snprintf ( new_src , PATH_MAX , " %s%s " , src , files [ i ] - > d_name ) ;
Fl : : check ( ) ; // update gui
if ( stop_now | | ! create_list ( new_src , list , list_size , list_capacity ) )
return false ;
}
}
return true ;
}
// Callback for Stop button on progress window
void stop_copying_cb ( Fl_Widget * , void * v ) {
stop_now = true ;
// Let's inform user that we're stopping...
Fl_Box * caption = ( Fl_Box * ) v ;
caption - > label ( _ ( " Stopping... " ) ) ;
caption - > redraw ( ) ;
caption - > parent ( ) - > redraw ( ) ;
}
// Execute paste operation - this will copy or move files based on last
// operation
void do_paste ( ) {
if ( ! cut_copy_buffer | | ! cut_copy_buffer [ 0 ] ) return ;
overwrite_all = false ; skip_all = false ;
// Moving files on same filesystem is trivial, just like rename
// We don't even need a progress bar
if ( ! operation_is_copy & & is_on_same_fs ( current_dir , cut_copy_buffer [ 0 ] ) ) {
for ( int i = 0 ; cut_copy_buffer [ i ] ; i + + ) {
char * newname ;
asprintf ( & newname , " %s%s " , current_dir , fl_filename_name ( cut_copy_buffer [ i ] ) ) ;
if ( fl_filename_exist ( newname ) ) {
int c = - 1 ;
if ( ! overwrite_all & & ! skip_all ) {
// here was choice_alert
c = fl_choice ( tsprintf ( _ ( " File already exists: %s. What to do? " ) , newname ) , _ ( " &Overwrite " ) , _ ( " Over&write all " ) , _ ( " *&Skip " ) , _ ( " Skip &all " ) ) ; // * means default
}
if ( c = = 1 ) overwrite_all = true ;
if ( c = = 3 ) skip_all = true ;
if ( c = = 2 | | skip_all ) {
free ( cut_copy_buffer [ i ] ) ;
continue ; // go to next entry
}
// At this point c==0 (Overwrite) or overwrite_all == true
unlink ( newname ) ;
}
rename ( cut_copy_buffer [ i ] , newname ) ;
free ( cut_copy_buffer [ i ] ) ;
}
free ( cut_copy_buffer ) ;
cut_copy_buffer = 0 ;
loaddir ( current_dir ) ; // Update display
return ;
//
// Real file moving / copying using recursive algorithm
//
} else {
stop_now = false ;
// Create srcdir string
char * srcdir = strdup ( cut_copy_buffer [ 0 ] ) ;
char * p = strrchr ( srcdir , ' / ' ) ;
if ( * ( p + 1 ) = = ' \0 ' ) { // slash is last - find one before
* p = ' \0 ' ;
p = strrchr ( srcdir , ' / ' ) ;
}
* ( p + 1 ) = ' \0 ' ;
if ( strcmp ( srcdir , current_dir ) = = 0 ) {
fl_alert ( _ ( " You cannot copy a file onto itself! " ) ) ;
return ;
}
// Draw progress dialog
// NOTE: sometimes when copying/moving just one file, the window
// can get "stuck"
// See: fltk STR 1255, http://www.fltk.org/str.php?L1255
Fl_Window * progress_window = new Fl_Window ( 350 , 150 ) ;
if ( operation_is_copy )
progress_window - > label ( _ ( " Copying files " ) ) ;
else
progress_window - > label ( _ ( " Moving files " ) ) ;
progress_window - > set_modal ( ) ;
progress_window - > begin ( ) ;
Fl_Box * caption = new Fl_Box ( 20 , 20 , 310 , 25 , _ ( " Counting files in directories " ) ) ;
caption - > align ( FL_ALIGN_LEFT | FL_ALIGN_INSIDE ) ;
cut_copy_progress = new Fl_Progress ( 20 , 60 , 310 , 20 ) ;
Fl_Button * stop_button = new Fl_Button ( 145 , 100 , 60 , 40 , _ ( " &Stop " ) ) ;
stop_button - > callback ( stop_copying_cb , caption ) ;
progress_window - > end ( ) ;
progress_window - > show ( ) ;
// How many items do we copy?
int copy_items = 0 ;
for ( ; cut_copy_buffer [ copy_items ] ; copy_items + + ) ;
// Set ProgressBar range accordingly
cut_copy_progress - > minimum ( 0 ) ;
cut_copy_progress - > maximum ( copy_items ) ;
cut_copy_progress - > value ( 0 ) ;
// Count files in directories
int list_size = 0 , list_capacity = 1000 ;
char * * files_list = ( char * * ) malloc ( sizeof ( char * * ) * list_capacity ) ;
for ( int i = 0 ; i < copy_items ; i + + ) {
// We must ensure that cut_copy_buffer is deallocated
// even if user clicked on Stop
if ( ! stop_now ) create_list ( cut_copy_buffer [ i ] , files_list , list_size , list_capacity ) ;
free ( cut_copy_buffer [ i ] ) ;
cut_copy_progress - > value ( i + 1 ) ;
Fl : : check ( ) ; // check to see if user pressed Stop
}
free ( cut_copy_buffer ) ;
cut_copy_buffer = 0 ;
// Now copying those files
if ( ! stop_now ) {
char label [ 150 ] ;
char dest [ PATH_MAX ] ;
cut_copy_progress - > minimum ( 0 ) ;
cut_copy_progress - > maximum ( list_size ) ;
cut_copy_progress - > value ( 0 ) ;
for ( int i = 0 ; i < list_size ; i + + ) {
// Prepare dest filename
char * srcfile = files_list [ i ] + strlen ( srcdir ) ;
snprintf ( dest , PATH_MAX , " %s%s " , current_dir , srcfile ) ;
snprintf ( label , 150 , _ ( " Copying %d of %d files to %s " ) , i , list_size , current_dir ) ;
caption - > label ( label ) ;
caption - > redraw ( ) ;
if ( stop_now | | ! my_copy ( files_list [ i ] , dest ) )
break ;
// Delete file after moving
if ( ! operation_is_copy ) unlink ( files_list [ i ] ) ;
cut_copy_progress - > value ( cut_copy_progress - > value ( ) + 1 ) ;
Fl : : check ( ) ; // check to see if user pressed Stop
}
}
progress_window - > hide ( ) ;
// Deallocate files_list[][]
for ( int i = 0 ; i < list_size ; i + + )
free ( files_list [ i ] ) ;
free ( files_list ) ;
// Reload current dir
loaddir ( current_dir ) ;
}
2006-08-30 13:20:54 +04:00
}
2007-07-17 23:16:39 +04:00
/*-----------------------------------------------------------------
Main menu callbacks
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-07-16 11:35:32 +04:00
// Open callback
void open_cb ( Fl_Widget * w , void * data ) {
fprintf ( stderr , " cb \n " ) ;
2007-07-17 23:16:39 +04:00
if ( Fl : : event_clicks ( ) | | Fl : : event_key ( ) = = FL_Enter | | w = = main_menu ) {
2007-07-16 11:35:32 +04:00
fprintf ( stderr , " enter \n " ) ;
2007-07-17 23:16:39 +04:00
static timeval tm = { 0 , 0 } ;
timeval newtm ;
gettimeofday ( & newtm , 0 ) ;
if ( newtm . tv_sec - tm . tv_sec < 1 | | ( newtm . tv_sec - tm . tv_sec = = 1 & & newtm . tv_usec < tm . tv_usec ) ) return ; // no calling within 1 second
tm = newtm ;
char * filename = strdup ( view - > text ( view - > value ( ) ) ) ;
if ( char * k = strchr ( filename , view - > column_char ( ) ) ) * k = ' \0 ' ;
2006-08-30 13:20:54 +04:00
2007-07-16 11:35:32 +04:00
char * path = ( char * ) view - > data ( view - > value ( ) ) ;
fprintf ( stderr , " Path: %s (ev %d) \n " , path , Fl : : event ( ) ) ;
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
if ( stat ( path , & buf ) ) return ; // error
2007-07-17 23:16:39 +04:00
if ( S_ISDIR ( buf . st_mode ) ) { // directory
2007-07-16 11:35:32 +04:00
loaddir ( path ) ;
2007-07-17 23:16:39 +04:00
return ;
}
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
// Call opener
2007-07-17 23:16:39 +04:00
mime_resolver . set ( path ) ;
char * opener = simpleopener ( mime_resolver . type ( ) . c_str ( ) ) ;
// dump core
struct rlimit * rlim = ( struct rlimit * ) malloc ( sizeof ( struct rlimit ) ) ;
getrlimit ( RLIMIT_CORE , rlim ) ;
rlim_t old_rlimit = rlim - > rlim_cur ; // keep previous rlimit
rlim - > rlim_cur = RLIM_INFINITY ;
setrlimit ( RLIMIT_CORE , rlim ) ;
const char * o2 = tsprintf ( opener , path ) ;
fprintf ( stderr , " run_program: %s \n " , o2 ) ;
if ( opener ) {
int k = edelib : : run_program ( o2 , false ) ; fprintf ( stderr , " retval: %d \n " , k ) ;
} else
statusbar - > label ( tasprintf ( _ ( " No program to open %s! " ) , filename ) ) ;
free ( filename ) ;
rlim - > rlim_cur = old_rlimit ;
setrlimit ( RLIMIT_CORE , rlim ) ;
2006-08-26 13:06:13 +04:00
}
2007-07-17 23:16:39 +04:00
} // open_cb
void location_cb ( Fl_Widget * , void * ) {
const char * dir = fl_dir_chooser ( _ ( " Choose location " ) , current_dir ) ;
if ( dir ) loaddir ( dir ) ;
2006-08-26 13:06:13 +04:00
}
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
void quit_cb ( Fl_Widget * , void * ) { exit ( 0 ) ; }
void cut_cb ( Fl_Widget * , void * ) { do_cut_copy ( false ) ; }
void copy_cb ( Fl_Widget * , void * ) { do_cut_copy ( true ) ; }
void paste_cb ( Fl_Widget * , void * ) { do_paste ( ) ; }
void showhidden_cb ( Fl_Widget * , void * ) { showhidden = ! showhidden ; loaddir ( current_dir ) ; }
void refresh_cb ( Fl_Widget * , void * ) {
loaddir ( current_dir ) ;
// TODO: reload directory tree as well-
}
void case_cb ( Fl_Widget * , void * ) { ignorecase = ! ignorecase ; loaddir ( current_dir ) ; }
void dirsfirst_cb ( Fl_Widget * , void * ) { dirsfirst = ! dirsfirst ; loaddir ( current_dir ) ; }
// dummy callbacks
void ow_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; } // make a list of openers
void delete_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; } // popup a warning
void pref_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; }
void iconsview_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; }
void listview_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; }
void showtree_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; }
void about_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; }
void aboutede_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; }
2006-08-30 13:20:54 +04:00
2006-08-20 22:43:09 +04:00
2006-08-30 13:20:54 +04:00
/*-----------------------------------------------------------------
GUI design
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
// Main window menu - definition
Fl_Menu_Item main_menu_definition [ ] = {
{ _ ( " &File " ) , 0 , 0 , 0 , FL_SUBMENU } ,
{ _ ( " &Open " ) , FL_CTRL + ' o ' , open_cb } ,
{ _ ( " Open &with... " ) , 0 , ow_cb , 0 , FL_MENU_DIVIDER } ,
{ _ ( " Open &location " ) , 0 , location_cb , 0 , FL_MENU_DIVIDER } ,
{ _ ( " &Quit " ) , FL_CTRL + ' q ' , quit_cb } ,
{ 0 } ,
{ _ ( " &Edit " ) , 0 , 0 , 0 , FL_SUBMENU } ,
{ _ ( " &Cut " ) , FL_CTRL + ' x ' , cut_cb } ,
{ _ ( " C&opy " ) , FL_CTRL + ' c ' , copy_cb } ,
{ _ ( " &Paste " ) , FL_CTRL + ' v ' , paste_cb } ,
{ _ ( " &Rename " ) , FL_F + 2 , 0 } , // no callback - view handles this
{ _ ( " &Delete " ) , FL_Delete , delete_cb , 0 , FL_MENU_DIVIDER } ,
{ _ ( " Pre&ferences " ) , FL_CTRL + ' p ' , pref_cb } ,
{ 0 } ,
{ _ ( " &View " ) , 0 , 0 , 0 , FL_SUBMENU } ,
{ _ ( " &Icons " ) , FL_F + 8 , iconsview_cb , 0 , FL_MENU_RADIO } , // coming soon
{ _ ( " &Detailed list " ) , FL_F + 8 , listview_cb , 0 , FL_MENU_RADIO | FL_MENU_DIVIDER } ,
{ _ ( " &Show hidden " ) , 0 , showhidden_cb , 0 , FL_MENU_TOGGLE } ,
{ _ ( " Directory &tree " ) , FL_F + 9 , showtree_cb , 0 , FL_MENU_TOGGLE | FL_MENU_DIVIDER } , // coming soon
{ _ ( " &Refresh " ) , FL_F + 5 , refresh_cb } ,
{ _ ( " S&ort " ) , 0 , 0 , 0 , FL_SUBMENU } ,
{ _ ( " &Case sensitive " ) , 0 , case_cb , 0 , FL_MENU_TOGGLE } ,
{ _ ( " D&irectories first " ) , 0 , dirsfirst_cb , 0 , FL_MENU_TOGGLE } ,
{ 0 } ,
{ 0 } ,
{ _ ( " &Help " ) , 0 , 0 , 0 , FL_SUBMENU } ,
{ _ ( " &About File Manager " ) , 0 , about_cb } , // coming soon
{ _ ( " &About EDE " ) , 0 , aboutede_cb } , // coming soon
{ 0 } ,
{ 0 }
} ;
// Main program
2006-08-20 22:43:09 +04:00
int main ( int argc , char * * argv ) {
2007-07-16 11:35:32 +04:00
fl_register_images ( ) ;
edelib : : IconTheme : : init ( " crystalsvg " ) ;
2007-07-17 23:16:39 +04:00
win = new Fl_Double_Window ( default_window_width , default_window_height ) ;
2007-07-16 11:35:32 +04:00
// win->color(FL_WHITE);
win - > begin ( ) ;
2007-07-17 23:16:39 +04:00
main_menu = new Fl_Menu_Bar ( 0 , 0 , default_window_width , menubar_height ) ;
main_menu - > menu ( main_menu_definition ) ;
main_menu - > textsize ( 12 ) ; // hack for label size
view = new FileDetailsView ( 0 , menubar_height , default_window_width , default_window_height - menubar_height - statusbar_height , 0 ) ;
view - > callback ( open_cb ) ;
Fl_Group * sbgroup = new Fl_Group ( 0 , default_window_height - statusbar_height , default_window_width , statusbar_height ) ;
statusbar = new Fl_Box ( 2 , default_window_height - statusbar_height + 2 , statusbar_width , statusbar_height - 4 ) ;
statusbar - > box ( FL_DOWN_BOX ) ;
statusbar - > labelsize ( 12 ) ; // hack for label size
statusbar - > align ( FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_CLIP ) ;
statusbar - > label ( _ ( " Ready. " ) ) ;
Fl_Box * filler = new Fl_Box ( statusbar_width + 2 , default_window_height - statusbar_height + 2 , default_window_width - statusbar_width , statusbar_height - 4 ) ;
sbgroup - > end ( ) ;
sbgroup - > resizable ( filler ) ;
2006-08-26 13:06:13 +04:00
2006-08-20 22:43:09 +04:00
win - > end ( ) ;
2007-07-16 11:35:32 +04:00
win - > resizable ( view ) ;
// win->icon(Icon::get("folder",Icon::TINY));
win - > show ( argc , argv ) ;
2007-07-17 23:16:39 +04:00
// TODO remember previous configuration
showhidden = false ; dirsfirst = true ; ignorecase = true ; semaphore = false ;
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
if ( argc = = 1 ) // No params
2006-08-20 22:43:09 +04:00
loaddir ( " " ) ;
2007-07-17 23:16:39 +04:00
else
2006-08-20 22:43:09 +04:00
loaddir ( argv [ 1 ] ) ;
2007-07-16 11:35:32 +04:00
return Fl : : run ( ) ;
2006-08-20 22:43:09 +04:00
}