Viewing file: FileDrop.php (12.03 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ // +----------------------------------------------------------------------+ // | PHP version 4 | // +----------------------------------------------------------------------+ // | Copyright (c) 1997-2004 The PHP Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 3.0 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available through the world-wide-web at the following url: | // | http://www.php.net/license/3_0.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | license@php.net so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Authors: Christian Weiske <cweiske@php.net> | // +----------------------------------------------------------------------+ // // $Id: FileDrop.php,v 1.1 2004/11/06 16:22:36 cweiske Exp $
require_once('MIME/Type.php'); require_once('PEAR.php');
/** * A FileDrop error code. * @const GTK_FILEDROP_WIDGET_NOT_SUPPORTED */ define('GTK_FILEDROP_WIDGET_NOT_SUPPORTED', 1);
/** * A class which makes it easy to * make a GtkWidget accept the dropping * of files or folders * @author Christian Weiske <cweiske@cweiske.de> * @package Gtk * * @date 2004-10-21 13:12 * @license PHP * * @todo * - reject files when moving the dragging mouse over the widget, just like opera does * how does this work? I don't know, but I suppose I should * * @example * Usage: * Simply change the text of a widget * (accept files with MIME-Types text/plain and text/html and files with .sgml extension): * Gtk_FileDrop::attach($entry, array('text/plain', 'text/html', '.sgml')); * Call a callback, and don't change the text (accept directories only): * Gtk_FileDrop::attach($entry, array( 'inode/directory'), array( &$this, 'callback'), false); */ class Gtk_FileDrop { /** * prepares a widget to accept file drops * @static * @param GtkWidget The widget which shall accept files * @param array List of MIME-Types to accept OR extensions, beginning with a dot "." * @param mixed Callback to call when a drop with valid files happened * @param boolean If the widget's text/label/content shall be changed automatically * * @return boolean If all was ok */ function attach($widget, $arTypes, $objCallback = null, $bSetText = true) { $widget->drag_dest_set(GTK_DEST_DEFAULT_ALL, array(array('text/uri-list', 0, 0)), GDK_ACTION_COPY | GDK_ACTION_MOVE); $fd = new Gtk_FileDrop( $arTypes, $objCallback, $bSetText); $widget->connect('drag-data-received', array( &$fd, 'dragDataReceived')); return true; }
/** * constructor * Use attach() instead! * * @access private */ function Gtk_FileDrop( $arTypes, $objCallback = null, $bSetText = true) { $this->arTypes = $arTypes; $this->objCallback = $objCallback; $this->bSetText = $bSetText; } /** * prepares a widget to accept directories only * Just a shortcut for the exhausted programmer * @static * @param GtkWidget The widget which shall accept directories * * @return boolean If all was ok */ function attachDirectory($widget) { return Gtk_FileDrop::attach($widget, array('inode/directory')); }
/** * Data have been dropped over the widget * @param GtkWidget The widget on which the data have been dropped * @param GdkDragContext The context of the drop * @param int X position * @param int Y position * @param int Info parameter (0 in our case) * @param int The time on which the event happened */ function dragDataReceived($widget, $context , $x, $y, $data , $info, $time) { $arData = explode("\n", $data->data); $arAccepted = array(); $arRejected = array(); $bDirectories = false; foreach ($arData as $strLine) { $strLine = trim($strLine); if ($strLine == '') { continue; } $strFile = Gtk_FileDrop::getPathFromUrilistEntry($strLine); $strFileMime = Gtk_FileDrop::getMimeType($strFile); $bAccepted = false; foreach ($this->arTypes as $strType) { if ($strType == 'inode/directory') { $bDirectories = true; } if (($strType[0] == '.' && Gtk_FileDrop::getFileExtension($strFile) == $strType) || $strType == $strFileMime || MIME_Type::wildcardMatch($strType, $strFileMime)) { $arAccepted[] = $strFile; $bAccepted = true; break; } }//foreach type if (!$bAccepted) { $arRejected[] = $strFile; } }//foreach line //make directories from the files if dirs are accepted //this is done here to give native directories first places on the list if ($bDirectories && count($arRejected) > 0) { foreach ($arRejected as $strFile) { $arAccepted[] = dirname( $strFile); } } if (count($arAccepted) == 0) { //no matching files return; } if ($this->bSetText) { $strClass = get_class($widget); switch ($strClass) { case 'GtkEntry': case 'GtkLabel': $widget->set_text($arAccepted[0]); break; case 'GtkButton': case 'GtkToggleButton': case 'GtkCheckButton': case 'GtkRadioButton': $childs = $widget->children(); $child = $childs[0]; if (get_class($child) == 'GtkLabel') { $child->set_text($arAccepted[0]); } else { trigger_error('No label found on widget.'); } break; case 'GtkCombo': $entry = $widget->entry; $entry->set_text($arAccepted[0]); break; case 'GtkFileSelection': $widget->set_filename($arAccepted[0]); break; case 'GtkList': foreach ($arAccepted as $strFile) { $items[] =& new GtkListItem($strFile); } $widget->append_items($items); $widget->show_all(); break; default: PEAR::raiseError( 'Widget class "' . $strClass . '" is not supported', GTK_FILEDROP_WIDGET_NOT_SUPPORTED, PEAR_ERROR_TRIGGER, E_USER_WARNING); break; } }//if bSetText if ($this->objCallback !== null) { call_user_func( $this->objCallback, $widget, $arAccepted); }//objCallback !== null } /** * converts a file path gotten from a text/uri-list * drop to a usable local filepath * * Php functions like parse_url can't be used as it is * likely that the dropped URI is no real URI but a * strange thing which tries to look like one * See the explanation at: * http://gtk.php.net/manual/en/tutorials.filednd.urilist.php * * @static * @param string The line from the uri-list * @return string The usable local filepath */ function getPathFromUrilistEntry($strUriFile) { $strUriFile = urldecode($strUriFile);//should be URL-encoded $bUrl = false; if (substr($strUriFile, 0, 5) == 'file:') { //(maybe buggy) file protocol if (substr($strUriFile, 0, 17) == 'file://localhost/') { //correct implementation $strFile = substr($strUriFile, 16); } else if (substr($strUriFile, 0, 8) == 'file:///') { //no hostname, but three slashes - nearly correct $strFile = substr($strUriFile, 7); } else if ($strUriFile[5] == '/') { //theoretically, the hostname should be the first //but no one implements it $strUriFile = substr($strUriFile, 5); for( $n = 1; $n < 5; $n++) { if ($strUriFile[$n] != '/') { break; } } $strUriFile = substr($strUriFile, $n - 1); if (!file_exists($strUriFile)) { //perhaps a correct implementation with hostname??? $strUriFileNoHost = strstr(substr($strUriFile, 1), '/'); if (file_exists($strUriFileNoHost)) { //seems so $strUriFile = $strUriFileNoHost; } } $strFile = $strUriFile; } else { //NO slash after "file:" - what is that for a crappy program? $strFile = substr ($strUriFile, 5); } } else if (strstr($strUriFile, '://')) { //real protocol, but not file $strFile = $strUriFile; $bUrl = true; } else { //local file? $strFile = $strUriFile; } if (!$bUrl && $strFile[2] == ':' && $strFile[0] == '/') { //windows file path $strFile = str_replace('/', '\\', substr($strFile, 1)); } return $strFile; } /** * returns the extension if a filename * including the leading dot * @static * @param string The filename * @return string The extension with a leading dot */ function getFileExtension($strFile) { $strExt = strrchr($strFile, '.'); if ($strExt == false) { return ''; } $strExt = str_replace('\\', '/', $strExt); if (strpos($strExt, '/') !== false) { return ''; } return $strExt; } /** * determines the mime-type for the given file * @static * @param string The file name * @return string The MIME type or FALSE in the case of an error */ function getMimeType($strFile) { //MIME_Type doesn't return the right type for directories //The underlying functions MIME_Type used don't return it right, //so there is no chance to fix MIME_Type itself if ((file_exists($strFile) && is_dir($strFile)) || substr($strFile, -1) == '/') { return 'inode/directory'; } $strMime = MIME_Type::autoDetect($strFile); if (!PEAR::isError($strMime)) { return $strMime; } //determine by extension | as MIME_TYPE doesn't support this, I have to do this myself $strExtension = Gtk_FileDrop::getFileExtension($strFile); switch ($strExtension) { case '.txt' : $strType = 'text/plain'; break; case '.gif' : $strType = 'image/gif'; break; case '.jpg' : case '.jpeg': $strType = 'image/jpg'; break; case '.png' : $strType = 'image/png'; break; case '.xml' : $strType = 'text/xml'; break; case '.htm' : case '.html': $strType = 'text/html'; break; default: $strType = false; break; } return $strType; } } ?>
|