TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: jlogan02 on November 18, 2022, 01:22:02 PM

Title: LM:SentenceCase Use in routine
Post by: jlogan02 on November 18, 2022, 01:22:02 PM
I want to set the layer filter name to Sentence Case using Lee Mac's LM:SentenceCase

Code - Auto/Visual Lisp: [Select]
  1. ;; Sentence Case - Lee Mac
  2. ;; Returns the supplied string converted to Sentence Case
  3.  
  4. (defun LM:SentenceCase ( s / f )
  5.     (vl-list->string
  6.         (mapcar
  7.             (function
  8.                 (lambda ( a b c )
  9.                     (if (or f (= 46 a)) (progn (setq f (= 32 b)) b) c)
  10.                 )
  11.             )
  12.             (cons 46 (vl-string->list s))
  13.             (vl-string->list (strcase s))
  14.             (vl-string->list (strcase s t))
  15.         )
  16.     )
  17. )

I'm just not sure where to put the defun (LM:SentenceCase) in the code below.

Code - Auto/Visual Lisp: [Select]
  1.  
  2. ;| --------------------------------
  3. Function created by unknown
  4. -------------------------------- |;
  5.  
  6. (defun get-layer-filter-names (/ collection)
  7.   (setq names (list ""))
  8.   (if
  9.     (not
  10.         (setq collection (vl-catch-all-apply
  11.                            (function
  12.                              (lambda ()
  13.                                (vla-item
  14.                                  (vla-getextensiondictionary
  15.                                    (vla-get-layers (vla-get-activedocument (vlax-get-acad-object)))
  16.                                  )
  17.                                  "ACAD_LAYERFILTERS"
  18.                                )
  19.                              )
  20.                            )
  21.                          )
  22.         )
  23.       )
  24.     )
  25.     (vlax-for item collection
  26.       (setq names (cons (strcase (vla-get-name item)) names))
  27.     )
  28.   )
  29.   names
  30. ); function
  31.  
  32. (get-layer-filter-names)
  33.  
  34. ;; get layer filter name..
  35.  
  36. (setq layn (strcase "Stations Standard Layers"))
  37. (if (member layn names)
  38.   (princ "\nStations Standard Layers already exists.")
  39.   (command "._-layer" "filter" "Rename" "Stations Standard Layer" layn "")
  40. ); if
Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 18, 2022, 02:57:03 PM
My question still stands. However, I was wanting Title Case not Sentence Case.
Code - Auto/Visual Lisp: [Select]
  1. ;; Title Case - Lee Mac
  2. ;; Returns the supplied string converted to Title Case
  3.  
  4. (defun LM:TitleCase ( s )
  5.     (vl-list->string
  6.         (mapcar
  7.             (function
  8.                 (lambda ( a b c ) (if (= 32 a) b c))
  9.             )
  10.             (cons 32 (vl-string->list s))
  11.             (vl-string->list (strcase s))
  12.             (vl-string->list (strcase s t))
  13.         )
  14.     )
  15. )

Usage (LM:TitleCase "Stations Standard Layers")
Title: Solved: LM:SentenceCase Use in routine
Post by: jlogan02 on November 18, 2022, 03:50:39 PM
Solved. Instead of using the variable
Code - Auto/Visual Lisp: [Select]
  1. layn
, just spell it out like you want it.

