Select Elements Modified Last by User

# -*- coding: utf-8 -*-

# ╦╔╦╗╔═╗╔═╗╦═╗╔╦╗╔═╗
# ║║║║╠═╝║ ║╠╦╝ ║ ╚═╗
# ╩╩ ╩╩  ╚═╝╩╚═ ╩ ╚═╝ IMPORTS
#==================================================
from Autodesk.Revit.DB import *
from pyrevit import forms

import clr
clr.AddReference('System')
from System.Collections.Generic import List

# ╦  ╦╔═╗╦═╗╦╔═╗╔╗ ╦  ╔═╗╔═╗
# ╚╗╔╝╠═╣╠╦╝║╠═╣╠╩╗║  ║╣ ╚═╗
#  ╚╝ ╩ ╩╩╚═╩╩ ╩╚═╝╩═╝╚═╝╚═╝ VARIABLES
#==================================================
uidoc     = __revit__.ActiveUIDocument
doc       = __revit__.ActiveUIDocument.Document
selection = uidoc.Selection # type: Selection

# ╔╦╗╔═╗╦╔╗╔
# ║║║╠═╣║║║║
# ╩ ╩╩ ╩╩╝╚╝ MAIN
#==================================================
# Get All Elements
elements = FilteredElementCollector(doc).WhereElementIsNotElementType()\
                                        .WhereElementIsViewIndependent()\
                                        .ToElements()

# Sort Elements by User LastChangedBy
from collections import defaultdict
elements_sorted_by_last_user = defaultdict(list)
for el in elements:
    try:
        wti = WorksharingUtils.GetWorksharingTooltipInfo(doc, el.Id)
        last = wti.LastChangedBy
        elements_sorted_by_last_user[last].append(el.Id)
    except:
        pass

# Select User
selected_user = forms.SelectFromList.show(elements_sorted_by_last_user.keys(), button_name='Select User')

# Prepare Selected Elements
element_ids        = elements_sorted_by_last_user[selected_user]
List_new_selection = List[ElementId](element_ids)

# Change Revit UI Selection
uidoc.Selection.SetElementIds(List_new_selection)



Explainer:


Get All Elements

➡️ First, let’s get all 3D elements in our Revit project. We’ll use the FilteredElementCollector for that. We can apply WhereElementIsViewIndependent to get all 3D Elements and exclude view dependant elements like tags and dimensions.

elements = FilteredElementCollector(doc)\
    .WhereElementIsNotElementType()\
    .WhereElementIsViewIndependent()\
    .ToElements()

💡 Tip: You can adapt this method to collect different types of elements depending on your needs.

Who Did That?

Now we can go through all elements and look inside who touched them last.

There is a WorksharingUtils class in Revit API that has a method - GetWorksharingTooltipInfo.


This method returns a WorksharingTooltipInfo object with these key properties:


Here is a code sample:

el = ...  # Get Element Here...

# Get WorksharingTooltipInfo
wti = WorksharingUtils.GetWorksharingTooltipInfo(doc, el.Id)

# Get Properties
owner       = wti.Owner
changed_by  = wti.LastChangedBy
creator     = wti.Creator

💡 Focus on the property that matters most to you.

Sort Elements by User

By now you have all 3D elements and you know who touched them last. Let's sort it in a dictionary sorted by LastChangedBy user.


I will use defaultdict. It allows you to specify the default value for items in case they don't exist. This will help you avoid the error and save a few lines of code so you can append items even to new keys right away.

❌ Otherwise you would need to check if user already exists in a dict, and either create an empty list or append to existing. Sounds boring, isn't it...

Here is the Code

# Get All Elements
elements = FilteredElementCollector(doc)\
    .WhereElementIsNotElementType()\
    .WhereElementIsViewIndependent()\
    .ToElements()

# Create defaultdict
from collections import defaultdict
elements_sorted_by_last_user = defaultdict(list)

# Sort Elements by User LastChangedBy
for el in elements:
    try:
        wti = WorksharingUtils.GetWorksharingTooltipInfo(doc, el.Id)
        last = wti.LastChangedBy
        elements_sorted_by_last_user[last].append(el.Id)
    except:
        pass

👉 Select User from List

Lastly, let's create a simple UI form to choose between users to select elements.

The easiest way to do that is to use ​SelectFromList ​form from ​pyrevit.forms​.


And that's how it will look:

from pyrevit import forms

# Get all Users from dict
all_users = elements_sorted_by_last_user.keys()

# Select User
selected_user = forms.SelectFromList.show(all_users, button_name='Select User')

print('Selected User')

Select Elements

Now we have everything we needed. We just need to select these elements with ​Selection.SetElementIds()​.

# import .NET List
import clr
clr.AddReference('System')
from System.Collections.Generic import List

# Prepare Selected Elements
element_ids          = elements_sorted_by_last_user[selected_user]
List_new_selection   = List[ElementId](element_ids)

# Change Revit UI Selection
uidoc.Selection.SetElementIds(List_new_selection)


Since it need ICollection<ElementId> we need t convert a list of items into a .NET List[ElementIds]. That's not complicated, you just need to import it and specify the right Type.

Here is the code:








⌨️ Happy Coding!
Erik Frits