Bugsplat after a component definition save_as

bug
components

#1

I have a problem with a bugsplat if I save a component in a separate skp file using the save_as method.
By now, I have noticed that the bugsplat can be prevented if I hold the mouse pointer not above the plot area (view) of Sketchup, but for example above the tray or the ruby console.
There is at that time a private tool active, but no observers.
Moreover, the save_as method still run correctly, but once the script is finished the bugsplat is there.
Anyone have any idea how to prevent this?


#2

SketchUp version ?
OS platform and version ?
Minimum reproducible code example ?


Official API Issue Tracker is here …


#3

Hmmm … if the mouse is moved SketchUp may try to call the tool’s onMouseMove callbacks in the middle of the save operation.

I strongly suggest suspending your tool until the save operation is complete.


#4

SU2018
Windows 10 Home

ruby_tool = Sketchup.active_model.tools.pop_tool()

if frame_definition.save_as("#{folder}/#{project_folder}#{self.code}.skp")

    store_succes = true

end

if ruby_tool

     # Do NOT prevent for bugsplat
     Sketchup.active_model.tools.push_tool(ruby_tool)
    
     # Do prevent, but tool must be reactivated by user
     Sketchup.active_model.select_tool(nil)
	
end

#5

Hi Dan,
How can i suspend a tool?
Simply by calling the suspend method?


#6

:suspend and :resume are really about ‘orbit’ and ‘pan’ not your code flow…

I tend to wrap exports of any kind in a timer as some things run in a spawned thread…

If overwriting an existing file I use File.remove first…

def wait4export(export_file)
  # check File.size() if the export is completed
  @export_size = 0
  wait_for_export = UI.start_timer(0.1, true) { 
    Sketchup.active_model.definitions[0].save_as(export_file) unless File.exists?(export_file)
    export_size = File.size(export_file) rescue export_size = 1
    if export_size != @export_size
      @export_size = export_size
      p export_size
    else 
      UI.stop_timer(wait_for_export)
      p 'export completed'
    end
   }
 end
# to test change the path
test = '/private/tmp/test.skp'
wait4export(test)

EDIT: you will need to point to your component as well…


#7

By doing exactly what you did in the example above.

The suspend() method is actually a SketchUp engine callback method that should have been named onSuspend(), but was not. So you need to let SketchUp call those callbacks.

In your case, you’d need to let the deactivate and activate callback methods to save and restore tool state. These are also called by the SketchUp engine, when you pop tool and push tool. (You do not call them directly.)

If SketchUp does not wait for the save_as() to complete, then you’d need to use a UI.start_timer block to test when the component SKP file’s modified time is updated. See File::mtime() class method. Once updated, you can then push your tool object back onto the model’s tool stack.


Please note how to post code in the forums …


#8

Thanks Dan!, pushing back the tool in a start_timer block is preventing a bugsplat. I wrote a special function for it.

def self.Save_As_With_Bugsplat_Prevention(component_definition, export_file)
	
	# Get the active ruby_tool, by removing from tool stack
	if !(Sketchup.active_model.tools.active_tool_id.equal? 0)
		ruby_tool = Sketchup.active_model.tools.pop_tool()
	else
		ruby_tool = false
	end
	
	# Remove file if already exist
	if File.exists?(export_file)
		File.delete(export_file)
	end
	
	# Save the component to file
	store_succes = component_definition.save_as(export_file)
	
	# Push back last ruby_tool to tool stack.
	if ruby_tool
		# Check on File.size() if export is completed
		previous_export_size = 0
		wait_for_export = UI.start_timer(0.1, true) {
			export_size_progress = File.size(export_file) rescue export_size_progress = 1
			if export_size_progress != previous_export_size
				previous_export_size = export_size_progress
			else
				Sketchup.active_model.tools.push_tool(ruby_tool)	
				UI.stop_timer(wait_for_export)
			end
		}
	end
	
	return store_succes
	
end

#9

Thanks John, for timer example.


#10

I’ll pick a nit for improvement of your future Ruby code:

You are using the fact that Ruby considers anything except the constants false and nil to be true in logic expressions. Many authors see this aspect of Ruby as muddy semantics since one can never be sure what “true” actually is. In your code, instead of setting

ruby_tool = false

I’d set it to nil. And then in the if expression to see if there is a tool to push, use

unless ruby_tool.nil? # or if !ruby_tool.nil? 

for the branch that decides whether to pop the tool back.