Code - Auto/Visual Lisp: [Select]
  1. (setq layn (strcase "Stations Standard Layers"))
  2. (if (member layn names)
  3.   (princ "\nStations Standard Layers already exists.")
  4.   (command "._-layer" "filter" "Rename" "Stations Standard Layer" "Stations Standard Layers" "")
Title: Re: LM:SentenceCase Use in routine
Post by: kdub_nz on November 18, 2022, 05:01:11 PM
Ahh, now I understand . . . You just want to add an 's' to a specific filter name.

. . . but you don't seem to be checking if the layerFilter you are renaming actually exists.

I assume you want to batch process drawings, or run this as part of a config routine, but you do realise that Right-click on the Filter name offers a rename option.

Regards,

added:

a piccy if 'Renamed' filter does not exist

Title: Dammit almost solved: LM:SentenceCase Use in routine
Post by: jlogan02 on November 18, 2022, 05:36:57 PM
The "Stations Standard Layers already exists" message doesn't work. If the filter name exists I get...

Invalid layer filter name.
Enter new layer filter name:

This is generated by the command line syntax for the layer filter rename.

Code - Auto/Visual Lisp: [Select]
  1.  (setq layn (strcase "Stations Standard Layers"))
  2. (if (member layn names)
  3.   (princ "Stations Standard Layers already exists.")
  4.   (command "._-layer" "filter" "Rename" "Stations Standard Layer" "Stations Standard Layers" "")
  5. ); if

Clearly I'm wrong somewhere.

kdub, this would be in startup. Check if it exists if not add the "s"
Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 18, 2022, 06:08:23 PM
Ahh, now I understand . . . You just want to add an 's' to a specific filter name.

. . . but you don't seem to be checking if the layerFilter you are renaming actually exists.

I assume you want to batch process drawings, or run this as part of a config routine, but you do realise that Right-click on the Filter name offers a rename option.

Regards,

added:

a piccy if 'Renamed' filter does not exist

I gotcha. My "if" statement should include a search for the filter name not the variable "layn".

I think I need to be looking at the extension directory for the layer filter name.
Title: Re: LM:SentenceCase Use in routine
Post by: kdub_nz on November 18, 2022, 07:13:53 PM
Perhaps something like :
(may not be bomb proof :)

Code - Auto/Visual Lisp: [Select]
  1.  
  2. (defun c:DoTest (/ oldName newName extensionDict layerFilter)
  3.   (or *acdoc*
  4.   )
  5.   (setq oldName "frutier"
  6.         newName "Fruitiers"
  7.   )
  8.  
  9.   (if (and
  10.         (setq extensionDict
  11.                (vla-getExtensionDictionary (vla-get-Layers *acdoc*))
  12.         )
  13.         (setq layerFilters
  14.                (kdub:safeitem extensionDict "ACAD_LAYERFILTERS")
  15.         )
  16.       )
  17.     (if (setq layerFilter (kdub:safeitem layerFilters newName))
  18.       (princ
  19.         (strcat "\n" (vla-get-Name layerFilter) " already exists.")
  20.       )
  21.       ;;else
  22.       (if (setq layerFilter (kdub:safeitem layerFilters oldName))
  23.         (progn
  24.           ;;(vla-put-Name layerFilter newName)
  25.           (command "._-layer" "filter" "Rename" oldName newName "")
  26.           (princ "\nFilter name was changed.")
  27.         )
  28.         ;;else
  29.         (princ (strcat "\n" oldName " filter does not exists."))
  30.       )
  31.     )
  32.     ;;else
  33.     ;;
  34.   )
  35.  
  36.   (princ)
  37. )
  38.  
  39.  
  40. ;;;--------------------------------------------------------------------
  41.  
  42. (defun kdub:safeitem (collection item / returnvalue)
  43.              (setq returnvalue
  44.                     (vl-catch-all-apply
  45.                       'vla-item
  46.                       (list collection item)
  47.                     )
  48.              )
  49.            )
  50.       )
  51.     returnvalue
  52.   )
  53. )
  54.  
  55. ;;;--------------------------------------------------------------------
  56.  
  57.  

Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 21, 2022, 11:12:15 AM
Thanks kdub, I'll take a look at this. Is your safeitem routine a shortened method for getting at the filters collection by using vla-item?
Title: Re: LM:SentenceCase Use in routine
Post by: kdub_nz on November 21, 2022, 02:47:31 PM
Thanks kdub, I'll take a look at this. Is your safeitem routine a shortened method for getting at the filters collection by using vla-item?

Hi,
It just a GuardClause function which either returns  the collection item (VLA-OBJECT) or nil

