jure
October 8, 2023, 9:21am
1
Hi!
I’m looking for a developer that would write the code for “XREF” extension. The specification can be found here:
Thanks!
One of the challenges with XREF workflow is the lack of an API method to reload / refresh / update existing definitions in the model’s DefinitionsList
collection.
REF:
opened 11:03AM - 13 Feb 18 UTC
closed 12:58PM - 28 Feb 23 UTC
bug
Ruby API
C API
SketchUp
logged
fixed-SU2023.0
The current DefinitionList.load method is a drag to work with. It refuses to loa… d components from paths associated withe existing components that haven't been modified (since when, I don't know). Instead it just returns the existing component, even if the external file has been modified.
Sometimes it fails to load a new component even if the existing component is modified, but I'm not sure when or why (when the existing component was modified within the same operation as load was called maybe?). For these cases we have to first save out the existing component to a temp file, just to dissociate it with the path. This hack causes other issues though as ComponentDefinition.save_as doesn't seem to record to the undo stack (despite changing the path property of the definition).
DefinitionList.load has so many weird behaviors and exceptions it's hard to even summarize it; I may have gotten this wrong. I literally get a headache from trying to figure out this mess. If someone could summarize the current behavior as pseudo code or something that would be appreciated.
To reload/relink a specific CompoenntDefiniton today you have to make sure Definitionlist.load regards it as a separate component to be able to load it at all, then you have to replace all references to the old component with the new one, make sure the name is correct (not having #1 appended), and finally purge the old definition.
I suggest a ComponentDefinition.reload method that by default reloads the definition from its associated path. The new data should be loaded into the existing ComponentDefinition object, with all instances and Ruby references now referring to the new data. This method should also take an optional path argument to relink the component from a custom location. This should be possible even with another component associated by that path and should not interfere with that other component in any way. The only way this method is affected by other definitions is that it makes sure the loaded component doesn't get a name that is already used by another component.
Simply but this should be a Ruby handle for what in the GUI is accessed from context menu > Reload...
````ruby
model = Sketchup.active_model
# Reload the first component from it's associated path, or raise error if internal (no associated path)
# or file is missing.
# The ComponentDefinition object is still the same, but its geometric content, name and other properties
# are loaded from the file.
model.definitions.first.reload
# Reload the first component from given path.
# If there is already a component in the model associated by this path, reload anyway and have
# two separate ComponentDefinitions both associated with the same file.
# If the component name inside the external file is already used by another component
# (regardless of whether it's associated by the same path) a new unique name is created for the
# loaded component, just as when a component is made unique.
model.definitions.first.reload(path: "C:/Users/Eneroth/SketchUp/Model.skp")
````
I also suggest an improved/corrected DefinitionList.load method that just doesn't do a any stupid stuff by its own. By default it should behave identically to pasting a component instance from the clipboard in the GUI, i.e. check if the GUID of the external file is used by an existing ComponentDefinition, if so return that, otherwise create a new CompoenntDefiniton and assure there are no name collisions.
There could be an optional argument to force loading into a separate ComponentDefiniton object even if there is an identical ComponentDefinition already present in the model (=identical GUID). This would be useful if the developer wants to edit the loaded component directly after loading, and don't want to affect any existing instances. This would of course create a new unique name, and therefore a unique GUID, directly on load.
````ruby
# Loading from the same path could return the same CompoenntDefinition,
# but ONLY if the GUID is identical.
model = Sketchup.active_model
model.definitions.size # => 0
model.definitons.load("C:/Users/Eneroth/SketchUp/Model.skp")
model.definitions.size # => 1
model.definitons.load("C:/Users/Eneroth/SketchUp/Model.skp")
model.definitions.size # => 1
# *Editing external file, or internal component here*
# Now a new ComponenDefinitiont is created.
model.definitons.load("C:/Users/Eneroth/SketchUp/Model.skp")
model.definitions.size # => 2
# The method can also be forced to load as a new unique ComponentDefinition,
# even with no modifications to the file or existing component(s).
model.definitons.load("C:/Users/Eneroth/SketchUp/Model.skp", force_separate: true)
model.definitions.size # => 3
# In this example all components are associated by the same path, but are still separate objects.
model.definitions.map(&:path) =>
[
"C:/Users/Eneroth/SketchUp/Model.skp",
"C:/Users/Eneroth/SketchUp/Model.skp",
"C:/Users/Eneroth/SketchUp/Model.skp"
]
````
Perhaps the new DefinitionList.load needs to have a different name, and the old be kept as it is but deprecated, to assure backward compatibility.
This has been discussed in a [forum thread](https://forums.sketchup.com/t/fix-definitionlist-load-problems-in-some-situations/5655) and ThomThom has already logged this as SU-30933 and SU-31274.
2 Likes
jure
October 21, 2023, 2:07pm
3
Thank you for your input @DanRathbun . I guess some work around could be found untill (if ever) this gets fixed?
Actually, the load method was extended for 2021.0, but did not work correctly until 2023.0.
See: Sketchup::DefinitionList.html#load
In the past, very clunky and tedious workarounds would use: Sketchup::ComponentInstance#definition=
… and copy any attribute dictionaries, etc.