Mercurial > hg > xemacs-beta
diff lisp/hm--html-menus/internal-drag-and-drop.el @ 2:ac2d302a0011 r19-15b2
Import from CVS: tag r19-15b2
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:46:35 +0200 |
parents | |
children | 8fc7fe29b841 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/hm--html-menus/internal-drag-and-drop.el Mon Aug 13 08:46:35 2007 +0200 @@ -0,0 +1,329 @@ +;;; $Id: internal-drag-and-drop.el,v 1.1.1.1 1996/12/18 03:46:48 steve Exp $ +;;; +;;; Copyright (C) 1996 Heiko Muenkel +;;; email: muenkel@tnt.uni-hannover.de +;;; +;;; This program is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 1, or (at your option) +;;; any later version. +;;; +;;; This program 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 General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with this program; if not, write to the Free Software +;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +;;; +;;; +;;; Description: +;;; +;;; This package provides functions to define and call internal +;;; drag and drop actions in the emacs. One could start such an +;;; action by clicking with the mouse in the source buffer and +;;; then in the destination buffer. The action could depend on +;;; the points where youve clicked with the mouse, on the state +;;; of the region, the point, the mark and any other properties +;;; of the source and the destination buffers. The actions are +;;; defined by the variable `idd-actions', which is a buffer local +;;; variable. The following is an example for the html-mode: +;;; (defvar html-idd-actions +;;; '((nil (((idd-major-mode-p . dired-mode) +;;; (idd-dired-file-on-line-p . ".*\\.\\(gif\\)\\|\\(jpq\\)")) +;;; hm--html-idd-add-include-image-from-dired-line) +;;; (((idd-major-mode-p . dired-mode) +;;; (idd-dired-no-file-on-line-p . nil)) +;;; hm--html-idd-add-file-link-to-file-on-dired-line) +;;; (((idd-major-mode-p . dired-mode) +;;; (idd-dired-no-file-on-line-p . t)) +;;; hm--html-idd-add-file-link-to-directory-of-buffer) +;;; (((idd-major-mode-p . w3-mode) +;;; (idd-url-at-point-p . t)) +;;; hm--html-idd-add-html-link-from-w3-buffer-point) +;;; (((idd-major-mode-p . w3-mode)) +;;; hm--html-idd-add-html-link-to-w3-buffer) +;;; (((idd-local-file-p . t)) +;;; hm--html-idd-add-file-link-to-buffer))) +;;; Look at the variable `idd-actions' for further descriptions. +;;; +;;; +;;; +;;; Installation: +;;; +;;; Put this file in one of your load path directories. +;;; +;;; Put the following in your .emacs: +;;; (autoload 'idd-mouse-drag-and-drop "internal-drag-and-drop" +;;; "Performs a drag and drop action. +;;; At first you must click on the source and +;;; after that on the destination." +;;; t) +;;; (define-key global-map [(meta button1)] 'idd-mouse-drag-and-drop) +;;; +;;; Define actions in the variable `idd-actions'. +;;; + +(defvar idd-actions nil + "The list with actions, depending on the source and the destination. +The list looks like: + '((<source-specification-1> (<destination-specification-1> <action-1-1>) + (<destination-specification-2> <action-1-2>) + : + ) + (<source-specification-2> (<destination-specification-1> <action-2-1>) + (<destination-specification-2> <action-2-2>) + : + ) + : + ) +The <source-specification> looks like the following: + '([(<specification-type> <value>)]) +with <specification-type> :== idd-minor-mode-p | idd-buffer-name-p + | idd-region-active-p ... + +The <destination-specification> looks like <source-specification>, except +that a valid <specification-type> is also idd-major-mode-p. + +If <source-specification-1> or <destination-specification-1> is set to +nil, then every source or destination matches. `idd-actions' is a +buffer local variable, which should be at least mode depended. So if +the <source-specification-1> is set to nil it says, that the source +buffer must only have a specific mode. But however, it's also possible +to define a general `idd-actions' list, where the source mode is +specified by idd-major-mode-p. + +<action> ist a function, which has two arguments, the specifies the +source and the second the destination.") + +(make-variable-buffer-local 'idd-actions) + +(defun idd-compare-a-specification (source-or-destination + specification) + "Tests if SOURCE-OR-DESTINATION matches the SPECIFICATION. +It returns a value (1 in general) if both are matching or nil." + (eval (list (car specification) + 'source-or-destination + '(cdr specification)))) + +(defun idd-compare-specifications-1 (source-or-destination + specifications + value) + "Internal function of `idd-compare-specifications'. +VALUE is the value of the last matches." + (cond ((not specifications) value) + (t (let ((match (idd-compare-a-specification source-or-destination + (car specifications)))) + (cond ((not match) 0) + (t (idd-compare-specifications-1 source-or-destination + (cdr specifications) + (+ value match)))))))) + +(defun idd-compare-specifications (source-or-destination + specifications) + "Determines how good SOURCE-OR-DESTINATION and SPECIFICATIONS are matching. +A return value of zero means, that they don't match. The higher the +return value the better is the matching." + (cond ((not specifications) 1) + (t (idd-compare-specifications-1 source-or-destination + specifications + 0)))) + +(defun idd-get-action-depending-on-destination (destination + actions-depending-on-dest + source-value + value-action-pair) + "Internal function of `idd-get-action-depending-on-source-and-destination'." + (let ((destination-value (idd-compare-specifications + destination + (car (car actions-depending-on-dest))))) + (cond ((not actions-depending-on-dest) value-action-pair) + ((or (= destination-value 0) + (<= (+ source-value destination-value) (car value-action-pair))) + (idd-get-action-depending-on-destination + destination + (cdr actions-depending-on-dest) + source-value + value-action-pair)) + (t (idd-get-action-depending-on-destination + destination + (cdr actions-depending-on-dest) + source-value + (cons (+ source-value destination-value) + (second (car actions-depending-on-dest)))))))) + +(defun idd-get-action-depending-on-source-and-destination (source + destination + actions + value-action-pair) + "Internal function of `idd-get-action'. +VALUE-ACTION-PAIR is a list like (<value> <action>). +It returns VALUE-ACTION-PAIR, if no other action is found, which has a +value higher than (car VALUE-ACTION-PAIR)." + (let ((source-value (idd-compare-specifications source (car (car actions))))) + (cond ((not actions) value-action-pair) + ((= source-value 0) + (idd-get-action-depending-on-source-and-destination + source + destination + (cdr actions) + value-action-pair)) + (t (idd-get-action-depending-on-source-and-destination + source + destination + (cdr actions) + (idd-get-action-depending-on-destination + destination + (cdr (car actions)) + source-value + value-action-pair)))))) + +(defun idd-get-action (source destination actions) + "Returns the action, which depends on the SOURCE and the DESTINATION. +The list ACTIONS contains all possible actions. Look at the variable +`idd-actions' for a description of the format of this list." + (idd-get-action-depending-on-source-and-destination source + destination + actions + '(0 . nil))) + +(defun idd-get-buffer-url (source-or-destination) + "Returns the URL of the buffer specified by SOURCE-OR-DESTINATION." + (save-excursion + (idd-set-point source-or-destination) + (url-view-url t))) + +(defun idd-get-url-at-point (source-or-destination) + "Returns the URL at the point specified by SOURCE-OR-DESTINATION. +It returns nil, if there is no URL." + (save-excursion + (idd-set-point source-or-destination) + (w3-view-this-url t))) + +(defun idd-url-at-point-p (source-or-destination value) + "Checks if there is an URL at the point of SOURCE-OR-DESTINATION. +If that is t and VALUE is t, or that is nil and VALUE is nil, then 1 +is returned. Otherwise nil is returned." + (if value + (if (idd-get-url-at-point source-or-destination) + 1 + nil) + (if (idd-get-url-at-point source-or-destination) + nil + 1))) + +(defun idd-major-mode-p (source-or-destination mode) + "Checks, if the major mode of SOURCE-OR-DESTINATION is MODE. +It returns 1, if that is t and nil otherwise." + (save-excursion + (set-buffer (cdr (assoc ':buffer source-or-destination))) + (if (eq major-mode mode) + 1 + nil))) + +(defun idd-set-point (source-or-destination) + "Sets the point and buffer to SOURCE-OR-DESTINATION." + (set-buffer (cdr (assoc ':buffer source-or-destination))) + (goto-char (cdr (assoc ':drag-or-drop-point source-or-destination)))) + +(defun idd-set-region (source-or-destination) + "Sets the point, mark and buffer to SOURCE-OR-DESTINATION. +The region is active after this function is called." + (set-buffer (cdr (assoc ':buffer source-or-destination))) + (goto-char (car (cdr (assoc ':region-active source-or-destination)))) + (set-mark (cdr (cdr (assoc ':region-active source-or-destination)))) + (activate-region)) + +(defun idd-get-dired-filename-from-line (source-or-destination) + "Returns the filename form the line in a dired buffer. +The position and the buffer is specified by SOURCE-OR-DESTINATION." + (save-excursion + (idd-set-point source-or-destination) + (dired-get-filename nil t))) + +(defun idd-dired-file-on-line-p (source-or-destination filename-regexp) + "Checks, if the filename on the line match FILENAME-REGEXP. +The function `dired-get-filename' is used, to get the filename from +the SOURCE-OR-DESTINATION. It returns 1, if it matchs or nil." + (let ((case-fold-search t)) + (if (and (idd-get-dired-filename-from-line source-or-destination) + (string-match filename-regexp + (idd-get-dired-filename-from-line + source-or-destination))) + 1 + nil))) + +(defun idd-dired-no-file-on-line-p (source-or-destination value) + "Checks, if a filename is in the dired buffer of SOURCE-OR-DESTINATION. +It returns 1, if a filename is on the line and if VALUE is t, or if +no filename is on the line and VALUE is nil, otherwise it returns +nil. For the test the function `dired-get-filename' is used." + (if (idd-get-dired-filename-from-line source-or-destination) + (if value nil 1) + (if value 1 nil))) + +(autoload 'ange-ftp-ftp-path "ange-ftp" + "Parse PATH according to ange-ftp-path-format (which see). +Returns a list (HOST USER PATH), or nil if PATH does not match the format.") + +(defun idd-get-local-filename (source-or-destination) + "Returns the filename of a local file specified by SOURCE-OR-DESTINATION." + (buffer-file-name (cdr (assoc ':buffer source-or-destination)))) + +(defun idd-get-directory-of-buffer (source-or-destination) + "Returns the directory name assigned to the SOURCE-OR-DESTINATION buffer." + (save-excursion + (idd-set-point source-or-destination) + default-directory)) + +(defun idd-local-file-p (source-or-destination value) + "Checks, if SOURCE-OR-DESTINATION has a file on the local filesystem. +If that is t and VALUE is t, or that is nil and VALUE is nil, then 1 +is returned. Otherwise nil is returned." + (let ((filename (idd-get-local-filename source-or-destination))) + (if (and filename + (not (ange-ftp-ftp-path filename))) + (if value 1 nil) + (if value nil 1)))) + +(defun idd-call-action (action source destination) + "Calls the drag and drop ACTION with its arguments SOURCE and DESTINATION." + (if (> (car action) 0) + (if (symbol-function (cdr action)) + (eval (list (cdr action) 'source 'destination)) + (error "Error: Action %s isn't a valid function!" (cdr action))) + (message "No valid action defined for this source and this destination!"))) + +(defun idd-mouse-drag-and-drop (source-event) + "Performs a drag and drop action. +At first you must click on the source and after that on the destination." + (interactive "@e") + (let ((source (list (cons ':buffer (current-buffer)) + (cons ':drag-or-drop-point + (event-closest-point source-event)) + (cons ':region-active (if (region-active-p) + (cons (point) + (mark)))))) + (destination nil) + (destination-event)) + (if (adapt-xemacsp) + (dispatch-event (next-command-event))) + (setq destination-event + (next-command-event nil "Drag&Drop: Click on the destination!")) + (cond ((button-press-event-p destination-event) + (setq destination (list (cons ':buffer + (event-buffer destination-event)) + (cons ':drag-or-drop-point + (event-closest-point + destination-event)) + (cons ':region-active nil))) + (if (adapt-emacs19p) + (while (not (button-release-event-p (next-command-event))))) + (idd-call-action (idd-get-action source destination idd-actions) + source + destination)) + (t (setq action "Wrong event") nil)))) + + +(provide 'internal-drag-and-drop)