An optimised version is
Code - Auto/Visual Lisp: [Select]
  1. (defun GetSafeItem (collection item / vlaObj)
  2.   (vl-catch-all-apply
  3.     (function (lambda () (setq vlaObj (vla-item collection item ))))
  4.   )
  5.   vlaObj
  6. )
  7.  

Test this
Code - Auto/Visual Lisp: [Select]
  1.   (or *acdoc*
  2.   )
  3. (GetSafeItem (vla-get-layers *acdoc*) "0")
  4.  
  5. (GetSafeItem (vla-get-layers *acdoc*) "NoSuchLayer")
  6.  
  7. (vla-item (vla-get-layers *acdoc*) "NoSuchLayer")
  8.  

result:
Code: [Select]
#<VLA-OBJECT IAcadLayer 0000021e6f957cd8>

nil

; error: Automation Error. Key not found


We just need to test the returned value, rather than have the function crash.
Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 21, 2022, 05:46:38 PM
Perhaps something like :
(may not be bomb proof :)

Code - Auto/Visual Lisp: [Select]
  1.  
  2. (defun c:DoTest (/ oldName newName extensionDict layerFilter)
  3.   (or *acdoc*
  4.   )
  5.   (setq oldName "frutier"
  6.         newName "Fruitiers"
  7.   )
  8.  
  9.   (if (and
  10.         (setq extensionDict
  11.                (vla-getExtensionDictionary (vla-get-Layers *acdoc*))
  12.         )
  13.         (setq layerFilters
  14.                (kdub:safeitem extensionDict "ACAD_LAYERFILTERS")
  15.         )
  16.       )
  17.     (if (setq layerFilter (kdub:safeitem layerFilters newName))
  18.       (princ
  19.         (strcat "\n" (vla-get-Name layerFilter) " already exists.")
  20.       )
  21.       ;;else
  22.       (if (setq layerFilter (kdub:safeitem layerFilters oldName))
  23.         (progn
  24.           ;;(vla-put-Name layerFilter newName)
  25.           (command "._-layer" "filter" "Rename" oldName newName "")
  26.           (princ "\nFilter name was changed.")
  27.         )
  28.         ;;else
  29.         (princ (strcat "\n" oldName " filter does not exists."))
  30.       )
  31.     )
  32.     ;;else
  33.     ;;
  34.   )
  35.  
  36.   (princ)
  37. )
  38.  
  39.  
  40. ;;;--------------------------------------------------------------------
  41.  
  42. (defun kdub:safeitem (collection item / returnvalue)
  43.              (setq returnvalue
  44.                     (vl-catch-all-apply
  45.                       'vla-item
  46.                       (list collection item)
  47.                     )
  48.              )
  49.            )
  50.       )
  51.     returnvalue
  52.   )
  53. )
  54.  
  55. ;;;--------------------------------------------------------------------
  56.  
  57.  

Just tested this with no luck. Well, that's not entirely true. Regardless if the old filter exists or not the routine tells me it doesn't exist. That's literally all it does.

For a dumb guy like me, your code makes perfect sense. I'll be darned if I see why it's not working. As I see it, it's an either or situation. If the "s" exists "NewName" do nothing. If the "s" doesn't exist OldName...rename the filter, add the "s".

Thanks for the explanation on the GetSafeItem.
Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 21, 2022, 06:15:21 PM
Just went through the whole process manually.

Used the command line to create the filter "Stations Standard Layers"
Set another filter current.
Used the command line to delete the filter. It did not delete it.

I couldn't rename it either.

Right click in the layers dialog works for both deleting and renaming.

Letter limit? Or spaces? I just manually named a filter Station and manually renamed it to Stations, just fine.
Title: Re: LM:SentenceCase Use in routine
Post by: kdub_nz on November 21, 2022, 06:36:32 PM
That's weird ;
The default name for a new Properties Filter (in the dialog) has spaces.

Running the version you posted :

