;;; ecb-create-layout.el --- creating new layouts

;; Copyright (C) 2000 - 2015 Jesper Nordenberg,
;;                           Klaus Berndl,
;;                           Kevin A. Burton,
;;                           Ryan Ware,
;;                           Free Software Foundation, Inc.

;; Author: Klaus Berndl <klaus.berndl@sdm.de>
;;         Ryan Ware <ryan.r.ware@intel.com>
;; Maintainer: Ryan Ware <ryan.r.ware@intel.com>
;; Keywords: browser, code, programming, tools
;; Created: 2002

;; 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$

;;; Commentary:
;;
;; Contains code for easy creating new layouts

;;; 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))

(eval-when-compile
  ;; to avoid compiler grips
  (require 'cl))

(require 'ecb-mode-line)
(require 'ecb-util)
(require 'ecb-compilation)

;; XEmacs stuff
(silentcomp-defvar vertical-divider-map)
(silentcomp-defvar modeline-map)
;; Emacs 21.X stuff
(silentcomp-defvar auto-hscroll-mode)
(silentcomp-defvar before-make-frame-hook)
(silentcomp-defvar after-make-frame-functions)
;; First loaded during activated ECB
(silentcomp-defvar ecb-buildin-layouts)

(defgroup ecb-create-layout nil
  "Settings for creating new ECB-layouts."
  :group 'ecb-layout
  :prefix "ecb-create-layout-")

(defcustom ecb-create-layout-file "~/.ecb-user-layouts.el"
  "*File where all layouts created by `ecb-create-new-layout' are stored."
  :group 'ecb-create-layout
  :type 'file)

(defcustom ecb-create-layout-frame-width 140
  "*Frame width of the layout creation frame."
  :group 'ecb-create-layout
  :type 'integer)

(defcustom ecb-create-layout-frame-height 51
  "*Frame height of the layout creation frame."
  :group 'ecb-create-layout
  :type 'integer)


;; internal vars and consts


(defconst ecb-create-layout-buf-prefix " *ECB-LC-")
(defconst ecb-create-layout-frame-name "Creation of a new ECB-layout")
(defconst ecb-create-layout-all-buf-types
  '("directories" "history" "methods" "sources" "speedbar" "analyse" "symboldef"))

(defconst ecb-create-layout-help-text-left-right
  "
 ECB layout creation mode
 ========================

 This is the help-screen of this mode. The window
 displaying this help text is called the edit-window
 which is neither selectable nor delete-able nor
 split-able in this mode.

 <left/right/up/down-arrow>: Moving around in current
 window C-n, C-p: Go to next/previous window (beside
 the edit-window)

 C-s: Split current window. You will be asked:
      - If \"vertical\" or \"horizontal\" split
      - How to split: \"at-point\", \"half\" or
        \"other\" (i.e. you can specify any fraction
        between 0.1 and 0.9)
      - Which type the current window should be
        \(see description of C-t below).
 C-u: Unsplit, ie. delete current window
 C-t: Give the current window a built-in type
      (\"directories\", \"sources\", \"methods\",
      \"history\" etc.) or any arbitrary user-defined
      type (\"other\"). See the Online-manual!

 C-c: Cancel layout creation. This does not save the
      layout. Deletes this frame.
 C-q: Save current defined layout and quit the layout
      creation. You will be asked for a layout-name.
      With TAB-completion you can get the names already
      in use. You have to choose a new name!
      Deletes this frame.

 There are NO other commands or keys available. ALL
 other keys are disabled in this mode!
")

(defconst ecb-create-layout-help-text-top
  " ECB layout creation mode
 ========================

 This is the help-screen of this mode. The window displaying this help text is called
 the edit-window which is neither selectable nor delete-able nor split-able in this mode.

 <left/right/up/down-arrow>: Moving around in current window
 C-n, C-p: Go to next/previous window (beside the edit-window)

 C-s: Split current window. You will be asked:
      - If \"vertical\" or \"horizontal\" split
      - How to split: \"at-point\", \"half\" or \"other\" (i.e. you can specify any
        fraction between 0.1 and 0.9)
      - Which type the current window should be \(see description of C-t below).
 C-u: Unsplit, ie. delete current window
 C-t: Give the current window a built-in type (\"directories\", \"sources\", \"methods\",
      \"history\" etc.) or any arbitrary user-defined type (\"other\").

 C-c: Cancel layout creation. This does not save the layout. Deletes this frame.
 C-q: Save current defined layout and quit the layout creation. You will be asked for a
      layout-name. With TAB-completion you can get the names already in use.
      You have to choose a new name! Deletes this frame.

 There are NO other commands or keys available. ALL other keys are disabled in this mode!
")

(defconst ecb-create-layout-file-header
     "

;;; Commentary:

;; This file contains all user-defined ECB-layouts created by the command
;; `ecb-create-new-layout'.

;; !!! DO NOT EDIT THIS FILE MANUALLY - IT IS GENERATED BY ECB !!!

")


(defvar ecb-create-layout-frame nil)
(defvar ecb-create-layout-edit-window nil)

(defvar ecb-create-layout-old-global-map nil)
(defvar ecb-create-layout-old-minor-mode-map-alist nil)
(defvar ecb-create-layout-old-hscroll nil)
(defvar ecb-create-layout-old-debug-on-error nil)
(defvar ecb-create-layout-old-frame nil)
(defvar ecb-create-layout-old-vertical-div-map nil)
(defvar ecb-create-layout-old-modeline-map nil)
(defvar ecb-create-layout-old-after-frame-h nil)
(defvar ecb-create-layout-old-before-frame-h nil)

(defvar ecb-create-layout-generated-lisp nil)
(defvar ecb-create-layout-gen-counter 0)

(defvar ecb-create-layout-buf-types nil)

;; can be 'left, 'right, 'top or 'left-right
(defvar ecb-create-layout-type 'left)

(defun ecb-create-layout-initilize ()
  (setq ecb-create-layout-buf-types
        (ecb-copy-list ecb-create-layout-all-buf-types))
  (setq ecb-create-layout-frame nil)
  (setq ecb-create-layout-edit-window nil)
  (setq ecb-create-layout-old-global-map nil)
  (setq ecb-create-layout-old-minor-mode-map-alist nil)
  (setq ecb-create-layout-old-hscroll nil)
  (setq ecb-create-layout-old-frame nil)

  (if ecb-running-xemacs
      (progn
        (setq ecb-create-layout-old-vertical-div-map nil)
        (setq ecb-create-layout-old-modeline-map nil))
    (setq ecb-create-layout-old-after-frame-h nil)
    (setq ecb-create-layout-old-before-frame-h nil))
  
  (setq ecb-create-layout-generated-lisp nil)
  (setq ecb-create-layout-gen-counter 0))

(defvar ecb-create-layout-frame-deleted nil)

(defadvice delete-frame (before ecb-create-layout)
  "Ensure calling `ecb-create-layout-cancel' during deleting the
layout-creation frame. Does nothing for any other other frame!"
  (let ((frame (or (ad-get-arg 0) (selected-frame))))
    (when (ecb-string= (ecb-frame-parameter frame 'name)
                       ecb-create-layout-frame-name)
      (setq ecb-create-layout-frame-deleted t)
      (ecb-create-layout-cancel))))

(defadvice delete-frame (after ecb-create-layout)
  "Ensures correct deleting of the layout-creation frame. Does nothing for any
other other frame!"
  (when ecb-create-layout-frame-deleted
    (setq ecb-create-layout-frame-deleted nil)
    (ecb-activate))
  (ad-disable-advice 'delete-frame 'after 'ecb-create-layout)
  (ad-activate 'delete-frame))
  

(defun ecb-create-layout-frame-ok ()
  "Return not nil if current frame is the `ecb-create-layout-frame'"
  (and ecb-create-layout-frame
       (frame-live-p ecb-create-layout-frame)
       (equal (selected-frame) ecb-create-layout-frame)))

(defun ecb-create-layout-cancel (&rest ignore)
  "Cancel layout-creation without saving the layout."
  (interactive)
  (when (ecb-create-layout-frame-ok)
    (ecb-create-layout-clear-all (ecb-interactive-p))
    (message "ECB Layout Creation canceled - the layout is not saved!")
    (and (ecb-interactive-p) (ecb-activate))))

(defun ecb-create-layout-clear-all (&optional delete-frame)
  "Resets all stuff to state before `ecb-create-new-layout' was called. If
DELETE-FRAME is not nil then the new created frame will be deleted and the
`ecb-create-layout-old-frame' will be selected."
  ;; disabling the advice
  (ad-disable-advice 'delete-frame 'before 'ecb-create-layout)
  (ad-activate 'delete-frame)
  ;; killing all white-space-filled layout-buffers
  (save-match-data
    (dolist (b (buffer-list ecb-create-layout-frame))
      (if (string-match "^ \\*ECB-LC-" (buffer-name b))
          (kill-buffer b))))
  ;; restore the global-map
  (if (keymapp ecb-create-layout-old-global-map)
      (use-global-map ecb-create-layout-old-global-map))
  ;; restore the minor-mode-maps
  (if ecb-create-layout-old-minor-mode-map-alist
      (setq minor-mode-map-alist
            ecb-create-layout-old-minor-mode-map-alist))
  ;; restore horiz. scrolling
  (unless ecb-running-xemacs
    (setq auto-hscroll-mode ecb-create-layout-old-hscroll))
  ;; for XEmacs restore these maps
  (if ecb-running-xemacs
      (progn
        (setq vertical-divider-map ecb-create-layout-old-vertical-div-map)
        (setq modeline-map ecb-create-layout-old-modeline-map))
    ;; before and after making frame stuff
    (setq before-make-frame-hook ecb-create-layout-old-before-frame-h)
    (setq after-make-frame-functions ecb-create-layout-old-after-frame-h))
  ;; restore old debug-on-error
  (setq debug-on-error ecb-create-layout-old-debug-on-error)
  ;; delete the layout-frame and select the ecb-create-layout-old-frame
  (when delete-frame
    (when (and ecb-create-layout-old-frame
               (frame-live-p ecb-create-layout-old-frame))
      (raise-frame ecb-create-layout-old-frame)
      (select-frame ecb-create-layout-old-frame))
    (when (and ecb-create-layout-frame
               (frame-live-p ecb-create-layout-frame))
      (ad-with-originals 'delete-frame
        (delete-frame ecb-create-layout-frame))))
  (setq ecb-create-layout-frame nil))

(defun ecb-create-layout-save-and-quit (&rest ignore)
  "Quit the ECB Layout creation and save the defined layout."
  (interactive)
  (when (ecb-create-layout-frame-ok)
    (if (ecb-create-layout-ready-for-save-p)
        (let ((delete-frame (ecb-interactive-p)))
          ;; if an error occurs during `ecb-create-layout-save-layout' or the
          ;; user hits C-q we must clean the layout creation stuff!
          (unwind-protect
              (ecb-create-layout-save-layout)
            ;; clean the layout creation stuff
            (ecb-create-layout-clear-all delete-frame)
            (message "ECB Layout Creation finished.")
            (ecb-activate)))
      (ecb-error "You must give every ECB-tree-window a type (use C-t)!"))))


(defun ecb-create-layout-ready-for-save-p ()
  "Returns only not nil if all windows in current layout have a type."
  (let ((save-p t))
    (save-excursion
      (dolist (win (ecb-window-list (selected-frame) 0))
        (unless (equal win ecb-create-layout-edit-window)
          (set-buffer (window-buffer win))
          (setq save-p (ecb-create-layout-buffer-type)))))
    save-p))


(defmacro ecb-create-layout-insert-line (line)
  "Insert LINE in current-buffer and adds a newline."
  `(progn
     (insert ,line)
     (insert "\n")))

(defun ecb-create-layout-insert-file-header ()
  (insert (format ";;; %s --- user defined ECB-layouts" ;;
                  (ecb-file-name-nondirectory ecb-create-layout-file)))
  (insert ecb-create-layout-file-header))

(defun ecb-create-layout-save-layout ()
  "Saves current layout in `ecb-create-layout-file'."
  ;; make edit-window the current selected window
  (ecb-create-layout-select-edit-window)
  ;; we need the reversed sequence of the generated code
  (setq ecb-create-layout-generated-lisp
        (nreverse ecb-create-layout-generated-lisp))
  ;; ensure we have load all layouts defined until now
  (ecb-load-layouts)
  ;; now we have the create-code in the right sequence so we can save the new
  ;; layout in the user-layout file
  (let ((layout-name ""))
    ;; a repeat...until-loop
    (while (progn
             ;;the while body
             (setq layout-name
                   (ecb-choose-layout-name (ecb-available-layouts-of-type nil)
                                           nil))
             ;; the while condition
             (ecb-available-layouts-member-p layout-name)))
    (with-temp-file (expand-file-name ecb-create-layout-file)
      (erase-buffer)
      (if (file-readable-p (expand-file-name ecb-create-layout-file))
          (insert-file-contents (expand-file-name ecb-create-layout-file))
        (ecb-create-layout-insert-file-header))
      (goto-char (point-max))
      ;; insert header of the layout-define macro
      (ecb-create-layout-insert-line
       (format "(ecb-layout-define \"%s\" %s nil"
               layout-name
               (symbol-name ecb-create-layout-type)))
      ;; insert all the generated layout-code of the new layout
      (dolist (line ecb-create-layout-generated-lisp)
        (ecb-create-layout-insert-line
         (format "  %s" line)))
      ;; close the new layout-function
      (ecb-create-layout-insert-line "  )"))
    ;; now we load the new layout
    (load-file (expand-file-name ecb-create-layout-file))
    (message "The new layout is saved in %s, loaded and available!"
             ecb-create-layout-file)))

(defun ecb-create-layout-gen-lisp (lisp-statement)
  (setq ecb-create-layout-generated-lisp
        (cons lisp-statement ecb-create-layout-generated-lisp)))

(defun ecb-create-layout-split-ver (&optional fraction)
  (let ((factor (or fraction
                    (/ (float (count-lines (window-start) (point)))
                       (float (- (ecb-window-full-height) 2))))))
    (ecb-split-ver factor t)
    (ecb-create-layout-gen-lisp `(ecb-split-ver ,factor t))
    factor))

(defun ecb-create-layout-split-hor (&optional fraction)
  (let ((factor (or fraction
                    (/ (float (- (point) (ecb-line-beginning-pos)))
                       (float (- (window-width) 3))))))
    (ecb-split-hor factor t)
    (ecb-create-layout-gen-lisp `(ecb-split-hor ,factor t))
    (beginning-of-line)
    factor))

(defun ecb-create-layout-add-to-buf-types (type)
  (when (and (stringp type)
             (member type ecb-create-layout-all-buf-types))
    (add-to-list 'ecb-create-layout-buf-types type)
    (setq ecb-create-layout-buf-types
          (sort ecb-create-layout-buf-types 'ecb-string<))))

(defun ecb-create-layout-remove-from-buf-type (type)
  (when (stringp type)
    (setq ecb-create-layout-buf-types
          (sort (delete type ecb-create-layout-buf-types) 'ecb-string<))))

(defun ecb-create-layout-buffer-type ()
  (get-text-property (point-min) 'ecb-create-layout-type))

(defun ecb-create-layout-buffer-factor ()
  (get-text-property (point-min) 'ecb-create-layout-factor))

(defun ecb-create-layout-set-buffer-type (type)
  (let ((buffer-read-only nil))
    (put-text-property (point-min) (1+ (point-min)) 'ecb-create-layout-type
                       type)))

(defun ecb-create-layout-set-buffer-factor (factor)
  (let ((buffer-read-only nil))
    (put-text-property (point-min) (1+ (point-min)) 'ecb-create-layout-factor
                       factor)))


(defun ecb-create-layout-gen-lisp-for-buffer-type (type)
  (let ((func-sym (intern (format "ecb-set-%s-buffer" type))))
    (ecb-create-layout-gen-lisp
     `(if (fboundp (quote ,func-sym))
          (,func-sym)
        (ecb-set-default-ecb-buffer)))))
  

(defun ecb-create-layout-set-buffer-to-type (&optional type)
  "Give current ECB-buffer a type."
  (interactive)
  (when (ecb-create-layout-frame-ok)
    ;; adding the old buffer type to the available-list
    (ecb-create-layout-add-to-buf-types (or type
                                            (ecb-create-layout-buffer-type)))
    (let ((new-type (or (and (stringp type) type)
                        (ecb-query-string "Type of current ECB-tree-buffer:"
                                          ecb-create-layout-buf-types
                                          "Insert the buffer type"))))
      ;; removing the new buffer type from the available-list
      (ecb-create-layout-remove-from-buf-type new-type)
      (ecb-mode-line-set (buffer-name (current-buffer))
                         (selected-frame)
                         (concat "ECB " new-type) nil t)
      ;; setting the new buffer type in the buffer itself
      (ecb-create-layout-set-buffer-type new-type)
      (when (ecb-interactive-p)
        (ecb-create-layout-gen-lisp-for-buffer-type new-type)
        (ecb-create-layout-next-window))
      new-type)))

(defun ecb-create-layout-select-edit-window ()
  (let ((counter 0))
    (while (not (equal (selected-window) ecb-create-layout-edit-window))
      (other-window 1)
      (setq counter (1+ counter)))
    (ecb-create-layout-gen-lisp `(dotimes (i ,counter)
                                   (other-window 1)
                                   (if (equal (selected-window)
                                              ecb-compile-window)
                                       (other-window 1))))))

(defun ecb-create-layout-split ()
  "Split current window."
  (interactive)
  (when (ecb-create-layout-frame-ok)
    ;; splitting
    (let* ((old-buf-type (ecb-create-layout-buffer-type))
           (split-choices (if (equal ecb-create-layout-type 'top)
                              '("horizontal" "vertical")
                            '("vertical" "horizontal")))
           (split-type (ecb-query-string "Split type:" split-choices))
           (split-method
            (ecb-query-string "Split method:"
                              '("at-point" "half")
                              "Insert a fraction between 0.1 and 0.9"))
           (fraction (cond ((ecb-string= split-method "at-point")
                            nil)
                           ((ecb-string= split-method "half")
                            0.5)
                           ((floatp (string-to-number split-method))
                            (string-to-number split-method))
                           (t 0.5)))
           (real-split-factor
            (if (ecb-string= split-type "horizontal")
                (ecb-create-layout-split-hor fraction)
              (ecb-create-layout-split-ver fraction))))
      ;; creating new fitting buffers
      (ecb-create-layout-new-buffer)
       (save-excursion
         (save-selected-window
           (select-window (next-window))
           (ecb-create-layout-new-buffer)))
      ;; asking for the buffer type
      (ecb-create-layout-set-buffer-factor real-split-factor)
      (ecb-create-layout-gen-lisp-for-buffer-type
       (ecb-create-layout-set-buffer-to-type old-buf-type))
      (ecb-create-layout-next-window))))

(defun ecb-create-layout-forward-char ()
  "Move one character forward."
  (interactive)
  (when (ecb-create-layout-frame-ok)
    (unless (> (- (point) (ecb-line-beginning-pos)) (- (window-width)
                                                       (if ecb-running-xemacs
                                                           3
                                                         2)))
      (call-interactively 'forward-char))))

(defun ecb-create-layout-next-window ()
  "Go to the next window.
This command always goes to the next special ECB-window, i.e. it never selects
the edit-window."
  (interactive)
  (when (ecb-create-layout-frame-ok)
    (let ((steps (if (equal (next-window) ecb-create-layout-edit-window) 2 1)))
      (other-window steps)
      (ecb-create-layout-gen-lisp `(dotimes (i ,steps)
                                     (other-window 1)
                                     (if (equal (selected-window)
                                                ecb-compile-window)
                                         (other-window 1)))))))

(defun ecb-create-layout-previous-window ()
  "Go to the previous window.
This command always goes to the ECB-window preceding current window, i.e. it
never selects the edit-window."
  (interactive)
  (when (ecb-create-layout-frame-ok)
    (let ((steps (if (equal (previous-window (selected-window) 0)
                            ecb-create-layout-edit-window)
                     -2 -1)))
      (other-window steps)
      (ecb-create-layout-gen-lisp `(dotimes (i ,(abs steps))
                                     (other-window -1)
                                     (if (equal (selected-window)
                                                ecb-compile-window)
                                         (other-window -1)))))))

(defun ecb-create-layout-delete-window ()
  "Delete current window."
  (interactive)
  (when (ecb-create-layout-frame-ok)
    (unless (or (equal (selected-window) ecb-create-layout-edit-window)
                (= (length (ecb-window-list nil 0))
                   (if (equal ecb-create-layout-type 'left-right) 3 2)))
      (if (and (member ecb-create-layout-type '(right left-right))
               (equal (previous-window (selected-window) 0)
                      ecb-create-layout-edit-window)
               (> (nth 0 (ecb-window-edges (next-window))) (nth 0 (ecb-window-edges)))
               (= (nth 3 (ecb-window-edges ecb-create-layout-edit-window))
                  (nth 3 (ecb-window-edges))))
          ;; In exactly this window context we can not delete the current
          ;; window because otherwise the edit-window would enlarge and the
          ;; wrong window would be deleted!
          (ecb-error "This window can not be deleted! Delete another one.")
        ;; add the buffer type of the deleted window to the available-list
        (ecb-create-layout-add-to-buf-types (ecb-create-layout-buffer-type))
        (kill-buffer (current-buffer))
        (delete-window)
        (ecb-create-layout-gen-lisp '(delete-window))
        (if (equal (selected-window) ecb-create-layout-edit-window)
            (ecb-create-layout-previous-window))
        ;; add the buffer type of the new bigger window to the available-list
        (ecb-create-layout-add-to-buf-types (ecb-create-layout-buffer-type))
        (kill-buffer (current-buffer))
        (ecb-create-layout-new-buffer)))))

(defvar ecb-create-layout-mode-map nil
  "`ecb-create-layout-mode' key-map.")

(if ecb-create-layout-mode-map
    ()
  (setq ecb-create-layout-mode-map (make-sparse-keymap))
;;  (suppress-key-map ecb-create-layout-mode-map t)

  ;; for minibuffer insertion we need the following
  (dotimes (i 26)
    (define-key ecb-create-layout-mode-map
      (string (+ i 97)) 'self-insert-command))

  (dotimes (i 26)
    (define-key ecb-create-layout-mode-map
      (string (+ i 65)) 'self-insert-command))

  (dotimes (i 10)
    (define-key ecb-create-layout-mode-map
      (string (+ i 48)) 'self-insert-command))

  (define-key ecb-create-layout-mode-map "." 'self-insert-command)
  (define-key ecb-create-layout-mode-map "-" 'self-insert-command)
  
  (if ecb-running-xemacs
      (define-key ecb-create-layout-mode-map (kbd "<BS>")
        'delete-backward-char)
    (define-key ecb-create-layout-mode-map (kbd "<DEL>")
      'backward-delete-char-untabify))

  (define-key ecb-create-layout-mode-map (kbd "C-q")
    'ecb-create-layout-save-and-quit)
  (define-key ecb-create-layout-mode-map (kbd "C-c")
    'ecb-create-layout-cancel)
  (define-key ecb-create-layout-mode-map (kbd "C-u")
    'ecb-create-layout-delete-window)
  (define-key ecb-create-layout-mode-map (kbd "C-s") 'ecb-create-layout-split)
  (define-key ecb-create-layout-mode-map (kbd "C-t")
    'ecb-create-layout-set-buffer-to-type)
  (define-key ecb-create-layout-mode-map (kbd "<left>") 'backward-char)
  (define-key ecb-create-layout-mode-map (kbd "<right>")
    'ecb-create-layout-forward-char)
  (define-key ecb-create-layout-mode-map (kbd "<up>") 'previous-line)
  (define-key ecb-create-layout-mode-map (kbd "<down>") 'next-line)
  (define-key ecb-create-layout-mode-map (kbd "C-n")
    'ecb-create-layout-next-window)
  (define-key ecb-create-layout-mode-map (kbd "C-p")
    'ecb-create-layout-previous-window)
  (set-keymap-parent ecb-create-layout-mode-map nil))


(defun ecb-create-layout-new-buffer (&optional do-not-fill)
  (set-window-dedicated-p (selected-window) nil)
  (switch-to-buffer (generate-new-buffer ecb-create-layout-buf-prefix))
  (erase-buffer)
  (unless do-not-fill
    (dotimes (i (ecb-window-full-height))
      (insert
       (format "%s\n"
               (make-string (- (window-width)
                               (if ecb-running-xemacs 3 1))
                            ?\ )))))
  (goto-char (point-min))
  (ecb-create-layout-mode)
  (set-window-dedicated-p (selected-window) t))



(defun ecb-create-layout-mode ()
  "Major mode for creating new ECB-layouts."
  (setq major-mode 'ecb-create-layout-mode)
  (setq mode-name "ECB Create-Layout")
  (use-local-map ecb-create-layout-mode-map)
  (make-local-variable 'buffer-read-only)
  (ecb-mode-line-set (buffer-name (current-buffer))
                     (selected-frame) "" nil t)
  (setq buffer-read-only t))

(defun ecb-create-layout-init-layout (&optional new)
  (delete-other-windows)
  (ecb-create-layout-new-buffer)
  (when new
    (setq ecb-create-layout-type (intern (ecb-query-string
                                          "Location of the the ECB-tree-windows:"
                                          '("left" "right" "top" "left-right")))))
  (case ecb-create-layout-type
    (left
     (ecb-split-hor ecb-windows-width))
    (right
     (ecb-split-hor (- ecb-windows-width) t))
    (top
     (ecb-split-ver ecb-windows-height))
    (otherwise
     (ecb-split-hor (- (* 0.667 ecb-windows-width)) t)
     (ecb-split-hor (* 0.667 ecb-windows-width) nil t)))
  ;; we set the buffer in the big edit-window
  (ecb-create-layout-new-buffer t)
  ;; now we insert the help in the edit-window
  (let ((buffer-read-only nil))
    (insert (if (equal ecb-create-layout-type 'top)
                ecb-create-layout-help-text-top
              ecb-create-layout-help-text-left-right)))
  (setq ecb-create-layout-edit-window (selected-window))
  (ecb-mode-line-set (buffer-name (current-buffer))
                     (selected-frame) "   ECB edit-window" nil t)
  ;; The edit window must not be dedicated
  (set-window-dedicated-p (selected-window) nil)
  ;; we set the buffer for the (currently unsplitted) ECB-window
  (other-window 1)
  (ecb-create-layout-new-buffer)
  ;; for the left-right type we have to set the other column too
  (when (equal ecb-create-layout-type 'left-right)
    (other-window 1)
    (ecb-create-layout-new-buffer)))


(defun ecb-create-layout-make-frame ()
  "Create a new frame for the layout creation process and return it."
  (if ecb-running-xemacs
      (make-frame `((name . ,ecb-create-layout-frame-name)
                    (minibuffer . t)
                    (user-position . t)
                    (width . ,ecb-create-layout-frame-width)
                    (height . ,ecb-create-layout-frame-height)
                    (default-toolbar-visible-p . nil)
                    (left-toolbar-visible-p . nil)
                    (right-toolbar-visible-p . nil)
                    (top-toolbar-visible-p . nil)
                    (bottom-toolbar-visible-p . nil)
                    (default-gutter-visible-p . nil)
                    (left-gutter-visible-p . nil)
                    (right-gutter-visible-p . nil)
                    (top-gutter-visible-p . nil)
                    (bottom-gutter-visible-p . nil)
                    (has-modeline-p . t)
                    (use-left-overflow . nil)
                    (vertical-scrollbar-visible-p . nil)
                    (horizontal-scrollbar-visible-p . nil)
                    (use-right-overflow . nil)
                    (menubar-visible-p . nil)))
    (make-frame `((name . ,ecb-create-layout-frame-name)
                  (minibuffer . t)
                  (user-position . t)
                  (width . ,ecb-create-layout-frame-width)
                  (height . ,ecb-create-layout-frame-height)
                  (vertical-scroll-bars . nil)
                  (horizontal-scroll-bars . nil)
                  (tool-bar-lines . 0)
                  (menu-bar-lines . 0)))))

;; TODO: Klaus Berndl <klaus.berndl@sdm.de>: Wir m￼ssen ev. ECB vorher
;; deaktivieren, da sonst ein 2. ECB-menu entsteht. Beim C-c oder C-q eben
;; dann wieder aktivieren.
(defun ecb-create-new-layout ()
  "Start interactively layout creating."
  (interactive)

  (ecb-deactivate)
  (ecb-create-layout-initilize)

  ;; before- and after make frame stuff
  (when (not ecb-running-xemacs)
    (setq ecb-create-layout-old-after-frame-h after-make-frame-functions)
    (setq after-make-frame-functions nil)
    (setq ecb-create-layout-old-before-frame-h before-make-frame-hook)
    (setq before-make-frame-hook nil))
    
  ;; saving old frame
  (setq ecb-create-layout-old-frame (selected-frame))

  ;; creating new frame
  (setq ecb-create-layout-frame (ecb-create-layout-make-frame))
  (raise-frame ecb-create-layout-frame)
  (select-frame ecb-create-layout-frame)
  (ad-enable-advice 'delete-frame 'before 'ecb-create-layout)
  (ad-enable-advice 'delete-frame 'after 'ecb-create-layout)
  (ad-activate 'delete-frame)

  ;; global map
  (setq ecb-create-layout-old-global-map (current-global-map))
  (use-global-map ecb-create-layout-mode-map)

  ;; minor-modes map
  (setq ecb-create-layout-old-minor-mode-map-alist minor-mode-map-alist)
  (setq minor-mode-map-alist nil)

  ;; horiz. scrolling
  (unless ecb-running-xemacs
    (setq ecb-create-layout-old-hscroll auto-hscroll-mode)
    (setq auto-hscroll-mode nil))

  ;; for XEmacs modeline- and vertical-divider maps
  (when ecb-running-xemacs
    (setq ecb-create-layout-old-vertical-div-map vertical-divider-map)
    (setq vertical-divider-map nil)
    (setq ecb-create-layout-old-modeline-map modeline-map)
    (setq modeline-map nil))

  ;; debug on error
  (setq ecb-create-layout-old-debug-on-error debug-on-error)
  (setq debug-on-error nil)

  (ecb-create-layout-init-layout t))


(defun ecb-delete-new-layout ()
  "Select a layout-name and delete this layout.
This means the layout-definition is removed from the file
`ecb-create-layout-file' and the layout-function and associated aliases are
unbound."
  (interactive)
  ;; ensure we have load all layouts defined until now
  (ecb-load-layouts)
  (let ((new-layout-list
         (sort (ecb-set-difference (ecb-available-layouts-of-type nil)
                                   (mapcar (function (lambda (elem)
                                                       (car elem)))
                                           ecb-buildin-layouts)
                                   'member)
               'ecb-string<))
        (layout-name nil))
    (if (= (length new-layout-list) 0)
        (ecb-error "There are no layouts to delete!")
      (setq layout-name (ecb-choose-layout-name new-layout-list t)))
    (with-temp-file (expand-file-name ecb-create-layout-file)
      (erase-buffer)
      (if (file-readable-p (expand-file-name ecb-create-layout-file))
          (insert-file-contents (expand-file-name ecb-create-layout-file))
        (ecb-error "This layout is not defined in %s!" ecb-create-layout-file))
      (goto-char (point-min))
      (if (re-search-forward (concat "^(ecb-layout-define +"
                                     "\"" layout-name "\".+$")
                             nil t)
          (progn
            ;; Deleting the layout definition in the file
            ;; `ecb-create-layout-file'.
            (beginning-of-line)
            (delete-region (match-beginning 0)
                           (progn
                             (forward-sexp)
                             (point)))
            (kill-line)
            ;; undefining the function and aliases.
            (ecb-layout-undefine layout-name))
        (ecb-error "This layout is not defined in %s!" ecb-create-layout-file)))))

(defun ecb-create-layout-debug ()
  "Debugging command for the ECB-developers."
  (interactive)
  (message "Layout-Debug: Type: %s, Factor: %s"
           (ecb-create-layout-buffer-type)
           (ecb-create-layout-buffer-factor)))

;; Klaus Berndl <klaus.berndl@sdm.de>: Cause of the magic autostart stuff of
;; the advice-package we must disable at load-time all these advices!!
;; Otherwise would just loading ecb (not activating!) activate each advice
;; AFTER the FIRST usage of our advices!!
(ad-disable-advice 'delete-frame 'after 'ecb-create-layout)
(ad-disable-advice 'delete-frame 'before 'ecb-create-layout)
(ad-activate 'delete-frame)


(silentcomp-provide 'ecb-create-layout)

;; ecb-help.el ends here
