diff --git a/efiler/EDE_Browser.cpp b/efiler/EDE_Browser.cpp new file mode 100644 index 0000000..efc6f3e --- /dev/null +++ b/efiler/EDE_Browser.cpp @@ -0,0 +1,527 @@ +/* + * $Id$ + * + * EDE Browser class + * Part of edelib. + * Copyright (c) 2005-2007 EDE Authors. + * + * This program is licenced under terms of the + * GNU General Public Licence version 2 or newer. + * See COPYING for details. + */ + + +#include "EDE_Browser.h" +#include +#include +#include +#include + +#include +#include + + + +// ---------------- SORT ---------------- + + +// convert size string to float - used for sorting files by size +double sizetof(char *s) { + double d=atof(s); + if (strchr(s,'g') || strchr(s,'G')) + d*=1024*1024*1024; + else if (strchr(s,'m') || strchr(s,'M')) + d*=1024*1024; + else if (strchr(s,'k') || strchr(s,'K')) + d*=1024; + return d; +} + +// Sort function - return true if first is larger then second, otherwise false +bool EDE_Browser::sortfn(char*s1,char*s2,SortType type) { + switch(type) { + case ALPHA_SORT: + return (strcmp(s1,s2)>0); + case ALPHA_CASE_SORT: + return (strcasecmp(s1,s2)>0); + case NUMERIC_SORT: + return (atof(s1)>atof(s2)); + case DATE_SORT: + // unimplemented + // TODO: use edelib::Date + return false; + case FILE_SIZE_SORT: + return (sizetof(s1)>sizetof(s2)); + } +} + + +// Optimized quick sort algorithm +void EDE_Browser::mqsort(char* arr[], int beg, int end, SortType type) { + bool k = sort_direction ? false : true; + if (end > beg + 1) + { + char* piv = arr[beg]; int l = beg + 1, r = end; + while (l < r) + { + if (k^sortfn(arr[l],piv,type)) // ^ is XOR + l++; + else if (l==r-1) // avoid costly swap if they're the same + r--; + else { + swap(--r,l); // Fl_Browser::swap() + char *tmp=arr[l]; // update array + arr[l]=arr[r]; + arr[r]=tmp; + } + } + // avoid costly swap if they're the same + if (beg==l-1) + l--; + else { + swap(--l,beg); + char*tmp=arr[beg]; // update array + arr[beg]=arr[l]; + arr[l]=tmp; + } + + // recursion + mqsort(arr, beg, l, type); + mqsort(arr, r, end, type); + } +} + + + +// callback for header buttons +void header_callback(Fl_Widget*w, void*) { + Fl_Group* heading = (Fl_Group*)w->parent(); + EDE_Browser* browser = (EDE_Browser*)w->parent()->parent(); + for (int i=heading->children(); i--; ) + if (w == heading->child(i)) { browser->sort(i); break; } +} + +// Toggle-type method +void EDE_Browser::sort(int column) { + SortType t = column_sort_types_[column]; + if (t==NO_SORT) t=ALPHA_SORT; + if (column!=sort_column || sort_type==NO_SORT) + sort(column, t, false); + else + sort(column, sort_type, !sort_direction); +} + +// Real sorting method with three parameters +#define SYMLEN 6 +void EDE_Browser::sort(int column, SortType type, bool reverse) { + char *h=column_header_; + int hlen=strlen(h); + char colchar = Fl_Icon_Browser::column_char(); + + // Remove old sort direction symbol (if any) from header + char *delim = 0; + int col=0; + if (sort_type != NO_SORT) { + bool found=false; + while (delim=strchr(h, colchar)) { + if (col==sort_column) { + strncpy(delim-SYMLEN+1,delim,strlen(delim)+1); + found=true; + break; + } + h=delim+1; + col++; + } + if (!found && col==sort_column) + column_header_[hlen-SYMLEN+1]='\0'; + h=column_header_; + delim = 0; + col=0; + } + + // Add new symbol + char *newheader = new char[hlen+6]; + if (type != NO_SORT) { + // Construct symbol + char sym[SYMLEN]; + if (reverse) snprintf(sym,SYMLEN,"@-22<"); + else snprintf(sym,SYMLEN,"@-22>"); + + // Find column + bool found=false; + while (delim=strchr(h, colchar)) { + if (col==column) { + *delim='\0'; + snprintf(newheader,hlen+SYMLEN,"%s%s\t%s",column_header_,sym,delim+1); + found=true; + break; + } + h=delim+1; + col++; + } + if (!found && col==column) // Just append symbol to string + snprintf(newheader, hlen+SYMLEN,"%s%s",column_header_,sym); + } else { + strncpy (newheader, column_header_, hlen); + newheader[hlen]='\0'; + } + column_header(newheader); + delete[] newheader; + sort_column=column; sort_type=type; sort_direction=reverse; + + // Start actually sorting + if (type != NO_SORT) { + // First create an array of strings in a given column + char* sorttext[size()+1]; // index starts from 1 for simplicity in mqsort + for (int i=1;i<=size();i++) { + char *tmp = strdup(text(i)); + char *l = tmp; + int col=0; + while (delim=strchr(l, Fl_Icon_Browser::column_char())) { + *delim = '\0'; + if (col==column) break; + l=delim+1; + col++; + } + sorttext[i] = strdup(l); + free(tmp); + } + + mqsort(sorttext, 1, size()+1, type); + redraw(); + + // Free the allocated memory + for (int i=1; i<=size(); i++) free (sorttext[i]); + } +} + + +// -------------------------------------- + + +static void scroll_cb(Fl_Widget* w, void*) { + Fl_Scrollbar *s = (Fl_Scrollbar*)w; + EDE_Browser *b = (EDE_Browser*)w->parent(); + b->hposition(s->value()); +} + + +// ctor +EDE_Browser::EDE_Browser(int X,int Y,int W,int H,const char *L) : Fl_Icon_Browser(X,Y,W,H), + totalwidth_(0), column_header_(0), sort_column(0), sort_type(NO_SORT), sort_direction(false) { + + heading = new Heading(X,Y,W,buttonheight); + heading->end(); + heading->hide(); + heading->parent(this); // for callback + + hscrollbar = new Fl_Scrollbar(X, Y+H-Fl::scrollbar_size(), W-Fl::scrollbar_size(), Fl::scrollbar_size()); + hscrollbar->type(FL_HORIZONTAL); + hscrollbar->hide(); + hscrollbar->parent(this); // for callback + hscrollbar->callback(scroll_cb); + + has_scrollbar(VERTICAL); + + resizable(0); + + // EDE_Browser is always a multiple-selection browser + type(FL_MULTI_BROWSER); + + column_sort_types_ = new SortType[256]; // 256 columns should be enough for anyone (tm) + for (int i=0; i<256; i++) column_sort_types_[i]=NO_SORT; +} + + +//make buttons invisible +void EDE_Browser::hide_header() { + if (heading->visible()) resize(x(),y()-buttonheight,w(),h()+buttonheight); + heading->clear(); + heading->hide(); +} + +// Regenerate and display header +void EDE_Browser::show_header() { + int button_x=0; + char *h = column_header_; + const int* l = Fl_Icon_Browser::column_widths(); + heading->clear(); + for (int i=0; i==0||l[i-1]; i++) { + // If the button is last, calculate size + int button_w = l[i]; + if (button_w == 0) button_w = totalwidth_-button_x; + + // Get part of header until delimiter char + char *delim = 0; + Fl_Button *b; + + if (h) { + delim = strchr(h, Fl_Icon_Browser::column_char()); + if (delim) *delim='\0'; // temporarily + b=new Fl_Button(button_x,heading->y(),button_w,buttonheight,strdup(h)); + } else { + b=new Fl_Button(button_x,heading->y(),button_w,buttonheight,""); + } + + b->align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT|FL_ALIGN_CLIP); + b->callback(header_callback); + b->labelsize(12); // FIXME: hack for label size + //b->labelcolor(FL_DARK3); + heading->add(b); + button_x += l[i]; + + if (delim) { + *delim=Fl_Icon_Browser::column_char(); // put back delimiter + h=delim+1; // next field + } + } + if (!heading->visible()) resize(x(),y()+buttonheight,w(),this->h()-buttonheight); + heading->resizable(0); // We will resize the heading and individual buttons manually + heading->show(); + heading->redraw(); //in case it was already visible +} + +// Subclassed to resize heading and browser if neccessary +void EDE_Browser::column_widths(const int* l) { + totalwidth_=0; + int i; + for (i=0; l[i]; i++) totalwidth_+=l[i]; +// if (total>=scroll->w()) { +// Fl_Icon_Browser::size(total,h()); +// } +fprintf(stderr, "Total width is: %d\n", totalwidth_); + // If there was heading before, regenerate + if (heading->visible()) + heading->size(totalwidth_,buttonheight); +// show_header(); + + // Second array for the Fl_Browser + int *tmp = new int[i]; // FIXME: Someone should cleanup this memory sometimes... + for (int j=0; jredraw(); +} + +const int* EDE_Browser::column_widths() const { + int i,total=0; + const int *l=Fl_Icon_Browser::column_widths(); + for (i=0; l[i]; i++) total+=l[i]; + + int *tmp = new int[i+2]; // FIXME: Someone should cleanup this memory sometimes... + for (int j=0; l[j]; j++) tmp[j]=l[j]; + + tmp[i]=(totalwidth_-total); + tmp[i+1]=0; + return tmp; +} + + +// Subclassed handle() for keyboard searching +int EDE_Browser::handle(int e) { + if (e==FL_KEYBOARD) { + // when user presses a key, jump to row starting with that character + int k=Fl::event_key(); + if ((k>='a'&&k<='z') || (k>='A'&&k<='Z') || (k>='0'&&k<='9')) { + if (k>='A'&&k<='Z') k+=('a'-'A'); + int ku = k - ('a'-'A'); //upper case + int p=lineno(selection()); + for (int i=1; i<=size(); i++) + if (i!=p && (text(i)[0]==k || text(i)[0]==ku)) { + // select(line,0) just moves focus to line without selecting + // if line was already selected, it won't be anymore + select(i,selected(i)); + middleline(i); + break; + } + } + // Attempt to fix erratic behavior on enter key + // Fl_Browser seems to do the following on enter key: + // - when item is both selected and focused, callback isn't called at all (even when FL_WHEN_ENTER...) + // - when no item is selected, callback is called 2 times on focused item + // - when one item is selected and other is focused, callback is first called on selected then on + // focused item + // This partial fix at least ensures that callback is always called. Callback should behave properly + // when called many times. + if ((when() & FL_WHEN_ENTER_KEY_ALWAYS) && k == FL_Enter) { +// if (changed()!=0) { + //fprintf(stderr,"do_callback()\n"); + do_callback(); +// } + } + } + return Fl_Icon_Browser::handle(e); +} + +// Overload resize for show/hide horizontal scrollbar +void EDE_Browser::resize(int X, int Y, int W, int H) { + if (W >= totalwidth_) { + // hide scrollbar + if (hscrollbar->visible()) + hscrollbar->hide(); + Fl_Icon_Browser::resize(X,Y,W,H); + } else { + // show scrollbar + int fsbs = Fl::scrollbar_size(); + if (!hscrollbar->visible()) + hscrollbar->show(); + Fl_Icon_Browser::resize(X,Y,W, H-fsbs); + hscrollbar->resize(X, Y+H-fsbs, W-fsbs, fsbs); + hscrollbar->value(hscrollbar->value(), W, 0, totalwidth_); + } +} + + + + +// ***************** +// class Heading - implementation +// ***************** + +// The following code is modified from Fl_Tile.cxx and extensively commented, as I was trying +// to figure it out ;) + +static void set_cursor(Fl_Group*t, Fl_Cursor c) { + static Fl_Cursor cursor; + if (cursor == c || !t->window()) return; + cursor = c; +#ifdef __sgi + t->window()->cursor(c,FL_RED,FL_WHITE); +#else + t->window()->cursor(c); +#endif +} + +static Fl_Cursor cursors[4] = { + FL_CURSOR_DEFAULT, + FL_CURSOR_WE, + FL_CURSOR_NS, + FL_CURSOR_MOVE +}; + +int EDE_Browser::Heading::handle(int event) { + + static int sdrag; // Type of drag + static int sdx; // Event distance from the widget boundary + static int sx; // Original event x +#define DRAGH 1 +#define DRAGV 2 + +// width of grabbing area in pixels: +#define GRABAREA 4 + + // Event coordinates + int evx = Fl::event_x(); + int evy = Fl::event_y(); + + switch (event) { + + case FL_MOVE: + case FL_ENTER: + case FL_PUSH: { + int mindx = 100; + int mindy = 100; + int oldx = 0; + int oldy = 0; + + Fl_Widget*const* a = array(); + + // Is there a button boundary within GRABAREA ? + for (int i=0; iy()<=evy+GRABAREA && o->y()+o->h()>=evy-GRABAREA) { + int t = evx - (o->x()+o->w()); + if (abs(t) < mindx) { + sdx = t; + mindx = abs(t); + } + } + } + + sdrag = 0; sx = 0; + if (mindx <= GRABAREA) {sdrag = DRAGH; sx = evx;} + set_cursor(this, cursors[sdrag]); + if (sdrag) return 1; + return Fl_Group::handle(event); + } + + case FL_LEAVE: + set_cursor(this, FL_CURSOR_DEFAULT); + break; + + case FL_DRAG: + // This is necessary if CONSOLIDATE_MOTION in Fl_x.cxx is turned off: + // if (damage()) return 1; // don't fall behind + case FL_RELEASE: { + if (!sdrag) return 0; // should not happen + Fl_Widget* r = resizable(); if (!r) r = this; + + // Calculate where the new boundary (newx) should be + int newx; + if (sdrag&DRAGH) { + newx = Fl::event_x()-sdx; + if (newx < r->x()) newx = r->x(); + else if (newx > r->x()+r->w()) newx = r->x()+r->w(); + } + + // Mouse movement distance (dx) + int dx = Fl::event_x()-sx; + + Fl_Widget*const* a = array(); + + // Here we check if any widget will get size 0 + // because column size 0 is illegal in Browser + for (int i=children(); i--; ) { + Fl_Widget* o = a[i]; + int end = o->x()+o->w(); // End coord. of widget + if ((end == newx-dx || newx<1) && o->w()+dx < 1) { + set_changed(); + do_callback(); + set_cursor(this, FL_CURSOR_DEFAULT); + return 1; + } + } + + if (newx>=w()) newx+=dx; // last button is resized by dragging the edge + + // Go again through list of widgets and resize everything + int *columns = new int[children()+1]; + int j=0; + for (int i=children(); i--; ) { + Fl_Widget* o = *a++; + int end = o->x()+o->w(); // End coord. of widget + + if (end == newx-dx) { + // Resize left widget + o->damage_resize( o->x(), o->y(), o->w()+dx, o->h()); + } else if (end > newx-dx) { + // Resize all remaining widgets to the right + o->damage_resize(o->x()+dx, o->y(), o->w(), o->h()); + } + // Push new width into the columns array + columns[j++]=o->w(); + } + columns[j]=0; + + // This is the EDE_Browser method. It will also resize the heading and + // the browser if neccessary + EDE_Browser*b = (EDE_Browser*)parent(); + b->column_widths(columns); + b->redraw(); // OPTIMIZE (some smart damage in column_widths() ?) + free(columns); + + // There will be many RELEASE events, so we update sx (used when calculating dx) + sx=Fl::event_x(); + + if (event == FL_DRAG) set_changed(); + do_callback(); + return 1; + } + } + + return Fl_Group::handle(event); +} diff --git a/efiler/EDE_Browser.h b/efiler/EDE_Browser.h new file mode 100644 index 0000000..a0f0765 --- /dev/null +++ b/efiler/EDE_Browser.h @@ -0,0 +1,186 @@ +/* + * $Id$ + * + * EDE Browser class + * Part of edelib. + * Copyright (c) 2005-2007 EDE Authors. + * + * This program is licenced under terms of the + * GNU General Public Licence version 2 or newer. + * See COPYING for details. + */ + + +#ifndef EDE_Browser_H +#define EDE_Browser_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "Fl_Icon_Browser.h" + +enum SortType { + NO_SORT = 0, ///< don't sort, items will be shown in order of adding + ALPHA_SORT = 1, ///< standard bibliographic sort + ALPHA_CASE_SORT = 2, ///< standard bibliographic sort ignoring the case + NUMERIC_SORT = 3, ///< items are converted to numbers and sorted by size + DATE_SORT = 4, ///< sort by date (depends on user locale) + FILE_SIZE_SORT = 5 ///< same as numeric, but also considering units such as kB, MB, GB +}; + +/** + * \class EDE_Browser + * \brief An improved version of Fl_Browser + * + * This is a (mostly compatible) version of Fl_Browser that adds + * following features: + * * sorting by column, using one of the several offered sort types, + * * optional header which enables resizing columns and sorting + * (by clicking the title of column that you wish to sort), + * * quick search (by pressing the first character of the item you + * are searching). + * + * The type of browser is set by default to FL_MULTI_BROWSER (call + * method type() to change). + * + * The class is based on Fl_Icon_Browser (which is just a Fl_Browser + * that can display icons) that I sincerelly hope will one day go + * upstream. + * +*/ +class EDE_Browser : public Fl_Icon_Browser { +private: + // Button row height + static const int buttonheight=20; + + // Subclass Fl_Group for handle()-ing button resizing and clicks + class Heading : public Fl_Group { + public: + Heading(int x, int y, int w, int h, const char *label = 0) : Fl_Group(x,y,w,h,label) {} + int handle(int e); + } *heading; + + Fl_Scrollbar *hscrollbar; + + int totalwidth_; // total width of all columns + + char *column_header_; + SortType *column_sort_types_; + + // current sort: + int sort_column; + SortType sort_type; + bool sort_direction; + + void hide_header(); + void show_header(); + + void mqsort(char *labels[], int beg, int end, SortType type); // my implementation of qsort + bool sortfn(char *,char*,SortType); // sort function, per type + +public: + EDE_Browser(int X,int Y,int W,int H,const char *L=0); + + ~EDE_Browser() { + delete[] column_sort_types_; + delete heading; + // delete scroll; + delete hscrollbar; + if (column_header_) free(column_header_); // this is a C-string + } + + /** + * Get or set the column titles and display the header. + * + * \param c is formatted just like other items, e.g. it uses the same column_char() + * To hide the header, just call with a null pointer (this is the default value). + */ + void column_header(const char *c) { + free(column_header_); + if (c) { + column_header_=strdup(c); + show_header(); + } else { + column_header_=0; + hide_header(); + } + } + const char *column_header() { return column_header_; } + + /** + * Sets the way various columns are sorted. By default all columns will use + * ALPHA_SORT e.g. classic bibliographic sort. Usually the programmer knows in + * advance what kind of data will be put into which column, so (s)he can set + * how each column will be sorted when the header buttons are clicked. + * + * \param l constant pointer to a sufficiently large array of SortType, corresponding + * to columns. Last value in this array must be 0 (NO_SORT) (there's no point for + * setting sort type of a column to NO_SORT; if you want to unsort the browser, just + * call sort(0, NO_SORT) ). + */ + void column_sort_types (const SortType *l) { for (int i=0; l[i]; i++) column_sort_types_[i]=l[i]; } + + /** + * Sort items by column. + * + * \param column number of column to use for sorting + * \param type type of sorting to be used + * \param reverse if true, items will be sorted in reverse order + */ + void sort(int column, SortType type, bool reverse=false); + + /** + * Sort items by column (toggle-type method). It will use the default sort type for + * given column, as set by column_sort_types(). If column is already sorted in normal + * order, this will resort in reverse - this method gives the same effect as clicking + * on column button. + * + * \param column number of column to use for sorting + */ + void sort(int column); + + /** + * Set and get column widths. + * NOTE: *Unlike* Fl_Browser, you need to specify the width of the + * last column as well! If the sum of witdhs is larger than the + * Browser, a horizontal scrollbar will be shown. If it is smaller, + * there will be some unused space to the right. + * + * \param l array of column widths in pixels, ending with zero (please + * don't forget to set the last value of the array to 0). If you wish + * to make a column (practically) invisible, set width to 1 pixel. + */ + void column_widths(const int* l); + const int* column_widths() const; + + // Overload handle for keyboard quick search + int handle(int e); + + // Overload resize for show/hide horizontal scrollbar + void resize(int X, int Y, int W, int H); + + // Overload hposition(), so that heading scrolls together with browser + void hposition(int x) { + if (heading->visible()) { + heading->resize(0-x,heading->y(),totalwidth_,buttonheight); + heading->redraw(); + } + Fl_Icon_Browser::hposition(x); + } +}; + +#endif + +// +// End of "$Id$". +// + diff --git a/efiler/EDE_DirTree.cpp b/efiler/EDE_DirTree.cpp deleted file mode 100644 index b6dc18d..0000000 --- a/efiler/EDE_DirTree.cpp +++ /dev/null @@ -1,395 +0,0 @@ -// -// "$Id: FileBrowser.cxx 5071 2006-05-02 21:57:08Z fabien $" -// -// FileBrowser routines. -// -// Copyright 1999-2006 by Michael Sweet. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This 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 -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -// USA. -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// -// Contents: -// -// FileBrowser::full_height() - Return the height of the list. -// FileBrowser::item_height() - Return the height of a list item. -// FileBrowser::item_width() - Return the width of a list item. -// FileBrowser::item_draw() - Draw a list item. -// FileBrowser::FileBrowser() - Create a FileBrowser widget. -// FileBrowser::load() - Load a directory into the browser. -// FileBrowser::filter() - Set the filename filter. -// - -// -// Include necessary header files... -// - -#include "EDE_DirTree.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -// This library is hopelessly single-platform - - -#include "../edelib2/Icon.h" -#include "../edelib2/Util.h" -#include "../edelib2/NLS.h" - -#include - - -#define MAX_TREE_DEPTH 100 - - - -using namespace fltk; - -// -// 'FileBrowser::FileBrowser()' - Create a FileBrowser widget. -// - - - -// Fn that makes sure path ends with slash -// (ensure that path allocation is large enough to take one extra char) -void make_end_with_slash(char* path) { - int i=strlen(path); - if (path[i-1] != '/') { - path[i]='/'; - path[i+1]='\0'; - } -} - - - - - - -DirTree::DirTree(int X, // I - Upper-lefthand X coordinate - int Y, // I - Upper-lefthand Y coordinate - int W, // I - Width in pixels - int H, // I - Height in pixels - const char *l) // I - Label text - : Browser(X, Y, W, H, l) { - // Initialize the filter pattern, current directory, and icon size... - //pattern_ = "*"; - //directory_ = ""; - //icon_size_ = 12.0f; - //filetype_ = FILES; - show_hidden_ = false; - - //Symbol* fileSmall = edelib::Icon::get(DEFAULT_ICON,edelib::Icon::SMALL); - //set_symbol(Browser::LEAF, fileSmall, fileSmall); -} - - - -// Filesystem data -// TODO: find better icons for Amiga, Macintosh etc. - -static struct { - char id[15]; - char uiname[50]; - char icon[20]; -} filesystems[] = { -// Filesystems that should be ignored - {"auto", "", ""}, // removables will be added another way - {"autofs", "", ""}, // removables will be added another way - {"binfmt_misc", "", ""}, - {"debugfs", "", ""}, - {"devfs", "", ""}, - {"devpts", "", ""}, - {"fd", "", ""}, - {"fdesc", "", ""}, - {"kernfs", "", ""}, - {"proc", "", ""}, - {"procfs", "", ""}, - {"swap", "", ""}, - {"sysfs", "", ""}, - {"tmpfs", "", ""}, - {"usbfs", "", ""}, - -// Common filesystems - {"ext2", "Linux disk (%s)", "hdd_unmount"}, - {"ext2fs", "Linux disk (%s)", "hdd_unmount"}, - {"ext3", "Linux disk (%s)", "hdd_unmount"}, - {"reiserfs", "Linux disk (%s)", "hdd_unmount"}, - {"ffs", "BSD disk (%s)", "hdd_unmount"}, - {"ufs", "Unix disk (%s)", "hdd_unmount"}, - {"dos", "Windows disk (%s)", "win_mount"}, - {"fat", "Windows disk (%s)", "win_mount"}, - {"msdos", "Windows disk (%s)", "win_mount"}, - {"ntfs", "Windows disk (%s)", "win_mount"}, - {"pcfs", "Windows disk (%s)", "win_mount"}, - {"umsdos", "Windows disk (%s)", "win_mount"}, - {"vfat", "Windows disk (%s)", "win_mount"}, - {"cd9660", "CD-ROM (%s)", "cdrom_unmount"}, - {"cdfs", "CD-ROM (%s)", "cdrom_unmount"}, - {"cdrfs", "CD-ROM (%s)", "cdrom_unmount"}, - {"hsfs", "CD-ROM (%s)", "cdrom_unmount"}, - {"iso9660", "CD-ROM (%s)", "cdrom_unmount"}, - {"isofs", "CD-ROM (%s)", "cdrom_unmount"}, - {"udf", "DVD-ROM (%s)", "dvd_unmount"}, - {"cifs", "Shared directory (%s)", "server"}, - {"nfs", "Shared directory (%s)", "server"}, - {"nfs4", "Shared directory (%s)", "server"}, - {"smbfs", "Shared directory (%s)", "server"}, - {"cramfs", "Virtual (RAM) disk (%s)", "memory"}, - {"mfs", "Virtual (RAM) disk (%s)", "memory"}, - {"ramfs", "Virtual (RAM) disk (%s)", "memory"}, - {"romfs", "Virtual (RAM) disk (%s)", "memory"}, - {"union", "Virtual (RAM) disk (%s)", "memory"}, // not accurate, but good enough - {"unionfs", "Virtual (RAM) disk (%s)", "memory"}, // not accurate, but good enough - {"jfs", "IBM AIX disk (%s)", "hdd_unmount"}, - {"xfs", "SGI IRIX disk (%s)", "hdd_unmount"}, - - -// Other filesystems - {"coherent", "Unix disk (%s)", "hdd_unmount"}, - {"sysv", "Unix disk (%s)", "hdd_unmount"}, - {"xenix", "Unix disk (%s)", "hdd_unmount"}, - {"adfs", "RiscOS disk (%s)", "hdd_unmount"}, - {"filecore", "RiscOS disk (%s)", "hdd_unmount"}, - {"ados", "Amiga disk (%s)", "hdd_unmount"}, - {"affs", "Amiga disk (%s)", "hdd_unmount"}, - {"afs", "AFS shared directory (%s)", "server"}, - {"befs", "BeOS disk (%s)", "hdd_unmount"}, - {"bfs", "UnixWare disk (%s)", "hdd_unmount"}, - {"efs", "SGI IRIX disk (%s)", "hdd_unmount"}, - {"ext", "Old Linux disk (%s)", "hdd_unmount"}, - {"hfs", "Macintosh disk (%s)", "hdd_unmount"}, // Also used for HP-UX filesystem!! - {"hpfs", "OS/2 disk (%s)", "hdd_unmount"}, -// {"lfs", "BSD LFS disk (%s)", "hdd_unmount"}, // This is said to not work - {"minix", "Minix disk (%s)", "hdd_unmount"}, - {"ncpfs", "NetWare shared directory (%s)", "server"}, - {"nwfs", "NetWare shared directory (%s)", "server"}, - {"qns", "QNX disk (%s)", "hdd_unmount"}, - {"supermount", "Removable disk (%s)", "cdrom_umnount"}, // ??? - {"xiafs", "Old Linux disk (%s)", "hdd_unmount"}, - -// Virtual filesystems (various views of existing files) -// How often are these used? -// {"cachefs", "Unix virtual disk ?? (%s)", "memory"}, -// {"lofs", "Solaris virtual disk ?? (%s)", "memory"}, -// {"null", "BSD virtual disk ?? (%s)", "memory"}, -// {"nullfs", "BSD virtual disk ?? (%s)", "memory"}, -// {"overlay", "BSD virtual disk ?? (%s)", "memory"}, -// {"portal", "BSD virtual disk ?? (%s)", "memory"}, -// {"portalfs", "BSD virtual disk ?? (%s)", "memory"}, -// {"umap", "BSD virtual disk ?? (%s)", "memory"}, -// {"umapfs", "BSD virtual disk ?? (%s)", "memory"}, - - {"", "", ""} -}; - -// -// 'FileBrowser::load()' - Load basic directory list into browser -// - -int // O - Number of files loaded -DirTree::load() -{ - - int num_files=0; - char buffer[PATH_MAX]; // buffer for labels - Group* o; // generic pointer - - this->begin(); - - // Top level icon - Group* system = (Group*)add_group(_("System"), 0, 0, edelib::Icon::get("tux",edelib::Icon::TINY)); - - // Home icon - snprintf(buffer,PATH_MAX,_("%s's Home"), getenv("USER")); - o = (Group*)add_group(strdup(buffer), system, 0, edelib::Icon::get("folder_home",edelib::Icon::TINY)); - strncpy(buffer,getenv("HOME"),PATH_MAX); - // Home env. var. often doesn't end with slash - make_end_with_slash(buffer); - o->user_data(strdup(buffer)); - - // Root icon - o = (Group*)add_group(_("Whole disk"), system, 0, edelib::Icon::get("folder_red",edelib::Icon::TINY)); - o->user_data(strdup("/")); - - num_files=3; - - // Read mtab/fstab/whatever - FILE *mtab; // /etc/mtab or /etc/mnttab file - char line[1024]; // Input line - char device[1024], mountpoint[1024], fs[1024]; - - // mtab doesn't contain removable entries, but we will find another way - // to add them (some day) - - 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 - - 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; - - make_end_with_slash(mountpoint); - - // Stuff that should be invisible cause we already show it - if (strcmp(mountpoint,"/") == 0) continue; // root - if (strcmp(mountpoint,getenv("HOME")) == 0) continue; // home dir - - // Device name without "/dev/" - char *shortdev = strrchr(device,'/'); - if (shortdev==NULL) shortdev=device; else shortdev++; - - // Go through list of known filesystems - for (int i=0; filesystems[i].id[0] != '\0'; i++) { - if (strcmp(fs, filesystems[i].id) == 0) { - if (filesystems[i].uiname[0] == '\0') break; // skipping this fs - - snprintf(buffer, PATH_MAX, filesystems[i].uiname, shortdev); - o = (Group*)add_group(strdup(buffer), system, 0, edelib::Icon::get(filesystems[i].icon, edelib::Icon::TINY)); - o->user_data(strdup(mountpoint)); - num_files++; - } - } - } - - this->end(); - system->set_flag(fltk::OPENED); - - this->redraw(); - - return (num_files); -} - -// Browser method for opening (expanding) a subtree -// We override this method so we could scan directory tree on demand -bool DirTree::set_item_opened(bool open) { - // Eliminate bogus call - if (!item()) return false; - // This is what we do different from Browser: -//fprintf (stderr, "Children: %d\n",children(current_index(),current_level()+1)); - if (open && children(current_index(),current_level()+1)<=0) { - dirent** files; - char* directory = (char*)item()->user_data(); - char filename[PATH_MAX]; - - // NOTE we default to casenumericsort! - int num_files = filename_list(directory, &files, casenumericsort); - Group* current = (Group*)item(); - - for (int i=0; id_name[0] == '.' && show_hidden_==false) continue; - if (!strcmp(files[i]->d_name,"./") || !strcmp(files[i]->d_name,"../")) continue; - - snprintf(filename, PATH_MAX, "%s%s", directory, files[i]->d_name); -//fprintf(stderr, "Testing: %s\n",filename); - if (filename_isdir(filename)) { - // Strip slash from label - char *n = strdup(files[i]->d_name); - n[strlen(n)-1] = '\0'; - Group* o = (Group*)add_group(n, current, 0, edelib::Icon::get("folder", edelib::Icon::TINY)); - o->user_data(strdup(filename)); - } - } - } - return Browser::set_item_opened(open); -} - - -// Recursively find tree entry whose user_data() (system path) -// contains the largest portion of given path -// Best match is focused, return value tells if perfect match was found -bool DirTree::set_current(const char* path) { - int tree[MAX_TREE_DEPTH]; - - // Copy of path where we add slash as needed - char mypath[PATH_MAX]; - strncpy(mypath,path,PATH_MAX-2); - make_end_with_slash(mypath); - - // There is always exactly one toplevel entry - "System" - tree[0]=0; - set_item(tree,1); - bool t = find_best_match(mypath,tree,1); - set_focus(); - // Expand current item - set_item_opened(true); - return t; -} - -// Recursive function called by set_current() -bool DirTree::find_best_match(const char* path, int* tree, int level) { - uint bestlen=0; - int bestindex=-1; - int n_children = children(tree,level); - - // Given entry has no children - // let's forward this result to first caller - if (n_children == -1) return false; - - // Look at all children of given entry and find the best match - for (int i=0; iuser_data(); - if (strlen(p)>strlen(path)) continue; // too specific - if ((strncmp(path, p, strlen(p)) == 0) && (strlen(p)>bestlen)) { - bestlen=strlen(p); - bestindex=i; - } - } - - // No matches found - if (bestindex==-1) return false; - - // Focus on best match - tree[level]=bestindex; - goto_index(tree,level); -//char* p = (char*)child(tree,level)->user_data(); -//fprintf (stderr, "Found: %s\n", p); - - // Is this a perfect match? - if (bestlen == strlen(path)) return true; - - // Can the best item be further expanded? - set_item_opened(true); - - // Try its children (if none, it will return false) - return find_best_match(path, tree, level+1); -} - - - -// -// End of "$Id: FileBrowser.cxx 5071 2006-05-02 21:57:08Z fabien $". -// diff --git a/efiler/EDE_DirTree.h b/efiler/EDE_DirTree.h deleted file mode 100644 index ffb439f..0000000 --- a/efiler/EDE_DirTree.h +++ /dev/null @@ -1,94 +0,0 @@ -// -// "$Id: FileBrowser.h 4926 2006-04-10 21:03:29Z fabien $" -// -// FileBrowser definitions. -// -// Copyright 1999-2006 by Michael Sweet. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This 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 -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -// USA. -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// - -// -// Include necessary header files... -// - -#ifndef edelib_DirTree_h -#define edelib_DirTree_h - -#include -#include - -//namespace fltk { - - -// -// FileBrowser class... -// - -class DirTree : public fltk::Browser -{ - - -public: - - DirTree(int, int, int, int, const char * = 0); - - /*float icon_size() const { - return (icon_size_ <0? (2.0f* textsize()) : icon_size_); - } - void icon_size(float f) { icon_size_ = f; redraw(); };*/ - - // Set given directory as current. Returns false if directory doesn't exist - // (the closest parent directory will be selected) - bool set_current(const char* path); - - // Load base directories into widget - int load(); - - // Browser method for opening (expanding) a subtree - // We override this method so we could scan directory tree on demand - bool set_item_opened(bool); - - // adding or inserting a line into the fileBrowser - //void insert(int n, const char* label, fltk::FileIcon* icon); - //void insert(int n, const char* label, void* data){fltk::Menu::insert(n, label,data);} - //void add(const char * line, fltk::FileIcon* icon); - - // Return full system path to given item - const char* system_path(int i) const { - return (const char*)child(i)->user_data(); } - - // Showing or not showing the hidden files, that's the question: -public: - // sets this flag if you want to see the hidden files in the browser - void show_hidden(bool show) { show_hidden_= show; } - bool show_hidden() const {return show_hidden_;} -private: - bool show_hidden_; - bool find_best_match(const char* path, int* indexes, int level); -}; - -//} - -#endif // !_Fl_File_Browser_H_ - -// -// End of "$Id: FileBrowser.h 4926 2006-04-10 21:03:29Z fabien $". -// diff --git a/efiler/EDE_FileBrowser.cpp b/efiler/EDE_FileBrowser.cpp deleted file mode 100644 index b3849ce..0000000 --- a/efiler/EDE_FileBrowser.cpp +++ /dev/null @@ -1,416 +0,0 @@ -// -// "$Id: FileBrowser.cxx 5071 2006-05-02 21:57:08Z fabien $" -// -// FileBrowser routines. -// -// Copyright 1999-2006 by Michael Sweet. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This 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 -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -// USA. -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// -// Contents: -// -// FileBrowser::full_height() - Return the height of the list. -// FileBrowser::item_height() - Return the height of a list item. -// FileBrowser::item_width() - Return the width of a list item. -// FileBrowser::item_draw() - Draw a list item. -// FileBrowser::FileBrowser() - Create a FileBrowser widget. -// FileBrowser::load() - Load a directory into the browser. -// FileBrowser::filter() - Set the filename filter. -// - -// -// Include necessary header files... -// - -#include "EDE_FileBrowser.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __CYGWIN__ -# include -#elif defined(WIN32) -# include -# include -// Apparently Borland C++ defines DIRECTORY in , which -// interfers with the FileIcon enumeration of the same name. -# ifdef DIRECTORY -# undef DIRECTORY -# endif // DIRECTORY -#endif // __CYGWIN__ - -#ifdef __EMX__ -# define INCL_DOS -# define INCL_DOSMISC -# include -#endif // __EMX__ - -// CodeWarrior (__MWERKS__) gets its include paths confused, so we -// temporarily disable this... -#if defined(__APPLE__) && !defined(__MWERKS__) -# include -# include -# include -#endif // __APPLE__ && !__MWERKS__ - -#include "../edelib2/Icon.h" -#include "../edelib2/Util.h" -#include "../edelib2/MimeType.h" -#include "../edelib2/NLS.h" - -#define DEFAULT_ICON "misc-vedran" -#define FOLDER_ICON "folder" -#define UPDIR_ICON "undo" - -#include - -#include -#include -#include - -#include - -using namespace fltk; -using namespace edelib; - - - -// Event handler for EditBox -int EditBox::handle(int event) { - if (!this->visible()) return parent()->handle(event); - bool above=false; - //fprintf(stderr,"Editbox event: %d (%s)\n",event,event_name(event)); - - // Change filename - if (event==KEY && (event_key()==ReturnKey || event_key()==KeypadEnter)) { - // split old filename to path and file - char path[PATH_MAX], file[PATH_MAX]; - strcpy(path, (char*)editing_->user_data()); - if (path[strlen(path)-1] == '/') path[strlen(path)-1]='\0'; - char *p = strrchr(path,'/'); - if (p==0 || *p=='\0') { - strcpy(file,path); - path[0]='\0'; - } else { // usual case - p++; - strcpy(file,p); - *p='\0'; - } - - if (strlen(file)!=strlen(text()) || strcmp(file,text())!=0) { - // Create new filename - strncat(path, text(), PATH_MAX-strlen(path)); - char oldname[PATH_MAX]; - strcpy(oldname, (char*)editing_->user_data()); - if (rename(oldname, path) == -1) { - alert(tsprintf(_("Could not rename file! Error was:\n\t%s"), strerror(errno))); - } else { - // Update browser - free(editing_->user_data()); - editing_->user_data(strdup(path)); - const char* l = editing_->label(); - editing_->label(tasprintf("%s%s",text(),strchr(l, '\t'))); - } - } - - above=true; - } - - // Hide editbox - if (above || ( event==KEY && event_key()==EscapeKey ) ) { - this->hide(); - return 1; - } - Input::handle(event); -} - - -// We override hide method to ensure certain things done -void EditBox::hide() { - Input::hide(); - // Remove box so it doesn't get in the way - this->x(0); - this->y(0); - this->w(0); - this->h(0); - // Return the browser item into "visible" state - if (editing_) { - editing_->textcolor(textcolor()); - editing_->redraw(); - parent()->take_focus(); - } -} - - - -// Column widths and titles -// TODO: make more configurable - -const char *labels[] = {_("Name"),_("Type"),_("Size"),_("Date"),0}; -int widths[] = {200, 150, 100, 150, 0}; - - -// -// 'FileBrowser::FileBrowser()' - Create a FileBrowser widget. -// - - -FileBrowser::FileBrowser(int X, // I - Upper-lefthand X coordinate - int Y, // I - Upper-lefthand Y coordinate - int W, // I - Width in pixels - int H, // I - Height in pixels - const char *l) // I - Label text - : Browser(X, Y, W, H, l) { - // Initialize the filter pattern, current directory, and icon size... - pattern_ = "*"; - directory_ = ""; - //icon_size_ = 12.0f; - filetype_ = BOTH; - show_hidden_ = false; - show_dotdot_ = true; - column_labels(labels); - column_widths(widths); - - // Editbox - editbox_ = new EditBox (0, 0, 0, 0); - editbox_->box(BORDER_FRAME); - editbox_->parent(this); - editbox_->hide(); -} - - -// -// 'FileBrowser::load()' - Load a directory into the browser. -// - -int // O - Number of files loaded -FileBrowser::load(const char *directory,// I - Directory to load - File_Sort_F *sort) // I - Sort function to use -{ - int i; // Looping var - int num_files; // Number of files in directory - int num_dirs; // Number of directories in list - char filename[PATH_MAX]; // Current file - //FileIcon *icon; // Icon to use - - -// printf("FileBrowser::load(\"%s\")\n", directory); - - if (!directory) - return (0); - - clear(); - directory_ = directory; - - if (directory_[0] == '\0') - { - // - // No directory specified; for UNIX list all mount points. For DOS - // list all valid drive letters... - // - - // TODO! - fprintf (stderr, "Drive list not implemented yet"); - return 0; - } - - // Scan directory and store list in **files - dirent **files; - num_files = fltk::filename_list(directory_, &files, sort); - if (num_files <= 0) return (0); - - // Allocate array for icons - Item** icon_array = (Item**) malloc (sizeof(Item*) * num_files + 1); - // fill array with zeros, for easier detection if item exists - for (i=0; iuser_data(strdup(filename)); - } - - // Main loop for populating browser - for (i = 0; i < num_files; i ++) { - if (strcmp(files[i]->d_name, "./")==0) - continue; - - char *n = files[i]->d_name; // shorter - - snprintf(filename, PATH_MAX, "%s%s", directory_, n); - - if (strcmp(n, ".")==0 || strcmp(n, "./")==0 || (!show_hidden_ && (n[0]=='.' || n[strlen(n)-1]=='~') ) ) - continue; - fltk::check(); //update interface - - // Add directory - if (filetype_ != FILES && fltk::filename_isdir(filename)) { - num_dirs ++; - - // strip slash from filename - char *fn = strdup(n); - if (fn[strlen(fn)-1] == '/') - fn[strlen(fn)-1] = '\0'; - - Item* o = new Item ( Icon::get ( FOLDER_ICON,Icon::TINY ), fn); - Menu::insert(*o, num_dirs-1); - o->user_data(strdup(filename)); // we keep full path for callback - icon_array[i]=o; - - // Add file - } else if (filetype_ != DIRECTORIES && fltk::filename_match(n, pattern_)) { - Item* o = new Item(Icon::get(DEFAULT_ICON,Icon::TINY), strdup(n)); - Menu::add(*o); - o->user_data(strdup(filename)); // we keep full path for callback - icon_array[i]=o; - } - } // end for - - this->redraw(); - - // - // Detect icon mimetypes etc. - // - - MimeType *m = new MimeType(); - - for (i=0; id_name); - m->set(filename); - - // change label to complete data in various tabs - char *label; - if (strncmp(m->id(),"directory",9)==0) { - // Strip slash from filename - char *n = strdup(files[i]->d_name); - n[strlen(n)-1] = '\0'; - asprintf(&label, "%s\t%s\t\t%s", n, m->type_string(), nice_time(filename_mtime(filename))); - free(n); - } else - asprintf(&label, "%s\t%s\t%s\t%s", files[i]->d_name, m->type_string(), nice_size(filename_size(filename)), nice_time(filename_mtime(filename))); - icon_array[i]->label(label); - - // icon - icon_array[i]->image(m->icon(Icon::TINY)); - - icon_array[i]->redraw(); - free(files[i]); - } - delete m; - free(files); - - return (num_files); -} - - -// -// 'FileBrowser::filter()' - Set the filename filter. -// -// I - Pattern string -void FileBrowser::filter(const char *pattern) { - // If pattern is NULL set the pattern to "*"... - if (pattern) pattern_ = pattern; - else pattern_ = "*"; -} - - - -// We override the fltk standard event handling to detect when -// user is clicking on already selected item and show filename editbox - -int FileBrowser::handle(int event) { - const int iconspace=20; - - // Handle all events in editbox - if (editbox_->visible()) { - if (event == PUSH && !event_inside(Rectangle(editbox_->x(), editbox_->y(), editbox_->w(), editbox_->h()))) - editbox_->hide(); - else - return editbox_->handle(event); - } - - if (event==PUSH && !event_clicks() && - // Don't accept clicks outside first column: - event_x()child(i)->y() && - // Handle last child - (i==children()-1 || event_y()y()) && - child(i)->flags()&SELECTED && - // Make sure only one item is selected: - child(i)==item() && - // Can't rename "up directory" - strcmp(child(i)->label(),"../") != 0) { - // "hide" item - editbox_->textcolor(child(i)->textcolor()); - child(i)->textcolor(child(i)->color()); - child(i)->throw_focus(); - - // deselect all - set_item_selected(false); - //deselect(); - - // Show editbox at item coordinates - editbox_->x(this->x()+child(i)->x()+iconspace); - editbox_->y(child(i)->y()); - editbox_->w(150); - editbox_->h(20); - editbox_->show(); - - // Copy last part of path to editbox - char*p = strdup((char*)child(i)->user_data()); - if (p[strlen(p)-1] == '/') p[strlen(p)-1]='\0'; - char*q = strrchr(p,'/'); - if (q!=0) - editbox_->text(q+1); - else - editbox_->text(p); - free(p); - /*char*p = strdup((char*)this->user_data()); - editbox_->text(filename_name(p));*/ - - editbox_->take_focus(); - editbox_->editing(child(i)); - return 0; - } - return Browser::handle(event); -} - - -// -// End of "$Id: FileBrowser.cxx 5071 2006-05-02 21:57:08Z fabien $". -// diff --git a/efiler/EDE_FileBrowser.h b/efiler/EDE_FileBrowser.h deleted file mode 100644 index 3f21efd..0000000 --- a/efiler/EDE_FileBrowser.h +++ /dev/null @@ -1,146 +0,0 @@ -// -// "$Id: FileBrowser.h 4926 2006-04-10 21:03:29Z fabien $" -// -// FileBrowser definitions. -// -// Copyright 1999-2006 by Michael Sweet. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This 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 -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -// USA. -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// - -// -// Include necessary header files... -// - -#ifndef edelib_FileBrowser_h -#define edelib_FileBrowser_h - -#include -#include -#include - -//namespace fltk { - - -// Class for the little input box used when we edit an item - -// FIXME: Why can this box be resized???? -// TODO: When editbox appears, select filename part and leave extension not-selected -// (as in Konqueror) - -class EditBox : public fltk::Input { - fltk::Widget* editing_; -public: - EditBox(int x, int y, int w, int h, const char* label = 0) : fltk::Input(x,y,w,h,label) , editing_(0) {} - void editing(fltk::Widget*w) { editing_=w; } - int handle (int event); - void hide(); -}; - - -/*! \class edelib::FileBrowser - -This class can be used as a drop-in replacement for fltk::FileBrowser because -it has much of the same API. In addition, it has the following features: - - uses edelib::MimeType and edelib::Icon to display file icons - - multicolumn view with columns: file name, type, size, date of last -modification and file permissions - - sorting by each column, by clicking on column headers or programmatically - - renaming files by clicking on a already selected file - - drag&drop support - - several other properties for fine tuning of display. - -By convention, real filename with full path of each item is stored in its -user_data() so you can easily access it from item callback or using the -const char* system_path(int index) method. - -Events that take place on double clicking, dropping files, popup menu etc. -should be implemented in callback, which enables you to create read-write -or read-only widgets as desired (e.g. in file chooser). - -*/ - -// -// FileBrowser class... -// - -class FileBrowser : public fltk::Browser -{ - int filetype_; - const char *directory_; - //float icon_size_; - const char *pattern_; - EditBox *editbox_; - - bool show_dotdot_; - -public: - enum { FILES, DIRECTORIES, BOTH }; - - FileBrowser(int, int, int, int, const char * = 0); - - /*float icon_size() const { - return (icon_size_ <0? (2.0f* textsize()) : icon_size_); - } - void icon_size(float f) { icon_size_ = f; redraw(); };*/ - - void filter(const char *pattern); - const char *filter() const { return (pattern_); }; - - int load(const char *directory, fltk::File_Sort_F *sort = (fltk::File_Sort_F*) fltk::casenumericsort); - -/* float textsize() const { return (fltk::Browser::textsize()); }; - void textsize(float s) { fltk::Browser::textsize(s); icon_size_ = (uchar)(3 * s / 2); };*/ - - int filetype() const { return (filetype_); }; - void filetype(int t) { filetype_ = t; }; - const char * directory() const {return directory_;} - - void show_up_directory(bool t) { show_dotdot_ = t; } - - // adding or inserting a line into the fileBrowser - //void insert(int n, const char* label, fltk::FileIcon* icon); - //void insert(int n, const char* label, void* data){fltk::Menu::insert(n, label,data);} - //void add(const char * line, fltk::FileIcon* icon); - - // Return full system path to given item - const char* system_path(int i) const { return (const char*)child(i)->user_data(); } - - // We override handle for displaying editbox - int handle(int); - // Showing or not showing the hidden files, that's the question: -public: - // sets this flag if you want to see the hidden files in the browser - void show_hidden(bool show) { show_hidden_= show; } - bool show_hidden() const {return show_hidden_;} -private: - bool show_hidden_; - - static void editbox_cb(Widget*,void*); - int editing; -}; - -//} - -#endif // !_Fl_File_Browser_H_ - -// -// End of "$Id: FileBrowser.h 4926 2006-04-10 21:03:29Z fabien $". -// diff --git a/efiler/EDE_FileView.h b/efiler/EDE_FileView.h new file mode 100644 index 0000000..d8b1d09 --- /dev/null +++ b/efiler/EDE_FileView.h @@ -0,0 +1,152 @@ +/* + * $Id$ + * + * EDE FileView class + * Part of edelib. + * Copyright (c) 2005-2007 EDE Authors. + * + * This program is licenced under terms of the + * GNU General Public Licence version 2 or newer. + * See COPYING for details. + */ + + +#ifndef EDE_FileView_H +#define EDE_FileView_H + +#include + +#include +#include + +#include "EDE_Browser.h" + +// This class provides the generic FileView class and two +// derived classes called FileIconView and FileDetailsView. +// These classes are interchangeable, so that application +// can just declare FileView* and use. +// FileView is populated with FileItem's. + +struct FileItem { + edelib::String name; // just the name + edelib::String icon; + edelib::String size; + edelib::String realpath; // whatever the caller uses to access the file + edelib::String description; + edelib::String date; + edelib::String permissions; +}; + + + +class FileDetailsView : public EDE_Browser { +private: +// EDE_Browser* browser; - yada + // internal list of items +/* struct myfileitem { + struct FileItem *item; + myfileitem* previous; + myfileitem* next; + } *firstitem;*/ + + int findrow(edelib::String realpath) { + for (int i=1; i<=size(); i++) { + char *tmp = (char*)data(i); + if (realpath==tmp) return i; + } + return 0; + } +/* struct myfileitem* finditem(edelib::String realpath) { + if (!firstitem) return; + struct myfileitem* work = firstitem; + do { + if (work->item->realpath == realpath) return work; + } while (work=work->next != 0); + return 0; + }*/ +public: + FileDetailsView(int X, int Y, int W, int H, char*label=0) : EDE_Browser(X,Y,W,H,label) { +// browser = new EDE_Browser(X,Y,W,H,label); +// browser->end(); +// end(); +// resizable(browser->the_scroll()); +// resizable(browser->the_group()); +// resizable(browser); + const int cw[]={250,200,70,130,100,0}; + column_widths(cw); + column_char('\t'); + column_header("Name\tType\tSize\tDate\tPermissions"); + textsize(12); // FIXME: hack for font size + const SortType st[]={ALPHA_CASE_SORT, ALPHA_CASE_SORT, FILE_SIZE_SORT, DATE_SORT, ALPHA_SORT, NO_SORT}; + column_sort_types(st); + when(FL_WHEN_ENTER_KEY_ALWAYS); + //when(FL_WHEN_ENTER_KEY_CHANGED); + //first=0; + } +// ~FileDetailsView() { delete browser; } + + void insert(int row, FileItem *item) { + // Construct browser line + edelib::String value; + value = item->name+"\t"+item->description+"\t"+item->size+"\t"+item->date+"\t"+item->permissions; + EDE_Browser::insert(row, value.c_str(), strdup(item->realpath.c_str())); // put realpath into data +fprintf (stderr, "value: %s\n", value.c_str()); + + // Get icon + edelib::String icon = edelib::IconTheme::get(item->icon.c_str(),edelib::ICON_SIZE_TINY); + if (icon=="") icon = edelib::IconTheme::get("misc",edelib::ICON_SIZE_TINY,edelib::ICON_CONTEXT_MIMETYPE); + set_icon(row, Fl_Shared_Image::get(icon.c_str())); + } + + + void add(FileItem *item) { insert(size()+1, item); } +// browser->redraw(); +/* struct myfileitem* i; + if (!first) + i = first = new myfileitem; + else { + i=first; + while (i->next!=0) i=i->next; + i->next = new myfileitem; + i->next->previous = i; + i=i->next; + } + i->item = item; + i->next = 0;*/ +// } + void remove(FileItem *item) { + int row = findrow(item->realpath); + if (row) EDE_Browser::remove(row); +/* struct myfileitem* i = finditem(item->realpath); + if (i) { + i->previous->next = i->next; + i->next->previous = i->previous; + delete i; + }*/ + } + void update(FileItem *item) { + int row=findrow(item->realpath); + if (row==0) return; + EDE_Browser::remove(row); + insert(row, item); +/* + // + edelib::String value = item->name + "\t" + item->description + "\t" + item->size + "\t" + item->date + "\t" + item->permissions; + browser->insert(row,value.c_str(),strdup(item->realpath.c_str())); + + edelib::String icon = edelib::IconTheme::get(item->icon.c_str(),edelib::ICON_SIZE_TINY); + browser->set_icon(row, Fl_Shared_Image::get(icon.c_str())); + + browser->redraw(); // OPTIMIZE +// browser->redraw_line(browser->find_item(row));*/ + } + +// void clear() { browser->clear(); } +// void callback(Fl_Callback* c) { browser->callback(c); } + +}; + + +#endif + +/* $Id */ diff --git a/efiler/Fl_Icon_Browser.cxx b/efiler/Fl_Icon_Browser.cxx new file mode 100644 index 0000000..ba968fb --- /dev/null +++ b/efiler/Fl_Icon_Browser.cxx @@ -0,0 +1,598 @@ + +// Icon Browser - modified from Fl_Browser.cxx by Vedran Ljubovic + +// "$Id: Fl_Icon_Browser.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Browser widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include +#include "Fl_Icon_Browser.h" + +// I modified this from the original Forms data to use a linked list +// so that the number of items in the browser and size of those items +// is unlimited. The only problem is that the old browser used an +// index number to identify a line, and it is slow to convert from/to +// a pointer. I use a cache of the last match to try to speed this +// up. + +// Also added the ability to "hide" a line. This set's it's height to +// zero, so the Fl_Icon_Browser_ cannot pick it. + +#define SELECTED 1 +#define NOTDISPLAYED 2 + +struct FL_BLINE { // data is in a linked list of these + FL_BLINE* prev; + FL_BLINE* next; + void* data; + Fl_Image* icon; + short length; // sizeof(txt)-1, may be longer than string + char flags; // selected, displayed + char txt[1]; // start of allocated array +}; + +void* Fl_Icon_Browser::item_first() const {return first;} + +void* Fl_Icon_Browser::item_next(void* l) const {return ((FL_BLINE*)l)->next;} + +void* Fl_Icon_Browser::item_prev(void* l) const {return ((FL_BLINE*)l)->prev;} + +int Fl_Icon_Browser::item_selected(void* l) const { + return ((FL_BLINE*)l)->flags&SELECTED;} + +void Fl_Icon_Browser::item_select(void* l, int v) { + if (v) ((FL_BLINE*)l)->flags |= SELECTED; + else ((FL_BLINE*)l)->flags &= ~SELECTED; +} + +FL_BLINE* Fl_Icon_Browser::find_line(int line) const { + int n; FL_BLINE* l; + if (line == cacheline) return cache; + if (cacheline && line > (cacheline/2) && line < ((cacheline+lines)/2)) { + n = cacheline; l = cache; + } else if (line <= (lines/2)) { + n = 1; l = first; + } else { + n = lines; l = last; + } + for (; n < line && l; n++) l = l->next; + for (; n > line && l; n--) l = l->prev; + ((Fl_Icon_Browser*)this)->cacheline = line; + ((Fl_Icon_Browser*)this)->cache = l; + return l; +} + +int Fl_Icon_Browser::lineno(void* v) const { + FL_BLINE* l = (FL_BLINE*)v; + if (!l) return 0; + if (l == cache) return cacheline; + if (l == first) return 1; + if (l == last) return lines; + if (!cache) { + ((Fl_Icon_Browser*)this)->cache = first; + ((Fl_Icon_Browser*)this)->cacheline = 1; + } + // assumme it is near cache, search both directions: + FL_BLINE* b = cache->prev; + int bnum = cacheline-1; + FL_BLINE* f = cache->next; + int fnum = cacheline+1; + int n = 0; + for (;;) { + if (b == l) {n = bnum; break;} + if (f == l) {n = fnum; break;} + if (b) {b = b->prev; bnum--;} + if (f) {f = f->next; fnum++;} + } + ((Fl_Icon_Browser*)this)->cache = l; + ((Fl_Icon_Browser*)this)->cacheline = n; + return n; +} + +FL_BLINE* Fl_Icon_Browser::_remove(int line) { + FL_BLINE* ttt = find_line(line); + deleting(ttt); + + cacheline = line-1; + cache = ttt->prev; + lines--; + full_height_ -= item_height(ttt); + if (ttt->prev) ttt->prev->next = ttt->next; + else first = ttt->next; + if (ttt->next) ttt->next->prev = ttt->prev; + else last = ttt->prev; + + return(ttt); +} + +void Fl_Icon_Browser::remove(int line) { + if (line < 1 || line > lines) return; + free(_remove(line)); +} + +void Fl_Icon_Browser::insert(int line, FL_BLINE* t) { + if (!first) { + t->prev = t->next = 0; + first = last = t; + } else if (line <= 1) { + inserting(first, t); + t->prev = 0; + t->next = first; + t->next->prev = t; + first = t; + } else if (line > lines) { + t->prev = last; + t->prev->next = t; + t->next = 0; + last = t; + } else { + FL_BLINE* n = find_line(line); + inserting(n, t); + t->next = n; + t->prev = n->prev; + t->prev->next = t; + n->prev = t; + } + cacheline = line; + cache = t; + lines++; + full_height_ += item_height(t); + redraw_line(t); +} + +void Fl_Icon_Browser::insert(int line, const char* newtext, void* d) { + int l = strlen(newtext); + FL_BLINE* t = (FL_BLINE*)malloc(sizeof(FL_BLINE)+l); + t->length = (short)l; + t->flags = 0; + strcpy(t->txt, newtext); + t->data = d; + t->icon = 0; + insert(line, t); +} + +void Fl_Icon_Browser::move(int to, int from) { + if (from < 1 || from > lines) return; + insert(to, _remove(from)); +} + +void Fl_Icon_Browser::text(int line, const char* newtext) { + if (line < 1 || line > lines) return; + FL_BLINE* t = find_line(line); + int l = strlen(newtext); + if (l > t->length) { + FL_BLINE* n = (FL_BLINE*)malloc(sizeof(FL_BLINE)+l); + replacing(t, n); + cache = n; + n->data = t->data; + n->length = (short)l; + n->flags = t->flags; + n->icon = t->icon; + n->prev = t->prev; + if (n->prev) n->prev->next = n; else first = n; + n->next = t->next; + if (n->next) n->next->prev = n; else last = n; + free(t); + t = n; + } + strcpy(t->txt, newtext); + redraw_line(t); +} + +void Fl_Icon_Browser::data(int line, void* d) { + if (line < 1 || line > lines) return; + find_line(line)->data = d; +} + +int Fl_Icon_Browser::item_height(void* lv) const { + FL_BLINE* l = (FL_BLINE*)lv; + if (l->flags & NOTDISPLAYED) return 0; + + int hmax = 2; // use 2 to insure we don't return a zero! + + if (!l->txt[0]) { + // For blank lines set the height to exactly 1 line! + fl_font(textfont(), textsize()); + int hh = fl_height(); + if (hh > hmax) hmax = hh; + } + else { + const int* i = column_widths(); + // do each column separately as they may all set different fonts: + for (char* str = l->txt; str && *str; str++) { + Fl_Font font = textfont(); // default font + int tsize = textsize(); // default size + while (*str==format_char()) { + str++; + switch (*str++) { + case 'l': case 'L': tsize = 24; break; + case 'm': case 'M': tsize = 18; break; + case 's': tsize = 11; break; + case 'b': font = (Fl_Font)(font|FL_BOLD); break; + case 'i': font = (Fl_Font)(font|FL_ITALIC); break; + case 'f': case 't': font = FL_COURIER; break; + case 'B': + case 'C': strtol(str, &str, 10); break;// skip a color number + case 'F': font = (Fl_Font)strtol(str,&str,10); break; + case 'S': tsize = strtol(str,&str,10); break; + case 0: case '@': str--; + case '.': goto END_FORMAT; + } + } + END_FORMAT: + char* ptr = str; + if (ptr && *i++) str = strchr(str, column_char()); + else str = NULL; + if((!str && *ptr) || (str && ptr < str)) { + fl_font(font, tsize); int hh = fl_height(); + if (hh > hmax) hmax = hh; + } + if (!str || !*str) break; + } + } + + if (l->icon && (l->icon->h()+2)>hmax) hmax=l->icon->h()+2; // leave 2px above/below + + return hmax; // previous version returned hmax+2! +} + +int Fl_Icon_Browser::item_width(void* v) const { + char* str = ((FL_BLINE*)v)->txt; + const int* i = column_widths(); + int ww = 0; + + while (*i) { // add up all tab-seperated fields + char* e; + e = strchr(str, column_char()); + if (!e) break; // last one occupied by text + str = e+1; + ww += *i++; + } + + // OK, we gotta parse the string and find the string width... + int tsize = textsize(); + Fl_Font font = textfont(); + int done = 0; + + while (*str == format_char_ && str[1] && str[1] != format_char_) { + str ++; + switch (*str++) { + case 'l': case 'L': tsize = 24; break; + case 'm': case 'M': tsize = 18; break; + case 's': tsize = 11; break; + case 'b': font = (Fl_Font)(font|FL_BOLD); break; + case 'i': font = (Fl_Font)(font|FL_ITALIC); break; + case 'f': case 't': font = FL_COURIER; break; + case 'B': + case 'C': strtol(str, &str, 10); break;// skip a color number + case 'F': font = (Fl_Font)strtol(str, &str, 10); break; + case 'S': tsize = strtol(str, &str, 10); break; + case '.': + done = 1; + break; + case '@': + str--; + done = 1; + } + + if (done) + break; + } + + if (*str == format_char_ && str[1]) + str ++; + + FL_BLINE* blind = (FL_BLINE*)v; + if (ww==0 && blind->icon) ww = blind->icon->w(); + + fl_font(font, tsize); + return ww + int(fl_width(str)) + 6; +} + +int Fl_Icon_Browser::full_height() const { + return full_height_; +} + +int Fl_Icon_Browser::incr_height() const { + return textsize()+2; +} + +void Fl_Icon_Browser::item_draw(void* v, int X, int Y, int W, int H) const { + char* str = ((FL_BLINE*)v)->txt; + const int* i = column_widths(); + bool first=true; // for icon + FL_BLINE*blind = (FL_BLINE*)v; + + while (W > 6) { // do each tab-seperated field + int w1 = W; // width for this field + char* e = 0; // pointer to end of field or null if none + if (*i) { // find end of field and temporarily replace with 0 + e = strchr(str, column_char()); + if (e) {*e = 0; w1 = *i++;} + } + + // Icon drawing code + if (first) { + first=false; + if (blind->icon != 0) { + blind->icon->draw(X+2,Y+1); // leave 2px left, 1px above + int iconw = blind->icon->w() + 2; + X += iconw; W -= iconw; w1 -= iconw; + } + } + + int tsize = textsize(); + Fl_Font font = textfont(); + Fl_Color lcol = textcolor(); + Fl_Align talign = FL_ALIGN_LEFT; + // check for all the @-lines recognized by XForms: + while (*str == format_char() && *++str && *str != format_char()) { + switch (*str++) { + case 'l': case 'L': tsize = 24; break; + case 'm': case 'M': tsize = 18; break; + case 's': tsize = 11; break; + case 'b': font = (Fl_Font)(font|FL_BOLD); break; + case 'i': font = (Fl_Font)(font|FL_ITALIC); break; + case 'f': case 't': font = FL_COURIER; break; + case 'c': talign = FL_ALIGN_CENTER; break; + case 'r': talign = FL_ALIGN_RIGHT; break; + case 'B': + if (!(((FL_BLINE*)v)->flags & SELECTED)) { + fl_color((Fl_Color)strtol(str, &str, 10)); + fl_rectf(X, Y, w1, H); + } else strtol(str, &str, 10); + break; + case 'C': + lcol = (Fl_Color)strtol(str, &str, 10); + break; + case 'F': + font = (Fl_Font)strtol(str, &str, 10); + break; + case 'N': + lcol = FL_INACTIVE_COLOR; + break; + case 'S': + tsize = strtol(str, &str, 10); + break; + case '-': + fl_color(FL_DARK3); + fl_line(X+3, Y+H/2, X+w1-3, Y+H/2); + fl_color(FL_LIGHT3); + fl_line(X+3, Y+H/2+1, X+w1-3, Y+H/2+1); + break; + case 'u': + case '_': + fl_color(lcol); + fl_line(X+3, Y+H-1, X+w1-3, Y+H-1); + break; + case '.': + goto BREAK; + case '@': + str--; goto BREAK; + } + } + BREAK: + fl_font(font, tsize); + if (((FL_BLINE*)v)->flags & SELECTED) + lcol = fl_contrast(lcol, selection_color()); + if (!active_r()) lcol = fl_inactive(lcol); + fl_color(lcol); + fl_draw(str, X+3, Y, w1-6, H, e ? Fl_Align(talign|FL_ALIGN_CLIP) : talign, 0, 0); + if (!e) break; // no more fields... + *e = column_char(); // put the seperator back + X += w1; + W -= w1; + str = e+1; + } +} + +static const int no_columns[1] = {0}; + +Fl_Icon_Browser::Fl_Icon_Browser(int X, int Y, int W, int H, const char*l) + : Fl_Browser_(X, Y, W, H, l) { + column_widths_ = no_columns; + lines = 0; + full_height_ = 0; + cacheline = 0; + format_char_ = '@'; + column_char_ = '\t'; + first = last = cache = 0; +} + +void Fl_Icon_Browser::lineposition(int line, Fl_Line_Position pos) { + if (line<1) line = 1; + if (line>lines) line = lines; + int p = 0; + + FL_BLINE* l; + for (l=first; l && line>1; l = l->next) { + line--; p += item_height(l); + } + if (l && (pos == BOTTOM)) p += item_height (l); + + int final = p, X, Y, W, H; + bbox(X, Y, W, H); + + switch(pos) { + case TOP: break; + case BOTTOM: final -= H; break; + case MIDDLE: final -= H/2; break; + } + + if (final > (full_height() - H)) final = full_height() -H; + position(final); +} + +int Fl_Icon_Browser::topline() const { + return lineno(top()); +} + +void Fl_Icon_Browser::clear() { + for (FL_BLINE* l = first; l;) { + FL_BLINE* n = l->next; + free(l); + l = n; + } + full_height_ = 0; + first = 0; + lines = 0; + new_list(); +} + +void Fl_Icon_Browser::add(const char* newtext, void* d) { + insert(lines+1, newtext, d); + //Fl_Icon_Browser_::display(last); +} + +const char* Fl_Icon_Browser::text(int line) const { + if (line < 1 || line > lines) return 0; + return find_line(line)->txt; +} + +void* Fl_Icon_Browser::data(int line) const { + if (line < 1 || line > lines) return 0; + return find_line(line)->data; +} + +int Fl_Icon_Browser::select(int line, int v) { + if (line < 1 || line > lines) return 0; + return Fl_Browser_::select(find_line(line), v); +} + +int Fl_Icon_Browser::selected(int line) const { + if (line < 1 || line > lines) return 0; + return find_line(line)->flags & SELECTED; +} + +void Fl_Icon_Browser::show(int line) { + FL_BLINE* t = find_line(line); + if (t->flags & NOTDISPLAYED) { + t->flags &= ~NOTDISPLAYED; + full_height_ += item_height(t); + if (Fl_Browser_::displayed(t)) redraw_lines(); + } +} + +void Fl_Icon_Browser::hide(int line) { + FL_BLINE* t = find_line(line); + if (!(t->flags & NOTDISPLAYED)) { + full_height_ -= item_height(t); + t->flags |= NOTDISPLAYED; + if (Fl_Browser_::displayed(t)) redraw_lines(); + } +} + +void Fl_Icon_Browser::display(int line, int v) { + if (line < 1 || line > lines) return; + if (v) show(line); else hide(line); +} + +int Fl_Icon_Browser::visible(int line) const { + if (line < 1 || line > lines) return 0; + return !(find_line(line)->flags&NOTDISPLAYED); +} + +int Fl_Icon_Browser::value() const { + return lineno(selection()); +} + +// SWAP TWO LINES +void Fl_Icon_Browser::swap(FL_BLINE *a, FL_BLINE *b) { + + if ( a == b || !a || !b) return; // nothing to do + swapping(a, b); + FL_BLINE *aprev = a->prev; + FL_BLINE *anext = a->next; + FL_BLINE *bprev = b->prev; + FL_BLINE *bnext = b->next; + if ( b->prev == a ) { // A ADJACENT TO B + if ( aprev ) aprev->next = b; else first = b; + b->next = a; + a->next = bnext; + b->prev = aprev; + a->prev = b; + if ( bnext ) bnext->prev = a; else last = a; + } else if ( a->prev == b ) { // B ADJACENT TO A + if ( bprev ) bprev->next = a; else first = a; + a->next = b; + b->next = anext; + a->prev = bprev; + b->prev = a; + if ( anext ) anext->prev = b; else last = b; + } else { // A AND B NOT ADJACENT + // handle prev's + b->prev = aprev; + if ( anext ) anext->prev = b; else last = b; + a->prev = bprev; + if ( bnext ) bnext->prev = a; else last = a; + // handle next's + if ( aprev ) aprev->next = b; else first = b; + b->next = anext; + if ( bprev ) bprev->next = a; else first = a; + a->next = bnext; + } + // Disable cache -- we played around with positions + cacheline = 0; + cache = 0; +} + +void Fl_Icon_Browser::swap(int ai, int bi) { + if (ai < 1 || ai > lines || bi < 1 || bi > lines) return; + FL_BLINE* a = find_line(ai); + FL_BLINE* b = find_line(bi); + swap(a,b); +} + +void Fl_Icon_Browser::set_icon(int line, Fl_Image* icon) { + if (icon && line>0 && line<=lines) { + // update full_height_ + FL_BLINE* bl = find_line(line); + int dh = icon->h() - item_height(bl) + 2; // leave 2px above/below + if (dh>0) full_height_ += dh; + bl->icon=icon; + redraw_line(bl); + } +} +void Fl_Icon_Browser::remove_icon(int line) { + if (line>0 && line<=lines) { + FL_BLINE* bl = find_line(line); + if (!bl->icon) return; + int dh = bl->icon->h()+2; // leave 2px above/below + bl->icon=0; + redraw_line(bl); + // update_full_height_ + dh -= item_height(bl); + if (dh>0) full_height_ -= dh; + } +} + + +// +// End of "$Id: Fl_Icon_Browser.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/efiler/Fl_Icon_Browser.h b/efiler/Fl_Icon_Browser.h new file mode 100644 index 0000000..5dfec54 --- /dev/null +++ b/efiler/Fl_Icon_Browser.h @@ -0,0 +1,143 @@ + +// Icon Browser - modified from Fl_Browser.h by Vedran Ljubovic + +// "$Id: Fl_Browser.H 4288 2005-04-16 00:13:17Z mike $" +// +// Browser header file for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Forms-compatable browser. Probably useful for other +// lists of textual data. Notice that the line numbers +// start from 1, and 0 means "no line". + +#ifndef Fl_Icon_Browser_H +#define Fl_Icon_Browser_H + +#include +#include + +#include + +struct FL_BLINE; + +class Fl_Icon_Browser : public Fl_Browser_ { + + FL_BLINE *first; // the array of lines + FL_BLINE *last; + FL_BLINE *cache; + int cacheline; // line number of cache + int lines; // Number of lines + int full_height_; + const int* column_widths_; + char format_char_; // alternative to @-sign + char column_char_; // alternative to tab + +protected: + + // required routines for Fl_Browser_ subclass: + void* item_first() const ; + void* item_next(void*) const ; + void* item_prev(void*) const ; + int item_selected(void*) const ; + void item_select(void*, int); + int item_height(void*) const ; + int item_width(void*) const ; + void item_draw(void*, int, int, int, int) const ; + int full_height() const ; + int incr_height() const ; + + FL_BLINE* find_line(int) const ; + FL_BLINE* _remove(int) ; + void insert(int, FL_BLINE*); + int lineno(void*) const ; + void swap(FL_BLINE *a, FL_BLINE *b); + +public: + + void remove(int); + void add(const char*, void* = 0); + void insert(int, const char*, void* = 0); + void move(int to, int from); + int load(const char* filename); + void swap(int a, int b); + void clear(); + + int size() const {return lines;} + void size(int W, int H) { Fl_Widget::size(W, H); } + + int topline() const ; + enum Fl_Line_Position { TOP, BOTTOM, MIDDLE }; + void lineposition(int, Fl_Line_Position); + void topline(int l) { lineposition(l, TOP); } + void bottomline(int l) { lineposition(l, BOTTOM); } + void middleline(int l) { lineposition(l, MIDDLE); } + + int select(int, int=1); + int selected(int) const ; + void show(int n); + void show() {Fl_Widget::show();} + void hide(int n); + void hide() {Fl_Widget::hide();} + int visible(int n) const ; + + int value() const ; + void value(int v) {select(v);} + const char* text(int) const ; + void text(int, const char*); + void* data(int) const ; + void data(int, void* v); + + Fl_Icon_Browser(int, int, int, int, const char* = 0); + ~Fl_Icon_Browser() { clear(); } + + char format_char() const {return format_char_;} + void format_char(char c) {format_char_ = c;} + char column_char() const {return column_char_;} + void column_char(char c) {column_char_ = c;} + const int* column_widths() const {return column_widths_;} + void column_widths(const int* l) {column_widths_ = l;} + + int displayed(int n) const {return Fl_Browser_::displayed(find_line(n));} + void make_visible(int n) { + if (n < 1) Fl_Browser_::display(find_line(1)); + else if (n > lines) Fl_Browser_::display(find_line(lines)); + else Fl_Browser_::display(find_line(n)); + } + + // for back compatability only: + void replace(int a, const char* b) {text(a, b);} + void display(int, int=1); + + + // icon support + void set_icon(int line, Fl_Image* icon); + void remove_icon(int line); + +}; + +#endif + +// +// End of "$Id: Fl_Browser.H 4288 2005-04-16 00:13:17Z mike $". +// diff --git a/efiler/Util.cpp b/efiler/Util.cpp new file mode 100644 index 0000000..ff40ecb --- /dev/null +++ b/efiler/Util.cpp @@ -0,0 +1,360 @@ +/* + * $Id$ + * + * Library of useful functions + * 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. + */ + +#include "Util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef _WIN32 + +# include +# include +# include +# define access(a,b) _access(a,b) +# define mkdir(a,b) _mkdir(a) +# define R_OK 4 + +#else + +# include + +#endif /* _WIN32 */ + + +// From Enumerations.h +#ifdef _WIN32 +# undef slash +# define slash '\\' +#else +# undef slash +# define slash '/' +#endif +// End Enumerations.h + + +//using namespace fltk; +//using namespace edelib; + + +// Test if path is absolute or relative +int is_path_rooted(const char *fn) +{ +#ifdef _WIN32 + if (fn[0] == '/' || fn[0] == '.' || fn[0] == '\\' || fn[1]==':') +#else + if (fn[0] == '/' || fn[0] == '.') +#endif + return 1; + return 0; +} + + +// recursively create a path in the file system +bool make_path( const char *path ) +{ + if(access(path, 0)) + { + const char *s = strrchr( path, slash ); + if ( !s ) return 0; + int len = s-path; + char *p = (char*)malloc( len+1 ); + memcpy( p, path, len ); + p[len] = 0; + make_path( (const char*)p ); + free( p ); + return ( mkdir( path, 0777 ) == 0 ); + } + return true; +} + + +// create the path needed for file using make_path +bool make_path_for_file( const char *path ) +{ + const char *s = strrchr( path, slash ); + if ( !s ) return false; + int len = s-path; + char *p = (char*)malloc( len+1 ); + memcpy( p, path, len ); + p[len] = 0; + bool ret=make_path( (const char*)p ); + free( p ); + return ret; +} + + +// Cross-platform function for system path +char* get_sys_dir() +{ +#ifndef _WIN32 + return SYSTEM_PATH; +#else + static char path[PATH_MAX]; + HKEY hKey; + if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", 0, KEY_READ, &hKey)==ERROR_SUCCESS) + { + DWORD size=4096; + RegQueryValueExW(hKey, L"CommonFilesDir", NULL, NULL, (LPBYTE)path, &size); + RegCloseKey(hKey); + return path; + } + return "C:\\EDE\\"; +#endif +} + + + +// Cross-platform function for home directory... +// I don't see the purpose since getenv("HOME") works just fine +/*char* get_homedir() { + char *path = new char[PATH_MAX]; + const char *str1; + + str1=getenv("HOME"); + if (str1) { + memcpy(path, str1, strlen(str1)+1); + return path; + } + + return 0; +}*/ + + +// strdupcat() - it's cool to strcat with implied realloc +// -- NOTE: due to use of realloc *always* use strdupcat return value: +// dest = strdupcat(dest,src); +// and *never* use it like: +// strdupcat(dest,src); +char* strdupcat(char *dest, const char *src) +{ + if (!dest) { + dest=(char*)malloc(strlen(src)); + } else { + dest=(char*)realloc (dest, strlen(dest)+strlen(src)+1); + } + strcat(dest,src); + return dest; +} + + +// wstrim() - for trimming characters (used in parser) +// parts of former fl_trimleft and fl_trimright from Fl_Util.cpp +char* wstrim(char *string) +{ + if(!string) + return NULL; + + char *start; + int len = strlen(string); + + if (len) { + char *p = string + len; + do { + p--; + if ( !isspace(*p) ) break; + } while ( p != string ); + + if ( !isspace(*p) ) p++; + *p = 0; + } + + for(start = string; *start && isspace (*start); start++); + memmove(string, start, strlen(start) + 1); + + return string; +} + +const char* twstrim(const char* string) +{ + static char buffer[4096]; + if (strlen(string)>4095) { + strncpy(buffer,string,4095); + buffer[4095]='\0'; + } else + strcpy(buffer,string); + wstrim((char*)buffer); + return (const char*)buffer; +} + +// hmmmh? +/* +char* wstrim(const char *string) +{ + char *newstring = strdup(string); + return wstrim(newstring); +}*/ + +// Returns nicely formatted string for byte sizes +const char* nice_size(double size) { + static char buffer[256]; + if (size<1024) { + snprintf(buffer,255,"%d B",(int)size); + } else if (size<1024*10) { + snprintf(buffer,255,"%.1f kB",(float)size/1024); + } else if (size<1024*1024) { + snprintf(buffer,255,"%d kB",(int)size/1024); + } else if (size<1024*1024*10) { + snprintf(buffer,255,"%.1f MB",(float)size/(1024*1024)); + } else if (size<1024*1024*1024) { + snprintf(buffer,255,"%d MB",(int)size/(1024*1024)); + } else if (size<1024*1024*1024*10) { + snprintf(buffer,255,"%.1f GB",(float)size/(1024*1024*1024)); + } else { + snprintf(buffer,255,"%d GB",(int)size/(1024*1024*1024)); + } + return (const char*) buffer; +} + + +const char* nice_time(long int epoch) { + static char buffer[256]; + + const time_t k = (const time_t)epoch; + const struct tm *timeptr = localtime(&k); + // Date/time format should be moved to configuration + snprintf(buffer,255,"%.2d.%.2d.%.4d. %.2d:%.2d", timeptr->tm_mday, timeptr->tm_mon+1, 1900+timeptr->tm_year, timeptr->tm_hour, timeptr->tm_min); + + return buffer; +} + + + +// Find in haystack any of needles (divided with separator) +char* strstrmulti(const char *haystack, const char *needles, const char *separator) { + if (!haystack || !needles || (strlen(haystack)==0) || (strlen(needles)==0)) + return (char*)haystack; // this means that empty search returns true + char *copy = strdup(needles); + char *token = strtok(copy, separator); + char *result = 0; + do { + if ((result = strstr(haystack,token))) break; + } while ((token = strtok(NULL, separator))); + free (copy); + if (!result && (strcmp(separator,needles+strlen(needles)-strlen(separator))==0)) + return (char*)haystack; // again + return result; +} + + + +// vec_from_string() - similar to explode() in PHP or split() in Perl +// adapted from Fl_String_List to use vector +/*std::vector vec_from_string(const char *str, const char *separator) +{ + if(!str) return std::vector (); + + const char *ptr = str; + const char *s = strstr(ptr, separator); + std::vector retval; + if(s) { + unsigned separator_len = strlen(separator); + do { + unsigned len = s - ptr; + if (len) { + retval.push_back(strndup(ptr,len)); + } else { + retval.push_back(NULL); + } + + ptr = s + separator_len; + s = strstr(ptr, separator); + } + while(s); + + if(*ptr) { + retval.push_back(strdup(ptr)); + } + } else { + retval.push_back(strdup(ptr)); + } + return retval; +}*/ + + + + +// Print to a static char[] and return pointer +const char* tsprintf(char *format, ...) +{ + static char buffer[4096]; + va_list args; + va_start(args, format); + vsnprintf(buffer, 4095, format, args); + va_end(args); + return (const char*)buffer; +} + +char* tasprintf(char *format, ...) +{ + char buffer[4096]; + va_list args; + va_start(args, format); + vsnprintf(buffer, 4095, format, args); + va_end(args); + return strdup(buffer); +} + + +// This function exists on some OSes and is mentioned in C textbooks +// However, we can just use sprintf instead + +/* +char * +itoa(int value, char *string, int radix) +{ + char tmp[33]; + char *tp = tmp; + int i; + unsigned v; + int sign; + char *sp; + + if (radix > 36 || radix <= 1) + { + return 0; + } + + sign = (radix == 10 && value < 0); + if (sign) + v = -value; + else + v = (unsigned)value; + while (v || tp == tmp) + { + i = v % radix; + v = v / radix; + if (i < 10) + *tp++ = i+'0'; + else + *tp++ = i + 'a' - 10; + } + + if (string == 0) + string = (char *)malloc((tp-tmp)+sign+1); + sp = string; + + if (sign) + *sp++ = '-'; + while (tp > tmp) + *sp++ = *--tp; + *sp = 0; + return string; +}*/ diff --git a/efiler/Util.h b/efiler/Util.h new file mode 100644 index 0000000..46580fe --- /dev/null +++ b/efiler/Util.h @@ -0,0 +1,93 @@ +/* + * $Id$ + * + * Library of useful functions + * 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. + */ + + +#ifndef edelib_Util_h +#define edelib_Util_h + +//#include "../edeconf.h" + + +//namespace edelib { + + +// Constants +//#define SYSTEM_PATH PREFIX"/share/ede" +#define SYSTEM_PATH "/usr/share/ede" +#define DOC_PATH SYSTEM_PATH"/doc" + + +// Cross-platform test if path is absolute or relative +int is_path_rooted(const char *fn); + +// Recursively create a path in the file system +bool make_path( const char *path ); + +// Create the path needed for file using make_path +bool make_path_for_file( const char *path ); + +// Cross-platform function for system files location +char* get_sys_dir(); + +// strcat() that also does realloc if needed. Useful if +// e.g. you have a loop which grows string in each pass +// -- Note: due to use of realloc *always* use strdupcat return value: +// dest = strdupcat(dest,src); +// and *never* use it like: +// strdupcat(dest,src); + +// NOTE this function is not used! Its use is not recommended + +char* strdupcat(char *dest, const char *src); + +// Whitespace trim (both left and right) +char* wstrim(char *string); + +// Version with temporary results (static char[]) +const char* twstrim(const char *string); + +// Finds in haystack any of strings contained in string "needles". The substrings +// are divided with separator. +// Not actually used... +char* strstrmulti(const char *haystack, const char *needles, const char *separator); + +// Returns nicely formatted string for byte sizes e.g. "1.2 kB" for size=1284 +const char* nice_size(double size); + +// Returns nicely formatted string for date and time given in seconds since +// Epoch. This should be in config +const char* nice_time(long int epoch); + +// Create vector from string using separator +//std::vector vec_from_string(const char *str, const char *separator); + + +/*! \fn const char* edelib::tsprintf(char* format, ...) + +A useful function which executes sprintf() on a static char[] variable big enough to +hold short temporary strings. The variable remains valid until next call. + +Use: + run_program(tsprintf(PREFIX"/bin/eiconsconf %s",param)); + +When setting text values of fltk objects, instead use tasprintf which executes a strdup. +Example: + window->label(tasprintf("%s, version %s",appname,appversion)); +*/ + +const char* tsprintf(char* format, ...); + +char* tasprintf(char* format, ...); + +//} + +#endif diff --git a/efiler/efiler.cpp b/efiler/efiler.cpp index 48faf5b..ba83b6e 100644 --- a/efiler/efiler.cpp +++ b/efiler/efiler.cpp @@ -10,780 +10,218 @@ * See COPYING for details. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include "../edelib2/about_dialog.h" -#include "../edelib2/Icon.h" -#include "../edelib2/MimeType.h" -#include "../edelib2/NLS.h" -#include "../edelib2/Run.h" -#include "../edelib2/Util.h" +#include +#include +#include -#include "EDE_FileBrowser.h" -#include "EDE_DirTree.h" +#include +#include +#include +#include + +#include +#include +#include + +#include "EDE_FileView.h" +#include "Util.h" #define DEFAULT_ICON "misc-vedran" +char current_dir[FL_PATH_MAX]; +FileDetailsView* view; +bool showhidden; +bool semaphore; +Fl_Window* win; +bool dirsfirst; +bool ignorecase; -using namespace fltk; -using namespace edelib; +// These variables are global to save time on construction/destruction +edelib::MimeType mime_resolver; +struct stat buf; - -Window *win; -TiledGroup* tile; -ScrollGroup* sgroup; -FileBrowser* fbrowser; -DirTree* dirtree; -char current_dir[PATH_MAX]; -static bool semaphore=false; -bool showhidden = false; -bool showtree = false; - -char **cut_copy_buffer = 0; -bool operation_is_copy = false; - - - - -/*----------------------------------------------------------------- - Icon View implementation - -NOTE: This will eventually be moved into a separate class. We know -there are ugly/unfinished stuff here, but please be patient. --------------------------------------------------------------------*/ - - -// Prototype (loaddir is called from button_press and vice versa -void loaddir(const char* path); - -// Callback for icons in icon view -void button_press(Widget* w, void*) { - if (event_clicks() || event_key() == ReturnKey) { - if (!w->user_data() || (strlen((char*)w->user_data())==0)) - alert(_("Unknown file type")); - else if (strncmp((char*)w->user_data(),"efiler ",7)==0) { - // don't launch new efiler instance - char tmp[PATH_MAX]; - strncpy(tmp,(char*)w->user_data()+7,PATH_MAX); - - // remove quotes - if (tmp[0] == '\'' || tmp[0] == '"') - memmove(tmp,tmp+1,strlen(tmp)-1); - int i=strlen(tmp)-2; - if (tmp[i] == '\'' || tmp[i] == '"') - tmp[i] = '\0'; - - loaddir(tmp); - } else { - fprintf(stderr, "Running: %s\n", (char*)w->user_data()); - run_program((char*)w->user_data(),false,false,true); - } - } - if (event_is_click()) w->take_focus(); - fprintf (stderr, "Event: %s (%d)\n",event_name(event()), event()); +// modification of versionsort which ignores case +void lowercase(char* s) { + for (int i=0;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; } - -// This function populates the icon view -// For convinience, it is now also called from other parts of code -// and also calls FileBrowser->load(path) which does the same -// thing for listview if neccessary - void loaddir(const char *path) { - // If user clicks too fast, it can cause problems - if (semaphore) { - return; - } - semaphore=true; + char old_dir[FL_PATH_MAX]; // Set current_dir - if (filename_isdir(path)) { + if (fl_filename_isdir(path)) { if (path[0] == '~') // Expand tilde snprintf(current_dir,PATH_MAX,"%s/%s",getenv("HOME"),path+1); else strcpy(current_dir,path); } else strcpy(current_dir,getenv("HOME")); + // Trailing slash should always be there if (current_dir[strlen(current_dir)-1] != '/') strcat(current_dir,"/"); + + // 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'; + } + fprintf (stderr, "loaddir(%s) = (%s)\n",path,current_dir); + strncpy(old_dir,current_dir,strlen(current_dir)); // Update directory tree - dirtree->set_current(current_dir); +// dirtree->set_current(current_dir); + + // variables used later + int size=0; + dirent **files; + + // List all files in directory + if (ignorecase) + size = scandir(current_dir, &files, 0, myversionsort); + else + size = scandir(current_dir, &files, 0, versionsort); + + if (size<0) { + fl_alert(_("Permission denied!")); + strncpy(current_dir,old_dir,strlen(current_dir)); + return; + } // set window label win->label(tasprintf(_("%s - File manager"), current_dir)); - // Update file browser... - if (fbrowser->visible()) { fbrowser->load(current_dir); semaphore=false; return; } - - // some constants - TODO: move to configuration - int startx=0, starty=0; - int sizex=90, sizey=58; - int spacex=5, spacey=5; - - // variables used later - Button **icon_array; - int icon_num=0; - dirent **files; - // Clean up window - sgroup->remove_all(); - sgroup->begin(); + view->clear(); - // List all files in directory - icon_num = fltk::filename_list(current_dir, &files, alphasort); // no sort needed because icons have coordinates - icon_array = (Button**) malloc (sizeof(Button*) * icon_num + 1); - // fill array with zeros, for easier detection if button exists - for (int i=0; id_name; //shortcut // don't show ./ (current directory) - if (strcmp(n,"./")==0) continue; + if (strcmp(n,".")==0) continue; // hide files with dot except ../ (up directory) - if (!showhidden && (n[0] == '.') && (strcmp(n,"../")!=0)) continue; + if (!showhidden && (n[0] == '.') && (strcmp(n,"..")!=0)) continue; // hide files ending with tilde (backup) - NOTE if (!showhidden && (n[strlen(n)-1] == '~')) continue; - Button* o = new Button(myx, myy, sizex, sizey); - o->box(NO_BOX); - //o->labeltype(SHADOW_LABEL); - o->labelcolor(BLACK); - o->callback((Callback*)button_press); - o->align(ALIGN_INSIDE|ALIGN_CENTER|ALIGN_WRAP); - //o->when(WHEN_CHANGED|WHEN_ENTER_KEY); + char fullpath[FL_PATH_MAX]; + snprintf (fullpath,FL_PATH_MAX-1,"%s%s",current_dir,files[i]->d_name); - o->label(n); - o->image(Icon::get(DEFAULT_ICON,Icon::SMALL)); + if (stat(fullpath,&buf)) continue; // error - myx=myx+sizex+spacex; - // 4 - edges - if (myx+sizex > sgroup->w()) { myx=startx; myy=myy+sizey+spacey; } + FileItem *item = new FileItem; + item->name = n; + item->size = nice_size(buf.st_size); + item->realpath = fullpath; + 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"; + } + item->date = nice_time(buf.st_mtime); + item->permissions = ""; // ? - icon_array[i] = o; + item_list[fsize++] = item; } - sgroup->end(); - // Give first icon the focus - sgroup->child(0)->take_focus(); - sgroup->redraw(); +// icon_array = (Button**) malloc (sizeof(Button*) * icon_num + 1); + // fill array with zeros, for easier detection if button exists +// for (int i=0; idescription == "Directory" || item_list[i]->description == "Go up") + view->add(item_list[i]); + } + for (int i=0; idescription != "Directory" && item_list[i]->description != "Go up") + view->add(item_list[i]); + } else { + for (int i=0; iadd(item_list[i]); + } + view->redraw(); + Fl::check(); - // get mime data - char fullpath[PATH_MAX]; - snprintf (fullpath,PATH_MAX-1,"%s%s",current_dir,files[i]->d_name); - m->set(fullpath); - -fprintf(stderr,"Adding: %s (%s), cmd: '%s'\n", fullpath, m->id(), m->command()); - - // tooltip - char *tooltip; - if (strcmp(m->id(),"directory")==0) - asprintf(&tooltip, "%s - %s", files[i]->d_name, m->type_string()); - else - asprintf(&tooltip, "%s (%s) - %s", files[i]->d_name, nice_size(filename_size(fullpath)), m->type_string()); - icon_array[i]->tooltip(tooltip); - - // icon - icon_array[i]->image(m->icon(Icon::SMALL)); - - // get command to execute - if (strcmp(files[i]->d_name,"../")==0) { - // up directory - we don't want ../ poluting filename - char exec[PATH_MAX]; - int slashes=0, j; - for (j=strlen(current_dir); j>0; j--) { - if (current_dir[j]=='/') slashes++; - if (slashes==2) break; + // Update mime types - can be slow... + for (int i=0; idescription != "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]); } - if (slashes<2) - sprintf(exec,"efiler /"); - else { - sprintf(exec,"efiler "); - strncat(exec,current_dir,j); - } - icon_array[i]->user_data(strdup(exec)); - - } else if (m->command() && (strlen(m->command())>0)) - icon_array[i]->user_data(strdup(m->command())); - else - icon_array[i]->user_data(0); - - // make sure label isn't too large - // TODO: move this to draw() method - int lx,ly; - icon_array[i]->measure_label(lx,ly); - int pos=strlen(icon_array[i]->label()); - if (pos>252) pos=252; - char fixlabel[256]; - while (lx>sizex) { - strncpy(fixlabel,icon_array[i]->label(),pos); - fixlabel[pos]='\0'; - strcat(fixlabel,"..."); - icon_array[i]->label(strdup(fixlabel)); - icon_array[i]->measure_label(lx,ly); - pos--; - } - icon_array[i]->redraw(); - } - // MimeType destructor - delete m; - - sgroup->redraw(); - semaphore=false; -} - - -/*----------------------------------------------------------------- - Directory tree - - (only callback, since most of the real work is done in class) --------------------------------------------------------------------*/ - -void dirtree_cb(Widget* w, void*) { - if (!event_clicks() && event_key() != ReturnKey) return; - char *d = (char*) dirtree->item()->user_data(); - if (d && strlen(d)>0) loaddir(d); -} - - -/*----------------------------------------------------------------- - List view - - (only callback, since most of the real work is done in class) --------------------------------------------------------------------*/ - -void fbrowser_cb(Widget* w, void*) { - // Take only proper callbacks - if (!event_clicks() && event_key() != ReturnKey) return; - - // Construct filename - const char *c = fbrowser->system_path(fbrowser->value()); - char filename[PATH_MAX]; - if (strncmp(c+strlen(c)-3,"../",3)==0) { - // User clicked on "..", we go up - strcpy(filename,current_dir); // both are [PATH_MAX] - filename[strlen(filename)-1] = '\0'; // remove trailing slash in a directory - char *c2 = strrchr(filename,'/'); // find previous slash - if (c2) *(c2+1) = '\0'; // cut everything after this slash - else strcpy(filename,"/"); // if nothing is found, filename becomes "/" - } else { - strncpy(filename,c,PATH_MAX); - } - - // Change directory - if (filename_isdir(filename)) - loaddir(filename); - - // Let elauncher handle this file... - else - run_program(tsprintf("file:%s",filename),false,false,true); -} - - - -/*----------------------------------------------------------------- - File moving and copying operations --------------------------------------------------------------------*/ - -ProgressBar* cut_copy_progress; -bool stop_now; -bool overwrite_all, skip_all; - -// Execute cut or copy operation when List View is active -void do_cut_copy_fbrowser(bool m_copy) { - // Count selected icons, for malloc - int num = fbrowser->children(); - int nselected = 0; - for (int i=0; iselected(i)) nselected++; - - // 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=0; ichild(i)->textcolor(BLACK); // FIXME: use color from style + Fl::check(); } } - // 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=0; i<=num; i++) { - if (fbrowser->selected(i)) { - cut_copy_buffer[buf] = strdup(fbrowser->system_path(i)); - if (!m_copy) fbrowser->child(i)->textcolor(GRAY50); - buf++; - } - } - cut_copy_buffer[buf] = 0; - operation_is_copy = m_copy; - - // Deselect all - fbrowser->deselect(); -} - -// Execute cut or copy operation when Icon View is active - -// (this one will become obsolete when IconBrowser class gets the same API -// as FileBrowser) - -void do_cut_copy_sgroup(bool m_copy) { - - // Group doesn't support type(MULTI) so only one item can be selected - - int num = fbrowser->children(); - - // Clear cut/copy buffer and optionally ungray the previously cutted icon - 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=0; ichild(i)->textcolor(BLACK); // FIXME: use color from style - } - } - - // Allocate buffer - cut_copy_buffer = (char**)malloc(sizeof(char*) * 3); - - // Add selected files to buffer and optionally grey icons (for cut effect) - // FIXME: label doesn't contain filename!! - asprintf(&cut_copy_buffer[0], "%s%s", current_dir, sgroup->child(sgroup->focus_index())->label()); - if (!m_copy) sgroup->child(sgroup->focus_index())->textcolor(GRAY50); - cut_copy_buffer[1]=0; - operation_is_copy=m_copy; + // Cleanup + for (int i=0; idata(view->value()); + fprintf(stderr, "Path: %s (ev %d)\n",path,Fl::event()); - // 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 + if (stat(path,&buf)) return; // error + if (S_ISDIR(buf.st_mode)) // directory + loaddir(path); - 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; imaxlen)) { - 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 (filename_exist(dest)) { - // if both src and dest are directories, do nothing - if (filename_isdir(src) && filename_isdir(dest)) - return true; - - int c = -1; - if (!overwrite_all && !skip_all) { - c = choice_alert(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 (filename_isdir(src)) - unlink(dest); - - // copy file over directory - // TODO: we will just skip this case, but ideally there should be - // another warning - if (filename_isdir(dest)) - return true; - } - - if (filename_isdir(src)) { - if (mkdir (dest, umask(0))==0) - return true; // success - int q = choice_alert(tsprintf(_("Cannot create directory %s"),dest), _("*&Continue"), _("&Stop"), 0); - if (q == 0) return true; else return false; - } - - if ( ( fold = fopen( src, "rb" ) ) == NULL ) { - int q = choice_alert(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 ); - int q = choice_alert(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 (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 = fltk::filename_list(src, &files, casenumericsort); - for (int i=0; id_name,"./")==0 || strcmp(files[i]->d_name,"../")==0) continue; - snprintf(new_src, PATH_MAX, "%s%s", src, files[i]->d_name); - fltk::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(Widget*,void* v) { - stop_now=true; - // Let's inform user that we're stopping... - InvisibleBox* caption = (InvisibleBox*)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 - // 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, filename_name(cut_copy_buffer[i])); - if (filename_exist(newname)) { - int c = -1; - if (!overwrite_all && !skip_all) { - c = choice_alert(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) { - alert(_("You cannot copy a file onto itself!")); - return; - } - - // Draw progress dialog - Window* progress_window = new 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(); - InvisibleBox* caption = new InvisibleBox(20,20,310,25, _("Counting files in directories")); - caption->align(ALIGN_LEFT|ALIGN_INSIDE); - cut_copy_progress = new ProgressBar(20,60,310,20); - Button* stop_button = new 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->range(0,copy_items,1); - cut_copy_progress->position(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; iposition(i+1); - fltk::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->range(0, list_size, 1); - cut_copy_progress->position(0); - - for (int i=0; ilabel(label); - caption->redraw(); - if (stop_now || !my_copy(files_list[i], dest)) - break; - cut_copy_progress->position(cut_copy_progress->position()+1); - fltk::check(); // check to see if user pressed Stop - } - } - progress_window->hide(); - - // Deallocate files_list[][] - for (int i=0; ivisible()) - w = sgroup->child(sgroup->focus_index()); - else - w = fbrowser; - event_clicks(2); - w->do_callback(); -} -void location_cb(Widget*, void*) { - const char *dir = dir_chooser(_("Choose location"),current_dir); - if (dir) loaddir(dir); -} -void quit_cb(Widget*, void*) {exit(0);} - - -// Edit menu callbacks - -void cut_cb(Widget*, void*) { - if (sgroup->visible()) - do_cut_copy_sgroup(false); - else - do_cut_copy_fbrowser(false); -} - -void copy_cb(Widget*, void*) { - if (sgroup->visible()) - do_cut_copy_sgroup(true); - else - do_cut_copy_fbrowser(true); -} - -void paste_cb(Widget*, void*) { - do_paste(); -} - - -// View menu - -void switchview() { - if (sgroup->visible()) { - sgroup->hide(); - fbrowser->show(); - fbrowser->take_focus(); - } else { - sgroup->show(); - fbrowser->hide(); - sgroup->take_focus(); - } - // We update the inactive view only when it's shown i.e. now - loaddir(current_dir); -} - -void iconsview_cb(Widget*,void*) { - // When user presses F8 we switch view regardles of which is visible - // However, when menu option is chosen we only switch *to* iconview - if (fbrowser->visible() || event_key() == F8Key) switchview(); -} -void listview_cb(Widget*,void*) { if (sgroup->visible()) switchview(); } - -void showhidden_cb(Widget* w, void*) { - // Presently, fbrowser has show_hidden() method while icon view - // respects value of showhidden global variable - - Item *i = (Item*)w; - if (showhidden) { - showhidden=false; - i->clear(); - } else { - showhidden=true; - i->set(); - } - if (fbrowser->visible()) fbrowser->show_hidden(showhidden); - // Reload current view - loaddir(current_dir); -} - -void showtree_cb(Widget*,void*) { - if (!showtree) { - tile->position(1,0,150,0); - showtree=true; - } else { - tile->position(150,0,0,0); - showtree=false; - } -} -void refresh_cb(Widget*,void*) { - loaddir(current_dir); - // TODO: reload directory tree as well- -} -void case_cb(Widget*,void*) { - fprintf(stderr,"Not implemented yet...\n"); -} - - -// Help menu - -void about_cb(Widget*, void*) { about_dialog("EFiler", "0.1", _("EDE File Manager"));} - - /*----------------------------------------------------------------- GUI design @@ -791,158 +229,21 @@ void about_cb(Widget*, void*) { about_dialog("EFiler", "0.1", _("EDE File Manage int main (int argc, char **argv) { - win = new fltk::Window(600, 400); - win->color(WHITE); + +fl_register_images(); +edelib::IconTheme::init("crystalsvg"); + win = new Fl_Window(600, 400); +// win->color(FL_WHITE); win->begin(); - - // Main menu - {MenuBar *m = new MenuBar(0, 0, 600, 25); - m->begin(); - {ItemGroup *o = new ItemGroup(_("&File")); - o->begin(); - {Item *o = new Item(_("&Open")); - o->callback(open_cb); - o->shortcut(CTRL+'o'); - } - {Item *o = new Item(_("Open &with...")); - //o->callback(open_cb); - //o->shortcut(CTRL+'o'); - } - new Divider(); - {Item *o = new Item(_("Open &location")); - o->callback(location_cb); - //o->shortcut(CTRL+'o'); - } - new Divider(); - {Item *o = new Item(_("&Quit")); - o->callback(quit_cb); - o->shortcut(CTRL+'q'); - } - o->end(); - } - {ItemGroup *o = new ItemGroup(_("&Edit")); - o->begin(); - {Item *o = new Item(_("&Cut")); - o->callback(cut_cb); - o->shortcut(CTRL+'x'); - } - {Item *o = new Item(_("C&opy")); - o->callback(copy_cb); - o->shortcut(CTRL+'c'); - } - {Item *o = new Item(_("&Paste")); - o->callback(paste_cb); - o->shortcut(CTRL+'v'); - } - {Item *o = new Item(_("&Rename")); - //o->callback(open_cb); - o->shortcut(F2Key); - } - {Item *o = new Item(_("&Delete")); - //o->callback(open_cb); - o->shortcut(DeleteKey); - } - new Divider(); - {Item *o = new Item(_("&Preferences...")); - o->shortcut(CTRL+'p'); - } - o->end(); - } - {ItemGroup *o = new ItemGroup(_("&View")); - o->begin(); - {Item *o = new Item(_("&Icons")); - o->type(Item::RADIO); - o->shortcut(F8Key); - o->set(); - o->callback(iconsview_cb); - } - {Item *o = new Item(_("&Detailed List")); - o->type(Item::RADIO); - o->callback(listview_cb); - } - new Divider(); - {Item *o = new Item(_("&Show hidden")); - o->type(Item::TOGGLE); - o->callback(showhidden_cb); - } - {Item *o = new Item(_("Directory &Tree")); - o->type(Item::TOGGLE); - o->shortcut(F9Key); - o->callback(showtree_cb); - } - new Divider(); - {Item *o = new Item(_("&Refresh")); - //o->type(); - o->callback(refresh_cb); - o->shortcut(F5Key); - } - {ItemGroup *o = new ItemGroup(_("S&ort")); - o->begin(); - {Item *o = new Item(_("&Case sensitive")); - //o->type(); - o->callback(case_cb); - } - o->end(); - } - o->end(); - } - {ItemGroup *o = new ItemGroup(_("&Help")); - o->begin(); - {Item *o = new Item(_("&About File Manager")); - o->shortcut(); - o->callback(about_cb); - } - o->end(); - } - m->end(); - } - - // Main tiled group - {tile = new TiledGroup(0, 25, 600, 375); - tile->color(WHITE); - tile->begin(); - - // Directory tree - {dirtree = new DirTree(0, 0, 150, 375); - dirtree->box(DOWN_BOX); - dirtree->color(WHITE); - dirtree->load(); - dirtree->callback(dirtree_cb); - dirtree->when(WHEN_CHANGED|WHEN_ENTER_KEY); - } - - // Icon view - {sgroup = new ScrollGroup(150, 0, 450, 375); - sgroup->box(DOWN_BOX); - sgroup->color(WHITE); - // sgroup->highlight_color(WHITE); - // sgroup->selection_color(WHITE); - sgroup->align(ALIGN_LEFT|ALIGN_TOP); - // g->label("There are no files in current directory"); - } - - // List view - {fbrowser = new FileBrowser(150, 0, 450, 375); - fbrowser->box(DOWN_BOX); - fbrowser->color(WHITE); - fbrowser->callback(fbrowser_cb); - // sgroup->align(ALIGN_LEFT|ALIGN_TOP); - // g->label("There are no files in current directory"); - fbrowser->when(WHEN_ENTER_KEY); - //fbrowser->labelsize(12); - fbrowser->type(Browser::MULTI); - fbrowser->hide(); - } - tile->end(); - } - - // We hide dirtree and browser expands to fill space - tile->position(150,0,1,0); + view = new FileDetailsView(0,0,600,400,0); + view->callback(open_cb); win->end(); - win->resizable(tile); - win->icon(Icon::get("folder",Icon::TINY)); - win->show(); + win->resizable(view); +// win->icon(Icon::get("folder",Icon::TINY)); + win->show(argc,argv); + +showhidden=false; dirsfirst=true; ignorecase=true; if (argc==1) { // No params loaddir (""); @@ -950,5 +251,5 @@ int main (int argc, char **argv) { loaddir (argv[1]); } - return fltk::run(); + return Fl::run(); }