;;; -------------------------------------------------------------------------------------
;;;    DictEdit.lsp v0.2
;;;    Copyright? 2008-06-12
;;;    Irn? Barnard
;;;    Contact: irneb@users.sourceforge.net
;;;
;;;
;;; -------------------------------------------------------------------------------------
;;; License
;;; -------------------------------------------------------------------------------------
;;;    This file is part of Caddons.
;;;
;;;    Caddons 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 3 of the License, or
;;;    (at your option) any later version.
;;;
;;;    Caddons 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 Caddons.  If not, see <http://www.gnu.org/licenses/>.
;;;
;;;
;;; -------------------------------------------------------------------------------------
;;; Disclaimer
;;; -------------------------------------------------------------------------------------
;;;	The following program(s) are provided "as is" and with all faults.
;;;	Irn? Barnard DOES NOT warrant that the operation of the program(s)
;;;	will be uninterrupted and/or error free.
;;;
;;;
;;; -------------------------------------------------------------------------------------
;;; Summary of routines contained in this file
;;; -------------------------------------------------------------------------------------
;;;	Lists the dictionaries contained in the drawing, allows to edit/remove some
;;;
;;;	Revision History:
;;; 0.1   First release
;;; 0.2   Complete rewrite, include dialog inside of LSP file & add error logging.
;;;       Added double click on Display dialog to show nested entities
;;;       Added RawDisplay command to show DXF list of entity
;;;       Added DictDeletePossible to delete all possible dictionaries
;;; -------------------------------------------------------------------------------------
;;; To Do:
;;; -------------------------------------------------------------------------------------

(vl-load-com)

;;; -------------------------------------------------------------------------------------
;;; Global variables to store DictEdit settings
;;; -------------------------------------------------------------------------------------
(setq *editable_dict_items* nil
      *deletable_dict_items* nil
      *editable_dicts* nil
      *deletable_dicts* nil)

;;; -------------------------------------------------------------------------------------
;;; Command to delete all possible dictionaries
;;; -------------------------------------------------------------------------------------
(defun C:DictDeletePossible  (/ dictlst dict func)
  (vla-StartUndoMark (setq doc (vla-get-ActiveDocument (vlax-get-acad-object))))
  (setq dictlst (GetAllDicts)
        default_warn_answer 0)
  (foreach dict  dictlst
    (if (setq func (cdr (assoc (car dict) deletable_dicts)))
      (if (apply func dict)
        (princ (strcat (car dict) " deleted successfully.\n"))
        (princ (strcat (car dict) " not deleted.\n")))
      (princ (strcat (car dict) " not deletable.\n"))))
  (setq default_warn_answer nil)
  (vla-EndUndoMark (setq doc (vla-get-ActiveDocument (vlax-get-acad-object))))
  (princ))

;;; Setup default deletable dictionaries
(progn (defun DictDelete_General  ($dict / subd del)
         (setq subd (cddr $dict)
               del  t)
         (while (and del subd)
           (setq del  (entdel (cdadar subd))
                 subd (cdr subd)))
         (and del (entdel (cdaadr $dict))))
       (setq deletable_dicts
              (mapcar '(lambda (name) (cons name 'DictDelete_General))
                      '("AEC_PROPERTY_SET_DEFS"        "AEC_CLASSIFICATION_SYSTEM_DEFS"
                        "AEC_DISP_REP_CONFIGURATIONS"  "AEC_DISP_REP_SETS"            "AEC_DISP_REPS"
                        "AEC_DISPLAY_PROPS_DEFAULTS"   "AEC_PROPERTY_SET_DEFS"        "AEC_VARS"
                        "ASE_INDEX_DICTIONARY"         "BNS_VARIABLES"                "REVIT_DICTIONARY"
                        "AcAec"                        "MAGI_DATADICT"))))

