Commits

Anonymous committed e4d0d49

sync with upstream 2.30.1

Comments (0)

Files changed (25)

 test-install
+test-start
 ecb*.html
 patches
 create-patch
+2004-12-01  Klaus Berndl  <klaus.berndl@sdm.de>
+	
+	* Sync with current upstream 2.30.1
+
 2004-09-06  Norbert Koch  <viteno@xemacs.org>
 
 	* Makefile (VERSION): XEmacs package 1.19 released.
 # Boston, MA 02111-1307, USA.
 
 VERSION = 1.19
-AUTHOR_VERSION = 2.27
+AUTHOR_VERSION = 2.30.1
 MAINTAINER = Klaus Berndl <klaus.berndl@sdm.de>
 PACKAGE = ecb
 PKG_TYPE = regular
 	ecb-upgrade.elc ecb-layout-defs.elc ecb-tod.elc silentcomp.elc \
 	ecb-create-layout.elc ecb-examples.elc ecb-autogen.elc ecb-jde.elc \
 	ecb-winman-support.elc ecb-file-browser.elc ecb-method-browser.elc \
-	ecb-semantic-wrapper.elc ecb-compatibility.elc
+	ecb-semantic-wrapper.elc ecb-compatibility.elc \
+	ecb-common-browser.elc
 
 
 EXTRA_SOURCES = NEWS README RELEASE_NOTES
 DATA_19_FILES = $(wildcard ecb-images/directories/height-14/*.xpm)
 DATA_19_DEST = $(PACKAGE)/ecb-images/directories/height-14
 
+DATA_20_FILES = $(wildcard ecb-images/sources/height-14_to_21/*.xpm)
+DATA_20_DEST = $(PACKAGE)/ecb-images/sources/height-14_to_21
+
 
 PRELOADS = -l compile -l ecb-util -l ecb-eshell \
 	-l ecb-layout -l tree-buffer -l esh-mode -l em-dirs -l jde-help \

Makefile.upstream

 
 #CEDET=
 CEDET=c:/Programme/emacs-21/site-lisp/package-development/cedet
-#CEDET=c:/Programme/emacs-21/site-lisp/multi-file-packages/cedet-1.0beta3b
+#CEDET=c:/Programme/emacs-21/site-lisp/multi-file-packages/cedet-1.0beta2b
 
 # -------- Compiling ECB with the semantic < 2.0 -------------------------
 
 
 # For the ECB-maintainers: Change the version-number here and not
 # elsewhere!
-ecb_VERSION=2.27
+ecb_VERSION=2.30.1
 
 include ecb-makedef.mk
 
+* Changes for ECB version 2.30.1
+
+** Enhancement to the automatic option-upgrading mechanism
+   ECB now automatically makes a backup-file of that file which will be
+   modified by storing the upgraded rsp. renamed ECB-options. This backup file
+   gets a unique name by adding a suffix ".before_ecb_<version>" to the name
+   of the modified file. If such a file already exists ECB adds a unique number
+   to the end of the filename to make the filename unique.
+   This is a safety mechanism if something fails during storing the upgraded
+   options, so you never lose the contents of your customization-file!
+    
+** Enhancement to the VC-support
+
+*** Better recomputing of the VC-state of a file when state changed outside
+    With the new check-state-function `ecb-vc-state' the heuristic state is
+    always computed right which is especially useful if the state for a file
+    has been changed outside Emacs (e.g. by checking in from command line or
+    Windows Explorer). This function is now added to the default-value of
+    `ecb-vc-supported-backends' for GNU Emacs.
+
+*** Added out-of-the-box support for VC-system Subversion
+    For this the latest version of the VC-package incl. the library vc-syn.el
+    is needed. Latest CVS Emacs contains this VC-version. The new function
+    `ecb-vc-dir-managed-by-SVN' is now added to the default-value of
+    `ecb-vc-supported-backends'. Thanks for first implementation to Ekkehard
+    G��rlach <ekkehard.goerlach@pharma.novartis.com>.
+
+** Fixed bugs
+
+*** Fixed errors occured at load-time of ECB 2.30
+
+
+
+* Changes for ECB version 2.30
+
+** Enhancements to the file-browser
+
+*** Much better performance of the file-browser display because all
+    time-consuming tasks (like the check if the displayed directories are
+    empty of not) are now performed "stealthy" - means when Emacs is idle.
+    Each stealthy task is interruptable by the user just by hitting any key or
+    clicking the mouse so Emacs/ECB will not be blocked by such tasks; next
+    time Emacs is idle again the interrupted task automatically proceeds from
+    the state it has been interrupted. There is a new macro `defecb-stealthy'
+    which can be used by a user to program own stealthy tasks.
+
+    Currently ECB performs three stealthy tasks:
+
+       Prescann directories for emptyness: Prescann directories and display
+       them as empty or not-empty in the directories-buffer. See the
+       documentation of the option `ecb-prescan-directories-for-emptyness' for
+       a description.
+     
+       File is read only: Check if sourcefile-items of the directories- or
+       sources-buffer are read-only or not. See documentation of the option
+       `ecb-sources-perform-read-only-check'.
+     
+       Version-control-state: Checks the version-control-state of files in
+       directories which are managed by a VC-backend. See the option
+       `ecb-vc-enable-support'.
+
+    There is also a new option `ecb-stealthy-tasks-delay'.
+
+    There are three options which allow excluding certain directories from
+    these stealthy tasks: `ecb-prescan-directories-exclude-regexps',
+    `ecb-read-only-check-exclude-regexps' and last but not least
+    `ecb-vc-directory-exclude-regexps'.
+
+*** ECB is now capable of handling remote paths.
+    "Remote" means file- or directory-paths in the sense of TRAMP, ANGE-FTP or
+    EFS. Such paths can now being added to the option `ecb-source-path' with
+    no limitation compared to "local" paths. Just work with remote-paths in
+    the same manner as with local paths. See also the additional choices of
+    the options `ecb-prescan-directories-for-emptyness',
+    `ecb-sources-perform-read-only-check' and `ecb-vc-enable-support' (new).
+    This new support is tested with the combinations GNU Emacs+TRAMP and
+    XEmacs+EFS but it should (hopefully) also work with all other
+    combinations. Thanks a lot to Tomas Orti for beta-testing!
+
+*** ECB displays the Version-control-state of a file in the tree-buffers.
+    There are four new options `ecb-vc-enable-support',
+    `ecb-vc-supported-backends', `ecb-vc-directory-exclude-regexps' and
+    `ecb-vc-state-mapping' which define if and how ECB should check the state
+    of a sourcefile in a directory managed by a version-control system. By
+    default ECB supports the same VC-backends as the builtin VC-support of
+    Emacs: CVS, RCS and SCCS. But the option `ecb-vc-supported-backends'
+    allows to add support for arbitrary VC-backends (e.g. Clearcase). New
+    image-icons are also included for a cute display of the VC-state in the
+    directories, sources and history-buffer. Thanks to Markus Gritsch
+    <gritsch@iue.tuwien.ac.at> for contributing the icons.
+
+    It's recommended to read the section "Version-control support" in the
+    chapter "Tips and Trick" of the ECB-info-manual!
+
+*** New hook which runs directly after the selected directory has changed.
+    See documentation of `ecb-after-directory-change-hook'.
+    
+** The popup-menu of the methods-browser allows precisely expanding of the
+   current node. This means you can precisely expand a certain node to an
+   exact indentation level relative to the node. This means all subnodes <=
+   this level will be expanded (full recursive expanding is therefore of
+   course also possible) and all subnodes indented deeper than this level will
+   be collapsed - this is very different from using the expand/collapse symbol
+   of a node. For forther details and examples the the manual and the section
+   "Expanding" and here the subsection "Explicit expanding of the current node
+   to a certain level".
+
+** Automatically upgraded ecb-option-settings are now not saved by default.
+   This means that ECB has now the new policy "Never touching the
+   customization-files of a user without asking". The result is a completely
+   redesigned upgraded-options-buffer: Now at the bottom of this buffer
+   (displayed by `ecb-display-upgraded-options') two clickable buttons [Save]
+   and [Cancel] are displayed which give the user the choice between saving
+   the upgraded options for future Emacs-sessions ot just to cancel this
+   buffer. In the latter case ECB has also upgraded the not compatible or
+   renamed options (as listed in the displayed upgraded-options-buffer) but
+   they will be not saved, i.e. no customization-file is touched and the
+   changed and upgraded values will be lost after quiting Emacs.
+
+** With XEmacs ECB temporary sets `progress-feedback-use-echo-area' to t
+   This is necessary because otherwise the progress-display with native
+   widgets modifies the window-sizes of ECB and does not exactly restore the
+   window-sizes as before that progress-display. Deactivating ECB
+   automatically restores the old value of this option.
+   
+** Fixed bugs
+
+*** Fixed resizing of the ecb-windows after opening a file
+    Sometimes (X)Emacs (the behavior has only been reported for XEmacs)
+    resizes the ecb-windows after opening a file by clicking onto a sourcefile
+    or calling `find-file' (or similar functions). This is not a bug of ECB
+    but nevertheless it is annoying for the ECB-users. Therefore ECB has now a
+    workaround which prevents the ecb-windows from resizing. The work around
+    is done via two simple advices of `find-file' and `find-file-other-window'.
+
+*** Fixed a bug in the upgrading feature (command `ecb-download-ecb') which has
+    occured when the user has set a different LOKALE (e.g. "de_DE@euro").
+
+*** Fixed a bug in restoring sizes of the ecb-windows.
+    Now a check will be performed if there are ecb-windows visible. If not
+    nothing will be done (versions < 2.30 have failed in such a case).
+    This bug has prevented ediff from working together with ECB when a
+    compile-window was visible and the user has stored window-sizes for the
+    current layout.
+
+
+
 * Changes for ECB version 2.27
 
 ** The option `ecb-auto-expand-tag-tree-collapse-other' now has three possible
-README for the Emacs Code Browser (ECB) version 2.27
+README for the Emacs Code Browser (ECB) version 2.30.1
 
 
 About
-This file contains some important release-notes for ECB version 2.27
+This file contains some important release-notes for ECB version 2.30.1
 
 General:
 --------

ecb-common-browser.el

+;;; ecb-common-browser.el --- common browsing stuff for  Emacs
+
+;; Copyright (C) 2000 - 2004 Jesper Nordenberg,
+;;                           Klaus Berndl,
+;;                           Kevin A. Burton,
+;;                           Free Software Foundation, Inc.
+
+;; Author: Jesper Nordenberg <mayhem@home.se>
+;;         Klaus Berndl <klaus.berndl@sdm.de>
+;;         Kevin A. Burton <burton@openprivacy.org>
+;; Maintainer: Klaus Berndl <klaus.berndl@sdm.de>
+;; Keywords: browser, code, programming, tools
+;; Created: 2004
+
+;; 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 2, 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
+;; GNU Emacs; see the file COPYING.  If not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;; $Id$
+
+
+;;; History
+;;
+;; For the ChangeLog of this file see the CVS-repository. For a complete
+;; history of the ECB-package see the file NEWS.
+
+;;; Code:
+
+(eval-when-compile
+  (require 'silentcomp))
+
+
+(require 'ecb-util)
+
+(require 'tree-buffer)
+;; (require 'ecb-layout)
+(require 'ecb-mode-line)
+
+;; various loads
+(require 'assoc)
+
+(eval-when-compile
+  ;; to avoid compiler grips
+  (require 'cl))
+
+
+
+(defgroup ecb-tree-buffer nil
+  "General settings related to the tree-buffers of ECB."
+  :group 'ecb
+  :prefix "ecb-")
+
+(defcustom ecb-bucket-node-display '("" "" ecb-bucket-node-face)
+  "*How ECB displays bucket-nodes in a ECB tree-buffer.
+Bucket-nodes have only one job: Nodes with similar properties will be dropped
+into one bucket for such a common property and all these nodes will be added
+as children to the bucket-node. Besides being expandable and collapsable a
+bucket-node has no senseful action assigned. Examples for bucket-nodes are
+\"[+] Variables\", \"[+] Dependencies\" etc. in the Methods-buffer or buckets
+which combine filenames with same extension under a bucket-node with name this
+extension.
+
+This option defines how bucket-node should be displayed. The name of the
+bucket-node is computed by ECB but you can define a prefix, a suffix and a
+special face for the bucket-node
+
+The default are empty prefix/suffix-strings and 'ecb-bucket-node-face'. But
+an alternative can be for example '\(\"[\" \"]\" nil) which means no special
+face and a display like \"[+] [<bucket-name>]\"."
+  :group 'ecb-general
+  :set (function (lambda (symbol value)
+		   (set symbol value)
+		   (ecb-clear-tag-tree-cache)))
+  :type '(list (string :tag "Bucket-prefix" :value "[")
+               (string :tag "Bucket-suffix" :value "]")
+               (choice :tag "Bucket-face" :menu-tag "Bucket-face"
+                       (const :tag "No special face" :value nil)
+                       (face :tag "Face" :value ecb-bucket-node-face)))
+  :initialize 'custom-initialize-default)
+
+(defcustom ecb-use-speedbar-instead-native-tree-buffer nil
+  "*If true then uses speedbar for directories, sources or methods.
+This means that speedbar is integrated in the ECB-frame and is displayed in
+that window normally displaying the standard ECB-directories-buffer,
+ECB-sources-buffer or ECB-methods-buffer.
+
+This option takes effect in all layouts which contain either a directory
+window, a sources window or a method window.
+
+This option can have four valid values:
+- nil: Do not use speedbar \(default)
+- dir: Use speedbar instead of the standard directories-buffer
+- source: Use speedbar instead of the standard sources-buffer
+- method: Use speedbar instead of the standard methods-buffer
+
+Note: For directories and sources a similar effect and usability is available
+by setting this option to nil \(or 'method) and setting
+`ecb-show-sources-in-directories-buffer' to not nil, because this combination
+displays also directories and sources in one window.
+
+`ecb-use-speedbar-instead-native-tree-buffer' is for people who like the
+speedbar way handling directories and source-files or methods and want it in
+conjunction with ECB."
+  :group 'ecb-general
+  :group 'ecb-directories
+  :group 'ecb-sources
+  :group 'ecb-methods
+  :type '(radio (const :tag "Do not use speedbar" :value nil)
+                (const :tag "For directories" :value dir)
+                (const :tag "For sources" :value source)
+                (const :tag "For methods" :value method))
+  :initialize 'custom-initialize-default
+  :set (function (lambda (sym val)
+                   (set sym val)
+                   (if (and (boundp 'ecb-minor-mode) ecb-minor-mode)
+                       (ecb-redraw-layout-full)))))
+
+(defvar ecb-tree-RET-selects-edit-window--internal nil
+  "Only set by customizing `ecb-tree-RET-selects-edit-window' or calling
+`ecb-toggle-RET-selects-edit-window'!
+Do not set this variable directly, it is only for internal uses!")
+
+(defcustom ecb-tree-RET-selects-edit-window
+  '(ecb-directories-buffer-name
+    ecb-sources-buffer-name
+    ecb-methods-buffer-name
+    ecb-history-buffer-name)
+  "*In which tree-buffers RET should finally select an edit-window.
+If one of the symbols `ecb-directories-buffer-name',
+`ecb-sources-buffer-name', `ecb-methods-buffer-name' or
+`ecb-history-buffer-name' is contained in this list then hitting RET in the
+associated tree-buffer selects as last action the right edit-window otherwise
+only the right action is performed \(opening a new source, selecting a method
+etc.) but point stays in the tree-buffer.
+
+A special remark for the `ecb-directories-buffer-name': Of course here the
+edit-window is only selected if the name of the current layout is contained in
+`ecb-show-sources-in-directories-buffer' or if the value of
+`ecb-show-sources-in-directories-buffer' is 'always and the hitted node
+represents a sourcefile \(otherwise this would not make any sense)!
+
+The setting in this option is only the default for each tree-buffer. With
+`ecb-toggle-RET-selects-edit-window' the behavior of RET can be changed fast
+and easy in a tree-buffer without customizing this option, but of course not
+for future Emacs sessions!"
+  :group 'ecb-tree-buffer
+  :set (function (lambda (sym val)
+                   (set sym val)
+                   (setq ecb-tree-RET-selects-edit-window--internal
+                         (ecb-copy-list val))))
+  :type '(set (const :tag "ecb-directories-buffer-name"
+                     :value ecb-directories-buffer-name)
+              (const :tag "ecb-sources-buffer-name"
+                     :value ecb-sources-buffer-name)
+              (const :tag "ecb-methods-buffer-name"
+                     :value ecb-methods-buffer-name)
+              (const :tag "ecb-history-buffer-name"
+                     :value ecb-history-buffer-name)))
+
+(defcustom ecb-tree-indent 4
+  "*Indent size for tree buffer.
+If you change this during ECB is activated you must deactivate and activate
+ECB again to take effect."
+  :group 'ecb-tree-buffer
+  :group 'ecb-most-important
+  :type 'integer)
+
+(defcustom ecb-tree-expand-symbol-before t
+  "*Show the expand symbol before the items in a tree.
+When the expand-symbol is located before the items then the tree looks like:
+
+\[-] ECB
+    \[+] code-save
+    \[-] ecb-images
+        \[-] directories
+
+When located after then the tree looks like:
+
+ECB \[-]
+  code-save \[+]
+  ecb-images \[-]
+    directories \[-]
+
+The after-example above use a value of 2 for `ecb-tree-indent' whereas the
+before-example uses a value of 4.
+
+It is recommended to display the expand-symbol before because otherwise it
+could be that with a deep nested item-structure with and/or with long
+item-names \(e.g. a deep directory-structure with some long
+subdirectory-names) the expand-symbol is not visible in the tree-buffer and
+the tree-buffer has to be horizontal scrolled to expand an item."
+  :group 'ecb-tree-buffer
+  :group 'ecb-most-important
+  :type 'boolean)
+
+
+(defcustom ecb-tree-buffer-style (if ecb-images-can-be-used
+                                     'image
+                                   'ascii-guides)
+  "*The style of the tree-buffers.
+There are three different styles available:
+
+Image-style \(value 'image):
+Very nice and modern - just try it. For this style the options
+`ecb-tree-indent' and `ecb-tree-expand-symbol-before' have no effect!
+Note: GNU Emacs <= 21.3.X for Windows does not support image-display so ECB
+uses always 'ascii-guides even when here 'image is set!
+
+Ascii-style with guide-lines \(value 'ascii-guides):
+\[-] ECB
+ |  \[+] code-save
+ `- \[-] ecb-images
+     |  \[-] directories
+     |   |  \[-] height-15
+     |   |   |  * close.xpm
+     |   |   |  * empty.xpm
+     |   |   |  * leaf.xpm
+     |   |   `- * open.xpm
+     |   |  \[+] height-17
+     |   |  \[+] height-19
+     |   `- \[+] height-21
+     |  \[x] history
+     |  \[x] methods
+     `- \[x] sources
+
+Ascii-style without guide-lines \(value 'ascii-no-guides) - this is the style
+used by ECB <= 1.96:
+\[-] ECB
+    \[+] code-save
+    \[-] ecb-images
+        \[-] directories
+            \[-] height-15
+                * close.xpm
+                * empty.xpm
+                * leaf.xpm
+                * open.xpm
+            \[+] height-17
+            \[+] height-19
+            \[+] height-21
+        \[x] history
+        \[x] methods
+        \[x] sources
+
+With both ascii-styles the tree-layout can be affected with the options
+`ecb-tree-indent' and `ecb-tree-expand-symbol-before'."
+  :group 'ecb-tree-buffer
+  :group 'ecb-most-important
+  :type '(radio (const :tag "Images-style" :value image)
+                (const :tag "Ascii-style with guide-lines" :value ascii-guides)
+                (const :tag "Ascii-style w/o guide-lines" :value ascii-no-guides)))
+
+(defcustom ecb-tree-image-icons-directories
+  (let ((base (concat (if ecb-regular-xemacs-package-p
+                          (format "%s" (locate-data-directory "ecb"))
+                        ecb-ecb-dir)
+                      "ecb-images/")))
+        (append (mapcar (function (lambda (i)
+                                    (if i
+                                        (concat base i))))
+                        '("default/height-17"
+                          "directories/height-17"
+                          "sources/height-14_to_21"
+                          "methods/height-14_to_21"
+                          nil))))
+  "*Directories where the images for the tree-buffer can be found.
+This is a five-element list where:
+1. element: Default directory where the default images for the tree-buffer can
+   be found. It should contain an image for every name of
+   `tree-buffer-tree-image-names'. The name of an image-file must be:
+   \"ecb-<NAME of TREE-BUFFER-TREE-IMAGE-NAMES>.<ALLOWED EXTENSIONS>\".
+2. element: Directory for special images for the Directories-buffer.
+3. element: Directory for special images for the Sources-buffer.
+4. element: Directory for special images for the Methods-buffer.
+5. element: Directory for special images for the History-buffer.
+
+The directories of the elements 2 - 5 are additional image-directories which
+are searched first for images needed for the respective tree-buffer. If the
+image can not be found in this directory then the default-directory \(1.
+element) is searched. If the image can't even be found there the related
+ascii-symbol is used - which is defined in `tree-buffer-tree-image-names'.
+
+All but the first element \(the default directory) can be nil.
+
+ECB comes with images defined in four different heights - so for the most
+senseful font-heights of a tree-buffer a fitting image-size should be
+available. The images reside either in the subdirectory \"ecb-images\" of the
+ECB-installation or - if ECB is installed as regular XEmacs-package - in the
+ECB-etc data-directory \(the directory returned by \(locate-data-directory
+\"ecb\")."
+  :group 'ecb-tree-buffer
+  :type '(list (directory :tag "Full default image-path")
+               (choice :tag "Directories" :menu-tag "Directories"
+                       (const :tag "No special path" :value nil)
+                       (directory :tag "Full image-path for directories"))
+               (choice :tag "Sources" :menu-tag "Sources"
+                       (const :tag "No special path" :value nil)
+                       (directory :tag "Full image-path for sources"))
+               (choice :tag "Methods" :menu-tag "Methods"
+                       (const :tag "No special path" :value nil)
+                       (directory :tag "Full image-path for methods"))
+               (choice :tag "History" :menu-tag "History"
+                       (const :tag "No special path" :value nil)
+                       (directory :tag "Full image-path for history"))))
+
+(defcustom ecb-truncate-lines '(t t t t)
+  "*Truncate lines in ECB buffers.
+If you change this during ECB is activated you must deactivate and activate
+ECB again to take effect."
+  :group 'ecb-tree-buffer
+  :group 'ecb-most-important
+  :type '(list (boolean :tag "Directories buffer")
+               (boolean :tag "Sources buffer")
+               (boolean :tag "Methods buffer")
+               (boolean :tag "History buffer")))
+
+(defcustom ecb-tree-easy-hor-scroll 5
+  "*Scroll step for easy hor. scrolling via mouse-click in tree-buffers.
+XEmacs has horizontal scroll-bars so invisible parts beyond the right
+window-border of a tree-buffer can always made visible very easy.
+
+GNU Emacs does not have hor. scroll-bars so especially with the mouse it is
+quite impossible to scroll smoothly right and left. The functions
+`scroll-left' and `scroll-right' can be annoying and are also not bound to
+mouse-buttons.
+
+If this option is a positive integer S then in all ECB-tree-buffers the keys
+\[M-mouse-1] and \[M-mouse-3] are bound to scrolling left rsp. right with
+scroll-step S - clicking with mouse-1 or mouse-2 onto the edge of the modeline
+has the same effect, i.e. if you click with mouse-1 onto the left \(rsp.
+right) edge of the modeline you will scroll left \(rsp. right). Additionally
+\[C-M-mouse-1] and \[C-M-mouse-3] are bound to scrolling left rsp. right with
+scroll-step `window-width' - 2. Default is a scroll-step of 5. If the value is
+nil then no keys for horizontal scrolling are bound."
+  :group 'ecb-tree-buffer
+  :type '(radio :value 5
+                (const :tag "No hor. mouse scrolling" :value nil)
+                (integer :tag "Scroll step")))
+
+(defcustom ecb-truncate-long-names t
+  "*Truncate long names that don't fit in the width of the ECB windows.
+If you change this during ECB is activated you must deactivate and activate
+ECB again to take effect."
+  :group 'ecb-tree-buffer
+  :group 'ecb-most-important
+  :type 'boolean)
+
+(defcustom ecb-tree-incremental-search 'prefix
+  "*Enable incremental search in the ECB-tree-buffers.
+For a detailed explanation see the online help section \"Working with the
+keyboard in the ECB buffers\". If you change this during ECB is activated you
+must deactivate and activate ECB again to take effect."
+  :group 'ecb-tree-buffer
+  :type '(radio (const :tag "Match only prefix"
+                       :value prefix)
+                (const :tag "Match every substring"
+                       :value substring)
+                (const :tag "No incremental search"
+                       :value nil)))
+
+(defcustom ecb-tree-navigation-by-arrow t
+  "*Enable smart navigation in the tree-windows by horizontal arrow-keys.
+If not nil then the left- and right-arrow keys work in the ECB tree-window in
+the following smart way if onto an expandable node:
++ Left-arrow: If node is expanded then it will be collapsed otherwise point
+  jumps to the next \"higher\" node in the hierarchical tree \(higher means
+  the next higher tree-level or - if no higher level available - the next
+  higher node on the same level).
++ Right-arrow: If node is not expanded then it will be expanded.
+Onto a not expandable node the horizontal arrow-keys go one character in the
+senseful correct direction.
+
+If this option is changed the new value takes first effect after deactivating
+ECB and then activating it again!"
+  :group 'ecb-tree-buffer
+  :type 'boolean)
+
+(defcustom ecb-show-node-info-in-minibuffer '((if-too-long . path)
+                                              (if-too-long . name)
+                                              (always . path)
+                                              (if-too-long . name+type))
+  "*Node info to display in a tree-buffer.
+Define which node info should displayed in a tree-buffer after
+mouse moving over the node or after a shift click onto the node.
+
+For every tree-buffer you can define \"when\" node info should be displayed:
+- always: Node info is displayed by moving with the mouse over a node.
+- if-too-long: Node info is only displayed by moving with the mouse over a
+  node does not fit into the window-width of the tree-buffer window.
+  In the ECB directories buffer this means also if a node is shortend or if
+  the node has an alias \(see `ecb-source-path').
+- shift-click: Node info is only displayed after a shift click with the
+  primary mouse button onto the node.
+- never: Node info is never displayed.
+
+For every tree-buffer you can define what info should be displayed:
++ Directory-buffer:
+  - name: Only the full node-name is displayed.
+  - path: The full-path of the node is displayed.
++ Sources-buffer:
+  - name: Only the full node-name is displayed.
+  - file-info: File infos for this file are displayed.
+  - file-info-full: Fill infos incl. full path for this file are displayed.
++ History-buffer:
+  see Directories-buffer.
++ Methods-buffer:
+  - name: Only the full node name is displayed.
+  - name+type: The full name + the type of the node \(function, class,
+    variable) is displayed.
+
+Do NOT set this option directly via setq but use always customize!"
+  :group 'ecb-tree-buffer
+  :group 'ecb-most-important
+  :set (function (lambda (symbol value)
+                   (set symbol value)
+                   (if (and (boundp 'ecb-minor-mode)
+                            ecb-minor-mode)
+                       (let ((when-list (mapcar (lambda (elem)
+                                                  (car elem))
+                                                value)))
+                         (if (or (member 'if-too-long when-list)
+                                 (member 'always when-list))
+                             (tree-buffer-activate-follow-mouse)
+                           (tree-buffer-deactivate-follow-mouse)
+                           (tree-buffer-deactivate-mouse-tracking))))))
+  :initialize 'custom-initialize-default 
+  :type '(list (cons :tag "* Directories-buffer"
+                     (choice :tag "When"
+                             (const :tag "Always" :value always)
+                             (const :tag "If too long" :value if-too-long)
+                             (const :tag "After shift click" :value shift-click)
+                             (const :tag "Never" :value never))
+                     (choice :tag "What"
+                             (const :tag "Node-name" :value name)
+                             (const :tag "Full path" :value path)))
+               (cons :tag "* Sources-buffer"
+                     (choice :tag "When"
+                             (const :tag "Always" :value always)
+                             (const :tag "If too long" :value if-too-long)
+                             (const :tag "After shift click" :value shift-click)
+                             (const :tag "Never" :value never))
+                     (choice :tag "What"
+                             (const :tag "Node-name" :value name)
+                             (const :tag "File info" :value file-info)
+                             (const :tag "File info \(full path)"
+                                    :value file-info-full)))
+               (cons :tag "* History-buffer"
+                     (choice :tag "When"
+                             (const :tag "Always" :value always)
+                             (const :tag "If too long" :value if-too-long)
+                             (const :tag "After shift click" :value shift-click)
+                             (const :tag "Never" :value never))
+                     (choice :tag "What"
+                             (const :tag "Node-name" :value name)
+                             (const :tag "Full path" :value path)))
+               (cons :tag "* Method-buffer"
+                     (choice :tag "When"
+                             (const :tag "Always" :value always)
+                             (const :tag "If too long" :value if-too-long)
+                             (const :tag "After shift click" :value shift-click)
+                             (const :tag "Never" :value never))
+                     (choice :tag "What"
+                             (const :tag "Node-name" :value name)
+                             (const :tag "Node-name + type" :value name+type)))))
+
+(defun ecb-show-any-node-info-by-mouse-moving-p ()
+  "Return not nil if for at least one tree-buffer showing node info only by
+moving the mouse over a node is activated. See
+`ecb-show-node-info-in-minibuffer'."
+  (let ((when-list (mapcar (lambda (elem)
+                             (car elem))
+                           ecb-show-node-info-in-minibuffer)))
+    (or (member 'if-too-long when-list)
+        (member 'always when-list))))
+
+(defun ecb-show-node-info-index (tree-buffer-name)
+  (cond ((ecb-string= tree-buffer-name ecb-directories-buffer-name)
+         0)
+        ((ecb-string= tree-buffer-name ecb-sources-buffer-name)
+         1)
+        ((ecb-string= tree-buffer-name ecb-history-buffer-name)
+         2)
+        ((ecb-string= tree-buffer-name ecb-methods-buffer-name)
+         3)))
+
+(defun ecb-show-node-info-when (tree-buffer-name)
+  (car (nth (ecb-show-node-info-index tree-buffer-name)
+            ecb-show-node-info-in-minibuffer)))
+
+(defun ecb-show-node-info-what (tree-buffer-name)
+  (cdr (nth (ecb-show-node-info-index tree-buffer-name)
+            ecb-show-node-info-in-minibuffer)))
+
+(defcustom ecb-primary-secondary-mouse-buttons 'mouse-2--C-mouse-2
+  "*Primary- and secondary mouse button for using the ECB-buffers.
+A click with the primary button causes the main effect in each ECB-buffer:
+- ECB Directories: Expanding/collapsing nodes and displaying files in the ECB
+  Sources buffer.
+- ECB sources/history: Opening the file in that edit-window specified by the
+  option `ecb-mouse-click-destination'.
+- ECB Methods: Jumping to the method in that edit-window specified by the
+  option `ecb-mouse-click-destination'.
+
+A click with the primary mouse-button while the SHIFT-key is pressed called
+the POWER-click and does the following \(depending on the ECB-buffer where the
+POWER-click occurs):
++ Directory-buffer: Refreshing the directory-contents-cache \(see
+  `ecb-cache-directory-contents').
++ Sources- and History-buffer: Only displaying the source-contents in the
+  method-buffer but not displaying the source-file in the edit-window.
++ Methods-buffer: Narrowing to the clicked method/variable/ect... \(see
+  `ecb-tag-visit-post-actions'). This works only for sources supported by
+  semantic!
+
+In addition always the whole node-name is displayed in the minibuffer after a
+POWER-click \(for this see `ecb-show-node-info-in-minibuffer').
+
+The secondary mouse-button is for opening \(jumping to) the file in another
+edit-window \(see the documentation `ecb-mouse-click-destination').
+
+The following combinations are possible:
+- primary: mouse-2, secondary: C-mouse-2 \(means mouse-2 while CTRL-key is
+  pressed). This is the default setting.
+- primary: mouse-1, secondary: C-mouse-1
+- primary: mouse-1, secondary: mouse-2
+
+Note: If the tree-buffers are used with the keyboard instead with the mouse
+then [RET] is interpreted as primary mouse-button and [C-RET] as secondary
+mouse-button!
+
+If you change this during ECB is activated you must deactivate and activate
+ECB again to take effect!"
+  :group 'ecb-tree-buffer
+  :group 'ecb-most-important
+  :type '(radio (const :tag "Primary: mouse-2, secondary: Ctrl-mouse-2"
+                       :value mouse-2--C-mouse-2)
+                (const :tag "Primary: mouse-1, secondary: Ctrl-mouse-1"
+                       :value mouse-1--C-mouse-1)
+                (const :tag "Primary: mouse-1, secondary: mouse-2"
+                       :value mouse-1--mouse-2)))
+
+(defcustom ecb-tree-mouse-action-trigger 'button-release
+  "*When the tree-buffer mouse-action should be triggered.
+This option determines the moment a mouse-action in a tree-buffer is
+triggered. This can be either direct after pressing a mouse-button \(value
+'button-press) or not until releasing the mouse-button \(value:
+'button-release).
+
+If you change this during ECB is activated you must deactivate and activate
+ECB again to take effect!"
+  :group 'ecb-tree-buffer
+  :type '(radio (const :tag "After button release" :value button-release)
+                (const :tag "After button press" :value button-press)))
+
+(defcustom ecb-mouse-click-destination 'last-point
+  "*Destination of a mouse-button click.
+Defines in which edit-window \(if splitted) ECB does the \"right\" action
+\(opening a source, jumping to a method/variable etc.) after clicking with a
+mouse-button \(see `ecb-primary-secondary-mouse-buttons') onto a node. There
+are two possible choices:
+- left-top: Does the \"right\" action always in the left/topmost edit-window.
+- last-point: Does the \"right\" action always in that edit-window which had
+  the point before.
+This is if the user has clicked either with the primary mouse-button or
+has activated a popup-menu in the tree-buffer.
+
+A click with the secondary mouse-button \(see again
+`ecb-primary-secondary-mouse-buttons') does the \"right\" action always in
+another edit-window related to the setting in this option: If there are two
+edit-windows then the \"other\" edit-window is used and for more than 2
+edit-windows the \"next\" edit-window is used \(whereas the next edit-window
+of the last edit-window is the first edit-window).
+
+If the edit-window is not splitted this setting has no effect.
+
+Note: If the tree-buffers are used with the keyboard instead with the mouse
+then this option takes effect too because [RET] is interpreted as primary
+mouse-button and [C-RET] as secondary mouse-button!"
+  :group 'ecb-general
+  :group 'ecb-most-important
+  :type '(radio (const :tag "Left/topmost edit-window"
+                       :value left-top)
+                (const :tag "Last edit-window with point"
+                       :value last-point)))
+
+
+(defcustom ecb-common-tree-buffer-after-create-hook nil
+  "*Local hook running at the end of each tree-buffer creation.
+Every function of this hook is called once without arguments direct after
+creating a tree-buffer of ECB and it's local key-map. So for example a function
+could be added which performs calls of `local-set-key' to define new
+key-bindings for EVERY tree-buffer.
+
+The following keys must not be rebind in all tree-buffers:
+- <RET> and all combinations with <Shift> and <Ctrl>
+- <TAB>
+- `C-t'"
+  :group 'ecb-tree-buffer
+  :type 'hook)
+  
+;;====================================================
+;; Internals
+;;====================================================
+
+;; the filename/path cache
+
+(defecb-multicache ecb-filename-cache 500 nil '(FILES-AND-SUBDIRS
+                                                EMPTY-DIR-P
+                                                SOURCES
+                                                VC
+                                                FIXED-FILENAMES
+                                                REMOTE-PATH
+                                                HOST-ACCESSIBLE)
+  "Cache used for the filebrowser to cache all necessary informations
+associated to file- or directory-names.
+
+Currently there are three subcaches managed within this cache:
+
+  FILES-AND-SUBDIRS:
+  
+  Cache for every directory all subdirs and files. This is a cache with
+     key:   <directory>
+     value: \(<file-list> . <subdirs-list>)
+  
+  EMPTY-DIR-P:
+  
+  Cache for every directory if it is empty or not. This is a cache with
+     key:   <directory>
+     value: \(\[nil|t] . <checked-with-show-sources>)
+  
+  SOURCES:
+  
+  Cache for the contents of the buffer `ecb-sources-buffer-name'. This is a
+  cache with
+     key:   <directory>
+     value: \(<full-content> . <filtered-content>)
+  whereas <full-content> is a 3-elem list \(tree-buffer-root <copy of
+  tree-buffer-nodes> buffer-string) for a full \(i.e. all files) cache and
+  <filtered-content> is a 4-elem list \(tree-buffer-root <copy of
+  tree-buffer-nodes> sources-buffer-string <filter>) for a filtered cache
+  where <filter> is a cons-cell \(<filter-regexp> . <filter-display>).
+
+  VC:
+
+  Cache necessary informations for the version-control-support. This is a
+  cache for filenames and directories. In case of a file with
+     key: <filename> of a sourcefile
+     value: \(<state> <check-timestamp> <checked-buffers>)
+  whereas <state> is the that VC-state the file had at time <check-timestamp>.
+  <checked-buffers> is a list of tree-buffer-names for which <state> was
+  checked.
+  In case of a directory with
+     key: <dirname> of a directory
+     value: <vc-state-fcn> or 'NO-VC
+  <vc-state-fcn> is the function used to get the VC-state if <check-timestamp>
+  is older than the most recent modification-timestamp of <filename>.
+
+  FIXED-FILENAMES:
+
+  Cache for fixed filenames which can speedup handling-remote-paths \(like
+  tramp-paths)
+     key: The concatenation of the args PATH and FILENAME of `ecb-fix-filename'.
+     value: The result of `ecb-fix-filename' for these args.
+
+  REMOTE-PATH:
+
+  Cache if a path is a remote path and store its components if yes.
+     key: a path
+     value: 'NOT-REMOTE if not a remote path otherwise the result of
+     `ecb-remote-path'.
+
+  HOST-ACCESSIBLE:
+
+  Cache if a host is accessible or not.
+     key: a host \(e.g. ecb.sourceforge.net)
+     value: \(<timestamp> . <value>) whereas <timestamp> is the cache time of
+     <value> and <value> is either 'NOT-ACCESSIBLE if host is not accessible
+     or t if accessible.
+")
+
+(defun ecb-filename-cache-init ()
+  "Initialize the whole cache for file- and directory-names"
+  (if (ecb-multicache-p 'ecb-filename-cache)
+      (ecb-multicache-clear 'ecb-filename-cache)))
+
+;; directory separator
+
+(defconst ecb-directory-sep-char
+  (if ecb-running-xemacs directory-sep-char ?/))
+
+(defsubst ecb-directory-sep-char (&optional refdir)
+  (if (or (null refdir)
+          (not (ecb-remote-path refdir)))
+      ecb-directory-sep-char
+    ?/))
+
+(defsubst ecb-directory-sep-string (&optional refdir)
+  (char-to-string (ecb-directory-sep-char refdir)))   
+
+;;; ----- Canonical filenames ------------------------------
+
+(defun ecb-fix-path (path)
+  "Fixes an annoying behavior of the native windows-version of XEmacs:
+When PATH contains only a drive-letter and a : then `expand-file-name' does
+not interpret this PATH as root of that drive. So we add a trailing
+`directory-sep-char' and return this new path because then `expand-file-name'
+treats this as root-dir of that drive. For all \(X)Emacs-version besides the
+native-windows-XEmacs PATH is returned."
+  (if (and ecb-running-xemacs
+           (equal system-type 'windows-nt))
+      (if (and (= (length path) 2)
+               (equal (aref path 1) ?:))
+          (concat path (ecb-directory-sep-string))
+        path)
+    path))
+
+;; accessors for the FIXED-FILENAMES-cache
+
+(defsubst ecb-fixed-filename-cache-put (path filename fixed-filename)
+  "Add FIXED-FILENAME for PATH and FILENAME to the FIXED-FILENAMES-cache
+of `ecb-filename-cache'."
+  (ecb-multicache-put-value 'ecb-filename-cache
+                            (concat path filename)
+                            'FIXED-FILENAMES
+                            fixed-filename))
+
+(defsubst ecb-fixed-filename-cache-get (path filename)
+  "Get the cached value for PATH and FILENAME from the FIXED-FILENAMES-cache
+in `ecb-filename-cache'. If no vaue is cached for PATH and FILENAME then nil
+is returned."
+  (ecb-multicache-get-value 'ecb-filename-cache
+                            (concat path filename)
+                            'FIXED-FILENAMES))
+
+(defun ecb-fixed-filename-cache-dump (&optional no-nil-value)
+  "Dump the whole FIXED-FILENAMES-cache. If NO-NIL-VALUE is not nil then these
+cache-entries are not dumped. This command is not intended for end-users of ECB."
+  (interactive "P")
+  (ecb-multicache-print-subcache 'ecb-filename-cache
+                                 'FIXED-FILENAMES
+                                 no-nil-value))
+
+;; TODO: Klaus Berndl <klaus.berndl@sdm.de>: What about the new cygwin-version
+;; of GNU Emacs 21? We have to test if this function and all locations where
+;; `ecb-fix-path' is used work correctly with the cygwin-port of GNU Emacs.
+(silentcomp-defun mswindows-cygwin-to-win32-path)
+(defun ecb-fix-filename (path &optional filename substitute-env-vars)
+  "Normalizes path- and filenames for ECB. If FILENAME is not nil its pure
+filename \(i.e. without directory part) will be concatenated to PATH. The
+result will never end with the directory-separator! If SUBSTITUTE-ENV-VARS is
+not nil then in both PATH and FILENAME env-var substitution is done. If the
+`system-type' is 'cygwin32 then the path is converted to win32-path-style!"
+  (when (stringp path)
+    (or (ecb-fixed-filename-cache-get path filename)
+        (let ((remote-path (ecb-remote-path path))
+              (norm-path nil)
+              (result nil))
+          (if (or (not remote-path)
+                  (ecb-host-accessible-p (nth 1 remote-path)))
+              (progn
+                (setq norm-path (if ecb-running-xemacs
+                                    (cond ((equal system-type 'cygwin32)
+                                           (mswindows-cygwin-to-win32-path
+                                            (expand-file-name path)))
+                                          ((equal system-type 'windows-nt)
+                                           (expand-file-name (ecb-fix-path path)))
+                                          (t (expand-file-name path)))
+                                  (expand-file-name path)))
+                ;; substitute environment-variables
+                (setq norm-path (expand-file-name (if substitute-env-vars
+                                                      (substitute-in-file-name norm-path)
+                                                    norm-path))))
+            (setq norm-path path))
+          ;; For windows systems we normalize drive-letters to downcase
+          (setq norm-path (if (and (member system-type '(windows-nt cygwin32))
+                                   (> (length norm-path) 1)
+                                   (equal (aref norm-path 1) ?:))
+                              (concat (downcase (substring norm-path 0 2))
+                                      (substring norm-path 2))
+                            norm-path))
+          ;; delete a trailing directory-separator if there is any
+          (setq norm-path (if (and (> (length norm-path) 1)
+                                   (= (aref norm-path (1- (length norm-path)))
+                                      (ecb-directory-sep-char path)))
+                              (substring norm-path 0 (1- (length norm-path)))
+                            norm-path))
+          (setq result
+                (concat norm-path
+                        (if (stringp filename)
+                            (concat (when (> (length norm-path) 1)
+                                      ;; currently all protocols like tramp,
+                                      ;; ange-ftp or efs support only not
+                                      ;; windows-remote-hosts ==> we must not
+                                      ;; add a backslash here (would be done
+                                      ;; in case of a native Windows-XEmacs)
+                                      (ecb-directory-sep-string path))
+                                    (file-name-nondirectory (if substitute-env-vars
+                                                                (substitute-in-file-name filename)
+                                                              filename))))))
+          (ecb-fixed-filename-cache-put path filename result)
+          result))))
+
+;; -- end of canonical filenames
+
+(defun ecb-find-optionsym-for-tree-buffer-name (name)
+  (cond ((string= name ecb-directories-buffer-name)
+         'ecb-directories-buffer-name)
+        ((string= name ecb-sources-buffer-name)
+         'ecb-sources-buffer-name)
+        ((string= name ecb-methods-buffer-name)
+         'ecb-methods-buffer-name)
+        ((string= name ecb-history-buffer-name)
+         'ecb-history-buffer-name)
+        (t (error "%s is not an ecb-tree-buffer!" name))))
+
+(defun ecb-toggle-RET-selects-edit-window ()
+  "Toggles if RET in a tree-buffer should finally select the edit-window.
+See also the option `ecb-tree-RET-selects-edit-window'."
+  (interactive)
+  (let ((tree-buffer (ecb-point-in-ecb-tree-buffer)))
+    (if tree-buffer
+        (let ((optionsym (ecb-find-optionsym-for-tree-buffer-name
+                          (buffer-name tree-buffer))))
+          (if (member optionsym
+                      ecb-tree-RET-selects-edit-window--internal)
+              (progn
+                (setq ecb-tree-RET-selects-edit-window--internal
+                      (delete optionsym
+                              ecb-tree-RET-selects-edit-window--internal))
+                (message "RET does not select the edit-window."))
+            (setq ecb-tree-RET-selects-edit-window--internal
+                  (append ecb-tree-RET-selects-edit-window--internal
+                          (list optionsym)))
+            (message "RET selects the edit-window.")))
+      (message "Point must stay in an ECB tree-buffer!"))))
+
+(defun ecb-combine-ecb-button/edit-win-nr (ecb-button edit-window-nr)
+  "Depending on ECB-BUTTON and EDIT-WINDOW-NR return one value:
+- nil if ECB-BUTTON is 1.
+- t if ECB-BUTTON is 2 and the edit-area of ECB is splitted.
+- EDIT-WINDOW-NR if ECB-BUTTON is 3."
+  (cond ((eq ecb-button 1) nil)
+        ((eq ecb-button 2) (ecb-edit-window-splitted))
+        ((eq ecb-button 3) edit-window-nr)))
+
+(defun ecb-get-edit-window (other-edit-window)
+  "Get the correct edit-window. Which one is the correct one depends on the
+value of OTHER-EDIT-WINDOW \(which is a value returned by
+`ecb-combine-ecb-button/edit-win-nr') and `ecb-mouse-click-destination'.
+- OTHER-EDIT-WINDOW is nil: Get the edit-window according to the option
+  `ecb-mouse-click-destination'.
+- OTHER-EDIT-WINDOW is t: Get the next edit-window in the cyclic list of
+  current edit-windows starting either from the left-top-most one or from the
+  last edit-window with point (depends on
+  `ecb-mouse-click-destination').
+- OTHER-EDIT-WINDOW is an integer: Get exactly the edit-window with that
+  number > 0."
+  (let ((edit-win-list (ecb-canonical-edit-windows-list)))
+    (cond ((null other-edit-window)
+           (if (eq ecb-mouse-click-destination 'left-top)
+               (car edit-win-list)
+             ecb-last-edit-window-with-point))
+          ((integerp other-edit-window)
+           (ecb-get-edit-window-by-number other-edit-window edit-win-list))
+          (t
+           (ecb-next-listelem edit-win-list
+                              (if (eq ecb-mouse-click-destination 'left-top)
+                                  (car edit-win-list)
+                                ecb-last-edit-window-with-point))))))
+
+;;====================================================
+;; Mouse callbacks
+;;====================================================
+
+(defun ecb-tree-buffer-node-select-callback (node
+					     mouse-button
+					     shift-pressed
+					     control-pressed
+                                             meta-pressed
+					     tree-buffer-name)
+  "This is the callback-function ecb.el gives to every tree-buffer to call
+when a node has been selected. This function does nothing if the click
+combination is invalid \(see `ecb-interpret-mouse-click'."
+  (let* ((ecb-button-list (ecb-interpret-mouse-click mouse-button
+						     shift-pressed
+						     control-pressed
+                                                     meta-pressed
+						     tree-buffer-name))
+	 (ecb-button (nth 0 ecb-button-list))
+	 (shift-mode (nth 1 ecb-button-list))
+         (meta-mode (nth 2 ecb-button-list))
+         (keyboard-p (equal (nth 3 ecb-button-list) 'keyboard)))
+    ;; we need maybe later that something has clicked in a tree-buffer, e.g.
+    ;; in `ecb-handle-major-mode-visibilty'.
+    (setq ecb-item-in-tree-buffer-selected t)
+    (if (not keyboard-p)
+        (setq ecb-layout-prevent-handle-ecb-window-selection t))
+    ;; first we dispatch to the right action
+    (when ecb-button-list
+      (cond ((ecb-string= tree-buffer-name ecb-directories-buffer-name)
+	     (ecb-directory-clicked node ecb-button nil shift-mode meta-mode))
+	    ((ecb-string= tree-buffer-name ecb-sources-buffer-name)
+	     (ecb-source-clicked node ecb-button nil shift-mode meta-mode))
+	    ((ecb-string= tree-buffer-name ecb-history-buffer-name)
+	     (ecb-history-clicked node ecb-button nil shift-mode meta-mode))
+	    ((ecb-string= tree-buffer-name ecb-methods-buffer-name)
+	     (ecb-method-clicked node ecb-button nil shift-mode meta-mode))
+	    (t nil)))
+
+    ;; now we go back to the tree-buffer but only if all of the following
+    ;; conditions are true:
+    ;; 1. RET is pressed in the tree-buffer
+    ;; 2. The tree-buffer-name is not contained in
+    ;;    ecb-tree-RET-selects-edit-window--internal
+    ;; 3. Either it is not the ecb-directories-buffer-name or
+    ;;    at least `ecb-show-sources-in-directories-buffer-p' is true and the
+    ;;    hitted node is a sourcefile
+    (when (and keyboard-p
+               (not (member (ecb-find-optionsym-for-tree-buffer-name tree-buffer-name)
+                            ecb-tree-RET-selects-edit-window--internal))
+               (or (not (ecb-string= tree-buffer-name ecb-directories-buffer-name))
+                   (and (ecb-show-sources-in-directories-buffer-p)
+                        (= ecb-directories-nodetype-sourcefile
+                           (tree-node-get-type node)))))
+      (ecb-goto-ecb-window tree-buffer-name)
+      (tree-buffer-remove-highlight))))
+
+
+(defun ecb-tree-buffer-node-collapsed-callback (node
+                                                mouse-button
+                                                shift-pressed
+                                                control-pressed
+                                                meta-pressed
+                                                tree-buffer-name)
+  "This is the callback-function ecb.el gives to every tree-buffer to call
+when a node has been collapsed."
+  (let* ((ecb-button-list (ecb-interpret-mouse-click mouse-button
+						     shift-pressed
+						     control-pressed
+                                                     meta-pressed
+						     tree-buffer-name))
+         (keyboard-p (equal (nth 3 ecb-button-list) 'keyboard)))
+    (if (not keyboard-p)
+        (setq ecb-layout-prevent-handle-ecb-window-selection t))))
+
+(defun ecb-tree-buffer-node-expand-callback (node
+					     mouse-button
+					     shift-pressed
+					     control-pressed
+                                             meta-pressed
+					     tree-buffer-name)
+  "This is the callback-function ecb.el gives to every tree-buffer to call
+when a node should be expanded. This function does nothing if the click
+combination is invalid \(see `ecb-interpret-mouse-click')."
+  (let* ((ecb-button-list (ecb-interpret-mouse-click mouse-button
+						     shift-pressed
+						     control-pressed
+                                                     meta-pressed
+						     tree-buffer-name))
+	 (ecb-button (nth 0 ecb-button-list))
+	 (shift-mode (nth 1 ecb-button-list))
+         (meta-mode (nth 2 ecb-button-list))
+         (keyboard-p (equal (nth 3 ecb-button-list) 'keyboard)))
+    (if (not keyboard-p)
+        (setq ecb-layout-prevent-handle-ecb-window-selection t))
+    (when ecb-button-list
+      (cond ((ecb-string= tree-buffer-name ecb-directories-buffer-name)
+	     (ecb-update-directory-node node))
+	    ((ecb-string= tree-buffer-name ecb-sources-buffer-name)
+	     (ecb-source-clicked node ecb-button nil shift-mode meta-mode))
+	    ((ecb-string= tree-buffer-name ecb-history-buffer-name)
+	     (ecb-history-clicked node ecb-button nil shift-mode meta-mode))
+	    ((ecb-string= tree-buffer-name ecb-methods-buffer-name)
+	     nil)
+	    (t nil)))))
+
+(defun ecb-interpret-mouse-click (mouse-button
+                                  shift-pressed
+                                  control-pressed
+                                  meta-pressed
+                                  tree-buffer-name)
+  "Converts the physically pressed MOUSE-BUTTON \(1 = mouse-1, 2 = mouse-2, 0 =
+no mouse-button but the keys RET or TAB) to ECB-mouse-buttons: either primary
+or secondary mouse-button depending on the value of CONTROL-PRESSED and the
+setting in `ecb-primary-secondary-mouse-buttons'. Returns a list
+'\(<ECB-button> <shift-mode> <meta-mode> <device>) where <ECB-button> is
+either 1 \(= primary) or 2 \(= secondary) and <shift-mode> and <meta-mode> are
+non nil if SHIFT-PRESSED rsp. META-PRESSED is non nil. <device> is either
+'mouse or 'keyboard dependent if the uses has used the mouse rsp. the keyboard
+in the tree-buffer. For an invalid and not accepted click combination nil is
+returned.
+
+Note: If MOUSE-BUTTON is 0 \(means no mouse-button but a key like RET or TAB
+was hitted) then CONTROL-PRESSED is interpreted as ECB-button 2.
+
+Currently the fourth argument TREE-BUFFER-NAME is not used here."
+  (if (eq mouse-button 0)
+      (list (if control-pressed 2 1) shift-pressed meta-pressed 'keyboard)
+    (if (and (not (eq mouse-button 1)) (not (eq mouse-button 2)))
+	nil
+      (cond ((eq ecb-primary-secondary-mouse-buttons 'mouse-1--mouse-2)
+	     (if control-pressed
+		 nil
+	       (list mouse-button shift-pressed meta-pressed 'mouse)))
+	    ((eq ecb-primary-secondary-mouse-buttons 'mouse-1--C-mouse-1)
+	     (if (not (eq mouse-button 1))
+		 nil
+	       (list (if control-pressed 2 1) shift-pressed meta-pressed 'mouse)))
+	    ((eq ecb-primary-secondary-mouse-buttons 'mouse-2--C-mouse-2)
+	     (if (not (eq mouse-button 2))
+		 nil
+	       (list (if control-pressed 2 1) shift-pressed meta-pressed 'mouse)))
+	    (t nil)))))
+
+(defun ecb-show-minibuffer-info (node window tree-buffer-name)
+  "Checks if in the minibuffer should be displayed any info about the current
+node in the ECB-window WINDOW for the tree-buffer TREE-BUFFER-NAME only by
+mouse-moving."
+  (let ((when-elem (ecb-show-node-info-when tree-buffer-name)))
+    (or (eq when-elem 'always)
+        (and (eq when-elem 'if-too-long)
+             window
+             (>= (+ (length (tree-node-get-name node))
+                    (tree-node-get-indentlength node))
+                 (window-width window))))))
+
+
+(tree-buffer-defpopup-command ecb-maximize-ecb-window-menu-wrapper
+  "Expand the current ECB-window from popup-menu."
+  (ecb-display-one-ecb-buffer (buffer-name (current-buffer))))
+
+;; stealthy mechanism
+
+(defvar ecb-stealthy-function-list nil
+  "List of functions which ECB runs stealthy. Do not modify this variable!
+This variable is autom. set by the macro `defecb-stealthy'!")
+
+(defvar ecb-stealthy-function-state-alist nil
+  "Alist which stores the state of each function of
+`ecb-stealthy-function-list'. Do not add new items to this variable because
+this is autom. done by the macro `defecb-stealthy'!")
+
+(defun ecb-stealthy-function-list-add (fcn)
+  (add-to-list 'ecb-stealthy-function-list fcn))
+
+(defun ecb-stealthy-function-state-alist-add (fcn)
+  (add-to-list 'ecb-stealthy-function-state-alist
+               (cons fcn 'done)))
+
+(defun ecb-stealthy-function-state-get (fcn)
+  "Getter for `ecb-stealthy-function-state-alist'. Return state for the
+stealthy function FCN."
+  (cdr (assoc fcn ecb-stealthy-function-state-alist)))
+
+(defun ecb-stealthy-function-state-set (fcn state)
+  "Setter for `ecb-stealthy-function-state-alist'. Set STATE for the
+stealthy function FCN. Return STATE."
+  (setcdr (assoc fcn ecb-stealthy-function-state-alist) state))
+
+(defun ecb-stealthy-function-p (fcn)
+  "Return not nil if FCN is a stealthy function defined with
+`defecb-stealthy'."
+  (member fcn ecb-stealthy-function-list))
+
+(defun ecb-stealthy-function-state-init (&optional fcn state)
+  "Reset the state of stealthy functions. If first optional arg FCN is a
+stealthy function then only the state of this function is reset - otherwise
+all stealthy functions of `ecb-stealthy-function-list' are reset. If second
+optional arg STATE is nil then the state will be reset to the special state
+'restart - otherwise to the value STATE."
+  (if (and fcn (ecb-stealthy-function-p fcn))
+      (ecb-stealthy-function-state-set fcn (or state 'restart))
+    (dolist (f ecb-stealthy-function-list)
+      (ecb-stealthy-function-state-set f (or state 'restart)))))
+
+(defmacro defecb-stealthy (name docstring &rest body)
+  "Define a so called stealthy function with NAME. This function will be
+registered by this macro in `ecb-stealthy-function-list' and
+`ecb-stealthy-function-state-alist'. During the evaluation of BODY the
+variable `state' will be bound and initialized with the stealthy state. BODY
+can use and modify `state'. After evaluating BODY `state' will be
+automatically saved so its available at the runtime of this stealthy function.
+BODY will only be evaluated if `state' is not 'done. BODY should be designed
+to be interruptable by the user \(e.g. with `input-pending-p'). If BODY
+completes then BODY has to set `state' to the special value 'done! If BODY has
+been interrupted then `state' can have an arbitrary value which will be autom.
+stored and at next runtime of the stealthy function NAME `state' will be
+initialized with this stored value. If `state' is initialized with the special
+value 'restart then this means the stealthy function should start from scratch
+because an eventually stored state is not longer valid. If the stealthy
+function sets `state' to 'done then this function will first being called
+after the state for this function has been reset to something else than 'done
+\(mostly to 'restart)\; such a reset of the state for a stealthy function can
+be done by any code and must be done via `ecb-stealthy-function-state-init'!"
+  `(progn
+     (unless (fboundp (quote ,name))
+       (ecb-stealthy-function-list-add (quote ,name))
+       (ecb-stealthy-function-state-alist-add (quote ,name)))
+     (eval-and-compile
+       (unless (fboundp (quote ,name))
+         (defun ,name nil
+           ,docstring
+           (let ((state (ecb-stealthy-function-state-get (quote ,name))))
+             (unless (equal state 'done)
+               ,@body)
+             (ecb-stealthy-function-state-set (quote ,name) state)))))))
+  
+(put 'defecb-stealthy 'lisp-indent-function 1)
+
+(defvar ecb-stealthy-update-running nil
+  "Recursion avoidance variable for stealthy performance.")
+
+(defun ecb-stealthy-updates ()
+  "Run all functions in the stealthy function list.
+Each function returns 'done if it completes successfully, or something else if
+interrupted by the user \(i.e. the function has been interrupted by the
+user). If a function is interrupted then `ecb-stealthy-function-list' is
+rotated so the interrupted function is the first element so the nect stealthy
+run starts with this interrupted function."
+  (unless ecb-stealthy-update-running
+    (let ((l ecb-stealthy-function-list)
+          (ecb-stealthy-update-running t))
+      (while (and l (equal 'done (funcall (car l))))
+        (setq l (cdr l)))
+      ;; if l is nil this means all functions have successfully completed -
+      ;; otherwise we ensure that next time we start with the interrupted
+      ;; function.
+      (when l
+        (setq ecb-stealthy-function-list
+              (ecb-rotate ecb-stealthy-function-list (car l)))))))
+
+
+
+;; generation of nodes rsp. of attributes of nodes
+
+;; (save-excursion
+;;   (set-buffer ecb-sources-buffer-name)
+;;   (tree-buffer-find-image "vc-added"))
+
+(defun ecb-generate-node-name (text-name first-chars icon-name name-of-buffer)
+  "Generate a new name from TEXT-NAME by adding an appropriate image according
+to ICON-NAME to the first FIRST-CHARS of TEXT-NAME. If FIRST-CHARS is < 0 then
+a string with length abs\(FIRST-CHARS) is created, the image is applied to
+this new string and this \"image\"-string is added to the front of TEXT-NAME.
+If no image can be found for ICON-NAME then the original TEXT-NAME is
+returned. NAME-OF-BUFFER is the name of the tree-buffer where the resulting
+node-name will be displayed."
+  (let ((image nil))
+    (save-excursion
+      (set-buffer name-of-buffer)
+      (setq image (and icon-name (tree-buffer-find-image icon-name)))
+      (if image
+          (if (> first-chars 0)
+              (tree-buffer-add-image-icon-maybe
+               0 first-chars text-name image)
+            (concat (tree-buffer-add-image-icon-maybe
+                     0 1 (make-string (- first-chars) ? ) image)
+                    text-name))
+        text-name))))
+
+
+(silentcomp-provide 'ecb-common-browser)
+
+;;; ecb-common-browser.el ends here
 
 (require 'ecb-util)
 (require 'ecb-compilation)
+(require 'ecb-common-browser)
 
 (silentcomp-defvar eshell-buffer-name)
 (silentcomp-defun eshell)
 
 (require 'ecb-util)
 (require 'ecb-layout)
+(require 'ecb-common-browser)
 
 
 ;; ---------------------------------------------------------------------------

ecb-file-browser.el

 (require 'ecb-face)
 (require 'ecb-speedbar)
 (require 'ecb-layout)
+(require 'ecb-common-browser)
 
 ;; various loads
 (require 'assoc)
   (require 'silentcomp))
 
 (silentcomp-defun ecb-speedbar-update-contents)
-
-(defvar ecb-path-selected-directory nil
-  "Path to currently selected directory.")
-
-(defvar ecb-path-selected-source nil
-  "Path to currently selected source.")
-
-(defun ecb-file-browser-initialize ()
-  (setq ecb-path-selected-directory nil
-        ecb-path-selected-source nil))
-  
+(silentcomp-defvar vc-cvs-stay-local)
+
 ;;====================================================
 ;; Customization
 ;;====================================================
   :group 'ecb
   :prefix "ecb-")
 
+(defgroup ecb-version-control nil
+  "Settings for the version-control support in the ECB."
+  :group 'ecb
+  :prefix "ecb-")
+
 (defcustom ecb-source-path nil
   "*Paths where to find code sources.
 Each path can have an optional alias that is used as it's display name. If no
-alias is set, the path is used as display name."
+alias is set, the path is used as display name.
+
+Lisp-type of this option: The value must be a list L whereas each element of L
+is either
+- a simple string which has to be the full path of a directory \(this string
+  is displayed in the directory-browser of ECB) or
+- a 2-element list whereas the first element is the full path of a directory
+  \(string) and the second element is an arbitrary alias \(string) for this
+  directory which is then displayed instead of the underlying directory."
   :group 'ecb-directories
   :group 'ecb-most-important
   :initialize 'custom-initialize-default
   :set (function (lambda (symbol value)
-		   (set symbol value)
-		   (if (and ecb-minor-mode
+                   (set symbol value)
+                   (if (and (boundp 'ecb-minor-mode)
+                            ecb-minor-mode
 			    (functionp 'ecb-update-directories-buffer))
 		       (ecb-update-directories-buffer))))
   :type '(repeat (choice :tag "Display type"
 			       (directory :tag "Path")
 			       (string :tag "Alias")))))
 
-
 (defcustom ecb-add-path-for-not-matching-files '(t . nil)
   "*Add path of a file to `ecb-source-path' if not already contained.
 This is done during the auto. windows synchronization which happens if a file
 for the current Emacs session. This option defines two things:
 1. Should only the root-part \(which means for Unix-like systems always '/'
    and for windows-like systems the drive) of the new file be added as
-   source-path to `ecb-source-path' or the whole directory-part?
+   source-path to `ecb-source-path' or the whole directory-part? For
+   remote-files \(e.g. tramp, ange-ftp- or efs-files) the root-part is the
+   complete host-part + the root-dir at that host \(example:
+   /berndl@ecb.sourceforge.net:/ would be the root-part of
+   /berndl@ecb.sourceforge.net:/tmp/test.txt).
 2. Should this path be added for future sessions too?
 
 The value of this option is a cons-cell where the car is a boolean for 1. and
 
 
 (defun ecb-show-sources-in-directories-buffer-p ()
+  "Return not nil if in current layout sources are shown in the
+directories-buffer."
   (cond ((equal ecb-show-sources-in-directories-buffer 'never)
          nil)
         ((equal ecb-show-sources-in-directories-buffer 'always)
               (member ecb-layout-name
                       ecb-show-sources-in-directories-buffer)))))
 
-(defcustom ecb-cache-directory-contents '((".*" . 50))
+(defcustom ecb-cache-directory-contents '(("^/\\([^:/]*@\\)?\\([^@:/]*\\):.*" . 0)
+                                          (".*" . 50))
   "*Cache contents of certain directories.
 This can be useful if `ecb-source-path' contains directories with many files
 and subdirs, especially if these directories are mounted net-drives \(\"many\"
 means here something > 1000, dependent of the speed of the net-connection and
-the machine). For these directories actualizing the sources- and/or directories-
-buffer of ECB \(if displayed in current layout!) can slow down dramatically so
-a caching increases speed a lot.
- 
+the machine). Or if it contains remote-source-paths which means paths in the
+sense of tramp, ange-ftp or efs. For these directories actualizing the
+sources- and/or directories- buffer of ECB \(if displayed in current layout!)
+can slow down dramatically so a caching increases speed a lot.
+
 The value of this option is a list where the each element is a cons-cell and
 looks like:
   \(<dir-regexp> . <filenumber threshold>)
 by using the POWER-click \(see `ecb-primary-secondary-mouse-buttons') in the
 directories-buffer of ECB.
 
+Default-value: ECB caches the contents of all remote directories regardless of
+the size and all other directories if more than 50 entries are contained.
+
 Examples:
 
-A value of \(\(\"/usr/home/john_smith/bigdir*\" . 1000)) means the contents of
+An entry \(\"/usr/home/john_smith/bigdir*\" . 1000) means the contents of
 every subdirectory of the home-directory of John Smith will be cached if the
 directory contains more than 1000 entries and its name begins with \"bigdir\".
 
-A value of \(\(\".*\" . 1000)) caches every directory which has more than 1000
+An entry \(\".*\" . 1000) caches every directory which has more than 1000
 entries.
 
-A value of \(\(\".*\" . 0)) caches every directory regardless of the number of
-entries.
+An entry \(\"^/\\\\\(\[^:/]*@\\\\)?\\\\\(\[^@:/]*\\\\):.*\" . 0) caches every
+remote \(in the sense of tramp, ange-ftp or efs) directory regardless of the
+number of entries.
 
 Please note: If you want your home-dir being cached then you MUST NOT use
 \"~\" because ECB tries always to match full path-names!"
   :group 'ecb-directories
   :type `(repeat (regexp :tag "Directory-regexp")))
 
-(defcustom ecb-prescan-directories-for-emptyness t
+(defcustom ecb-ping-program "ping"
+  "Program to send network test packets to a host.
+See also `ecb-ping-options'."
+  :group 'ecb-directories
+  :type  'string)
+
+(defcustom ecb-ping-options
+  (if (eq system-type 'windows-nt)
+      (list "-n" "1")
+    (list "-c" "1"))
+  "List of options for the ping program.
+These options can be used to limit how many ICMP packets are emitted. Ping is
+used to test if a remote host of a remote path \(e.g. a tramp-, ange-ftp- or
+efs-path) is accessible. See also `ecb-ping-program'."
+  :group 'ecb-directories
+  :type  '(repeat string))
+
+(defcustom ecb-host-accessible-check-valid-time nil
+  "Time in seconds a cached accessible-state of a remote host is valid.
+This option is a list where each element specifies how long for a certain
+remote host the cached ping-state \(i.e. if the host is accessible or not)
+should be valid. During this time-intervall ECB pings such a remote host only
+once, all other checks use the cached value of that real check. But it the
+cached value is older than the value of this option ECB will ping again.
+
+Per default ECB discards after 1 minute the cached ping-state of each remote
+host. But if you are sure that a certain remote host is always accessible
+\(i.e. means in consequence that you are always online when working with ECB
+and remote-paths) then add an entry to this option with a high valid-interval.
+
+Examples: An entry \(\".*sourceforge.*\" . 3600) ensures that all remote hosts
+machting the string \"sourceforge\" will only once pinged during one hour. Or
+\(\".*\" . 300) would ensure that every remote host would be pinged only once
+during 5 minutes."
+  :group 'ecb-directories
+  :type '(repeat (cons (regexp :tag "Remote host regexp")
+                       (integer :tag "Valid interval"))))
+
+(defcustom ecb-prescan-directories-for-emptyness 'unless-remote
   "*Prescan directories for emptyness.
 ECB does this so directories are displayed as empty in the directories-buffer
 even without user-interaction \(i.e. in previous ECB-versions the emptyness of
 a directory has been first checked when the user has clicked onto a
 directory). ECB optimizes this check as best as possible but if a directory
 contains a lot of subdirectories which contain in turn a lot of entries, then
-expanding such a directory or selecting it takes of course more time as
+expanding such a directory or selecting it would take of course more time as
 without this check - at least at the first time \(all following selects of a
 directory uses the cached information if its subdirectories are empty or not).
-Therefore this feature can be switched of via this option."
+Therefore ECB performs this check stealthy \(see `ecb-stealthy-tasks-delay')
+so normally there should no performance-decrease or additional waiting-time
+for the user. There is one exception: For remote directories \(in the sense of
+tramp, ange-ftp, or efs) this check can descrease performance even if
+performed stealthy and interruptable. Therefore this option offers three
+possible settings:
+
+  t: Switch on this feature
+
+  'unless-remote: Switch on this feature but not for remote directories. The
+  term \"remote\" means here directories which are used via tramp, ange-ftp or
+  efs. So mounted directories are counted not as remote directories here even
+  if such a directory is maybe hosted on a remote machine. But normally only
+  directories in a LAN are mounted so there should be no performance-problems
+  with such mounted directories.
+
+  nil: Switch off this feature completely.
+
+The option `ecb-prescan-directories-exclude-regexps' offers are more fine
+granularity to exclude certain directories from this prescan."
   :group 'ecb-directories
-  :type 'boolean)
+  :type '(radio (const :tag "Switch on" :value t)
+                (const :tag "Switch off for remote directories" :value unless-remote)
+                (const :tag "Switch off completely" :value nil)))
+
+(defcustom ecb-prescan-directories-exclude-regexps nil
+  "*Which directories should be excluded from the empty-prescan.
+If a directory matches any of the regexps of this option it will not be
+prescanned for emptyness - This option takes only effect if
+`ecb-prescan-directories-for-emptyness' is not nil."
+  :group 'ecb-directories
+  :type '(repeat (regexp :tag "Directory-regexp")))
+
+(defsubst ecb-directory-should-prescanned-p (dir)
+  "Return not nil if DIR should be prescanned for emptyness.
+The check is performed according to the settings in the options
+`ecb-prescan-directories-for-emptyness' and
+`ecb-prescan-directories-exclude-regexps'."
+  (and (or (equal t ecb-prescan-directories-for-emptyness)
+           (and (equal 'unless-remote ecb-prescan-directories-for-emptyness)
+                (not (ecb-remote-path dir))))
+       (not (ecb-match-regexp-list dir ecb-prescan-directories-exclude-regexps))))
+
+(defcustom ecb-after-directory-change-hook nil
+  "*Hook which run directly after the selected directory has changed.
+This means not onyl after a click onto a directory in the directory-window of
+ECB but it means this hook runs always when the current directory changes
+regardless of the trigger of this change. So for example it runs also when you
+just switches from one buffer to another via `switch-to-buffer' or
+`switch-to-buffer-other-window' and the directory of these filebuffers is
+different but only when auto-synchronizing of the ECB-windows is on (see
+`ecb-window-sync'). It runs not when switching between buffers and the
+associated files reside in the same directory.
+
+Each function added to this hook will be called with two arguments: The
+directory which was current _before_ the directory-change-trigger and the
+directory which was now the current \(i.e. after the trigger).
+
+Example: If you switch from a filebuffer \"~/.emacs\" to a filebuffer
+\"/tmp/test.txt\" then the functions of this hook will be called with the
+two arguments \"~\" and \"/tmp\"."
+  :group 'ecb-directories
+  :type 'hook)
+
+(defcustom ecb-sources-perform-read-only-check 'unless-remote
+  "*Check if source-items in the tree-buffers are read-only.
+If a sourcefile is read-only then it will be displayed with that face set in
+the option `ecb-source-read-only-face'.
+
+Because this check can be take some time if files are used via a mounted
+net-drive ECB performs this check stealthy \(see `ecb-stealthy-tasks-delay')
+so normally there should no performance-decrease or additional waiting-time
+for the user. But to get sure this option offers three choices: t,
+'unless-remote and nil. See `ecb-prescan-directories-for-emptyness' for an
+explanation for these three choices.
+
+The option `ecb-read-only-check-exclude-regexps' offers are more fine
+granularity to exclude the sources of certain directories from the read-only
+state-check."
+  :group 'ecb-sources
+  :group 'ecb-directories
+  :type '(radio (const :tag "Switch on" :value t)
+                (const :tag "Switch off for remote directories" :value unless-remote)
+                (const :tag "Switch off completely" :value nil)))
+
+(defcustom ecb-read-only-check-exclude-regexps nil
+  "*Which directories should be excluded from the sources-read-only-check.
+If a directory matches any of the regexps of this option their sources will
+not be checked if they are writable - This option takes only effect if
+`ecb-sources-perform-read-only-check' is not nil."
+  :group 'ecb-sources
+  :group 'ecb-directories
+  :type '(repeat (regexp :tag "Directory-regexp")))
+
+(defsubst ecb-sources-read-only-check-p (dir)
+  "Return not nil if the sources of DIR should be checked for read-only-state.
+The check is performed according to the settings in the options
+`ecb-sources-perform-read-only-check' and
+`ecb-read-only-check-exclude-regexps'."
+  (and (or (equal t ecb-sources-perform-read-only-check)
+           (and (equal 'unless-remote ecb-sources-perform-read-only-check)
+                (not (ecb-remote-path dir))))
+       (not (ecb-match-regexp-list dir ecb-read-only-check-exclude-regexps))))
 
 (defcustom ecb-directories-buffer-name " *ECB Directories*"
   "*Name of the ECB directory buffer.
 - nil: No sorting, means the most recently used buffers are on the top of the
        history and the seldom used buffers at the bottom.
 See also `ecb-history-sort-ignore-case'."
-  :group 'ecb-sources
+  :group 'ecb-history
   :type '(radio (const :tag "By name"
                        :value name)
                 (const :tag "By extension"
      (ecb-file-popup-vc-next-action "Check In/Out")
      (ecb-file-popup-vc-log "Revision history")
      (ecb-file-popup-vc-annotate "Annotate")
-     (ecb-file-popup-vc-diff "Diff against last version")))
+     (ecb-file-popup-vc-diff "Diff against last version")
+     ("---")
+     (ecb-file-popup-vc-refresh-file "Recompute state for file")
+     (ecb-file-popup-vc-refresh-dir "Recompute state for whole dir")))
   "*Static user extensions for the popup-menu of the sources buffer.
 For further explanations see `ecb-directories-menu-user-extension'.
 
      (ecb-file-popup-vc-next-action "Check In/Out")
      (ecb-file-popup-vc-log "Revision history")
      (ecb-file-popup-vc-annotate "Annotate")
-     (ecb-file-popup-vc-diff "Diff against last version")))
-  "*Static user extensions for the popup-menu of the history buffer.
+     (ecb-file-popup-vc-diff "Diff against last version")
+     ("---")
+     (ecb-file-popup-vc-refresh-file "Recompute state for file")
+     (ecb-file-popup-vc-refresh-all-files "Recompute state for whole history")))
+      "*Static user extensions for the popup-menu of the history buffer.
 For further explanations see `ecb-directories-menu-user-extension'.
 
 The node-argument of a menu-function contains as data the filename of the
   :group 'ecb-history
   :type 'hook)
 
+(defcustom ecb-vc-enable-support 'unless-remote
+  "*Enable support for version-control \(VC) systems.
+If on then in the directories-buffer \(if the value of the option
+`ecb-show-sources-in-directories-buffer' is on for current layout), the
+sources-buffer and the history-buffer all file-items are displayed with an
+appropriate icon in front of the item-name to indicate the VC-state of this
+item. If off then no version-control-state checking is done.
+
+Because this check can be take some time if files are managed by a not local
+Version-control-server ECB performs this check stealthy \(see
+`ecb-stealthy-tasks-delay') so normally there should no performance-decrease
+or additional waiting-time for the user. But to get sure this option offers
+three choices: t, 'unless-remote and nil. See the option
+`ecb-prescan-directories-for-emptyness' for an explanation for these three
+choices.
+
+The option `ecb-vc-directory-exclude-regexps' offers are more fine granularity
+to exclude the sources of certain directories from the VC-state-check.
+
+See `ecb-vc-supported-backends' how to customize the VC-support itself."
+  :group 'ecb-version-control
+  :group 'ecb-sources
+  :type '(radio (const :tag "Switch on" :value t)
+                (const :tag "Switch off for remote directories" :value unless-remote)
+                (const :tag "Switch off completely" :value nil)))
+
+(defcustom ecb-vc-directory-exclude-regexps nil
+  "*Which directories should be excluded from VC-state-check.
+If a directory matches any of the regexps of this option the VC-state of its
+sources will not be checked - This option takes only effect if
+`ecb-vc-enable-support' is not nil."
+  :group 'ecb-version-control
+  :group 'ecb-sources
+  :type '(repeat (regexp :tag "Directory-regexp")))
+
+(defsubst ecb-vc-directory-should-be-checked-p (dir)
+  "Return not nil if the sources of DIR should be checked for VC-state.
+The check is performed according to the settings in the options
+`ecb-vc-enable-support' and `ecb-vc-directory-should-be-checked-p'."
+  (and (or (equal t ecb-vc-enable-support)
+           (and (equal 'unless-remote ecb-vc-enable-support)
+                (not (ecb-remote-path dir))))
+       (not (ecb-match-regexp-list dir ecb-vc-directory-exclude-regexps))))
+
+(defcustom ecb-vc-state-mapping '((up-to-date       . up-to-date)
+                                  (edited           . edited)
+                                  (locally-modified . edited)
+                                  (needs-patch      . needs-patch)
+                                  (needs-checkout   . needs-patch)
+                                  (needs-merge      . needs-merge)
+                                  (unlocked-changes . unlocked-changes)
+                                  (added            . added)
+                                  (locally-added    . added)
+                                  (ignored          . ignored)
+                                  (unknown          . unknown))
+  "*Mapping from VC-state-values of the backends to VC-state-values of ECB.
+ECB understands the following state-values:
+
+  'up-to-date        The working file is unmodified with respect to the
+                     latest version on the current branch, and not locked.
+
+  'edited            The working file has been locally edited by the user. If
+                     locking is used for the file, this state means that
+                     the current version is locked by the calling user.
+
+  'needs-patch       The file has not been edited by the user, but there is
+                     a more recent version on the current branch stored
+                     in the master file.
+
+  'needs-merge       The file has been edited by the user, and there is also
+                     a more recent version on the current branch stored in
+                     the master file. This state can only occur if locking
+                     is not used for the file.
+
+  'unlocked-changes  The current version of the working file is not locked,
+                     but the working file has been changed with respect
+                     to that version. This state can only occur for files
+                     with locking\; it represents an erroneous condition that
+                     should be resolved by the user.
+
+  'added             The working file has already been added/registered to the
+                     VC-system but not yet commited.
+
+  'ignored           The version-control-system ignores this file \(e.g.
+                     because included in a .cvsignore-file in case of CVS).
+
+  'unknown           The state of the file can not be retrieved\; probably the
+                     file is not under a version-control-system.
+
+All state-values a check-vc-state-function of `ecb-vc-supported-backends' can
+return must have a mapping to one of the ECB-state-values listed above. If for
+a certain backend-VC-state no mapping can be found then per default 'edited is
+assumed!
+
+The default value of this option maps already the possible returned
+state-values of `ecb-vc-state', `vc-state' and `vc-recompute-state' \(both GNU
+Emacs) and `vc-cvs-status' \(Xemacs) to the ECB-VC-state-values."
+  :group 'ecb-version-control
+  :group 'ecb-sources
+  :initialize 'custom-initialize-default  
+  :set (function (lambda (sym val)
+                   (set sym val)
+                   (ecb-vc-cache-clear)))
+  :type '(repeat (cons (choice :tag "Backend VC-state"
+                               :menu-tag "Backend VC-state"
+                               (const :tag "up-to-date" :value up-to-date)
+                               (const :tag "edited" :value edited)
+                               (const :tag "locally-modified" :value locally-modified)
+                               (const :tag "needs-patch" :value needs-patch)
+                               (const :tag "needs-checkout" :value needs-checkout)
+                               (const :tag "needs-merge" :value needs-merge)
+                               (const :tag "unlocked-changes" :value unlocked-changes)
+                               (const :tag "added" :value added)
+                               (const :tag "locally-added" :value locally-added)
+                               (const :tag "ignored" :value ignored)
+                               (const :tag "unknown" :value unknown)
+                               (symbol :tag "Other..."))
+                       (choice :tag "ECB VC-state"
+                               :menu-tag "ECB VC-state"
+                               (const :tag "up-to-date" :value up-to-date)
+                               (const :tag "edited" :value edited)
+                               (const :tag "needs-patch" :value needs-patch)
+                               (const :tag "needs-merge" :value needs-merge)
+                               (const :tag "unlocked-changes" :value unlocked-changes)
+                               (const :tag "added" :value added)
+                               (const :tag "ignored" :value ignored)
+                               (const :tag "unknown" :value unknown)))))
+
+(defcustom ecb-vc-supported-backends
+  (if ecb-running-xemacs
+      '((ecb-vc-dir-managed-by-CVS . vc-cvs-status))
+    '((ecb-vc-dir-managed-by-CVS . ecb-vc-state)
+      (ecb-vc-dir-managed-by-RCS . ecb-vc-state)
+      (ecb-vc-dir-managed-by-SCCS . ecb-vc-state)
+      (ecb-vc-dir-managed-by-SVN . ecb-vc-state)))
+  "*Define how to to identify the VC-backend and how to check the state.
+The value of this option is a list containing cons-cells where the car is a
+function which is called to identify the VC-backend for a DIRECTORY and the
+cdr is a function which is called to check the VC-state of the FILEs contained
+in DIRECTORY.
+
+Identify-backend-function: It gets a full directory-name as argument - always
+without ending slash \(rsp. backslash for native Windows-XEmacs) - and has to
+return a unique symbol for the VC-backend which manages that directory \(e.g.
+'CVS for the CVS-system or 'RCS for the RCS-system) or nil if the file is not
+managed by a version-control-system.
+
+Check-vc-state-function: It gets a full filename \(ie. incl. the complete
+directory-part) and has to return a symbol which indicates the VC-state of
+that file. The possible returned values of such a check-vc-state-function have
+to be mapped with `ecb-vc-state-mapping' to the allowed ECB-VC-state values.
+
+ECB runs for a certain DIRECTORY all identify-backend-functions in that order
+they are listed in this option. For the first which returns a value unequal
+nil the associated check-state-function is used to retrieve the VC-state of
+all sourcefiles in that DIRECTORY.
+
+There is no need for the identify-backend-function or the
+check-vc-state-function to cache any state because ECB automatically caches
+internally all necessary informations for directories and files for best
+possible performance.
+
+To prepend ECB from checking the VC-state for any file set
+`ecb-vc-enable-support' to nil.
+
+Default value for GNU Emacs: Support for CVS, RCS, SCCS and Subversion \(for
+the later one the most recent version of the VC-package incl. the vc-svn
+library is needed) is added per default. To identify the VC-backend the
+functions `ecb-vc-managed-by-CVS', `ecb-vc-managed-by-RCS' rsp.
+`ecb-vc-managed-by-SCCS' rsp. `ecb-vc-managed-by-SVN' are used. For all three
+backends the function `ecb-vc-state' of the VC-package is used.
+
+Default value for XEmacs: XEmacs contains only a quite outdated VC-package,
+especially there is no backend-independent check-vc-state-function available
+\(like `vc-state' for GNU Emacs). Only for CVS a check-vc-state-function is
+available: `vc-cvs-status'. Therefore ECB adds per default only support for
+CVS and uses `ecb-vc-managed-by-CVS' rsp. `vc-cvs-status'.
+
+Example for GNU Emacs: If `vc-recompute-state' \(to get real state-values not
+only heuristic ones) should be used to check the state for CVS-managed files
+and `vc-state' for all other backends then an element
+\(ecb-vc-dir-managed-by-CVS . vc-recompute-state) should be added at the
+beginning of this option."
+  :group 'ecb-version-control
+  :group 'ecb-sources
+  :initialize 'custom-initialize-default  
+  :set (function (lambda (sym val)
+                   (set sym val)
+                   (ecb-vc-cache-clear)))
+  :type '(repeat (cons (symbol :tag "Identify-backend-function")
+                       (symbol :tag "Check-state-function"))))
+
+;; Klaus Berndl <klaus.berndl@sdm.de>: For XEmacs a function like the
+;; following could be used to get always fresh state-values:
+
+;; (defun ecb-vc-recompute-state (file)
+;;   ;; Return the cvs status of FILE
+;;   ;; (Status field in output of "cvs status")
+;;   (vc-fetch-master-properties file)
+;;   (vc-file-getprop file 'vc-cvs-status))
 
 ;;====================================================
 ;; Internals
 ;;====================================================
 
+;; constants for the node-types
+(defconst ecb-directories-nodetype-directory 0)
+(defconst ecb-directories-nodetype-sourcefile 1)
+(defconst ecb-directories-nodetype-sourcepath 2)
+(defconst ecb-sources-nodetype-sourcefile 0)
+(defconst ecb-history-nodetype-sourcefile 0)
+
+
+(defvar ecb-path-selected-directory nil
+  "Path to currently selected directory.")
+
+(defvar ecb-path-selected-source nil
+  "Path to currently selected source.")
+
+;; accessors for the FILES-AND-SUBDIRS-cache
+
+(defun ecb-files-and-subdirs-cache-add (dir cached-value)
+  "Add the files and subdirs of DIR to the cache."
+  (ecb-multicache-put-value 'ecb-filename-cache dir 'FILES-AND-SUBDIRS
+                             cached-value))
+
+(defun ecb-files-and-subdirs-cache-get (dir)
+  "Get the files and subdirs of DIR from the cache. Nil if not cached."
+  (ecb-multicache-get-value 'ecb-filename-cache dir 'FILES-AND-SUBDIRS))
+
+(defun ecb-files-and-subdirs-cache-remove (dir)
+  "Remove DIR from the cache."
+  (ecb-multicache-clear-value 'ecb-filename-cache dir 'FILES-AND-SUBDIRS))
+
+(defun ecb-files-and-subdirs-cache-clear ()
+  "Clear the whole FILES-AND-SUBDIRS-cache."
+  (ecb-multicache-clear-subcache 'ecb-filename-cache 'FILES-AND-SUBDIRS))
+
+(defun ecb-files-and-subdirs-cache-dump (&optional no-nil-value)
+  "Dump the whole FILES-AND-SUBDIRS-cache in another window. If NO-NIL-VALUE
+is not nil then these cache-entries are not dumped. This command is not
+intended for end-users of ECB."
+  (interactive "P")
+  (ecb-multicache-print-subcache 'ecb-filename-cache
+                                 'FILES-AND-SUBDIRS
+                                 no-nil-value))
+  
+;; accessors for the EMPTY-DIR-P-cache
+
+(defun ecb-directory-empty-cache-add (dir cached-value)
+  "Add information if DIR is empty or not to the cache."
+  (ecb-multicache-put-value 'ecb-filename-cache dir 'EMPTY-DIR-P
+                             cached-value))
+
+(defun ecb-directory-empty-cache-get (dir)
+  "get information if DIR is empty or not from the cache."
+  (ecb-multicache-get-value 'ecb-filename-cache dir 'EMPTY-DIR-P))
+
+(defun ecb-directory-empty-cache-remove (dir)
+  "Remove DIR from the EMPTY-DIR-P-cache."
+  (ecb-multicache-clear-value 'ecb-filename-cache dir 'EMPTY-DIR-P))
+
+(defun ecb-directory-empty-cache-remove-all (dir)
+  "Remove DIR and all its suddirs from the EMPTY-DIR-P-cache."
+  (ecb-directory-empty-cache-remove dir)
+  ;; now we remove the subdirs
+  (save-match-data
+    (ecb-multicache-mapsubcache
+     'ecb-filename-cache 'EMPTY-DIR-P
+     (function (lambda (key old-value)
+                 (if (string-match (concat "^"
+                                           (regexp-quote dir)
+                                           ".+")
+                                   key)
+                     ;; the directory-key matches DIR so its a cache
+                     ;; subdirectory of DIR so we return nil ==> in fact we
+                     ;; remove this subdir from the empty-dir-p-cache
+                     nil
+                   ;; the directory-key doesn't match DIR so we just return
+                   ;; the old-value, which means in fact that nothing changes
+                   old-value))))))
+
+(defun ecb-directory-empty-cache-clear ()
+  "Clear the whole EMPTY-DIR-P-cache."
+  (ecb-multicache-clear-subcache 'ecb-filename-cache 'EMPTY-DIR-P))
+
+(defun ecb-directory-empty-cache-dump (&optional no-nil-value)
+  "Dump the whole EMPTY-DIR-P-cache. If NO-NIL-VALUE is not nil then these
+cache-entries are not dumped. This command is not intended for end-users of
+ECB."
+  (interactive "P")
+  (ecb-multicache-print-subcache 'ecb-filename-cache
+                                 'EMPTY-DIR-P no-nil-value))
+
+
+;; accessors for the SOURCES-cache
+
+(defun ecb-sources-cache-remove (dir)
+  "Remove the cache-entry for DIR from the cache."
+  (ecb-multicache-clear-value 'ecb-filename-cache dir 'SOURCES))
+
+(defun ecb-sources-cache-add-full (dir cache-elem-full)
+  "Add the full sources-cache CACHE-ELEM-FULL for DIR to the cache. If there
+is already a full cache-entry then replace it. CACHE-ELEM-FULL has to be a
+list as returned by `ecb-sources-cache-get-full'."
+  (ecb-multicache-apply-to-value
+   'ecb-filename-cache dir 'SOURCES
+   (function (lambda (old-cached-value)
+               (if (consp old-cached-value)
+                   (progn
+                     (setcar old-cached-value cache-elem-full)
+                     old-cached-value)
+                 (cons cache-elem-full nil))))))
+
+(defun ecb-sources-cache-add-filtered (dir cache-elem-filtered)
+  "Add the filtered sources-cache CACHE-ELEM-FILTERED for DIR to the cache. If
+there is already a filtered cache-entry then replace it. CACHE-ELEM-FILTERED
+has to be a list as returned by `ecb-sources-cache-get-filtered'."
+  (ecb-multicache-apply-to-value
+   'ecb-filename-cache dir 'SOURCES
+   (function (lambda (old-cached-value)
+               (if (consp old-cached-value)
+                   (progn
+                     (setcdr old-cached-value cache-elem-filtered)
+                     old-cached-value)
+                 (cons nil cache-elem-filtered))))))
+
+(defun ecb-sources-cache-get-full (dir)
+  "Return the full value of a cached-directory DIR, means the 3-element-list
+\(tree-buffer-root, tree-buffer-nodes, sources-buffer-string). If no
+cache-entry for DIR is available then nil is returned."
+  (car (ecb-multicache-get-value 'ecb-filename-cache dir 'SOURCES)))
+
+(defun ecb-sources-cache-get-filtered (dir)
+  "Return the filtered value of a cached-directory DIR, means the
+4-element-list \(tree-buffer-root, tree-buffer-nodes, sources-buffer-string,
+filter-regexp). If no cache-entry for DIR is available then nil is returned."
+  (cdr (ecb-multicache-get-value 'ecb-filename-cache dir 'SOURCES)))
+
+(defun ecb-sources-cache-clear ()
+  "Clear the whole SOURCES-cache."
+  (ecb-multicache-clear-subcache 'ecb-filename-cache 'SOURCES))
+
+(defun ecb-sources-cache-dump (&optional no-nil-value)
+  "Dump the whole SOURCES-cache. If NO-NIL-VALUE is not nil then these
+cache-entries are not dumped. This command is not intended for end-users of
+ECB."
+  (interactive "P")
+  (ecb-multicache-print-subcache 'ecb-filename-cache 'SOURCES no-nil-value))
+
+;; accessors for the VC-cache
+
+(defun ecb-vc-cache-add-file (file state checked-buffer-names)
+  (ecb-multicache-put-value 'ecb-filename-cache file 'VC
+                            (list state
+                                  (ecb-subseq (current-time) 0 2)
+                                  checked-buffer-names))
+  state)
+
+(defun ecb-vc-cache-add-dir (dir backend)
+  (ecb-multicache-put-value 'ecb-filename-cache dir 'VC backend)
+  backend)
+
+(defun ecb-vc-cache-get (file)
+  (ecb-multicache-get-value 'ecb-filename-cache file 'VC))
+
+(defun ecb-vc-cache-remove (file)
+  "Remove FILE from the VC-cache."
+  (ecb-multicache-clear-value 'ecb-filename-cache file 'VC))
+