Model.save don't generate the thumbnails

Hello
I wrote a script to batch rename the component definition saved in a folder.
The script works well and does its job.

The only issue is that the copies don’t have their thumbnails generated on save.
Here is the recording part of my script

def renommer_definition(file,prefixe,dossier_cible,erreur)
  file_name = File.basename(file,".skp")  
  status = Sketchup.open_file(file, with_status: true)
  if status == false
    erreur = "#{erreur}\n#{file}"
    return erreur
  else
  model = Sketchup.active_model
  model.name = prefixe + file_name
  view = Sketchup.active_model.active_view
  new_view = view.zoom_extents
  file_new_path = dossier_cible + "/" + File.basename(file)
  model.save(file_new_path)
  puts "File => #{file}\n\tNouvelle définition : #{prefixe + file_name}\n "
  end
end

Did I forget a parameter, or a command call to generate the thumbnail?

Thank you for your lights!

A few observations …

This method call may be asynchronous. The view may not be done redrawing before subsequent Ruby statements (saving the model) are executed.

Your code may need to use a temporary ViewObserver and detect that the view has been changed and save the model in the in onViewChanged() callback.

The temporary observer can be detached just before the file save in the observer callback. (Be careful here with saving. Internally, saving is moving towards a multi-threaded operation.)


Just noting that , if the path is changed, there will still be an old file with the old name property and the view unzoomed at the previous file location.


Try to leverage existing library methods.
String concatenation creates excessive intermediate String objects.

Ie:

  file_new_path = File.join(dossier_cible, File.basename(file))

The File.join method will automatically join the string arguments with the File::SEPARATOR character (which is set to "/" for the two operating systems SketchUp Desktop runs on.)


Note that you do not really need the else clause in the above snippet, as you have a return within the if clause. Replace the else with end; and delete the unneeded end after the puts statement.

Also, you could replace …

  if status == false
    erreur = "#{erreur}\n#{file}"
    return erreur
  end

… with a one-liner using the conditional expression in modifier position. Ex:

  return "#{erreur}\n#{file}" unless status

Generally it is poor practice to use boolean test expressions like :

  if status == false

This is because the if and unless statements are already testing for truth and falsehood (respectively). So calling the #== method upon the preceding object (and passing a true or false argument) is just adding unnecessary time to the execution of your code.

So use:
if !status
… or …
unless status
… in such places.

1 Like

Thanks De for this lesson Ruby. I will try to digest all of this.
The new file path is the consequence of a previous option in the code which proposes to overwrite or create a copy in another folder.
I will try the implementation of the view observer.
I risk coming back to be corrected, because I have never had a fulfilling relationship with them! :cold_sweat:
Thank you again and good night French time

Hello Dan
I tried to add two observers, but the result is the same. The backup command is faster than “view.zoom_extents”. And the new files don’t have thumbnails.

I can’t synchronize responses.

Here is my code:

# SCRIPT RUBY
# TITRE : BATCH RENAME DEFINITION MODEL FROM NAME FILE
# AUTOR : Simon JOUBERT
# Date : 2022/10/11
# VERSION : 1.0
# OBJET : Renommer par lot le nom de la définition du modèle. en utilisant le nom du fichier et un prefixe

# INVITES 1 : Sélection du dossier source
# INVITES 2 : Choix du mode d'enregistrement  (Ecrasement ou copie dans un dossier cible)
# INVITES 2 BIS : Sélection du dossier cible
# INVITES 3 : Définir le préfixe

# INITIALISATION : Copiez le code dans la console ruby et appyer sur la touche "Entrée"
# UTILISATION : Taper la commande suivante "renommer_model_de_tous_les_fichiers()" sans les guillemets



