; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; File: grph-whier.lsp ; RCS: $Header: /disk3/npm/src/widgit/examples/RCS/grph-whier.lsp,v 2.2 1994/09/14 20:09:45 npm Exp npm $ ; Description: Displays the widget hierarchy under a shell widget. Click ; on "Show Widget Hierarchy" button, then click mouse on a ; window created by WINTERP -- a widget hierarchy will be ; displayed. Click on a "node" within the graph widget -- ; the fully qualified resource name and other info will be ; displayed in the Text widget more info will also be printed ; onto standard output. ; NOTE: this file requires version of WINTERP compiled with ; the optional HP Graph Widget ; (see "WANT_XMGRAPH_WIDGET=-DHP_GRAPH_WIDGET" in Makefile.*) ; Author: Niels Mayer ; Created: Tue Dec 24 21:25:50 1991 ; Modified: Sat May 27 00:04:52 1995 (Niels Mayer) npm@indeed ; Language: Lisp ; Status: X11r6 contrib release ; ; Copyright (C) 1994, Enterprise Integration Technologies Corp. and Niels Mayer. ; WINTERP 1.15-1.99, Copyright (c) 1993, Niels P. Mayer. ; WINTERP 1.0-1.14, Copyright (c) 1989-1992 Hewlett-Packard Co. and Niels Mayer. ; ; Permission to use, copy, modify, distribute, and sell this software and its ; documentation for any purpose is hereby granted without fee, provided that ; the above copyright notice appear in all copies and that both that ; copyright notice and this permission notice appear in supporting ; documentation, and that the name of Enterprise Integration Technologies, ; Hewlett-Packard Company, or Niels Mayer not be used in advertising or ; publicity pertaining to distribution of the software without specific, ; written prior permission. Enterprise Integration Technologies, Hewlett-Packard ; Company, and Niels Mayer makes no representations about the suitability of ; this software for any purpose. It is provided "as is" without express or ; implied warranty. ; ; ENTERPRISE INTEGRATION TECHNOLOGIES, HEWLETT-PACKARD COMPANY AND NIELS MAYER ; DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED ; WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ENTERPRISE ; INTEGRATION TECHNOLOGIES, HEWLETT-PACKARD COMPANY OR NIELS MAYER BE LIABLE ; FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ; RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF ; CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ; CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (require "lib-utils/classes") ;define :superclass, etc (require "lib-widgets/text-view") ;define Text_Display_Widget_Class (setq *default_graph_orientation* :horizontal) ;; this global gets set to a WIDGETOBJ when you click on a node in the graph. ;; When experiemnting with applications, this can be used for further programmatic ;; manipulation/access on the selected widget. (defvar *grph-whier-cur-widget* NIL) (setq Reference-Widget-Class (send Class :new '(ref-widget textdisp-widget) ;new instance vars '() ;no class vars XM_PUSH_BUTTON_GADGET_CLASS)) ;superclass (send Reference-Widget-Class :set-pname "REFERENCE-WIDGET-CLASS") ;;; ;;; Override instance initializer (method :isnew). ;;; (send Reference-Widget-Class :answer :ISNEW '(managed_k widget_name widget_parent ref_w txt_w) '( ;; set instance variables (setq ref-widget ref_w ;the widget to which the 'Reference-Widget-Class' instance refers to textdisp-widget txt_w) ;Text_Display_Widget_Class for displaying :display-info method result information ;; create 'self', an instance of XM_PUSH_BUTTON_GADGET_CLASS (send-super :isnew ;call superclass's init to create widget managed_k widget_name widget_parent :XMN_HIGHLIGHT_ON_ENTER nil ;setting to T interfere's w/ XmGraph's display of selection :XMN_HIGHLIGHT_THICKNESS 1 ;make sure user hasn't set it to 0 :XMN_ALIGNMENT :alignment_center :XMN_SHADOW_THICKNESS 1 :XMN_LABEL_STRING (format nil "\"~A\"\n~A" (send ref_w :name) ;; The following looks for 'PNAME' ivar on the class, which ;; is the string print name of the widget-class. Chains up ;; superclasses until it finds a non-NIL 'PNAME'... ;; Returns abbreviated class-name as string. (do* ((clip_len (length "_WIDGET_CLASS")) (cls (send ref_w :class) (send cls :superclass)) (str (aref (generic cls) 8) (aref (generic cls) 8)) ) (str ;stop iterating as soon as we find a non-NIL PNAME field giving the class name string (let ((siz (- (length str) clip_len))) ;DO-RETURN (if (plusp siz) (subseq str 0 siz) "") )) )) ) ;; create a callback (send-super :add_callback :XMN_ACTIVATE_CALLBACK '() `( (send ,self :display-info) )) self ;METHOD RETURN VALUE )) (send Reference-Widget-Class :answer :GET-REFERENCE '() '( ref-widget )) (send Reference-Widget-Class :answer :DISPLAY-INFO '() '( (setq *grph-whier-cur-widget* ref-widget) (send textdisp-widget :disable_redisplay) (send textdisp-widget :clear) ;; print out the fully qualified resource name (let* ((cur-w ref-widget) (name (send cur-w :name)) (resname (if (string= name "") "*" name)) (wildcard-p nil)) (loop (cond ((null (setq cur-w (send cur-w :parent))) ;loop up widget tree ;; when you hit the root, print out the loop-accumulated resource name string.. (send textdisp-widget :append-string (format nil "Xresource Name = ~A\n" resname)) (return) ;END OF LOOP )) (setq name (send cur-w :name)) (if (string= name "") ;if no name given on this widget (if (not wildcard-p) ;then if previously not in wildcard state, prepend a '*' (setq resname (concatenate 'string "*" resname)) (setq wildcard-p t)) ;else make sure to print only one '*' at beginning of a unnamed sequence... (if wildcard-p ;if a name was given to a widget and previously wrote a unnamed sequence, (setq resname (concatenate 'string name resname) ;then prepend the current resource to '*...' (we're going up-tree) wildcard-p nil) ;and exit the wildcard state... (setq resname (concatenate 'string name "." resname))) ;else prepend the current resource name with '.' separator ) )) ;; display a bunch of information on the selected widget. (let* ((x 0) (y 0) (height 0) (width 0) (cls (send ref-widget :class)) (wclass (generic cls)) (methods-list (aref wclass 1)) ;;; (ivars-list (aref wclass 2)) (cvars-list (aref wclass 3)) (cvals-list (aref wclass 4)) (superclass (aref wclass 5)) ;;; (ivar-cnt (aref wclass 6)) ;;; (cvar-cnt (aref wclass 7)) ;;; (pname (aref wclass 8)) ) (send ref-widget :get_values :XMN_X 'x :XMN_Y 'y :XMN_HEIGHT 'height :XMN_WIDTH 'width) (send textdisp-widget :append-string (format nil "Widget/ParentW = ~S // ~A\nClass/Supercls = ~S // ~A\nHxW+X+Y = ~Ax~A+~A+~A\nInst.Vars/Vals = ~S // ~S\nCls. Vars/Vals = ~S // ~S\nMETHODS = ~S" ref-widget (send ref-widget :parent) cls superclass height width x y (cdr (send cls :get-ivars-from-class-and-superclasses)) ;CDR removes the IVAR | _bogus_ivar_ | from WIDGET_CLASS (cddr (map 'list #'(lambda (x) x) (generic ref-widget))) ;(generic ref-widget) returns #( NIL ...), so use CDDR to remove first two elements... cvars-list cvals-list methods-list )) ) (send textdisp-widget :show_position 0) (send textdisp-widget :set_insertion_position 0) (send textdisp-widget :enable_redisplay) )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (send WIDGET_CLASS :answer :IS-CASCADE-BUTTON '() `( (let ((cls (send self :class))) (or (eq cls ,XM_CASCADE_BUTTON_GADGET_CLASS) (eq cls ,XM_CASCADE_BUTTON_WIDGET_CLASS)) ) ;return BOOLEAN result )) ;; returns the complete list of ivars from the class and suplerclasses ;; note that the first element returned from this when applying this to ;; a WIDGET_CLASS (or subclass) is | _bogus_ivar_ |, which corresponds ;; to an internal hack instance variable for WINTERP's WIDGET_CLASS. (send CLASS :answer :GET-IVARS-FROM-CLASS-AND-SUPERCLASSES '() '( (let* ((wclass (generic self)) (ivars-list (aref wclass 2)) (superclass (aref wclass 5)) ) (if superclass (append (send superclass :get-ivars-from-class-and-superclasses ) ivars-list) ;RECURSE... NIL ;terminate recursion by returning NIL ) ) )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; recursive display of 's children, where is represented by ;; Reference-Widget-Class . ;; must be a composite widget. (defun show-composite-widget-tree (tree_w text_w super_node_w node_w) (do* ((node_children_array (send node_w :get_children)) (len (length node_children_array)) (node_ref_widget_array (make-array len)) (arc_array (make-array len)) (i 0 (1+ i))) ;; do -- while more children of ((<= len i) (xt_manage_children arc_array) (xt_manage_children node_ref_widget_array) ;RETURN/EXIT ) (setf (aref node_ref_widget_array i) (cond ;; handle Motif OOP obfuscation (TM) -- "hidden" dialogues and "hidden" shells ((not (eq (send super_node_w :get-reference) (send (aref node_children_array i) :parent))) (setf (aref node_children_array i) (send (aref node_children_array i) :parent)) (send Reference-Widget-Class :new :unmanaged (format nil "ref-~A" i) tree_w (aref node_children_array i) text_w) ) (t (send Reference-Widget-Class :new :unmanaged (format nil "ref-~A" i) tree_w (aref node_children_array i) text_w) ) )) (setf (aref arc_array i) (send XM_ARC_WIDGET_CLASS :new :unmanaged "" tree_w :XMN_TO (aref node_ref_widget_array i) :XMN_FROM super_node_w )) ;; recurse on Composite or CascadeButton widgets -- for composites the call to ;; :GET_CHILDREN in 'SHOW-COMPOSITE-WIDGET-TREE' will return list of children of ;; the widget. For cascades, 'SHOW-CASCADE-WIDGET-TREE' calls :GET_SUB_MENU_WIDGET ;; and will subsequently recurse on the resulting ROW-COLUMN widget... (let ((cur_w (aref node_children_array i))) (cond ((send cur_w :is_composite) (show-composite-widget-tree tree_w text_w (aref node_ref_widget_array i) cur_w) ) ((send cur_w :is-cascade-button) (show-cascade-widget-tree tree_w text_w (aref node_ref_widget_array i) cur_w) ) (T super_node_w ) )) )) ;; recursive display of 's children, where is represented by ;; Reference-Widget-Class . ;; must be a cascade-button widget/gadget ;; (i.e. method :IS-CASCADE-BUTTON returns true) (defun show-cascade-widget-tree (tree_w text_w super_node_w node) (let ((submenu_widget (send node :get_sub_menu_widget)) (node_ref_widget nil)) (if submenu_widget (progn (setq node_ref_widget (send Reference-Widget-Class :new :managed "ref" tree_w submenu_widget text_w)) (send XM_ARC_WIDGET_CLASS :new :managed "" tree_w :XMN_TO node_ref_widget :XMN_FROM super_node_w ) ;; recurse on Composite or CascadeButton widgets -- for composites the call to ;; :GET_CHILDREN in 'SHOW-COMPOSITE-WIDGET-TREE' will return list of children of ;; the widget. For cascades, 'SHOW-CASCADE-WIDGET-TREE' calls :GET_SUB_MENU_WIDGET ;; and will subsequently recurse on the resulting ROW-COLUMN widget... (cond ((send submenu_widget :is_composite) (show-composite-widget-tree tree_w text_w node_ref_widget submenu_widget) ) ((send submenu_widget :is-cascade-button) (show-cascade-widget-tree tree_w text_w node_ref_widget submenu_widget) ) (T super_node_w ) ) ) super_node_w ) )) ;; ;; toplevel function to create a widget-tree displayer ;; (defun show-widget-tree () (let* ((top_w (send TOP_LEVEL_SHELL_WIDGET_CLASS :new "grph-whier" :XMN_TITLE "WINTERP: Widget Hierarchy Inspector" :XMN_ICON_NAME "W:grph-whier" )) (paned_w (send XM_PANED_WINDOW_WIDGET_CLASS :new :managed "paned" top_w )) (rc_w (send XM_ROW_COLUMN_WIDGET_CLASS :new :managed "rc" paned_w :XMN_PACKING :pack_tight :XMN_ORIENTATION :horizontal )) (sho_pb_w (send XM_PUSH_BUTTON_GADGET_CLASS :new :managed "sho_pb" rc_w :XMN_LABEL_STRING "Show widget hierarchy of ..." )) (graph_editable_tbw (send XM_TOGGLE_BUTTON_GADGET_CLASS :new :managed "graph_editable_tb" rc_w :XMN_LABEL_STRING "Editable" :XMN_SET nil )) (clr_pb_w (send XM_PUSH_BUTTON_GADGET_CLASS :new :managed "clr_pb" rc_w :XMN_LABEL_STRING "Clear All" )) (graph_destroy_selected_pbw (send XM_PUSH_BUTTON_GADGET_CLASS :new :managed "graph_destroy_selected_pb" rc_w :XMN_LABEL_STRING "Clear Selected" :XMN_SENSITIVE nil ;note the button is inactive unless :XMN_EDITABLE is true )) (graph_relayout_pbw (send XM_PUSH_BUTTON_GADGET_CLASS :new :managed "graph_relayout_pb" rc_w :XMN_LABEL_STRING "Re-Layout" )) (graph_reorient_pbw (send XM_PUSH_BUTTON_GADGET_CLASS :new :managed "graph_reorient_pb" rc_w :XMN_LABEL_STRING "Flip Layout Direction" )) (text_w (send Text_Display_Widget_Class :new :managed "text" paned_w :XMN_ROWS 7 :XMN_COLUMNS 100 )) (tree_w (send XM_GRAPH_WIDGET_CLASS :new :managed :scrolled "w-hier-tree" paned_w :XMN_SIBLING_SPACING 2 :XMN_CHILD_SPACING 15 :XMN_ARC_DRAW_MODE :position_fixed :XMN_ORIENTATION *default_graph_orientation* :XMN_EDITABLE nil ;setting to T means the buttons won't be pushable :XMN_AUTO_LAYOUT_MODE :never )) ) ;;; set the size of the graph window pane -- note Motif's lamo use of hidden ;;; scroller->drawingarea->graph hierarchy when dealing with a scrolled widget (grrr). (send (send (send tree_w :parent) :parent) :set_values :XMN_HEIGHT 600 :XMN_SCROLL_BAR_DISPLAY_POLICY :static ) (send sho_pb_w :add_callback :XMN_ACTIVATE_CALLBACK '() `( (winterp_show_busy t) ;set busy cursor... (send ,tree_w :unmanage) (progv '(*breakenable*) '(nil) (unwind-protect ;remanage tree_w and unset busy cursor no matter what happens (let* ((root_w (do ((w (get_moused_widget) ;initialize to widget designated by user... (send w :parent))) ;increment up tree... ((send w :is_shell) ;loop until you hit a shell... w))) (super_root_w (send Reference-Widget-Class :new :managed ;create the widget representing the root of the widget tree "ref-root" ,tree_w root_w ,text_w)) ) ;; recursively display children and cascade-button-submenus of root_w (show-composite-widget-tree ,tree_w ,text_w super_root_w root_w) ) ;; always unwind-protect (progn (send ,tree_w :layout) (send ,tree_w :manage) (winterp_show_busy nil) ;always unset busy cursor via unwind-protect ) )) )) (send clr_pb_w :add_callback :XMN_ACTIVATE_CALLBACK '() `( (send ,tree_w :destroy_all_nodes) )) (send graph_editable_tbw :set_callback :XMN_VALUE_CHANGED_CALLBACK '(CALLBACK_SET) `( (send ,tree_w :set_values :XMN_EDITABLE CALLBACK_SET) (send ,graph_destroy_selected_pbw :set_values :XMN_SENSITIVE CALLBACK_SET) (send ,text_w :set_values :XMN_SENSITIVE (not CALLBACK_SET)) )) (send graph_destroy_selected_pbw :set_callback :XMN_ACTIVATE_CALLBACK '() `( (let* ((array-sel-widgets (send ,tree_w :get_selected_nodes)) (num-sel-widgets (length array-sel-widgets)) ) (do ((i 0 (1+ i))) ((eq i num-sel-widgets)) (progv '(*breakenable*) '(nil) ;temporarily unset *breakenable* s.t. errset works even when in "debugging" mode. (errset (send (aref array-sel-widgets i) :destroy) ;trap errors incase widget has already been destroyed via :destroy on it's parent... NIL) ;don't print error messages ) ) ))) (send graph_relayout_pbw :set_callback :XMN_ACTIVATE_CALLBACK '() `( (send ,tree_w :layout) )) (send graph_reorient_pbw :set_callback :XMN_ACTIVATE_CALLBACK '() `( (send ,tree_w :set_values :xmn_reorient t) (cond ((eq *default_graph_orientation* :horizontal) (setq *default_graph_orientation* :vertical) ) ((eq *default_graph_orientation* :vertical) (setq *default_graph_orientation* :horizontal) ) ) )) (send top_w :realize) ;; remove paned window sash from rc_w (let (height) (send rc_w :get_values :xmn_height 'height) (send rc_w :set_values :XMN_PANE_MAXIMUM height :XMN_PANE_MINIMUM height ) ) )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (show-widget-tree)