- Add notify support with edelib::DirWatch

- Fix support for large files (>2GB)
- Fix switching between iconview and listview (sometimes both checkboxes would be active)
- Import local copy of strverscmp (doesn't compile at the moment)
- EDE_Browser: fix redrawing of column title buttons
- EDE_FileIconView: switch back to ordinary FLAT_BOX (RFLAT_BOX is ugly :), fix bug with using scrollbar when view 
isn't focused, laso-selection sometimes selected too much
- Clean up some compiler warnings
This commit is contained in:
Vedran Ljubovic 2008-05-27 18:58:37 +00:00
parent acae1abb06
commit 9f8409e863
9 changed files with 288 additions and 45 deletions

View File

@ -201,6 +201,12 @@ public:
thegroup->hide(); /* group */
Fl_Widget::hide();
}
void show() {
Fl_Widget::show();
heading->show();
thegroup->show();
}
};
#endif

View File

@ -187,7 +187,8 @@ void FileIconView::insert(int row, FileItem *item) {
m_selected[children()]=0;
Fl_Button* b = new Fl_Button(0,0,ICONW,ICONH);
b->box(FL_RFLAT_BOX);
// b->box(FL_RFLAT_BOX); // Rounded box - has bug with selection box
b->box(FL_FLAT_BOX);
b->color(FL_BACKGROUND2_COLOR);
b->align(FL_ALIGN_INSIDE|FL_ALIGN_CENTER|FL_ALIGN_CLIP);
@ -663,6 +664,7 @@ EDEBUG(DBG"stop rename\n");
// "laso" a.k.a. selection box is common name for box used to select many widgets at once
static bool laso=false; // are we laso-ing?
static bool scrolling=false;
static int dragx,dragy; // to check for min dnd distance
if (e==FL_DRAG) {
EDEBUG(DBG"FL_DRAG! ");
@ -671,6 +673,21 @@ EDEBUG(DBG"FL_DRAG! ");
if (!laso) {
// Drag inside child is dnd
int ex=Fl::event_x(); int ey=Fl::event_y();
#ifdef USE_FLU_WRAP_GROUP
if (scrollbar.visible() && (ex>x()+w()-scrollbar.w() || scrolling)) {
EDEBUG(DBG"scrolling\n");
this->take_focus();
scrolling=true;
return scrollbar.handle(e);
}
#else
if (get_scroll()->visible() && (ex>x()+w()-get_scroll()->w() || scrolling)) {
EDEBUG(DBG"scrolling\n");
this->take_focus();
scrolling=true;
return get_scroll()->handle(e);
}
#endif
int inside=0;
for (int i=0; i<children(); i++) {
Fl_Button* b = (Fl_Button*)child(i);
@ -765,6 +782,11 @@ EDEBUG(DBG"FL_RELEASE! ");
while (m_selected[i]!=0) m_selected[i++]=0;
}
if (scrolling) {
EDEBUG(DBG"- stop scrolling.\n");
scrolling=false;
}
// Stop laso operation
if (laso) {
EDEBUG(DBG"- stop laso.\n");
@ -788,6 +810,12 @@ EDEBUG(DBG"After fixing the box coords: (%d,%d,%d,%d)\n", select_x1, select_y1,
Fl_Widget* w = child(i); // some shortcuts
int wx2 = w->x()+w->w();
int wy2 = w->y()+w->h();
// ignore the empty space below label -- equals number of \n's
const char* lbl=w->label();
for (int j=strlen(lbl)-2; j>0; j--) {
if (lbl[j]!='\n') break;
wy2 -= fl_size();
}
if (select_x2>w->x() && select_x1<wx2 && select_y2>w->y() && select_y1<wy2) {
select(i+1,1);
EDEBUG(DBG"Select widget: '%20s' (%d,%d,%d,%d)\n", w->label(), w->x(), w->y(), wx2, wy2);
@ -845,29 +873,19 @@ if (e==FL_DND_ENTER) { EDEBUG(DBG"FL_DND_ENTER\n"); }
if (e==FL_DND_DRAG) { EDEBUG(DBG"FL_DND_DRAG\n"); }
if (e==FL_DND_RELEASE) { EDEBUG(DBG"FL_DND_RELEASE\n"); }
// Let the window manager know that we accept dnd
if (e==FL_DND_ENTER||e==FL_DND_DRAG||e==FL_DND_LEAVE) return 1;
/* // Scroll the view by dragging to border
if (e==FL_DND_LEAVE) {
if (Fl::event_y()<y())
position(position()-1);
if (Fl::event_y()>y()+h())
position(position()+1);
return 1;
}*/
if (e==FL_DND_ENTER||e==FL_DND_LEAVE||e==FL_DND_DRAG) return 1;
static bool dndrelease=false;
if (e==FL_DND_RELEASE) {
EDEBUG(DBG"FL_DND_RELEASE '%s'\n", Fl::event_text());
// Sometimes drag is accidental
if (abs(Fl::event_x()-dragx)>MIN_DISTANCE_FOR_DND || abs(Fl::event_y()-dragy)>MIN_DISTANCE_FOR_DND) {
dndrelease=true;
Fl::paste(*this,0);
}
if (abs(Fl::event_x()-dragx)<MIN_DISTANCE_FOR_DND && abs(Fl::event_y()-dragy)<MIN_DISTANCE_FOR_DND)
return 0;
// return 1 would call Fl::paste(*belowmouse(),0) (see fl_dnd_x.cxx around line 168).
// In our case that could be catastrophic
return 0;
// return 1 would call Fl::paste(*belowmouse(),0) (see fl_dnd_x.cxx around line 168).
// In our case that could be catastrophic
dndrelease=true;
Fl::paste(*this,0);
}
if (e==FL_PASTE) {

View File

@ -10,7 +10,8 @@
SubDir TOP efiler ;
SOURCE = Fl_Icon_Browser.cxx EDE_Browser.cpp EDE_DirTree.cpp Util.cpp efiler.cpp fileops.cpp filesystem.cpp Flu_Wrap_Group.cpp EDE_FileIconView.cpp EDE_FileDetailsView.cpp ;
SOURCE = Fl_Icon_Browser.cxx EDE_Browser.cpp EDE_DirTree.cpp Util.cpp efiler.cpp fileops.cpp filesystem.cpp
Flu_Wrap_Group.cpp EDE_FileIconView.cpp EDE_FileDetailsView.cpp ede_strverscmp.c ;
LinkAgainst efiler : -lXpm ;

View File

@ -295,7 +295,7 @@ char* strstrmulti(const char *haystack, const char *needles, const char *separat
// Print to a static char[] and return pointer
const char* tsprintf(char *format, ...)
const char* tsprintf(const char *format, ...)
{
static char buffer[4096];
va_list args;
@ -305,7 +305,7 @@ const char* tsprintf(char *format, ...)
return (const char*)buffer;
}
char* tasprintf(char *format, ...)
char* tasprintf(const char *format, ...)
{
char buffer[4096];
va_list args;

View File

@ -102,10 +102,10 @@ shortcut for strdup(tsprintf(...)) - with tasprintf you have to explicitely call
free() on created strings, with tsprintf you don't.
*/
const char* tsprintf(char* format, ...);
const char* tsprintf(const char* format, ...);
char* tasprintf(char* format, ...);
char* tasprintf(const char* format, ...);
//}

109
efiler/ede_strverscmp.c Normal file
View File

@ -0,0 +1,109 @@
/* Compare strings while treating digits characters numerically.
Copyright (C) 1997, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jean-Fran<EFBFBD>ois Bignolles <bignolle ecoledoc ibp fr>, 1997.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <ctype.h>
/* states: S_N: normal, S_I: comparing integral part, S_F: comparing
fractionnal parts, S_Z: idem but with leading Zeroes only */
#define S_N 0x0
#define S_I 0x4
#define S_F 0x8
#define S_Z 0xC
/* result_type: CMP: return diff; LEN: compare using len_diff/diff */
#define CMP 2
#define LEN 3
/* Compare S1 and S2 as strings holding indices/version numbers,
returning less than, equal to or greater than zero if S1 is less than,
equal to or greater than S2 (for more info, see the texinfo doc).
*/
extern int ede_strverscmp (const char *s1, const char *s2)
{
const unsigned char *p1 = (const unsigned char *) s1;
const unsigned char *p2 = (const unsigned char *) s2;
unsigned char c1, c2;
int state;
int diff;
/* Symbol(s) 0 [1-9] others (padding)
Transition (10) 0 (01) d (00) x (11) - */
static const unsigned int next_state[] =
{
/* state x d 0 - */
/* S_N */ S_N, S_I, S_Z, S_N,
/* S_I */ S_N, S_I, S_I, S_I,
/* S_F */ S_N, S_F, S_F, S_F,
/* S_Z */ S_N, S_F, S_Z, S_Z
};
static const int result_type[] =
{
/* state x/x x/d x/0 x/- d/x d/d d/0 d/-
0/x 0/d 0/0 0/- -/x -/d -/0 -/- */
/* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
/* S_I */ CMP, -1, -1, CMP, +1, LEN, LEN, CMP,
+1, LEN, LEN, CMP, CMP, CMP, CMP, CMP,
/* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
/* S_Z */ CMP, +1, +1, CMP, -1, CMP, CMP, CMP,
-1, CMP, CMP, CMP
};
if (p1 == p2)
return 0;
c1 = *p1++;
c2 = *p2++;
/* Hint: '0' is a digit too. */
state = S_N | ((c1 == '0') + (isdigit (c1) != 0));
while ((diff = c1 - c2) == 0 && c1 != '\0')
{
state = next_state[state];
c1 = *p1++;
c2 = *p2++;
state |= (c1 == '0') + (isdigit (c1) != 0);
}
state = result_type[state << 2 | (((c2 == '0') + (isdigit (c2) != 0)))];
switch (state)
{
case CMP:
return diff;
case LEN:
while (isdigit (*p1++))
if (!isdigit (*p2++))
return 1;
return isdigit (*p2) ? -1 : diff;
default:
return state;
}
}

6
efiler/ede_strverscmp.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef EDE_STRVERSCMP_H
#define EDE_STRVERSCMP_H
extern int ede_strverscmp (const char *, const char *);
#endif

View File

@ -39,6 +39,7 @@
#include <edelib/Run.h>
#include <edelib/IconTheme.h> // for setting the icon theme
#include <edelib/MessageBox.h>
#include <edelib/DirWatch.h>
#include "EDE_FileView.h" // our file view widget
#include "EDE_DirTree.h" // directory tree
@ -46,6 +47,8 @@
#include "fileops.h" // file operations
#include "filesystem.h" // filesystem support
//#include "ede_strverscmp.h" // local copy of strverscmp
Fl_Window* win;
@ -83,6 +86,8 @@ int default_tree_width=150;
// Subclassed Fl_Window for switching views
void iconsview_cb(Fl_Widget*, void*);
void listview_cb(Fl_Widget*, void*);
class EFiler_Window : public Fl_Double_Window {
public:
@ -93,17 +98,12 @@ public:
int handle(int e) {
// Have F8 function as switch between active views
if (e == FL_KEYBOARD && Fl::event_key()==FL_F+8) {
void*p;
if (view->type() == FILE_DETAILS_VIEW) {
view->type(FILE_ICON_VIEW);
// We do this juggling with tsprintf to avoid duplicate strings for localization
Fl_Menu_Item* i = (Fl_Menu_Item*) main_menu->find_item(tsprintf("%s/%s", _("&View"), _("&Icons")));
i->set();
iconsview_cb(main_menu,p);
} else {
view->type(FILE_DETAILS_VIEW);
Fl_Menu_Item* i = (Fl_Menu_Item*) main_menu->find_item(tsprintf("%s/%s", _("&View"), _("&Detailed list")));
i->set();
listview_cb(main_menu,p);
}
loaddir(current_dir);
return 1;
}
return Fl_Double_Window::handle(e);
@ -177,7 +177,7 @@ public:
// These variables are global to save time on construction/destruction
edelib::MimeType mime_resolver;
struct stat stat_buffer;
struct stat64 stat_buffer;
struct sopeners {
char* type;
@ -230,8 +230,16 @@ char *simpleopener(const char* mimetype) {
LoadDir()
-------------------------------------------------------------------*/
// modification of versionsort which ignores case
int myversionsort(const void *a, const void *b) {
// Use local copy of strverscmp
int ede_versionsort(const void *a, const void *b) {
struct dirent** ka = (struct dirent**)a;
struct dirent** kb = (struct dirent**)b;
return strverscmp((*ka)->d_name,(*kb)->d_name);
}
// Modification of versionsort which ignores case
int ede_versioncasesort(const void *a, const void *b) {
struct dirent** ka = (struct dirent**)a;
struct dirent** kb = (struct dirent**)b;
char* ma = strdup((*ka)->d_name);
@ -242,6 +250,7 @@ int myversionsort(const void *a, const void *b) {
return k;
}
// Return a string describing permissions relative to the current user
const char* permission_text(mode_t mode, uid_t uid, gid_t gid) {
static uid_t uuid = getuid();
@ -358,9 +367,9 @@ void loaddir(const char *path) {
int size=0;
dirent **files;
if (ignorecase)
size = scandir(current_dir, &files, 0, myversionsort);
size = scandir(current_dir, &files, 0, ede_versioncasesort);
else
size = scandir(current_dir, &files, 0, versionsort);
size = scandir(current_dir, &files, 0, ede_versionsort);
if (size<1) { // there should always be . and ..
edelib::alert(_("Permission denied!"));
@ -372,6 +381,10 @@ void loaddir(const char *path) {
// Ok, now we know everything is fine...
// Remove old watch and add new one
edelib::DirWatch::remove(old_dir);
edelib::DirWatch::add(current_dir, edelib::DW_CREATE | edelib::DW_DELETE | edelib::DW_ATTRIB | edelib::DW_RENAME | edelib::DW_MODIFY);
// Update directory tree
dirtree->set_current(current_dir);
location_input->value(current_dir);
@ -402,7 +415,7 @@ void loaddir(const char *path) {
char fullpath[FL_PATH_MAX];
snprintf (fullpath,FL_PATH_MAX-1,"%s%s",current_dir,n);
if (stat(fullpath,&stat_buffer)) continue; // happens when user has traverse but not read privilege
if (stat64(fullpath,&stat_buffer)) continue; // happens when user has traverse but not read privilege
FileItem *item = new FileItem;
item->name = n;
@ -463,7 +476,7 @@ void loaddir(const char *path) {
if (icon != "") item_list[i]->icon = icon;
view->update(item_list[i]);
}
Fl::check();
Fl::check(); // keep interface responsive while updating mimetypes
}
}
@ -505,7 +518,7 @@ void open_cb(Fl_Widget*w, void*data) {
char* path = (char*)view->path(view->get_focus());
if (stat(path,&stat_buffer)) return; // error
if (stat64(path,&stat_buffer)) return; // error
if (S_ISDIR(stat_buffer.st_mode)) { // directory
loaddir(path);
return;
@ -609,6 +622,10 @@ void dirsfirst_cb(Fl_Widget*, void*) {
}
// Implemented after menu definition
void update_menu_item(const char* label, bool value);
// dummy callbacks - TODO
void ow_cb(Fl_Widget*, void*) { fprintf(stderr, "callback\n"); } // make a list of openers
void pref_cb(Fl_Widget*, void*) { fprintf(stderr, "callback\n"); }
@ -616,12 +633,16 @@ void iconsview_cb(Fl_Widget*, void*) {
if (view->type() != FILE_ICON_VIEW) {
view->type(FILE_ICON_VIEW);
loaddir(current_dir);
update_menu_item(_("&Icons"),true);
update_menu_item(_("&Detailed list"),false);
}
}
void listview_cb(Fl_Widget*, void*) {
if (view->type() != FILE_DETAILS_VIEW) {
view->type(FILE_DETAILS_VIEW);
loaddir(current_dir);
update_menu_item(_("&Icons"),false);
update_menu_item(_("&Detailed list"),true);
}
}
@ -713,6 +734,69 @@ void location_input_cb(Fl_Widget*, void*) {
}
// Callback called by edelib::DirWatch
void directory_change_cb(const char* dir, const char* what_changed, int flags, void* d) {
if (!what_changed || flags==edelib::DW_REPORT_NONE) return; // edelib whas unable to figure out what exactly changed
if (strcmp(current_dir,dir)) return; // for some reason we're being notified about non-current dir
// Find item in view
int found=-1;
for (int i=1; i<=view->size(); i++) {
const char *item = view->path(i);
if (strcmp(item+strlen(dir),what_changed)==0) { found=i; break; }
}
// If item was changed, it's simplest to remove it from the list then add it again
if (found>-1) view->remove(found);
if (flags==edelib::DW_REPORT_DELETE) return; // delete ends here
// Adding new item - code mostly copied from loaddir()
// TODO: create a separate function for this
char fullpath[FL_PATH_MAX];
snprintf (fullpath,FL_PATH_MAX-1,"%s%s",dir,what_changed);
if (stat64(fullpath,&stat_buffer)) return; // happens when user has traverse but not read privilege
FileItem *item = new FileItem;
item->name = what_changed;
item->realpath = fullpath;
item->date = nice_time(stat_buffer.st_mtime);
item->permissions = permission_text(stat_buffer.st_mode,stat_buffer.st_uid,stat_buffer.st_gid);
if (strcmp(what_changed,"..")==0) {
item->icon = "undo";
item->description = "Go up";
item->size = "";
} else if (S_ISDIR(stat_buffer.st_mode)) { // directory
item->icon = "folder";
item->description = "Directory";
// item->name += "/";
item->size = "";
item->realpath += "/";
} else {
item->icon = "unknown";
item->description = "Unknown";
item->size = nice_size(stat_buffer.st_size);
}
view->add(item);
view->redraw();
Fl::check(); // update interface to give time for mimetype resolver
mime_resolver.set(fullpath);
edelib::String desc,icon;
desc = mime_resolver.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 = mime_resolver.icon_name();
if (desc!="" || icon!="") {
if (desc != "") item->description = desc;
if (icon != "") item->icon = icon;
view->update(item);
}
view->redraw();
}
// TODO: move this to view
// every item should have own context menu defined
@ -759,8 +843,8 @@ Fl_Menu_Item main_menu_definition[] = {
{0},
{_("&View"), 0, 0, 0, FL_SUBMENU},
{_("&Icons"), 0, iconsview_cb, 0, FL_MENU_RADIO},
{_("&Detailed list"), 0, listview_cb, 0, FL_MENU_RADIO|FL_MENU_VALUE|FL_MENU_DIVIDER},
{_("&Icons"), 0, iconsview_cb, 0, FL_MENU_TOGGLE},
{_("&Detailed list"), 0, listview_cb, 0, FL_MENU_TOGGLE|FL_MENU_VALUE|FL_MENU_DIVIDER},
{_("Directory &tree"), FL_F+9, showtree_cb, 0, FL_MENU_TOGGLE|FL_MENU_VALUE},
{_("&Location bar"), FL_F+10, locationbar_cb, 0, FL_MENU_TOGGLE|FL_MENU_VALUE},
{_("&Hidden files"), 0, showhidden_cb, 0, FL_MENU_TOGGLE|FL_MENU_DIVIDER},
@ -779,6 +863,18 @@ Fl_Menu_Item main_menu_definition[] = {
};
// Update checkbox in main menu
// (needs to come after the menu)
void update_menu_item(const char* label, bool value) {
Fl_Menu_Item *k = main_menu_definition;
while(k!=0 && k+1!=0) {
if (k->label()!=0 && strcmp(k->label(),label)==0) break;
k++;
}
if (k!=0)
if (value) k->set(); else k->clear();
}
// Main program
extern int FL_NORMAL_SIZE;
@ -799,9 +895,10 @@ int main (int argc, char **argv) {
strncpy(current_dir, argv[unknown], strlen(argv[unknown])+1);
}
fl_register_images();
edelib::IconTheme::init("crystalsvg");
edelib::DirWatch::init();
edelib::DirWatch::callback(directory_change_cb);
FL_NORMAL_SIZE=12;
fl_message_font(FL_HELVETICA, 12);
@ -864,7 +961,7 @@ edelib::themed_dialog_icons(MSGBOX_ICON_INFO, MSGBOX_ICON_WARNING, MSGBOX_ICON_Q
// FIXME: due to fltk bug this icon doesn't have transparency
fl_open_display();
Pixmap p, mask;
XpmCreatePixmapFromData(fl_display, DefaultRootWindow(fl_display), efiler_xpm, &p, &mask, NULL);
XpmCreatePixmapFromData(fl_display, DefaultRootWindow(fl_display), (char**)efiler_xpm, &p, &mask, NULL);
win->icon((char*)p);
@ -880,5 +977,11 @@ edelib::themed_dialog_icons(MSGBOX_ICON_INFO, MSGBOX_ICON_WARNING, MSGBOX_ICON_Q
dirtree->ignore_case(ignorecase);
loaddir(current_dir);
return Fl::run();
// Main event loop
Fl::run();
// Cleanup and shutdowns
edelib::DirWatch::shutdown();
return 0;
}

View File

@ -1,5 +1,5 @@
/* XPM */
static char * efiler_xpm[] = {
static const char * efiler_xpm[] = {
"16 16 83 1",
" c None",
". c #091D91",