Code: [Select]
Command: DOTEST
._-layer
Current layer:  "Apple"
Enter an option [?/Make/Set/New/Rename/ON/OFF/Color/Ltype/LWeight/TRansparency/MATerial/Plot/Freeze/Thaw/LOck/Unlock/stAte/Description/rEconcile/Xref]: filter
Current layer filter: "All"
Enter a layer filter option [New/Set/Rename/Edit/Delete/eXit]: Rename
Enter layer filter to rename: Fruit Drops
Enter new layer filter name: Fruit Dropper
Current layer filter: "All"
Enter a layer filter option [New/Set/Rename/Edit/Delete/eXit]:
Command:
Filter name was changed.


If the Layer Properties Manager is OPEN, the changes ( made by the program) are not displayed untill it is closed and re-opened

Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 22, 2022, 12:33:29 PM
Ok, now do me a favor and run the routine with the new name Fruit Dropper as the filter. Does that give you the "already exists" message?
Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 22, 2022, 01:59:11 PM
Is it the difference between a group filter and a properties filter? All works fine if I make it a properties filter.
Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 22, 2022, 02:21:53 PM
Group filter test...again. Says the filter I'm looking for is Current, but then says isn't found.

Title: Re: LM:SentenceCase Use in routine
Post by: kdub_nz on November 22, 2022, 05:04:48 PM
For Properties Filter :
consecutive changes => ok

I'll have a look at the Groups . .

Title: Re: LM:SentenceCase Use in routine
Post by: kdub_nz on November 22, 2022, 05:25:17 PM
@jlogan02,
You're correct.
The Group filters can be changed from the 'Rename' in the Layer Properties Manager,
and from the command Line manually,
but NOT using the function

I'll have a better look tonight.
Title: Re: LM:SentenceCase Use in routine
Post by: kdub_nz on November 22, 2022, 05:40:50 PM
Looks like the Group data is kept somewhere else than theDictionary attached to the Table !!


added:
Unless the report from MgdDbg snoop is incomplete ??
Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 22, 2022, 06:52:55 PM
ACLYDICTIONARY ???

Code - Auto/Visual Lisp: [Select]
  1. (defun :LayerFilterList (/ :SubFilterList)
  2.  
  3.   ; su returns list of main filter and sub filters right behind
  4.   (defun :SubFilterList (dict / ent lst)
  5.     (foreach ent (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 350)) dict))
  6.       (setq lst (append lst
  7.                         (cons ent (if (assoc 360 (entget ent))
  8.                                     (:SubFilterList (entget (cdr (assoc 360 (entget (cdr (assoc 360 (entget ent)))))))))))))
  9.     lst)
  10.  
  11.   (mapcar '(lambda (x) (cdr (assoc 300 (entget x))))
  12.           (:SubFilterList (dictsearch
  13.                             (vlax-vla-object->ename
  14.                               (vla-getextensiondictionary
  15.                                 (vla-get-layers
  16.                                   (vla-get-activedocument
  17.                                     (vlax-get-acad-object)))))
  18.                             "ACLYDICTIONARY"))))

This returns the list of Property and Group filters.

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/layer-filter-existence-test/m-p/7910315#M367448
Title: Re: LM:SentenceCase Use in routine
Post by: kdub_nz on November 22, 2022, 11:23:18 PM
Cool, That looks like it will return names of Properties, Groups and nested Filters.

Could solve most of your issues :)

I learnt something 'cause I've not played with these before.
Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 23, 2022, 10:50:53 AM
I'm going to whittle with it today and see what I come up with.
Title: Re: LM:SentenceCase Use in routine
Post by: kdub_nz on November 23, 2022, 12:37:49 PM
@jlogan02.

Fairly clean from here.

run (:LayerFilterList) to determine the current complete filter list.

determine if the newName exists (position) or (member) in list
    if so ; finished

determine if the 0ldName exists (position) or (member) in list
    if so ; proceed

run the .-layer filter command as previously.

have a beer.

Regards,
stay well
Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 23, 2022, 06:25:53 PM
Took a little stab before calling it a day.

Keeps getting a nil.

