ordering and limited resultsets

This commit is contained in:
Ralf Becker 2008-03-03 07:53:43 +00:00
parent 233875a181
commit 0af252ad55
4 changed files with 83 additions and 32 deletions

View File

@ -4,7 +4,7 @@
* Filemanager - Command line interface: ls * Filemanager - Command line interface: ls
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @package admin * @package filemanager
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2006 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2006 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
@ -58,7 +58,7 @@ function usage($action=null,$ret=0)
echo "\t$cmd chmod [-r|--recursive] mode=[ugoa]*[+-=][rwx]+,... URL [URL2 ...]\n"; echo "\t$cmd chmod [-r|--recursive] mode=[ugoa]*[+-=][rwx]+,... URL [URL2 ...]\n";
echo "\t$cmd chown [-r|--recursive] user URL [URL2 ...]\n"; echo "\t$cmd chown [-r|--recursive] user URL [URL2 ...]\n";
echo "\t$cmd chgrp [-r|--recursive] group URL [URL2 ...]\n"; echo "\t$cmd chgrp [-r|--recursive] group URL [URL2 ...]\n";
echo "\t$cmd find URL [URL2 ...] [-type (d|f)][-depth][-mindepth n][-maxdepth n][-mime type[/sub]][-name pattern][-path pattern][-uid id][-user name][-nouser][-gid id][-group name][-nogroup][-size N][-cmin N][-ctime N][-mmin N][-mtime N] (N: +n --> >n, -n --> <n, n --> =n)\n"; echo "\t$cmd find URL [URL2 ...] [-type (d|f)][-depth][-mindepth n][-maxdepth n][-mime type[/sub]][-name pattern][-path pattern][-uid id][-user name][-nouser][-gid id][-group name][-nogroup][-size N][-cmin N][-ctime N][-mmin N][-mtime N] (N: +n --> >n, -n --> <n, n --> =n) [-limit N[,n]][-order (name|size|...)][-sort (ASC|DESC)]\n";
echo "\t$cmd mount URL [path] (without path prints out the mounts)\n"; echo "\t$cmd mount URL [path] (without path prints out the mounts)\n";
echo "\t$cmd umount URL|path\n"; echo "\t$cmd umount URL|path\n";
@ -94,7 +94,7 @@ while(!is_null($option = array_shift($argv)))
{ {
if (!in_array($option,array('-type','-depth','-mindepth','-maxdepth','-name','-path', if (!in_array($option,array('-type','-depth','-mindepth','-maxdepth','-name','-path',
'-uid','-user','-nouser','-gid','-group','-nogroup','-mime', '-uid','-user','-nouser','-gid','-group','-nogroup','-mime',
'-empty','-size','-cmin','-ctime','-mmin','-mtime'))) '-empty','-size','-cmin','-ctime','-mmin','-mtime','-limit','-order','-sort')))
{ {
usage(); usage();
} }

View File

@ -3,7 +3,7 @@
* Filemanager - user interface * Filemanager - user interface
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @package admin * @package filemanager
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2008 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2008 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
@ -42,33 +42,15 @@ class filemanager_ui
{ {
$content['nm'] = array( $content['nm'] = array(
'get_rows' => 'filemanager.filemanager_ui.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows' 'get_rows' => 'filemanager.filemanager_ui.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows'
// 'filter_label' => // I label for filter (optional)
// 'filter_help' => // I help-msg for filter (optional)
'no_filter' => True, // I disable the 1. filter 'no_filter' => True, // I disable the 1. filter
'no_filter2' => True, // I disable the 2. filter (params are the same as for filter) 'no_filter2' => True, // I disable the 2. filter (params are the same as for filter)
'no_cat' => True, // I disable the cat-selectbox 'no_cat' => True, // I disable the cat-selectbox
// 'cat_app' => // I application the cat's should be from, default app in get_rows
// 'template' => // I template to use for the rows, if not set via options
// 'header_left' => // I template to show left of the range-value, left-aligned (optional)
// 'header_right' => // I template to show right of the range-value, right-aligned (optional)
// 'bottom_too' => True// I show the nextmatch-line (arrows, filters, search, ...) again after the rows
// 'never_hide' => True, // I never hide the nextmatch-line if less then maxmatch entrie
// 'lettersearch' => True, // I show a lettersearch // 'lettersearch' => True, // I show a lettersearch
'searchletter' => false, // I0 active letter of the lettersearch or false for [all] 'searchletter' => false, // I0 active letter of the lettersearch or false for [all]
'start' => 0, // IO position in list 'start' => 0, // IO position in list
// 'num_rows' => // IO number of rows to show, defaults to maxmatches from the general prefs
// 'cat_id' => // IO category, if not 'no_cat' => True
// 'search' => // IO search pattern
'order' => 'name', // IO name of the column to sort after (optional for the sortheaders) 'order' => 'name', // IO name of the column to sort after (optional for the sortheaders)
'sort' => 'ASC', // IO direction of the sort: 'ASC' or 'DESC' 'sort' => 'ASC', // IO direction of the sort: 'ASC' or 'DESC'
// 'col_filter' => // IO array of column-name value pairs (optional for the filterheaders) 'default_cols' => '!comment,ctime', // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns
// 'filter' => // IO filter, if not 'no_filter' => True
// 'filter_no_lang' => True// I set no_lang for filter (=dont translate the options)
// 'filter_onchange'=> 'this.form.submit();'// I onChange action for filter, default: this.form.submit();
// 'filter2' => // IO filter2, if not 'no_filter2' => True
// 'filter2_no_lang'=> True// I set no_lang for filter2 (=dont translate the options)
// 'filter2_onchange'=> 'this.form.submit();'// I onChange action for filter, default: this.form.submit();
'default_cols' => '!comment', // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns
'csv_fields' => false, // I false=disable csv export, true or unset=enable it with auto-detected fieldnames, 'csv_fields' => false, // I false=disable csv export, true or unset=enable it with auto-detected fieldnames,
//or array with name=>label or name=>array('label'=>label,'type'=>type) pairs (type is a eT widget-type) //or array with name=>label or name=>array('label'=>label,'type'=>type) pairs (type is a eT widget-type)
'path' => '/home/'.$GLOBALS['egw_info']['user']['account_lid'], 'path' => '/home/'.$GLOBALS['egw_info']['user']['account_lid'],
@ -336,12 +318,13 @@ class filemanager_ui
$dir_is_writable = egw_vfs::is_writable($query['path']); $dir_is_writable = egw_vfs::is_writable($query['path']);
$rows = array(); $rows = array();
foreach(egw_vfs::find($query['path'],array('mindepth'=>1,'maxdepth'=>1)) as $path) foreach(egw_vfs::find($query['path'],array(
'mindepth' => 1, 'maxdepth' => 1, // no recursion into subdirs
'order' => $query['order'], 'sort' => $query['sort'],
'limit' => (int)$query['num_rows'].','.(int)$query['start'],
'need_mime' => true,
),true) as $path => $row)
{ {
$row = egw_vfs::stat($path);
$row['name'] = egw_vfs::basename($path);
$row['path'] = $path;
$row['mime'] = egw_vfs::mime_content_type($path);
$row['icon'] = self::mime_icon($row['mime']); $row['icon'] = self::mime_icon($row['mime']);
$row['perms'] = egw_vfs::int2mode($row['mode']); $row['perms'] = egw_vfs::int2mode($row['mode']);
// only show link if we have access to the file or dir // only show link if we have access to the file or dir
@ -371,6 +354,6 @@ class filemanager_ui
} }
} }
//_debug_array($readonlys); //_debug_array($readonlys);
return count($rows); return egw_vfs::$find_total;
} }
} }

