Subscribe to this thread
Home - General / All posts - Script to delete all components in a folder
oisink
370 post(s)
#31-Mar-16 18:58

Hi

I have the following simple vbscript that is intended to delete all components within a folder called "DWG_Import". The script does not throw an error, but also does not delete all components in the folder. If I run it several times it eventually deletes all components, with no errors. Any ideas why this is not behaving as expected.

Sub Main

 set compset=document.componentset

 set dwgcompset=compset("DWG_Import").children

 for each dwgcomp in dwgcompset

 compset.remove(dwgcomp)

 next

End Sub

Thanks

Oisin

tjhb
10,094 post(s)
#31-Mar-16 19:17

The short answer is: do it backwards, with an explicit (decreasing) index.

The long answer is that For Each gets translated as follows.

x = 0

stop if x >= N

otherwise delete member x, increase x by 1, check again

So if N is initially 5, we get member 0 removed (now there are 4), member 1 removed (now 3), member 2 (now 2): therefore stop. We still have 2 members.

An increasing index is not the right way to remove members of a set--and For Each just masks this.

oisink
370 post(s)
#01-Apr-16 15:54

Thanks for the explanation - it makes sense now.

tjhb
10,094 post(s)
#31-Mar-16 22:15

E.g. like this. (An add-in I use a lot, slightly revised--a bit more.)

Select a folder in the Project pane then run the script. Everything in the folder is deleted from the project--including any subfolders and their contents.

Option Explicit

Dim app ' Application

Dim comps ' ComponentSet

Dim folder ' Component

Dim i

Sub Main

    Set app = Application

    Set comps = Document.ComponentSet

    Set folder = CurrentFolder

    If folder Is Nothing Then

        app.MessageBox "Select a folder in the Project pane" & vbCrLf & "before running the script.", _

            "Empty current folder"

    Else

        If folder.Children.Count = 0 Then

            app.MessageBox Chr(34) & folder.Name & Chr(34) & " is already empty.", _

                "Empty current folder"

        Else

            If app.MessageBoxEx("Are you sure you want to delete all components in " _

                    & Chr(34) & folder.Name & Chr(34) & "?", _

                    "Empty this folder", _

                    MessageBoxTypeYesNo) = MessageBoxResultYes Then

                With folder.Children

                    For i = .Count - 1 To 0 Step -1

                        If Not IsEmpty(.Item(i).Owner) Then

                            ' bound component: will be deleted implicitly

                        Else

                            app.History.Log "Delete " & Chr(34) & .Item(i).Name & Chr(34) & "..." & vbCrLf, True

                            comps.Remove .Item(i)

                        End If

                    Next

                End With

            End If

        End If

    End If

End Sub

'

Private Function CurrentFolder

    ' Returns the folder selected in the Project pane

    ' (if any)

    Dim comps

    Dim folder

    Dim name

    Set comps = Document.ComponentSet

    Set folder = Nothing

    If comps.Count > 0 Then

        name = Application.UserInterface.Panes("Project").ControlSet("TreeViewComponents").Text 

        If name <> "" Then 

            If comps(name).Type = ComponentFolder Then

                Set folder = comps(name)

            End If

        End If

    End If

    Set CurrentFolder = folder

End Function

Attachments:
Empty current folder.txt

tjhb
10,094 post(s)
#01-Apr-16 00:02

I see I had already posted the earlier version.

steveFitz

340 post(s)
#01-Apr-16 01:59

Oisin,

Why not throw out the baby with the bathwater and get a new a baby?

Executes pretty quick too.

Sub Main

set compset=document.componentset

set dwgcompset=compset("Folder")

' for each dwgcomp in dwgcompset

 compset.remove(dwgcompset)

 'next

set dwgcompset=Document.NewFolder("Folder",true)

End Sub

tjhb
10,094 post(s)
#01-Apr-16 02:01

.

steveFitz

340 post(s)
#01-Apr-16 02:04

..

tjhb
10,094 post(s)
#01-Apr-16 02:18

This is very efficient, a good idea. It might be worth remembering where the folder is (if it is in a folder) so the new empty folder can be returned there.

If the folder has a lot of components, you might get an error trying to recreate a new folder with the same name immediately after asking for the original to be deleted. Manifold needs to do some cleanup--I don't know if script execution will necessarily wait until that's done.

You could wait for ComponentSet.ItemByName() to return -1 for the original folder name before recreating it. That would be safe.

steveFitz

340 post(s)
#01-Apr-16 02:23

All good things to think about as well as a test to make sure the script itself doesn't reside in the folder too.

tjhb
10,094 post(s)
#01-Apr-16 02:33

Excellent point! Neither bathwater nor baby.

oisink
370 post(s)
#01-Apr-16 15:53

Hi Steve

Nice, works well. I tried it with 156 components in the folder. All were deleted and the folder recreated almost instantaneously, with no errors.

As an aside, I previously tried folder.children.removeall, but unexpectedly (to me anyway) this removed the folder component, but only orphaned the children, i.e. they remained but outside of any folder.

Others should note, whilst the code above works, the variable names may mislead. In your revised code above 'dwgcompset' is a Component, not a ComponentSet.

Rgds O

tjhb
10,094 post(s)
#01-Apr-16 16:59

As an aside, I previously tried folder.children.removeall, but unexpectedly (to me anyway) this removed the folder component, but only orphaned the children, i.e. they remained but outside of any folder.

By 'removed the folder component', you mean 'removed the components from the folder', right? The folder itself was not removed.

oisink
370 post(s)
#01-Apr-16 18:39

No, the opposite. The folder was not removed, but nor were the components within the folder, which were no longer within any folder.

tjhb
10,094 post(s)
#01-Apr-16 19:24

Good. The components were removed from the folder (from the set Folder.Children), but not from the project (from Document.ComponentSet). Exactly correct.

tjhb
10,094 post(s)
#01-Apr-16 22:02

I tried it with 156 components in the folder. All were deleted and the folder recreated almost instantaneously, with no errors.

I still think this is risky, especially if some or many of the components are in one or more maps (and especially if the maps have recently been open). A script with no delay and no checking may sometimes fail with "unknown error". That could be wrong.

steveFitz

340 post(s)
#02-Apr-16 07:41

I still think this is risky, especially if some or many of the components are in one or more maps (and especially if the maps have recently been open). A script with no delay and no checking may sometimes fail with "unknown error". That could be wrong.

Interesting conjecture tjhb.

While I don't have reason to doubt, I would like to see a concrete example to help us refine our code.

tjhb
10,094 post(s)
#02-Apr-16 08:03

An example of a reproducible error using your code? Or an example of safer code?

steveFitz

340 post(s)
#02-Apr-16 08:17

Ideally both. One to demonstrate the need for the other.

Or perhaps some principals of good coding in this instance to point us in the right direction?

tjhb
10,094 post(s)
#02-Apr-16 09:10

Thanks, of course--it's been a long day and my intuition is not working as well as it should.

Manifold User Community Use Agreement Copyright (C) 2007-2021 Manifold Software Limited. All rights reserved.