2007-08-01 22:04:35 +04:00
/*
* $ Id $
*
* EFiler - EDE File Manager
* Part of Equinox Desktop Environment ( EDE ) .
2007-08-03 13:59:31 +04:00
* Copyright ( c ) 2000 - 2007 EDE Authors .
2007-08-01 22:04:35 +04:00
*
* This program is licenced under terms of the
* GNU General Public Licence version 2 or newer .
* See COPYING for details .
*/
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
// This file implements various operations with files (copy, delete...)
2007-07-23 23:59:48 +04:00
// NOT TO BE CONFUSED WITH edelib::File.h !!!
// Functions here usually call stuff from File.h, but also update
// efiler interface, display warnings to user etc.
# include "fileops.h"
# include <sys/stat.h>
# include <Fl/Fl_Window.H>
# include <Fl/Fl_Progress.H>
# include <Fl/Fl_Button.H>
2007-08-01 22:04:35 +04:00
# include <Fl/Fl_Menu_Button.H>
2007-07-23 23:59:48 +04:00
# include <Fl/filename.H>
# include <edelib/File.h>
2007-08-03 22:47:56 +04:00
# include <edelib/Directory.h>
2007-07-23 23:59:48 +04:00
# include <edelib/Nls.h>
2007-08-01 22:04:35 +04:00
# include <edelib/String.h>
# include <edelib/StrUtil.h>
# include <edelib/MimeType.h>
2007-09-05 12:26:28 +04:00
# include <edelib/MessageBox.h>
2007-07-23 23:59:48 +04:00
# include "EDE_FileView.h"
# include "Util.h"
2007-08-17 15:16:11 +04:00
# include "filesystem.h" // is_on_same_fs()
2007-07-23 23:59:48 +04:00
Fl_Progress * cut_copy_progress ;
bool stop_now ;
bool overwrite_all , skip_all ;
2008-06-04 01:55:05 +04:00
enum OperationType_ { // Stop idiotic warnings from gcc (anonymous enum in global scope)
2007-08-01 22:04:35 +04:00
CUT ,
COPY ,
ASK
} operation = ASK ;
2007-07-23 23:59:48 +04:00
2007-09-05 12:26:28 +04:00
2007-09-05 15:19:01 +04:00
// --------------------------------------------------------------------------------------------
// ede_choice_alert() - display choice with alert icon.
// First parameter is message text, followed by variable number of buttons. Last button
// always must be 0! Return value is sequence number of the button pressed, or -1 on window
// close.
// Note that function doesn't support text formatting.
// --------------------------------------------------------------------------------------------
2007-09-05 12:26:28 +04:00
2007-09-05 15:19:01 +04:00
# include <stdarg.h>
2007-09-05 12:26:28 +04:00
2007-09-05 15:19:01 +04:00
int ede_choice_alert ( const char * msg , . . . ) {
2007-09-05 12:26:28 +04:00
va_list ap ;
edelib : : MessageBox mb ;
2007-09-05 15:19:01 +04:00
va_start ( ap , msg ) ; {
char * btn ;
while ( ( btn = va_arg ( ap , char * ) ) ) {
mb . add_button ( btn ) ;
fprintf ( stderr , " Add button: '%s' \n " , btn ) ;
}
}
va_end ( ap ) ;
mb . set_text ( msg ) ;
2007-09-05 12:26:28 +04:00
mb . set_theme_icon ( MSGBOX_ICON_WARNING ) ; // specified in edelib/MessageBox.h
mb . set_modal ( ) ;
return mb . run ( ) ;
}
2007-08-03 22:47:56 +04:00
// ----------------------------------------------
// Some helper functions
// ----------------------------------------------
// is last character a / (avoid calling stat)?
2007-08-01 22:04:35 +04:00
bool my_isdir ( const char * path ) {
return ( path [ strlen ( path ) - 1 ] = = ' / ' ) ;
}
2007-07-23 23:59:48 +04:00
2007-08-03 22:47:56 +04:00
// wrapper around fl_filename_name() that also works with directories
2007-08-01 22:04:35 +04:00
const char * my_filename_name ( const char * path ) {
2007-08-03 22:47:56 +04:00
if ( ! my_isdir ( path ) ) return fl_filename_name ( path ) ;
2007-08-17 15:16:11 +04:00
2007-08-01 22:04:35 +04:00
static char buffer [ FL_PATH_MAX ] ;
strncpy ( buffer , path , FL_PATH_MAX ) ;
buffer [ strlen ( path ) - 1 ] = ' \0 ' ;
return fl_filename_name ( buffer ) ;
}
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
// opposite to fl_filename_name(), returns the first part of path (a.k.a. directory)
2007-08-03 22:47:56 +04:00
const char * my_filename_dir ( const char * path ) {
const char * name = my_filename_name ( path ) ;
2007-08-17 15:16:11 +04:00
int pathlen = strlen ( path ) - strlen ( name ) ;
if ( pathlen > = FL_PATH_MAX ) pathlen = FL_PATH_MAX - 1 ;
2007-08-03 22:47:56 +04:00
static char buffer [ FL_PATH_MAX ] ;
2007-08-17 15:16:11 +04:00
strncpy ( buffer , path , pathlen ) ;
buffer [ pathlen ] = ' \0 ' ;
2007-08-03 22:47:56 +04:00
return buffer ; // This is pointer to static buffer!! warning!
}
2007-07-23 23:59:48 +04:00
2008-06-04 01:55:05 +04:00
// Execute cut or copy operation from GUI (this actually does nothing
// on the filesystem, just store list of files in buffer and mark operation; files
// will be copied or moved when do_paste is called)
2007-08-01 22:04:35 +04:00
void do_cut_copy ( bool m_copy ) {
int num = view - > size ( ) ;
if ( m_copy ) operation = COPY ; else operation = CUT ;
2007-07-23 23:59:48 +04:00
// Allocate buffer
2007-08-03 22:47:56 +04:00
uint bufsize = 10000 ;
2007-08-01 22:04:35 +04:00
char * buf = ( char * ) malloc ( sizeof ( char ) * bufsize ) ;
buf [ 0 ] = ' \0 ' ;
2007-07-23 23:59:48 +04:00
// Add selected files to buffer and optionally grey icons (for cut effect)
2007-08-01 22:04:35 +04:00
int nselected = 0 ;
2007-07-23 23:59:48 +04:00
for ( int i = 1 ; i < = num ; i + + ) {
2007-08-01 22:04:35 +04:00
view - > ungray ( i ) ;
2007-07-23 23:59:48 +04:00
if ( view - > selected ( i ) = = 1 ) {
2007-08-17 15:16:11 +04:00
char * p = ( char * ) view - > path ( i ) ;
if ( strncmp ( p + strlen ( p ) - 3 , " /.. " , 3 ) = = 0 ) {
2007-08-01 22:04:35 +04:00
// Can't cut/copy the Up button ("..")
free ( buf ) ;
return ;
}
2007-08-04 00:18:09 +04:00
while ( strlen ( buf ) + strlen ( p ) + 8 > = bufsize ) {
2007-08-01 22:04:35 +04:00
bufsize + = 10000 ;
buf = ( char * ) realloc ( buf , sizeof ( char ) * bufsize ) ;
}
2007-08-17 15:16:11 +04:00
strcat ( buf , " file:// " ) ;
2007-08-01 22:04:35 +04:00
strncat ( buf , p , strlen ( p ) ) ;
2007-08-17 15:16:11 +04:00
strcat ( buf , " \r \n " ) ;
2007-08-01 22:04:35 +04:00
if ( operation = = CUT ) view - > gray ( i ) ;
nselected + + ;
2007-07-23 23:59:48 +04:00
}
}
2007-08-01 22:04:35 +04:00
if ( nselected = = 0 ) { //nothing selected, use the focused item
2007-07-23 23:59:48 +04:00
int i = view - > get_focus ( ) ;
2007-08-01 22:04:35 +04:00
char * p = ( char * ) view - > path ( i ) ;
// an individual path should never be longer > 10000 chars!
2007-08-17 15:16:11 +04:00
strcat ( buf , " file:// " ) ;
2007-08-01 22:04:35 +04:00
strncat ( buf , p , strlen ( p ) ) ;
2007-08-17 15:16:11 +04:00
strcat ( buf , " \r \n " ) ;
2007-07-23 23:59:48 +04:00
nselected = 1 ;
}
2007-08-01 22:04:35 +04:00
Fl : : copy ( buf , strlen ( buf ) , 1 ) ; // use clipboard
free ( buf ) ;
2007-07-23 23:59:48 +04:00
2007-08-01 22:04:35 +04:00
// Deselect all and restore focus
2007-07-23 23:59:48 +04:00
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 )
2007-08-01 22:04:35 +04:00
statusbar - > copy_label ( tsprintf ( _ ( " Selected %d items for copying " ) , nselected ) ) ;
2007-07-23 23:59:48 +04:00
else
2007-08-01 22:04:35 +04:00
statusbar - > copy_label ( tsprintf ( _ ( " Selected %d items for moving " ) , nselected ) ) ;
2007-08-17 15:16:11 +04:00
// TODO: add total selected size? would require a stat on each file + expanding directories
2007-07-23 23:59:48 +04:00
}
2008-06-04 01:55:05 +04:00
// Copy single file on filesystem. Returns false if operation failed and process should be stopped
2007-08-01 22:04:35 +04:00
2008-06-04 01:55:05 +04:00
// Note that at this point directories should be expanded into subdirectories and files,
2007-08-17 15:16:11 +04:00
// so when "copying" a directory we actually mean creating a new directory with same properties
2007-07-23 23:59:48 +04:00
bool my_copy ( const char * src , const char * dest ) {
FILE * fold , * fnew ;
int c ;
2007-08-17 15:16:11 +04:00
// this shouldn't happen
2007-07-23 23:59:48 +04:00
if ( strcmp ( src , dest ) = = 0 )
return true ;
2007-08-17 15:16:11 +04:00
// This case is already checked in do_paste() so it shouldn't happen here
if ( edelib : : file_exists ( dest ) )
return true ;
2007-07-23 23:59:48 +04:00
2007-08-01 22:04:35 +04:00
if ( my_isdir ( src ) ) {
// try to preserve permissions
2007-08-03 22:47:56 +04:00
// FIXME: this is not entirely cross-platform (due to different headers on *BSD)
2007-08-01 22:04:35 +04:00
struct stat buf ;
stat ( src , & buf ) ;
if ( mkdir ( dest , buf . st_mode ) = = 0 )
2007-07-23 23:59:48 +04:00
return true ; // success
2007-08-03 22:47:56 +04:00
2007-08-03 13:59:31 +04:00
int q = ede_choice_alert ( tsprintf ( _ ( " Cannot create directory %s (%d) " ) , dest , strerror ( errno ) ) , _ ( " &Stop " ) , _ ( " &Continue " ) , 0 ) ;
2007-09-05 15:19:01 +04:00
if ( q = = 1 ) return true ; else return false ;
2007-07-23 23:59:48 +04:00
}
if ( ! edelib : : file_readable ( src ) ) {
2007-08-03 22:47:56 +04:00
int q = ede_choice_alert ( tsprintf ( _ ( " Cannot read file \n \t %s \n %s " ) , src , strerror ( errno ) ) , _ ( " &Stop " ) , _ ( " &Continue " ) , 0 ) ;
2007-09-05 15:19:01 +04:00
if ( q = = 1 ) return true ; else return false ;
2007-07-23 23:59:48 +04:00
}
2007-08-03 22:47:56 +04:00
// edelib::file_writeable() returns false if dest doesn't exist
2007-08-17 15:16:11 +04:00
if ( edelib : : file_exists ( dest ) & & ! edelib : : file_writeable ( dest ) ) {
int q = ede_choice_alert ( tsprintf ( _ ( " You don't have permission to overwrite file \n \t %s " ) , dest ) , _ ( " &Stop " ) , _ ( " &Continue " ) , 0 ) ;
2007-09-05 15:19:01 +04:00
if ( q = = 1 ) return true ; else return false ;
2007-08-17 15:16:11 +04:00
// this is redundant ATM cause dest is removed in do_paste()
2007-08-01 22:04:35 +04:00
}
2007-07-23 23:59:48 +04:00
2007-08-03 22:47:56 +04:00
if ( ! edelib : : dir_exists ( my_filename_dir ( dest ) ) ) {
2007-08-17 15:16:11 +04:00
// Shouldn't happen, unless someone is deleting stuff behind our back
2007-08-03 22:47:56 +04:00
int q = ede_choice_alert ( tsprintf ( _ ( " Directory \n \t %s \n doesn't exist. " ) , my_filename_dir ( dest ) ) , _ ( " &Stop " ) , _ ( " &Continue " ) , 0 ) ;
2007-09-05 15:19:01 +04:00
if ( q = = 1 ) return true ; else return false ;
2007-08-03 22:47:56 +04:00
}
if ( ! edelib : : file_exists ( dest ) & & ! edelib : : dir_writeable ( my_filename_dir ( dest ) ) ) {
2007-08-17 15:16:11 +04:00
int q = ede_choice_alert ( tsprintf ( _ ( " Cannot create file in directory \n \t %s \n You don't have permission. " ) , my_filename_dir ( dest ) ) , _ ( " &Stop " ) , _ ( " &Continue " ) , 0 ) ;
2007-09-05 15:19:01 +04:00
if ( q = = 1 ) return true ; else return false ;
2007-08-03 22:47:56 +04:00
}
/* // we don't use edelib::file_copy because we want to call Fl::check() periodically so user
// can stop copying
2007-07-23 23:59:48 +04:00
if ( ! edelib : : file_copy ( src , dest , true ) )
2007-08-01 22:04:35 +04:00
fl_alert ( tsprintf ( _ ( " Error copying %s to %s " ) , src , dest ) ) ; */
2007-08-03 22:47:56 +04:00
2008-06-04 01:55:05 +04:00
// This should already be checked by file_readable and file_writeable
2007-08-01 22:04:35 +04:00
if ( ( fold = fopen ( src , " rb " ) ) = = NULL ) {
2007-08-03 13:59:31 +04:00
int q = ede_choice_alert ( tsprintf ( _ ( " Cannot read file \n \t %s \n %s " ) , src , strerror ( errno ) ) , _ ( " &Stop " ) , _ ( " &Continue " ) , 0 ) ;
2007-09-05 15:19:01 +04:00
if ( q = = 1 ) return true ; else return false ;
2007-08-01 22:04:35 +04:00
}
if ( ( fnew = fopen ( dest , " wb " ) ) = = NULL )
{
fclose ( fold ) ;
2007-08-03 13:59:31 +04:00
int q = ede_choice_alert ( tsprintf ( _ ( " Cannot create file \n \t %s \n %s " ) , dest , strerror ( errno ) ) , _ ( " &Stop " ) , _ ( " &Continue " ) , 0 ) ;
2007-09-05 15:19:01 +04:00
if ( q = = 1 ) return true ; else return false ;
2007-08-01 22:04:35 +04:00
}
2007-08-03 22:47:56 +04:00
2007-08-01 22:04:35 +04:00
int count = 0 ;
while ( ! feof ( fold ) ) {
c = fgetc ( fold ) ;
fputc ( c , fnew ) ;
// Update interface
if ( count + + > 1000 ) {
count = 0 ;
Fl : : check ( ) ;
}
2007-08-17 15:16:11 +04:00
if ( stop_now ) {
2008-06-04 01:55:05 +04:00
edelib : : alert ( _ ( " Copying interrupted! \n File %s is only half-copied and probably incorrect. " ) , my_filename_name ( dest ) ) ;
2007-08-17 15:16:11 +04:00
break ;
}
2007-08-01 22:04:35 +04:00
}
2007-08-17 15:16:11 +04:00
if ( ferror ( fold ) | | ferror ( fnew ) ) {
// This is probably a filesystem error (such as ejected disk or bad sector)
fclose ( fold ) ; // don't flush error buffer before calling ferror
2007-08-01 22:04:35 +04:00
fclose ( fnew ) ;
2007-08-17 15:16:11 +04:00
int q ;
if ( ferror ( fold ) )
q = ede_choice_alert ( tsprintf ( _ ( " Error while reading file \n \t %s \n %s " ) , src , strerror ( errno ) ) , _ ( " &Stop " ) , _ ( " &Continue " ) , 0 ) ;
else
q = ede_choice_alert ( tsprintf ( _ ( " Error while writing file \n \t %s \n %s " ) , dest , strerror ( errno ) ) , _ ( " &Stop " ) , _ ( " &Continue " ) , 0 ) ;
2007-09-05 15:19:01 +04:00
if ( q = = 1 ) return true ; else return false ;
2007-08-17 15:16:11 +04:00
} else {
fclose ( fold ) ;
2007-08-01 22:04:35 +04:00
fclose ( fnew ) ;
}
2007-08-03 13:59:31 +04:00
// attempt to preserve permissions - if it fails, we don't care
2007-08-03 22:47:56 +04:00
// FIXME: this is not entirely cross-platform (due to different headers on *BSD)
2007-08-03 13:59:31 +04:00
struct stat buf ;
stat ( src , & buf ) ;
chmod ( dest , buf . st_mode ) ;
2007-07-23 23:59:48 +04:00
return true ;
}
2007-08-01 22:04:35 +04:00
// Recursive function that creates a list of all files to be copied. All
2007-07-23 23:59:48 +04:00
// directories are opened and all files and subdirectories etc. are added
// separately to the list. The total number of elements will be stored in
// listsize. Returns false if user decided to interrupt copying.
bool expand_dirs ( 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 directories to list
list [ list_size + + ] = strdup ( src ) ;
2007-08-01 22:04:35 +04:00
if ( my_isdir ( src ) ) { // fl_filename_list makes sure that directories are appended with /
2007-08-17 15:16:11 +04:00
char new_src [ FL_PATH_MAX ] ;
2007-07-23 23:59:48 +04:00
dirent * * files ;
// FIXME: use same sort as used in view
2007-08-17 15:16:11 +04:00
// FIXME: detect errors on accessing directory
2007-07-23 23:59:48 +04:00
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 | | ! expand_dirs ( new_src , list , list_size , list_capacity ) )
return false ;
}
}
return true ;
}
2007-08-01 22:04:35 +04:00
// Delete currently selected file(s) and directory(es)
void do_delete ( ) {
// TODO: Add a progress bar???
// Delete is, in my experience, *very* fast (don't know why Konqueror takes so long)
// Count all selected items, expanding directories as neccessary
int list_size = 0 , list_capacity = 1000 ;
char * * files_list = ( char * * ) malloc ( sizeof ( char * * ) * list_capacity ) ;
for ( int i = 1 ; i < = view - > size ( ) ; i + + )
if ( view - > selected ( i ) = = 1 )
expand_dirs ( view - > path ( i ) , files_list , list_size , list_capacity ) ;
if ( list_size = = 0 ) { //nothing selected, use the focused item
int i = view - > get_focus ( ) ;
expand_dirs ( view - > path ( i ) , files_list , list_size , list_capacity ) ;
}
// Issue a warning
int c ;
2007-08-17 15:16:11 +04:00
if ( list_size = = 1 & & my_isdir ( files_list [ 0 ] ) )
2007-08-03 13:59:31 +04:00
c = ede_choice_alert ( tsprintf ( _ ( " Are you sure that you want to delete directory \n \t %s \n including everything in it? " ) , files_list [ 0 ] ) , _ ( " Do&n't delete " ) , _ ( " &Delete " ) , 0 ) ;
2007-08-17 15:16:11 +04:00
else if ( list_size = = 1 )
2007-08-03 13:59:31 +04:00
c = ede_choice_alert ( tsprintf ( _ ( " Are you sure that you want to delete file %s ? " ) , my_filename_name ( files_list [ 0 ] ) ) , _ ( " Do&n't delete " ) , _ ( " &Delete " ) , 0 ) ;
2007-08-17 15:16:11 +04:00
else
2007-08-03 13:59:31 +04:00
c = ede_choice_alert ( tsprintf ( _ ( " Are you sure that you want to delete %d files and directories? " ) , list_size ) , _ ( " Do&n't delete " ) , _ ( " &Delete " ) , 0 ) ;
2007-08-01 22:04:35 +04:00
if ( c = = 1 ) {
// first remove files...
for ( int i = 0 ; i < list_size ; i + + )
if ( ! my_isdir ( files_list [ i ] ) )
if ( ! edelib : : file_remove ( files_list [ i ] ) )
2007-09-05 15:19:01 +04:00
edelib : : alert ( _ ( " Couldn't delete file \n \t %s \n %s " ) , files_list [ i ] , strerror ( errno ) ) ;
2007-08-01 22:04:35 +04:00
// ...then directories
// since expand_dirs() returns first dirs then files, we should go in oposite direction
for ( int i = list_size - 1 ; i > = 0 ; i - - )
if ( my_isdir ( files_list [ i ] ) )
2007-08-03 22:47:56 +04:00
if ( ! edelib : : dir_remove ( files_list [ i ] ) )
2007-09-05 15:19:01 +04:00
edelib : : alert ( _ ( " Couldn't delete directory \n \t %s \n %s " ) , files_list [ i ] , strerror ( errno ) ) ;
2007-08-01 22:04:35 +04:00
// refresh directory listing - optimized
2008-06-04 01:55:05 +04:00
// if notify is available, it will do it for us
if ( ! notify_available ) {
for ( int i = 1 ; i < = view - > size ( ) ; i + + )
for ( int j = 0 ; j < list_size ; j + + )
if ( strcmp ( files_list [ j ] , view - > path ( i ) ) = = 0 )
view - > remove ( i ) ;
}
2007-08-01 22:04:35 +04:00
}
// Cleanup memory
for ( int i = 0 ; i < list_size ; i + + ) free ( files_list [ i ] ) ;
free ( files_list ) ;
}
2007-08-17 15:16:11 +04:00
// Rename the file that has focus to the given name 'newname'
2007-08-03 22:47:56 +04:00
void do_rename ( const char * newname ) {
2007-08-01 22:04:35 +04:00
int focus = view - > get_focus ( ) ;
2007-08-17 15:16:11 +04:00
const char * oldname = fl_filename_name ( view - > path ( focus ) ) ; // get filename
2007-08-01 22:04:35 +04:00
2007-08-17 15:16:11 +04:00
char oldpath [ FL_PATH_MAX ] , newpath [ FL_PATH_MAX ] ;
snprintf ( oldpath , FL_PATH_MAX - 1 , " %s%s " , current_dir , oldname ) ;
snprintf ( newpath , FL_PATH_MAX - 1 , " %s%s " , current_dir , newname ) ;
2007-08-01 22:04:35 +04:00
2007-08-17 15:16:11 +04:00
if ( edelib : : file_exists ( newpath ) )
2007-09-05 15:19:01 +04:00
edelib : : alert ( _ ( " Filename already in use: %s " ) , newname ) ;
2007-08-17 15:16:11 +04:00
else if ( ! edelib : : file_rename ( oldpath , newpath ) )
2007-09-05 15:19:01 +04:00
edelib : : alert ( _ ( " Rename %s to %s failed! " ) , oldname , newname ) ;
2007-08-23 15:09:05 +04:00
else
2008-06-04 01:55:05 +04:00
if ( ! notify_available ) view - > update_path ( oldpath , newpath ) ;
2007-08-01 22:04:35 +04:00
}
2007-08-17 15:16:11 +04:00
// Callback for Stop button on progress window (created in do_paste())
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 ( ) ;
}
2007-08-01 22:04:35 +04:00
// Execute paste - this will copy or move files based on chosen operation
// FIXME: if user cuts some files, then does dnd from another window,
2007-08-17 15:16:11 +04:00
// do_paste() will assume operation==CUT and won't ask the user!
// - Konqueror handles this by inventing a different mimetype for non-dnd buffer
// - Nautilus has the same bug!
2007-08-01 22:04:35 +04:00
2007-08-17 15:16:11 +04:00
void do_paste ( const char * t ) {
2007-08-01 22:04:35 +04:00
char * to = ( char * ) t ;
if ( ! t | | ! fl_filename_isdir ( t ) | | ( strncmp ( t + strlen ( t ) - 3 , " /.. " , 3 ) = = 0 ) )
to = current_dir ;
fprintf ( stderr , " PASTE from '%s', to '%s', type=%d \n " , ( char * ) Fl : : event_text ( ) , to , operation ) ;
if ( ! strchr ( Fl : : event_text ( ) , ' / ' ) )
return ; // User is pasting something that isn't files
2007-08-17 15:16:11 +04:00
// TODO: create a text file?
2007-08-01 22:04:35 +04:00
// Tokenize event text into an array of strings ("from")
char * tmp = ( char * ) Fl : : event_text ( ) ;
int count = 0 ;
do count + + ; while ( tmp & & ( tmp = strchr ( tmp + 1 , ' \n ' ) ) ) ;
char * * from = ( char * * ) malloc ( sizeof ( char * ) * count ) ;
tmp = ( char * ) Fl : : event_text ( ) ;
char * tmp2 ;
int k = 0 ;
do {
tmp2 = strchr ( tmp , ' \n ' ) ;
int len = tmp2 - tmp ;
if ( ! tmp2 ) len = strlen ( tmp ) ;
2007-08-04 00:18:09 +04:00
if ( len < 2 ) { tmp = tmp2 + 1 ; count - - ; continue ; }
2007-08-01 22:04:35 +04:00
from [ k ] = ( char * ) malloc ( sizeof ( char ) * ( len + 2 ) ) ;
strncpy ( from [ k ] , tmp , len ) ;
from [ k ] [ len ] = ' \0 ' ;
2007-08-17 15:16:11 +04:00
if ( from [ k ] [ len - 1 ] = = ' \r ' ) from [ k ] [ - - len ] = ' \0 ' ;
2007-08-04 00:18:09 +04:00
// We accept both URIs (beginning with file://) and plain filename
2007-08-01 22:04:35 +04:00
if ( strncmp ( from [ k ] , " file:// " , 7 ) = = 0 )
for ( int i = 0 ; i < = len - 7 ; i + + )
from [ k ] [ i ] = from [ k ] [ i + 7 ] ;
// All directories must end in /
if ( fl_filename_isdir ( from [ k ] ) & & ( from [ k ] [ len - 1 ] ! = ' / ' ) ) {
from [ k ] [ len + + ] = ' / ' ;
from [ k ] [ len ] = ' \0 ' ;
}
fprintf ( stderr , " from[%d]='%s' \n " , k , from [ k ] ) ;
k + + ;
tmp = tmp2 + 1 ;
} while ( tmp2 ) ;
// Some sanity checks
for ( int i = 0 ; i < count ; i + + ) {
// If this window is below others, try to get focus
win - > take_focus ( ) ;
if ( strcmp ( to , from [ i ] ) = = 0 ) {
2007-08-03 13:59:31 +04:00
//ede_alert(tsprintf(_("Can't copy directory\n\t%s\ninto itself."), to));
2007-08-01 22:04:35 +04:00
2007-08-03 22:47:56 +04:00
// This usually happens accidentally, so statusbar is less annoying
2007-08-01 22:04:35 +04:00
statusbar - > copy_label ( tsprintf ( _ ( " Can't copy directory %s into itself. " ) , my_filename_name ( to ) ) ) ;
goto FINISH ;
}
if ( ( strncmp ( to , from [ i ] , strlen ( to ) ) = = 0 ) ) {
char * k = strchr ( from [ i ] + strlen ( to ) , ' / ' ) ;
if ( ! k | | * ( k + 1 ) = = ' \0 ' ) {
2007-08-03 13:59:31 +04:00
//ede_alert(tsprintf(_("File %s is already in directory\n\t%s"), from[i]+strlen(to), to));
2007-08-01 22:04:35 +04:00
statusbar - > copy_label ( tsprintf ( _ ( " File %s is already in directory %s " ) , from [ i ] + strlen ( to ) , to ) ) ;
goto FINISH ;
}
}
}
// Resolve operation
if ( operation = = ASK ) {
// TODO make a popup menu just like in Konqueror
/* fprintf(stderr, "x=%d y=%d\n", Fl::event_x_root(),Fl::event_y_root());
Fl_Menu_Button * mb = new Fl_Menu_Button ( Fl : : event_x_root ( ) , Fl : : event_y_root ( ) , 0 , 0 ) ;
mb - > box ( FL_NO_BOX ) ;
mb - > type ( Fl_Menu_Button : : POPUP123 ) ;
mb - > add ( _ ( " &Copy " ) , 0 , cb_dnd_copy ) ;
mb - > add ( _ ( " _&Move " ) , 0 , cb_dnd_cut ) ;
mb - > add ( _ ( " C&ancel " ) , 0 , 0 ) ;
mb - > popup ( ) ;
goto FINISH ; */
int c ;
if ( count = = 1 & & my_isdir ( from [ 0 ] ) )
2007-09-05 15:19:01 +04:00
c = ede_choice_alert ( tsprintf ( _ ( " Copy or move directory \n \t %s \n to directory \n \t %s ? " ) , from [ 0 ] , to ) , _ ( " C&ancel " ) , _ ( " &Copy " ) , _ ( " &Move " ) , 0 ) ;
2007-08-01 22:04:35 +04:00
else if ( count = = 1 )
2007-09-05 15:19:01 +04:00
c = ede_choice_alert ( tsprintf ( _ ( " Copy or move file %s to directory \n \t %s ? " ) , fl_filename_name ( from [ 0 ] ) , to ) , _ ( " C&ancel " ) , _ ( " &Copy " ) , _ ( " &Move " ) , 0 ) ;
2007-08-01 22:04:35 +04:00
else
2007-09-05 15:19:01 +04:00
c = ede_choice_alert ( tsprintf ( _ ( " Copy or move these %d files to directory \n \t %s ? " ) , count , to ) , _ ( " C&ancel " ) , _ ( " &Copy " ) , _ ( " &Move " ) , 0 ) ;
2007-08-01 22:04:35 +04:00
2007-09-05 15:19:01 +04:00
if ( c < 1 ) goto FINISH ;
2007-08-01 22:04:35 +04:00
if ( c = = 1 ) operation = COPY ; else operation = CUT ;
}
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
2008-06-04 01:55:05 +04:00
{ // to silence warning caused by goto
2007-08-17 15:16:11 +04:00
2007-07-23 23:59:48 +04:00
overwrite_all = false ; skip_all = false ;
2007-08-17 15:16:11 +04:00
stop_now = false ;
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
// srcdir is root directory of from[] array
char * srcdir = strdup ( my_filename_dir ( from [ 0 ] ) ) ;
if ( strcmp ( srcdir , to ) = = 0 ) {
// This should never happen cause we already checked it...
2007-09-05 12:26:28 +04:00
edelib : : alert ( _ ( " You cannot copy a file onto itself! " ) ) ;
2007-08-17 15:16:11 +04:00
free ( srcdir ) ;
goto FINISH ;
}
2007-08-01 22:04:35 +04:00
2007-08-17 15:16:11 +04:00
// Draw progress dialog
Fl_Window * progress_window = new Fl_Window ( 350 , 150 ) ;
if ( operation = = 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 ( ) ;
// Set ProgressBar range
cut_copy_progress - > minimum ( 0 ) ;
cut_copy_progress - > maximum ( count ) ;
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 < count ; i + + ) {
if ( ! stop_now ) expand_dirs ( from [ i ] , files_list , list_size , list_capacity ) ;
cut_copy_progress - > value ( i + 1 ) ;
Fl : : check ( ) ; // check to see if user pressed Stop
}
2007-08-01 22:04:35 +04:00
2007-08-17 15:16:11 +04:00
if ( stop_now ) { // user pressed stop while counting, cleanup and exit
for ( int i = 0 ; i < list_size ; i + + ) free ( files_list [ i ] ) ;
free ( files_list ) ;
goto FINISH ;
}
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
// Now copying those files
cut_copy_progress - > minimum ( 0 ) ;
cut_copy_progress - > maximum ( list_size ) ;
cut_copy_progress - > value ( 0 ) ;
char dest [ FL_PATH_MAX ] ;
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
// This list is used for updating mimetypes after the copying is finished
FileItem * * item_list = 0 ;
int item_list_size = 0 ;
2008-06-04 01:55:05 +04:00
if ( ! notify_available & & strncmp ( to , current_dir , strlen ( to ) ) = = 0 )
2007-08-17 15:16:11 +04:00
// avoid malloc if current dir isn't inside the scope of paste
item_list = new FileItem * [ list_size ] ;
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
for ( int i = 0 ; i < list_size ; i + + ) {
2007-07-27 12:36:05 +04:00
2007-08-17 15:16:11 +04:00
// Prepare dest filename
char * srcfile = files_list [ i ] + strlen ( srcdir ) ;
snprintf ( dest , PATH_MAX , " %s%s " , to , srcfile ) ;
char * src = files_list [ i ] ; // shortcut
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
if ( operation = = COPY )
caption - > copy_label ( tsprintf ( _ ( " Copying %d of %d files to %s " ) , i , list_size , to ) ) ;
else
caption - > copy_label ( tsprintf ( _ ( " Moving %d of %d files to %s " ) , i , list_size , to ) ) ;
caption - > redraw ( ) ;
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
if ( edelib : : file_exists ( dest ) ) {
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
// if both src and dest are directories, do nothing
if ( my_isdir ( src ) & & my_isdir ( dest ) )
continue ;
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
// copy file over directory
// TODO: we will just skip this case because it's "impossible",
// but maybe there should be another warning
if ( my_isdir ( dest ) )
continue ;
// copy directory over file
if ( my_isdir ( src ) ) {
int q = ede_choice_alert ( tsprintf ( _ ( " You're trying to copy directory \n \t %s \n but there is already a file with this name. What to do? " ) , dest ) , _ ( " &Stop " ) , _ ( " S&kip directory " ) , _ ( " &Delete file " ) , 0 ) ;
2007-09-05 15:19:01 +04:00
if ( q < 1 ) break ;
2007-08-17 15:16:11 +04:00
else if ( q = = 1 ) continue ;
// else q==2 (delete file)
// copy file over file
} else {
2007-08-01 22:04:35 +04:00
int c = - 1 ;
2007-08-17 15:16:11 +04:00
if ( ! overwrite_all & & ! skip_all )
2007-09-05 15:19:01 +04:00
c = ede_choice_alert ( tsprintf ( _ ( " File with name \n \t %s \n already exists. What to do? " ) , dest ) , _ ( " &Overwrite " ) , _ ( " Over&write all " ) , _ ( " &Skip " ) , _ ( " Skip &all " ) , 0 ) ;
2007-08-17 15:16:11 +04:00
2007-08-01 22:04:35 +04:00
if ( c = = 1 ) overwrite_all = true ;
2007-09-05 15:19:01 +04:00
if ( c = = 3 ) skip_all = true ;
if ( c = = 2 | | c = = - 1 | | skip_all ) continue ; // go to next entry
2007-07-23 23:59:48 +04:00
2007-08-01 22:04:35 +04:00
// At this point c==0 (Overwrite) or overwrite_all == true
}
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
if ( ! edelib : : file_remove ( dest ) ) {
int q = ede_choice_alert ( tsprintf ( _ ( " Couldn't remove file \n \t %s " ) , dest ) , _ ( " &Stop " ) , _ ( " &Continue " ) , 0 ) ;
2007-09-05 15:19:01 +04:00
if ( q = = 1 ) continue ;
else break ;
2007-08-17 15:16:11 +04:00
}
// Update interface - add file to list (if we are viewing the destination directory)
2008-06-04 01:55:05 +04:00
} else if ( ! notify_available & & strcmp ( current_dir , my_filename_dir ( dest ) ) = = 0 ) {
2007-08-17 15:16:11 +04:00
FileItem * item = new FileItem ;
item - > name = my_filename_name ( dest ) ;
item - > realpath = dest ;
if ( my_isdir ( dest ) ) {
item - > icon = " folder " ;
item - > description = " Directory " ;
// item->name += "/";
} else {
item - > icon = " unknown " ;
item - > description = " Unknown " ;
}
item_list [ item_list_size + + ] = item ;
view - > add ( item ) ; // don't bother with sorting, that would be too complex
}
// Moving on same filesystem is actually rename
if ( operation = = CUT & & is_on_same_fs ( to , from [ 0 ] ) )
edelib : : file_rename ( src , dest ) ;
// this is extremely fast, user won't have time to click on stop ;)
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
else {
if ( stop_now | | ! my_copy ( src , dest ) )
break ;
2007-08-01 22:04:35 +04:00
// Delete file after moving
2007-08-17 15:16:11 +04:00
if ( operation = = CUT ) edelib : : file_remove ( src ) ;
2007-08-01 22:04:35 +04:00
cut_copy_progress - > value ( cut_copy_progress - > value ( ) + 1 ) ;
Fl : : check ( ) ; // check to see if user pressed Stop
}
2007-08-17 15:16:11 +04:00
}
progress_window - > hide ( ) ;
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
// Cleanup memory
for ( int i = 0 ; i < list_size ; i + + ) free ( files_list [ i ] ) ;
free ( files_list ) ;
free ( srcdir ) ;
2007-07-23 23:59:48 +04:00
2007-08-17 15:16:11 +04:00
if ( stop_now ) { // User pressed Stop but we don't know when, so we'll just reload
loaddir ( current_dir ) ;
goto FINISH ;
2007-07-23 23:59:48 +04:00
}
2008-06-04 01:55:05 +04:00
// -- Update interface in a smart way - but only if there is no notify
if ( ! notify_available ) {
2007-08-17 15:16:11 +04:00
2007-08-01 22:04:35 +04:00
// Remove cutted files
if ( operation = = CUT )
for ( int i = 0 ; i < count ; i + + )
for ( int j = 1 ; j < = view - > size ( ) ; j + + )
if ( strcmp ( from [ i ] , view - > path ( j ) ) = = 0 )
view - > remove ( j ) ;
// Update mimetypes for pasted files
for ( int i = 0 ; i < item_list_size ; i + + ) {
struct stat buf ;
if ( stat ( from [ i ] , & buf ) ) { delete item_list [ i ] ; continue ; }
FileItem * item = item_list [ i ] ;
item - > date = nice_time ( buf . st_mtime ) ;
item - > permissions = " " ; // todo
if ( item - > description ! = " Directory " ) {
item - > size = nice_size ( buf . st_size ) ;
edelib : : MimeType mt ;
mt . set ( from [ i ] ) ;
edelib : : String desc , icon ;
desc = mt . comment ( ) ;
// First letter of desc should be upper case:
if ( desc . length ( ) > 0 & & desc [ 0 ] > = ' a ' & & desc [ 0 ] < = ' z ' ) desc [ 0 ] = desc [ 0 ] - ' a ' + ' A ' ;
icon = mt . icon_name ( ) ;
if ( desc ! = " " | | icon ! = " " ) {
if ( desc ! = " " ) item - > description = desc ;
if ( icon ! = " " ) item - > icon = icon ;
}
Fl : : check ( ) ;
2007-07-27 12:36:05 +04:00
}
2007-08-01 22:04:35 +04:00
view - > update ( item ) ;
delete item_list [ i ] ;
2008-06-04 01:55:05 +04:00
} // for...
delete [ ] item_list ; // this was allocated before
} // if (!notify_available)...
2007-07-27 12:36:05 +04:00
2007-08-01 22:04:35 +04:00
// Select the just pasted files (they're at the bottom)
if ( item_list_size > 0 ) {
view - > redraw ( ) ;
2007-08-17 15:16:11 +04:00
for ( int i = view - > size ( ) , j = 0 ; j < item_list_size ; i - - , j + + )
2007-08-01 22:04:35 +04:00
view - > select ( i , 1 ) ;
2007-07-27 12:36:05 +04:00
}
2007-08-01 22:04:35 +04:00
2008-06-04 01:55:05 +04:00
} // scoping to silence goto warning
2007-08-17 15:16:11 +04:00
2007-08-01 22:04:35 +04:00
// Cleanup memory and exit
FINISH :
for ( int i = 0 ; i < count ; i + + ) free ( from [ i ] ) ;
free ( from ) ;
2007-08-17 15:16:11 +04:00
// Set operation for future dnd; do_cut_copy() will change this if
2007-08-01 22:04:35 +04:00
// classic cut or copy is used
operation = ASK ;
2007-07-27 12:36:05 +04:00
}