View File

@ -8,6 +8,7 @@
<column width="30%"/> <column width="30%"/>
<column/> <column/>
<column width="120"/> <column width="120"/>
<column width="120"/>
<column/> <column/>
<column/> <column/>
<column/> <column/>
@ -16,10 +17,11 @@
</columns> </columns>
<rows> <rows>
<row class="th"> <row class="th">
<nextmatch-sortheader label="Type" id="type" align="center"/> <nextmatch-sortheader label="Type" id="mime" align="center"/>
<nextmatch-sortheader label="Name" id="name"/> <nextmatch-sortheader label="Name" id="name"/>
<nextmatch-sortheader label="Size" id="size"/> <nextmatch-sortheader label="Size" id="size"/>
<nextmatch-sortheader label="Modified" id="mtime"/> <nextmatch-sortheader label="Modified" id="mtime"/>
<nextmatch-sortheader label="Created" id="ctime"/>
<nextmatch-sortheader label="Permissions" id="mode"/> <nextmatch-sortheader label="Permissions" id="mode"/>
<nextmatch-sortheader id="uid" label="Owner"/> <nextmatch-sortheader id="uid" label="Owner"/>
<nextmatch-sortheader id="gid" label="Group"/> <nextmatch-sortheader id="gid" label="Group"/>
@ -34,6 +36,7 @@
<description options=",$row_cont[link]" id="${row}[name]" no_lang="1"/> <description options=",$row_cont[link]" id="${row}[name]" no_lang="1"/>
<description id="${row}[hsize]" align="right"/> <description id="${row}[hsize]" align="right"/>
<date-time id="${row}[mtime]" readonly="true"/> <date-time id="${row}[mtime]" readonly="true"/>
<date-time id="${row}[ctime]" readonly="true"/>
<description value="$row_cont[perms]" class="perms"/> <description value="$row_cont[perms]" class="perms"/>
<description id="${row}[user]" no_lang="1"/> <description id="${row}[user]" no_lang="1"/>
<description id="${row}[group]" no_lang="1"/> <description id="${row}[group]" no_lang="1"/>