;;; -------------------------------------------------------------------------------------
;;; Command to view raw data of picked entity
;;; -------------------------------------------------------------------------------------
(defun c:RawDisplay  (/ *error* en ed)
  ;; Error handler
  (defun *error*  (msg)
    (vl-catch-all-apply 'unload_dialog (list *DictEdit_DCL*))
    (setq *DictEdit_DCL* nil)
    (cond ((not msg))
          ((wcmatch (strcase msg) "*EXIT*,*QUIT*,*ABORT*"))
          (t (princ (strcat "*** Error: " msg " ***")) (DictEdit_ErrorLog msg)))
    (princ))
  (if (and (setq en (entsel "\nPick entity to display: ")) (setq ed (entget (car en))))
    (run_dialog_DictEdit_ItemData (strcat "Raw Data - " (vl-prin1-to-string en)) ed t))
  (*error* nil))

;;; -------------------------------------------------------------------------------------
;;; Command to view / delete / edit dictionaries
;;; -------------------------------------------------------------------------------------
(defun c:DictEdit  (/ *error* doc dictlst DE:Disp DE:Dict DE:Item DE:Save DE:Delete DE:ItemEdit DE:ItemDel DE:ItemDisp
                    DE:Data cmdecho)
  ;; Error handler
  (defun *error*  (msg)
    (vl-catch-all-apply 'unload_dialog (list *DictEdit_DCL*))
    (setq *DictEdit_DCL* nil)
    (and cmdecho (setvar "CMDECHO" cmdecho))
    (and doc (vla-EndUndoMark doc))
    (cond ((not msg))
          ((wcmatch (strcase msg) "*EXIT*,*QUIT*,*ABORT*"))
          (t (princ (strcat "*** Error: " msg " ***")) (DictEdit_ErrorLog msg)))
    (princ))
  ;; Initialize sysvars
  (vla-StartUndoMark (setq doc (vla-get-ActiveDocument (vlax-get-acad-object))))
  (setq cmdecho (getvar "CMDECHO"))
  (setvar "CMDECHO" 0)
  (setq dictlst (GetAllDicts))
  ;; Function to display Dictionary data
  (defun DE:Data  (/ dnum)
    (if (and (/= (setq dnum (get_tile "dicts")) "") (setq dnum (nth (atoi dnum) dictlst)))
      (run_dialog_DictEdit_ItemData (strcat "Raw Data - " (car dnum)) (cadr dnum) nil)))
  ;; Function to display Item data
  (defun DE:ItemDisp  (/ dnum inum d val)
    (if (and (/= (setq dnum (get_tile "dicts")) "")
             (setq dnum (nth (atoi dnum) dictlst))
             (/= (setq inum (get_tile "items")) "")
             (setq inum (nth (atoi inum) (cddr dnum))))
      (run_dialog_DictEdit_ItemData (strcat "Raw Data - " (car inum)) (cdr inum) nil)))
  ;; Function to select item
  (defun DE:Item  (inum / dnum dict item)
    (setq dnum (get_tile "dicts"))
    (if (and inum (/= inum "") dnum (/= dnum ""))
      (progn (mode_tile "dispitem" 0)
             (if (and (setq dict (nth (atoi dnum) dictlst)) (setq item (nth (atoi inum) (cddr dict))))
               (progn (if (assoc (cdr (assoc 0 (cdr item))) editable_dict_items)
                        (mode_tile "edtitem" 0)
                        (mode_tile "edtitem" 1))
                      (if (assoc (cdr (assoc 0 (cdr item))) deletable_dict_items)
                        (mode_tile "delitem" 0)
                        (mode_tile "delitem" 1)))
               (progn (mode_tile "delitem" 1) (mode_tile "edtitem" 1))))
      (progn (mode_tile "delitem" 1) (mode_tile "edtitem" 1) (mode_tile "dispitem" 1))))
  ;; Function to view dictionary details
  (defun DE:Dict  (dnum / dict item)
    (if (and dnum (/= dnum ""))
      (progn (setq dict (nth (atoi dnum) dictlst))
             (set_tile "name" (car dict))
             (if (assoc 280 (cadr dict))
               (progn (set_tile "owned" (itoa (cdr (assoc 280 (cadr dict))))) (mode_tile "owned" 0))
               (mode_tile "owned" 1))
             (if (assoc 281 (cadr dict))
               (progn (set_tile "duplicate" (itoa (cdr (assoc 281 (cadr dict))))) (mode_tile "duplicate" 0))
               (mode_tile "duplicate" 1))
             (start_list "items" 3)
             (foreach item (cddr dict) (add_list (car item)))
             (end_list)
             (if (> (length dict) 2)
               (mode_tile "items" 0)
               (mode_tile "items" 1))
             (set_tile "items" "")
             (DE:Item "")
             (if (assoc (car dict) editable_dicts)
               (mode_tile "save" 0)
               (mode_tile "save" 1))
             (if (assoc (car dict) deletable_dicts)
               (mode_tile "delete" 0)
               (mode_tile "delete" 1))
             (mode_tile "disp" 0))
      (progn (set_tile "name" "")
             (set_tile "owned" "")
             (set_tile "duplicate" "")
             (start_list "items" 3)
             (end_list)
             (set_tile "items" "")
             (DE:Item "")
             (mode_tile "owned" 1)
             (mode_tile "duplicate" 1)
             (mode_tile "items" 1)
             (mode_tile "delitem" 1)
             (mode_tile "edtitem" 1)
             (mode_tile "dispitem" 1)
             (mode_tile "save" 1)
             (mode_tile "delete" 1)
             (mode_tile "disp" 1))))
  ;; Function to re-display
  (defun DE:Disp  (dnum inum / dict)
    (start_list "dicts" 3)
    (foreach dict dictlst (add_list (car dict)))
    (end_list)
    (if (> (length dictlst) 0)
      (mode_tile "dicts" 0)
      (mode_tile "dicts" 1))
    (if dnum
      (set_tile "dicts" dnum)
      (set_tile "dicts" ""))
    (DE:Dict dnum)
    (if inum
      (set_tile "items" inum)
      (set_tile "items" ""))
    (DE:Item inum))
  ;; Function for saving edits of Dictionary
  (defun DE:Save  (/ dnum dict func)
    (if
      (and (setq dnum (get_tile "dicts"))
           (/= dnum "")
           (setq dict (nth (atoi dnum) dictlst))
           (setq func (cdr (assoc (car dict) editable_dicts)))
           (= 1
              (WarnMsg
                (strcat "You're about to overwrite " (car dict) "'s raw data. Are you sure you want to do this?")))
           (apply func (list (cadr dict) (get_tile "owned") (get_tile "duplicate"))))
       (progn (setq dictlst (GetAllDicts)) (DE:Disp dnum ""))))
  ;; Function for deleting Dictionary
  (defun DE:Delete  (/ dnum dict func)
    (if
      (and (setq dnum (get_tile "dicts"))
           (/= dnum "")
           (setq dict (nth (atoi dnum) dictlst))
           (setq func (cdr (assoc (car dict) deletable_dicts)))
           (= 1
              (WarnMsg
                (strcat "You're about to delete all " (car dict) "'s raw data. Are you sure you want to do this?")))
           (apply func (list (cadr dict))))
       (progn (setq dictlst (GetAllDicts))
              (if (setq dict (nth (atoi dnum) dictlst))
                (DE:Disp dnum "")
                (DE:Disp "" "")))))
  ;; Function for editing items of Dictionary
  (defun DE:ItemEdit  (/ dnum dict inum item func)
    (if (and (setq dnum (get_tile "dicts"))
             (/= dnum "")
             (setq dict (nth (atoi dnum) dictlst))
             (setq inum (get_tile "items"))
             (/= inum "")
             (setq item (nth (atoi inum) (cddr dict)))
             (setq func (cdr (assoc (cdr (assoc 0 (cdr item))) deletable_dict_items)))
             (apply func (list (cadr dict) item)))
      (progn (apply func (list (cadr dict) item)) (setq dictlst (GetAllDicts)) (DE:Disp dnum inum))))
  ;; Function for deleting items of Dictionary
  (defun DE:ItemDel  (/ dnum dict inum item func)
    (if (and (setq dnum (get_tile "dicts"))
             (/= dnum "")
             (setq dict (nth (atoi dnum) dictlst))
             (setq inum (get_tile "items"))
             (/= inum "")
             (setq item (nth (atoi inum) (cddr dict)))
             (setq func (cdr (assoc (cdr (assoc 0 (cdr item))) deletable_dict_items)))
             (= 1
                (WarnMsg (strcat "You're about to delete "
                                 (car dict)
                                 "'s  - item "
                                 (car item)
                                 ". Are you sure you want to do this?")))
             (apply func (list (cadr dict) item)))
      (progn (setq dictlst (GetAllDicts))
             (if (setq dict (nth (atoi dnum) dictlst))
               (if (setq item (nth (atoi inum) dict))
                 (DE:Disp dnum inum)
                 (DE:Disp dnum ""))
               (DE:Disp "" "")))))
  ;; Clean exit with reset of sysvars
  (run_dialog_DictEdit_ListDict
    '(("disp" nil "(DE:Data)")
      ("dispitem" nil "(DE:ItemDisp)")
      ("items" nil "(DE:Item $value)")
      ("dicts" nil "(DE:Dict $value)")
      ("save" nil "(DE:Save)")
      ("delete" nil "(DE:Delete)")
      ("edtitem" nil "(DE:ItemEdit)"))
    '(DE:Disp "" "")
    t)
  (*error* nil))

;;; -------------------------------------------------------------------------------------
;;; Helper function to ask user with warning message
;;; -------------------------------------------------------------------------------------
(defun WarnMsg (msg / dcl ret) (run_dialog_DictEdit_YesNoMessage (list (list "msg" msg)) nil nil))

;;; -------------------------------------------------------------------------------------
;;; Helper function to get all dictionary data
;;; -------------------------------------------------------------------------------------
(defun GetAllDicts  (/ lst dn dd dict name elem item dlst n)
  (setq dn   (namedobjdict)
        dd   (entget dn)
        lst  nil
        dict (dictnext dn t))
  (while dict
    (setq name (cdr (nth (1- (vl-position (cons 350 (cdr (assoc -1 dict))) dd)) dd)))
    (setq item (list dict name))
    (setq elem (dictnext (cdr (assoc -1 dict)) t))
    (while elem
      (cond ((member (cons 350 (cdr (assoc -1 elem))) dict)
             (setq name (cdr (nth (1- (vl-position (cons 350 (cdr (assoc -1 elem))) dict)) dict))))
            ((member (cons 360 (cdr (assoc -1 elem))) dict)
             (setq name (cdr (nth (1- (vl-position (cons 360 (cdr (assoc -1 elem))) dict)) dict))))
            (t (setq name "")))
      (setq item (cons (cons name elem) item))
      (setq elem (dictnext (cdr (assoc -1 dict)))))
    (if (assoc 90 dict)
      (progn (setq dlst (member (assoc 90 dict) dict)
                   n    1)
             (while (< n (length dlst))
               (if (= 330 (car (nth n dlst)))
                 (progn (setq name (strcat "Item" (itoa n))
                              elem (entget (cdr (nth n dlst))))
                        (setq item (cons (cons name elem) item))))
               (setq n (1+ n)))))
    (setq lst (cons (reverse item) lst))
    (setq dict (dictnext (namedobjdict))))
  (reverse lst))

;;; -------------------------------------------------------------------------------------
;;; Function for editing DataLink Items
;;; -------------------------------------------------------------------------------------
(defun DictItemEdit_DATALINK ($dict $item / dcl) (alert "ToDo"))
(setq editable_dict_items (cons (cons "DATALINK" 'DictItemEdit_DATALINK) editable_dict_items))

;;; -------------------------------------------------------------------------------------
;; Function for deleting DataLink Items
;;; -------------------------------------------------------------------------------------
(defun DictItemDelete_DATALINK  ($dict $item / n lst en)
  (setq n (cdr (assoc 94 (cdr $item))))
  (setq en (cdr (assoc -1 (cdr $item))))
  (if (or (= n 1)
          (and (= n 2) (= 1 (WarnMsg "There's one table linked to this, do you want to delete this?")))
          (and (> n 2)
               (= 1
                  (WarnMsg
                    (strcat "There are " (itoa (1- n)) " tables linked to this, do you want to deletete these?")))))
    (progn (setq lst (member (assoc 94 (cdr $item)) (cdr $item)))
           (while (> n 0) (entdel (cdr (nth n lst))) (setq n (1- n)))
           (entdel (cdr (assoc 360 (cdr $item))))
           (entdel (cdr (assoc -1 (cdr $item)))))
    (if (= n 0)
      (entdel (cdr (assoc -1 (cdr $item))))))
  (not (entget en)))
(setq deletable_dict_items (cons (cons "DATALINK" 'DictItemDelete_DATALINK) deletable_dict_items))


;;; -------------------------------------------------------------------------------------
;;; Error logging routine
;;; -------------------------------------------------------------------------------------
(defun DictEdit_ErrorLog  (msg / fn f)
  (if (setq f (open (setq fn (strcat (getvar "TEMPPREFIX") "DictEdit.LOG")) "w"))
    (progn (princ "Error Occured: ")
           (princ msg f)
           (princ "\n--------------\nAtoms dump:\n--------------\nName\tType\tValue\n--------------" f)
           (foreach a  (acad_strlsort (atoms-family 1))
             (princ "\n" f)
             (princ a f)
             (princ "\t" f)
             (princ (type a) f)
             (princ "\t" f)
             (prin1 (vl-catch-all-apply 'eval (list (read a))) f))
           (close f)
           (princ (strcat "\nError log created in: " fn)))
    (princ "\nError log could not be created.")))


;;; -------------------------------------------------------------------------------------
;;; Helper functions to load and setup dialogs
;;; -------------------------------------------------------------------------------------

;;; Function to load DictEdit dialog
(defun load_dialog_DictEdit  (/ fn f)
  (setq fn (strcat (getvar "TEMPPREFIX") "DictEdit.DCL"))
  (setq f (open fn "w"))
  (write-line "ListDict : dialog {" f)
  (write-line "  label = \"Dictionaries in Current Drawing\";" f)
  (write-line "  : row {" f)
  (write-line "    : list_box {" f)
  (write-line "      label = \"Dictionaries\";" f)
  (write-line "      key = \"dicts\";" f)
  (write-line "      width = 50;" f)
  (write-line "    }" f)
  (write-line "    : column {" f)
  (write-line "      : edit_box {" f)
  (write-line "        label = \"Name:\";" f)
  (write-line "        key = \"name\";" f)
  (write-line "        is_enabled = false;" f)
  (write-line "      }" f)
  (write-line "      : boxed_column {" f)
  (write-line "        label = \"Items\";" f)
  (write-line "\t      : popup_list {" f)
  (write-line "\t        label = \"Ownership of items:\";" f)
  (write-line "\t        key = \"owned\";" f)
  (write-line "\t        list = \"Not owned by Dictionary\\nOwned by Dictionary\";" f)
  (write-line "\t        is_enabled = false;" f)
  (write-line "\t      }" f)
  (write-line "\t      : popup_list {" f)
  (write-line "\t        label = \"Duplicate handling:\";" f)
  (write-line "\t        key = \"duplicate\";" f)
  (write-line
    "\t        list = \"Not applicable\\nKeep existing\\nUse clone\\n<xref>$0$<name>\\n$0$<name>\\nUnmangle name\";"
    f)
  (write-line "\t        is_enabled = false;" f)
  (write-line "\t      }" f)
  (write-line "\t\t    : list_box {" f)
  (write-line "\t\t      label = \"List of Items\";" f)
  (write-line "\t\t      key = \"items\";" f)
  (write-line "\t\t      height = 15;" f)
  (write-line "\t\t      width = 50;" f)
  (write-line "\t\t      is_enabled = false;" f)
  (write-line "\t\t    }" f)
  (write-line "\t\t    : row {" f)
  (write-line "\t\t      : button {" f)
  (write-line "\t\t        label = \"Delete Item\";" f)
  (write-line "\t\t        key = \"delitem\";" f)
  (write-line "\t\t        is_enabled = false;" f)
  (write-line "\t\t      }" f)
  (write-line "\t\t      : button {" f)
  (write-line "\t\t        label = \"Edit Item\";" f)
  (write-line "\t\t        key = \"edtitem\";" f)
  (write-line "\t\t        is_enabled = false;" f)
  (write-line "\t\t      }" f)
  (write-line "\t\t      : button {" f)
  (write-line "\t\t        label = \"Display Item\";" f)
  (write-line "\t\t        key = \"dispitem\";" f)
  (write-line "\t\t        is_enabled = false;" f)
  (write-line "\t\t      }" f)
  (write-line "\t\t    }" f)
  (write-line "\t\t  }" f)
  (write-line "\t    : row {" f)
  (write-line "        : button {" f)
  (write-line "\t        label = \"Display\";" f)
  (write-line "\t        key = \"disp\";" f)
  (write-line "\t        is_enabled = false;" f)
  (write-line "\t      }" f)
  (write-line "\t      : button {" f)
  (write-line "\t        label = \"Save\";" f)
  (write-line "\t        key = \"save\";" f)
  (write-line "\t        is_enabled = false;" f)
  (write-line "\t      }" f)
  (write-line "\t      : button {" f)
  (write-line "\t        label = \"Delete\";" f)
  (write-line "\t        key = \"delete\";" f)
  (write-line "\t        is_enabled = false;" f)
  (write-line "\t      }" f)
  (write-line "\t      : button {" f)
  (write-line "\t        label = \"Close\";" f)
  (write-line "\t        key = \"close\";" f)
  (write-line "\t        is_default = true;" f)
  (write-line "\t        is_cancel = true;" f)
  (write-line "\t      }" f)
  (write-line "\t    }" f)
  (write-line "    }" f)
  (write-line "  }" f)
  (write-line "}" f)
  (write-line "" f)
  (write-line "YesNoMessage : dialog {" f)
  (write-line "  label = \"Warning\";" f)
  (write-line "  : text {" f)
  (write-line "    width = 50;" f)
  (write-line "    height = 3;" f)
  (write-line "    key = \"msg\";" f)
  (write-line "  }" f)
  (write-line "  : row {" f)
  (write-line "    spacer;" f)
  (write-line "    : button {" f)
  (write-line "      key = \"yes\";" f)
  (write-line "      label = \"Yes\";" f)
  (write-line "      action = \"(done_dialog 1)\";" f)
  (write-line "    }" f)
  (write-line "    : button {" f)
  (write-line "      key = \"no\";" f)
  (write-line "      label = \"No\";" f)
  (write-line "      is_default = true;" f)
  (write-line "      is_cancel = true;" f)
  (write-line "      action = \"(done_dialog 0)\";" f)
  (write-line "    }" f)
  (write-line "    spacer;" f)
  (write-line "  }" f)
  (write-line "}" f)
  (write-line "" f)
  (write-line "ItemData : dialog {" f)
  (write-line "  label = \"Item data\";" f)
  (write-line "  key = \"main\";" f)
  (write-line "  : list_box {" f)
  (write-line "    key = \"dlist\";" f)
  (write-line "    width = 70;" f)
  (write-line "    height = 25;" f)
  (write-line "  }" f)
  (write-line
    "  : row { : text { label = \"Double-click on <EName: ####> to drill into nested data\"; } ok_only; }"
    f)
  (write-line "}" f)
  (write-line "" f)
  (write-line "DictItemEdit_DATALINK_AcExcel : dialog {" f)
  (write-line "  label = \"Edit Excel DataLink\";" f)
  (write-line "  : edit_box {" f)
  (write-line "    label = \"Name:     \";" f)
  (write-line "    key = \"name\";" f)
  (write-line "  }" f)
  (write-line "  : row {" f)
  (write-line "    : edit_box {" f)
  (write-line "      label = \"Filename:\";" f)
  (write-line "      key = \"file\";" f)
  (write-line "      width = 60;" f)
  (write-line "    }" f)
  (write-line "    : button {" f)
  (write-line "      label = \"...\";" f)
  (write-line "      key = \"browse\";" f)
  (write-line "    }" f)
  (write-line "  }" f)
  (write-line "  :row {" f)
  (write-line "\t  : edit_box {" f)
  (write-line "\t    label = \"Page:       \";" f)
  (write-line "\t    key = \"page\";" f)
  (write-line "\t  }" f)
  (write-line "\t  : popup_list {" f)
  (write-line "\t    label = \"Link Type:\";" f)
  (write-line "\t    key = \"type\";" f)
  (write-line "\t    list = \"Entire Sheet\\nNamed Range\\nRange\";" f)
  (write-line "\t  }" f)
  (write-line "  }" f)
  (write-line "  : edit_box {" f)
  (write-line "    label = \"Range:     \";" f)
  (write-line "    key = \"range\";" f)
  (write-line "  }" f)
  (write-line "  ok_cancel;" f)
  (write-line "}" f)
  (close f)
  (load_dialog fn))

(setq *DictEdit_DCL* nil)

;;; General function to unload the dialogs in the DictEdit routine
(defun unload_dialog_DictEdit () (unload_dialog *DictEdit_DCL*) (setq *DictEdit_DCL* nil))

;;; General function to run a dialog in the DictEdit routine
(defun run_dialog_DictEdit  (name key_list extra unload / return)
  (if (and (or *DictEdit_DCL* (setq *DictEdit_DCL* (load_dialog_DictEdit)))
           (new_dialog name *DictEdit_DCL*))
    (progn (foreach key  key_list
             (if (cadr key)
               (set_tile (car key) (cadr key)))
             (if (caddr key)
               (action_tile (car key) (caddr key)))
             (if (cadddr key)
               (progn (start_list (car key)) (mapcar 'add_list (cdddr key)) (end_list))))
           (if extra
             (eval extra))
           (setq return (start_dialog))
           (and unload (unload_dialog_DictEdit))))
  return)

;;; Function to run the DictItemEdit_DATALINK_AcExcel dialog
(defun run_dialog_DictEdit_DictItemEdit_DATALINK_AcExcel  (key_list extra unload)
  (run_dialog_DictEdit "DictItemEdit_DATALINK_AcExcel" key_list extra unload))

;;; Function to run the ItemData dialog
(defun run_dialog_DictEdit_ItemData  (msg data unload / ItemData:DoubleClick)
  (defun ItemData:DoubleClick  ($reason / item dxf)
    (if (and (= $reason 4)
             (/= (setq item (get_tile "dlist")) "")
             (= (type (cdr (setq item (nth (atoi item) data)))) 'EName)
             (setq dxf (entget (cdr item))))
      (run_dialog_DictEdit_ItemData (strcat "Raw Data - " (vl-prin1-to-string item)) dxf nil)))
  (run_dialog_DictEdit
    "ItemData"
    (list (list "main" msg)
          (append (list "dlist" nil "(ItemData:DoubleClick $reason)") (mapcar 'vl-prin1-to-string data)))
    nil
    unload))

;;; Function to run the YesNoMessage dialog
(defun run_dialog_DictEdit_YesNoMessage  (key_list extra unload)
  (run_dialog_DictEdit "YesNoMessage" key_list extra unload))

;;; Function to run the ListDict dialog
(defun run_dialog_DictEdit_ListDict  (key_list extra unload)
  (run_dialog_DictEdit "ListDict" key_list extra unload))

 ;|?Visual LISP? Format Options?
(120 2 1 0 nil "end of " 100 9 0 0 0 nil nil nil T)
;*** DO NOT add text below the comment! ***|;
