Protection for Editing Families

Hi all,
Idea is next - in the project we have some families what I would like nobody have a possibility to edit in Family Editor
These families have some text parameter “Protection” what means If this parametr exist - you cant open it
Problem for now - that I cannot close family document after
Maybe there are another more smart ways how to implement it
Thanks in advance
some code what I tried to make below

from pyrevit import forms
from pyrevit import EXEC_PARAMS
from Autodesk.Revit.DB import *

doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument
app = __revit__.Application

PName = 'Protection'
rf = []

if EXEC_PARAMS.event_args.Document.IsFamilyDocument:
    for a in EXEC_PARAMS.event_args.Document.FamilyManager.GetParameters():
        r = a.Definition.Name
        rf.append(r)
    if PName in rf:
        forms.alert("You Can NOT Edit This Family")
        prv = EXEC_PARAMS.event_args.PreviousActiveView
        prd = prv.Document
        Document(prd).RequestViewChange(prv)

Hi @ginttaras!

I’m not 100% sure, but I think such modifications are not possible during the event handling.
RequestViewChange() should be called from the previous UIDocument which has to be activated prior to that. And when you try to do that, you will most likely get an exception :frowning_face:

Maybe you can figure something out with the IUpdater

Also check this article:

1 Like

I managed (edit) almost managed to do it using the doc-updater hook and FailureMessage :grinning:

code in startup.py:

from System import Guid
from pyrevit import DB, HOST_APP

definition_guid = Guid('A4F1CF93-CD36-42A7-AE6F-1CF55EB333DA')
definition_id = DB.FailureDefinitionId(definition_guid)

definition_registry = HOST_APP.app.GetFailureDefinitionRegistry()

if definition_registry.FindFailureDefinition(definition_id) is None:
    failure_def = DB.FailureDefinition.CreateFailureDefinition(
        definition_id,
        DB.FailureSeverity.Error,
        "This is a protected Family Document.\n :'-("
    )

code in doc-updater.py:

import traceback
from System import Guid
from pyrevit import DB, EXEC_PARAMS

event_doc = EXEC_PARAMS.event_doc  # type: DB.Document
updater_data = EXEC_PARAMS.event_args  # type: DB.UpdaterData

# kept for the reference, no need in this script
added_elem_ids = updater_data.GetAddedElementIds()
deleted_elem_ids = updater_data.GetDeletedElementIds()
modified_elem_ids = updater_data.GetModifiedElementIds()


def get_param_formula(family_doc, param_name):
    # type: (DB.Document, str) -> str
    param = family_doc.FamilyManager.get_Parameter(param_name)
    if param is not None:
        return param.Formula


def post_failure(event_doc, definition_guid):
    # type: (DB.Document, Guid) -> DB.FailureMessageKey
    definition_id = DB.FailureDefinitionId(definition_guid)
    failure_message = DB.FailureMessage(definition_id)
    return event_doc.PostFailure(failure_message)


if event_doc.IsFamilyDocument:
    try:
        param_formula = get_param_formula(event_doc, 'IsFamilyProtected')
        if param_formula == '2 > 1':
            definition_guid = Guid('A4F1CF93-CD36-42A7-AE6F-1CF55EB333DA')
            post_failure(event_doc, definition_guid)
    except Exception:
        print(traceback.format_exc())

In the protected family I created an integer parameter with the name IsFamilyProtected and set its formula to 2 > 1 (check-mark checked):

image

If you open this family as a file and try to modify anything, it shows the error message with only one option: to cancel the modification.

image

If you try to open this family directly from the project, it gives you the same message, then tells that family can not be edited. Even though it was not planned so… I don’t know why Revit counts it as a modification.

That was fun! :grinning:


edit:
Further testing showed that if I open family as a file, I still can change or delete the parameter, then protection will be lost. Would need to figure out some other workaround
:stuck_out_tongue:

2 Likes

Maybe you can store the info about protection status in an element in the family which is not so visible to the users. I would try to store it in a parameter of a View e.g. Ref.Level, Front or one with your custom name but the latter can be purged easily by error. User can delete it the same way, but my experience is that basically nobody checks these parameters.

Another way could be to store list of families on your server and check if the name is in the list. If it is you will cancel the event. However if user renames the family in the project browser it won’t work.

1 Like

I would create a DataStorage element in the Family for this purpose, and use ExtensibleStorage on this element to mark the Family. Still not bulletproof, but requires an advanced user with advanced tools to figure this out.

1 Like