Is there a way to access the list of recently opened sketchup files?


#1

As I enter into Sketchup, I would like to provide a prompt that allows me to immediately open the last Sketchup file opened. Is the list of recent files available to ruby?


#2

For older versions of Sketchup the Recent File List is in the registry. Look at:
HKEY_CURRENT_USER\Software\SketchUp\SketchUp 20xx\Recent File List. I don’t have a machine with Sketchup 2018 in front of me at the moment to check the latest.

Access from Ruby is by Win32::Registry::HKEY_CURRENT_USER
see: https://ruby-doc.org/stdlib-2.0.0/libdoc/dl/rdoc/Win32/Registry.html
or here: https://ruby-doc.org/stdlib-2.0.0/libdoc/fiddle/rdoc/Win32/Registry.html


#3

when you click “file” to open a file, at the bottom of the roll out there should be a list of recent files. but this is in SU 2018, not sure how it is in SU8?


#4

… also if you pin the SketchUp shortcut to the Windows taskbar or the start page, a recent files list will appear on the shortcut’s right-click popup menu.


To do a prompt at startup, try …

require "win32ole"

# Microsoft Docs > Windows Scripting Host > SendKeys method:
# https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/windows-scripting/8c6yea83(v=vs.84)

SJN ||= Module.new
module SJN::LastModelOpener

  # NOTE: This module is also used as an Sketchup::AppObserver object.

  extend self

  @@loaded = false unless defined?(@@loaded)
  @@first  = true  unless defined?(@@first)

  WshShell = WIN32OLE.new("WScript.Shell")

  def expectsStartupModelNotifications # AppObserver callback
    return true
  end

  def onNewModel(model) # AppObserver callback
    if @@first
      @@first = false
      Sketchup.remove_observer(self) # detach AppObserver
      # Do not automatically open last model if another
      # skp file was double-clicked to start SketchUp:
      if Sketchup.active_model.title.empty?
        # PROMPT ...
        choice = UI.messagebox("Open model from last session?",MB_YESNO)
        open_recent_skp("1") if choice == IDYES
      end
    end
  end

  def open_recent_skp(num)
    # % means ALT key. ALT+F will be File menu on English systems.
    # The last saved model opened will always be prefixed by "1".
    # This will be the current open model if it was saved, or the
    # model file from previous session if not. IF the current skp
    # has been saved or SketchUp was opened by double-clicking a
    # a file, then the last session model will be prefixed by "2".
    WshShell.SendKeys("%F#{num}")
  end

  unless @@loaded # Do this code ONCE ...

    UI.add_context_menu_handler do |popup|
      if Sketchup.active_model.title.empty? # ie "Untitled"
        popup.add_item("Open Model from Last Session") { open_recent_skp("1") }
      else
        popup.add_item("Open Previous Model") { open_recent_skp("2") }
      end
    end

    # Attach this module itself as the AppObserver object:
    Sketchup.add_observer(self)

    @@loaded = true
  end

end # outer namespace modules

#5

Thank you for being so responsive, and helpfully instructive.

And Dan, thanks for the example you sent. That was quite generous, and I will give it try and see how it works. It took me a while to get through the Namespaces concept, but I have finally conquered the concept and am implementing throughout my code. My first attempts were not successful because of urgency of the projects, and of course, as a result my code was quite unwieldingly long and difficult to debug. But these last few weeks, I have returned to the project and have studied and experimented with the information you have previously shared with others about Namespaces. I get it now, and I have been able to successfully create the modules I need for the application I am developing.

While awaiting feedback for my question, I was able to experiment with a few ideas, in which the result allowed me to generate a different method in order to achieve my objective and provided with a few more details about the files themselves. If anyone is interested I’d by happy to share the concept and the results.

Thanks again.

Scott.


#7

If you don’t want to rely on OS specific hacks or directly read the Windows Registry you could also keep your own list of recent files, and use an observer to save values to that list. This allows the script to work on other platforms, on localized builds where access keys may differ and on future SketchUp versions where the data may be saved elsewhere.


#8

Here’s a code example of how to get prompted for opening the last saved model on SketchUp launch

module YourName
module OpenLastModel
  PLUGIN_ID = "your_name_open_last_model"

  class MyAppObserver < Sketchup::AppObserver
    @@launching = true

    def expectsStartupModelNotifications
      true
    end

    def onOpenModel(model)
      @@launching = false
      return if model.title.empty? # Empty new model.

      # SketchUp's write_default fails if String contain backslashes.
      Sketchup.write_default(PLUGIN_ID, "last_model", model.path.tr("\\", "/"))
    end

    def onNewModel(model)
      return unless @@launching
      @@launching = false

      path = Sketchup.read_default(PLUGIN_ID, "last_model")
      return unless path

      text = "Do you want to open last saved file?"
      return unless UI.messagebox(text, MB_YESNO) == IDYES

      Sketchup.open_file(path)
    end
  end

  unless @loaded
    @loaded = true
    Sketchup.add_observer(MyAppObserver.new)
  end
end
end

In an actual plugin I’d get PLUGIN_ID from the basename of the loader file. You can also update onNewModel to include the path in the text box, as a mean to identify the last file before loading.

Btw, I would strongly advise against misusing the context menu for entries not related to the current selection.