Code - Auto/Visual Lisp: [Select]
  1. (defun C:LayerFilterList (/ :SubFilterList oldName newName)
  2.  
  3.   ; su returns list of main filter and sub filters right behind
  4.   (defun :SubFilterList (dict / ent lst)
  5.     (foreach ent (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 350)) dict))
  6.       (setq lst (append lst
  7.                         (cons ent (if (assoc 360 (entget ent))
  8.                                     (:SubFilterList (entget (cdr (assoc 360 (entget (cdr (assoc 360 (entget ent)))))))))))))
  9.     lst)
  10.  
  11.   (mapcar '(lambda (x) (cdr (assoc 300 (entget x))))
  12.           (:SubFilterList (dictsearch
  13.                             (vlax-vla-object->ename
  14.                               (vla-getextensiondictionary
  15.                                 (vla-get-layers
  16.                                   (vla-get-activedocument
  17.                                     (vlax-get-acad-object)))))
  18.                             "ACLYDICTIONARY"))))
  19.  
  20.  
  21.   (setq oldName "Stations Standard Layer"
  22.         newName "Stations Standard Layers"
  23.   )
  24.  
  25. (if (member newName lst)
  26.   (princ "Stations Standard Layers already exists.")
  27. )
  28.  
  29. (if (member oldName lst)
  30.   (progn
  31.    (command "._-layer" "filter" "Rename" oldName newName "")
  32.   )
  33. )
  34.  
  35.  

Happy Thanksgiving. Back at it Monday.

Title: Re: LM:SentenceCase Use in routine
Post by: kdub_nz on November 23, 2022, 07:43:48 PM
perhaps something like this

Code - Auto/Visual Lisp: [Select]
  1. ;;===========================================================
  2. (defun c:NewDoIt (/ oldName newName currentFilterList)
  3.   (setq oldName           "Stations Standard Layer"
  4.         newName           "Stations Standard Layers"
  5.         currentFilterList (:LayerFilterList)
  6.   )
  7.   (if (vl-position newname currentFilterList)
  8.     (princ
  9.       (strcat "\n\t'" newName "' filter already exists.")
  10.     )
  11.     ;; else
  12.     (if (vl-position oldname currentFilterList)
  13.       (progn (command "._-layer"  "filter"    "Rename"
  14.                       oldName     newName     ""
  15.                      )
  16.              (princ (strcat "\n\t'"
  17.                             oldName
  18.                             "' filter changed to '"
  19.                             newName
  20.                             "'."
  21.                            )
  22.              )
  23.       )
  24.       ;;else
  25.       (princ
  26.         (strcat "\n\t'" oldName "' filter does not exists.")
  27.       )
  28.     )
  29.   )
  30.   (princ)
  31. )
  32.  
  33.  
  34.  
  35. ;;===========================================================
  36. (defun :LayerFilterList (/ :SubFilterList)
  37.  
  38.   ; su returns list of main filter and sub filters right behind
  39.   (defun :SubFilterList (dict / ent lst)
  40.   (foreach ent (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 350)) dict))
  41.   ( setq lst (append lst
  42.                 (cons ent (if (assoc 360 (entget ent))
  43.                             (:SubFilterList (entget (cdr (assoc 360 (entget (cdr (assoc 360 (entget ent)))))))))))))
  44.   lst)
  45.  
  46.   (mapcar '(lambda (x) (cdr (assoc 300 (entget x))))
  47.     (:SubFilterList (dictsearch
  48.                     (vlax-vla-object->ename
  49.                       (vla-getextensiondictionary
  50.                         (vla-get-layers
  51.                           (vla-get-activedocument
  52.                             (vlax-get-acad-object)))))
  53.                     "ACLYDICTIONARY"))))
  54. ;;===========================================================
  55.  

Enjoy your holiday.
Title: Re: LM:SentenceCase Use in routine
Post by: jlogan02 on November 29, 2022, 05:06:02 PM
kdub, that did the trick. Made some minor adjustments to messaging but other than that, all is good. Thanks for your help. Much appreciated.