View File

@ -84,6 +84,12 @@ class egw_vfs extends vfs_stream_wrapper
* @var int * @var int
*/ */
static $user; static $user;
/**
* Total of last find call
*
* @var int
*/
static $find_total;
/** /**
* fopen working on just the eGW VFS * fopen working on just the eGW VFS
@ -251,6 +257,10 @@ class egw_vfs extends vfs_stream_wrapper
* - ctime/mtime => (+|-|)N file/dir created/modified in the last N days * - ctime/mtime => (+|-|)N file/dir created/modified in the last N days
* - depth => (+|-)N * - depth => (+|-)N
* - url => false(default),true allow (and return) full URL's instead of VFS pathes (only set it, if you know what you doing securitywise!) * - url => false(default),true allow (and return) full URL's instead of VFS pathes (only set it, if you know what you doing securitywise!)
* - need_mime => false(default),true should we return the mime type
* - order => name order rows by name column
* - sort => (ASC|DESC) sort, default ASC
* - limit => N,[n=0] return N entries from position n on, which defaults to 0
* @param string/array/true $exec=null function to call with each found file or dir as first param or * @param string/array/true $exec=null function to call with each found file or dir as first param or
* true to return file => stat pairs * true to return file => stat pairs
* @param array $exec_params=null further params for exec as array, path is always the first param! * @param array $exec_params=null further params for exec as array, path is always the first param!
@ -294,6 +304,10 @@ class egw_vfs extends vfs_stream_wrapper
$options['gid'] = 0; $options['gid'] = 0;
} }
} }
if ($options['order'] == 'mime')
{
$options['need_mime'] = true; // we need to return the mime colum
}
$url = $options['url']; $url = $options['url'];
if (!is_array($base)) if (!is_array($base))
@ -338,6 +352,8 @@ class egw_vfs extends vfs_stream_wrapper
$opts = $options; $opts = $options;
if ($opts['mindepth']) $opts['mindepth']--; if ($opts['mindepth']) $opts['mindepth']--;
if ($opts['maxdepth']) $opts['maxdepth']++; if ($opts['maxdepth']) $opts['maxdepth']++;
unset($opts['order']);
unset($opts['limit']);
foreach(self::find($options['url']?$file:parse_url($file,PHP_URL_PATH),$opts,true) as $p => $s) foreach(self::find($options['url']?$file:parse_url($file,PHP_URL_PATH),$opts,true) as $p => $s)
{ {
unset($result[$p]); unset($result[$p]);
@ -352,6 +368,47 @@ class egw_vfs extends vfs_stream_wrapper
self::_check_add($options,$path,$result); self::_check_add($options,$path,$result);
} }
} }
// ordering of the rows
if (isset($options['order']))
{
$sort = strtolower($options['sort']) == 'desc' ? '-' : '';
switch($options['order'])
{
// sort numerical
case 'size':
case 'uid':
case 'gid':
case 'mode':
case 'ctime':
case 'mtime':
uasort($result,create_function('$a,$b',$c='return '.$sort.'($a[\''.$options['order'].'\']-$b[\''.$options['order'].'\']);'));
break;
// sort alphanumerical
default:
$options['order'] = 'name';
// fall throught
case 'name':
case 'mime':
case 'comment': // ToDo: fetch it for sqlfs or oldvfs
uasort($result,create_function('$a,$b',$c='return '.$sort.'strcasecmp($a[\''.$options['order'].'\'],$b[\''.$options['order'].'\']);'));
break;
}
//echo "order='$options[order]', sort='$options[sort]' --> '$c'<br>\n";
}
// limit resultset
self::$find_total = count($result);
if (isset($options['limit']))
{
list($limit,$start) = explode(',',$options['limit']);
if (!$limit && !($limit = $GLOBALS['egw_info']['user']['preferences']['comman']['maxmatches'])) $limit = 15;
//echo "total=".egw_vfs::$find_total.", limit=$options[limit] --> start=$start, limit=$limit<br>\n";
if ((int)$start || self::$find_total > $limit)
{
$result = array_slice($result,(int)$start,(int)$limit,true);
}
}
//echo $path; _debug_array($result); //echo $path; _debug_array($result);
if ($exec !== true && is_callable($exec)) if ($exec !== true && is_callable($exec))
{ {
@ -394,8 +451,16 @@ class egw_vfs extends vfs_stream_wrapper
if (!($stat = self::url_stat($path,0))) if (!($stat = self::url_stat($path,0)))
{ {
return; // not found, should not happen return; // not found, should not happen
}
$stat = array_slice($stat,13); // remove numerical indices 0-12
$stat['name'] = self::basename($path);
$stat['path'] = $path;
if ($options['mime'] || $options['need_mime'])
{
$stat['mime'] = self::mime_content_type($path);
} }
if (isset($options['name_preg']) && !preg_match($options['name_preg'],self::basename($path)) ||
if (isset($options['name_preg']) && !preg_match($options['name_preg'],$stat['name']) ||
isset($options['path_preg']) && !preg_match($options['path_preg'],$path)) isset($options['path_preg']) && !preg_match($options['path_preg'],$path))
{ {
return; // wrong name or path return; // wrong name or path
@ -405,7 +470,7 @@ class egw_vfs extends vfs_stream_wrapper
{ {
return; // wrong user or group return; // wrong user or group
} }
if (isset($options['mime']) && $options['mime'] != ($mime = self::mime_content_type($path))) if (isset($options['mime']) && $options['mime'] != $stat['mime'])
{ {
list($type,$subtype) = explode('/',$options['mime']); list($type,$subtype) = explode('/',$options['mime']);
// no subtype (eg. 'image') --> check only the main type // no subtype (eg. 'image') --> check only the main type