module Simjoubert
  module BatchRenameModel

    def self.renommer_model_de_tous_les_fichiers()
      puts "### DEPART MODIFICATION NOMS DES DEFINITION PAR LOT"
      # 1 - selection du dossier source
      dossier_source = selection_repertoire
      puts "Dossier Source: #{dossier_source}"
      return if dossier_source.nil?
      test_fichiers_existants(dossier_source)
    end

    # 2 - recuperation de  tous les fichiers Sketchup du dossier source
    def self.test_fichiers_existants(dossier_source)
      all_files = recuperation_des_fichiers(dossier_source)
      if all_files.length == 0
        message = UI.messagebox("Il n'ya aucun fichier Sketchup dans le dossier !\n#{dossier_source}\n Voulez-vous sélectionner un autre dossier ?", MB_RETRYCANCEL)
        if message == 4
          renommer_model_de_tous_les_fichiers
        else
          puts "### ABANDON ###"
        end
      else
        puts "Liste des fichiers :"
        all_files.each do |file|
          puts file
        end

        # 3 - Choix du répertoire cible
        dossier_cible = formulaire_Dossier_cible(dossier_source)
        if dossier_cible.nil?
          dossier_cible = dossier_source
        end


        # 4 - Choix du préfixe pour le nom des définitions
        dossier_name = (dossier_source.split("/"))[-1]

        preference_prefixe = formulaire_prefixe(dossier_name)
        ajouter_prefixe = (preference_prefixe[2] == "Oui" ? true : false )
        compeur_digit = preference_prefixe[1].length
        prefixe_name = preference_prefixe[0]

        # 5 - Boucle sur chaque fichier

        # initialisation compteur
        i=0
        # initialisation erreur
        erreur = []

        # add model spy
        model = Sketchup.active_model
        model_spy = MyModelObserver.new
        model.add_observer(model_spy)

        all_files.each do |file|
          if ajouter_prefixe == true
            prefixe = prefixe_name + "%0#{compeur_digit}d" % i + "_"
          else
            prefixe = ""
          end
          puts "Préfixe #{prefixe}"
          renommer_definition(file,prefixe,dossier_cible,erreur,model_spy)
          i +=1
        end
        if erreur != []
          erreur = "Impossible d'ouvrir les fichiers suivants :\n\t#{erreur.join("\n\t")}"
          puts erreur
        end

        message = UI.messagebox("Les définitions des #{i} fichiers ont été renommées.", MB_OK)
        puts "### FIN MODIFICATION NOMS DES DEFINITION PAR LOT"
        model.remove_observer(model_spy)
      end

    end



    def self.selection_repertoire()
      UI.select_directory(
        title: "Sèlection du dossier contenant les composants à renommer"
      )
    end

    def self.recuperation_des_fichiers(dossier_source)
      Dir.glob("#{dossier_source}/**/*.skp")
    end

    def self.formulaire_Dossier_cible(dossier_source)
      prompts = ["Créer copie dans un autre dossier"]
      defaults = ["Créer des copies dans un sous dossier"]
      list = ["Ecraser les originaux|Créer des copies dans un sous dossier"]
      input = UI.inputbox(prompts, defaults, list, "Mode d'enregistrement")
      if input[0] == "Ecraser les originaux"
        dossier_cible = dossier_source
      else
        dossier_cible = selection_repertoire
      return dossier_cible
      end
    end

    def self.formulaire_prefixe(dossier_name)
    prompts = ["Préfixe", "Compteur", "Ajouter un préfixe"]
    defaults = [dossier_name, "000","Oui"]
    list = ["", "|0|00|000|0000","Oui|Non"]
    input = UI.inputbox(prompts, defaults, list, "Definir le préfixe du nom des définitions")
    return input
    end


    def self.renommer_definition(file,prefixe,dossier_cible,erreur,model_spy)
      file_name = File.basename(file,".skp")  
      status = Sketchup.open_file(file, with_status: true)
      unless status
        erreur << file
        return erreur
      else
      model = Sketchup.active_model   
      model.name = prefixe + file_name
      file_new_path = File.join(dossier_cible, File.basename(file))
      view = Sketchup.active_model.active_view

      # Modify model_spy 
      model_spy.set_view = view
      
      # add view spy
      view_spy = MyViewObserver.new(file_new_path)
      view.add_observer(view_spy)

      # Modify model_spy 
      model_spy.set_viewSpy = view_spy  

      new_view = view.zoom_extents
      
      
      puts "File => #{file}\n\tNouvelle définition : #{prefixe + file_name}\n "
      
      end
    end


    def self.save_model(path)
      Sketchup.active_model.save(path)
    end

    class MyViewObserver < Sketchup::ViewObserver
      def initialize(path)
        @path = path
      end
      def onViewChanged(view)
        puts "onViewChanged: #{view}"
        Sketchup.active_model.save(@path)    
      end
    end


    class MyModelObserver < Sketchup::ModelObserver
      def initialize()
        @view = nil
        @view_spy = nil
      end
      def set_view=(new_view)
        @view = new_view
      end
      def set_viewSpy=(new_view_spy)
        @view_spy = new_view_spy
      end

      def onPreSaveModel(model)
        puts "onPreSaveModel: #{model}"
        @view.remove_observer(@view_spy)
      end
      def onPostSaveModel(model)
        puts "onPostSaveModel: #{model}"     
      end
    end

  end #fin modul
end #fin espace de nom

Thanks for your feedback.

1 Like

All I can say is log an issue in the API tracker at GitHub.

1 Like