How to get the saved file path
-
SketchUp version: 8.0.4811
Operating system: windows 7As I need to save an XML file with the same name of the sketchup file and in the same directory from a ruby script,
I've tried to use the model observer's OnPostSaveModel event, but the model.path is not updated.Let me explain with an example.
Let's say that I create a MyModelObserver class:
class MyModelObserver < Sketchup::ModelObserver
def onPostSaveModel(model)
UI.messagebox("Path = '#{model.path}' ")
end
endand that I attach an istance of this class to the model:
Sketchup.active_model.add_observer(MyModelObserver.new)
Now, if I create a new file from SketchUp and then save it on my desktop as, i.e., "Try1.skp", the message box shows: Path = ''
But after this, opening the console and writing: puts Sketchup.active_model.path
shows the correct info.Conclusion: it seems to me that this is a bug, and I've already filled the bug form, but meanwhile anybody knows a workaround?
-
You need to have an AppObserver AS WELL - see here -
http://code.google.com/apis/sketchup/docs/ourdoc/appobserver.html
This will spot when Sketchup opens a new SKP or just other model, you then attach your observer to the current SKP to get its path...BUT... why do you need to go to the convolution of observers etc if all you want is a way to get the folder the SKP is in and its name to create a matching xml file ?
This does it without complications...
model=Sketchup.active_model path=model.path if not path or path=="" UI.messagebox("Save the model before making the XML file!") return nil end xmlpath=File.join(File.dirname(path), model.title+".xml")
Then do your stuff writing the xml file etc...
This code always returns the current path/name of the model if it's been saved...
-
The
Dir.pwd
will return the current working directory this might be 'Plugins' and not the SKP's folder.- With a new [unsaved] SKP you don't know where to save your file - I showed this in my example...
- The onSaveModel observer should then return the current 'model.path' ?
??
-
Hi TIG,
I don't think I need the AppObserver, I only need to save the xml file whenever the user save the sketchup file, without disturb him.
Lets see two example where the AppObserver doesn't help.1Β° Scenario: The user create a new file:
The "Sketchup.active_model.path" is an empty string, until is saved. So is useless during the AppObserver "onNewModel" event firing.2Β° scenario: Lets say the user has saved the file, or opened one, so that the "Sketchup.active_model.path" contain his path. But then, if the user decide to use the "Save as" command to save the file to a new location, then I need to save the xml file to the new location, and in this case only the ModelObserver events ("onPreSaveModel", "onSaveModel" and "onPostSaveModel") are fired, not the AppObserver ones.
And if you use the "Sketchup.active_model.path" in the "onPostSaveModel" event, it's not nil nor empty, it contains the old folder and name info!
Note that the word "post" should state that everything involved with the saving action is done, but something still appen after the firing of the event, because when you check again the value of "Sketchup.active_model.path" from the console, it the right one!
So this is definitely a bug, and I hope they will fix it as soon as possible.
I do think that SketchUp is an incredible powerfull program (that I use from version 1.0 !) but IMHO they should revise the full set of observers, and give us (working) pre and post events for all the events. Observers are great, easy to use and a very neat way to extend and personalize SKU, but without pre and post events, many of those are useless at best, and a sure way to crash the program at worst.
The second scenario is also a good answer for your question, i.e. "why do I need to bother with observers": I need to observe the user and take an action (build the xml file and save it with the same name of the SKU file, in the same directory) whenever he save the SKU file.
Meanwhile, I've found that when the user save the file I can find the directory using the standard ruby "Dir" class, with "Dir.pwd" (program working directory) but alas this doesn't help me on regard of the filename that the user has chosen for the SKU file.
-
Hi TIG,
second first: I'm talking about the onPostSaveModel. I don't pretend to save the xml file before or during the saving of the SKU file (where obviously the model.path and model.title cannot contain any data) but after the user has saved it. That's why I use the onPostSaveModel.You know you can create a class that is a descendant of the Sketchup::ModelObserver class and override the desired methods, like this one:
class MyModelObserver < Sketchup;;ModelObserver def onPostSaveModel(model) msg = "OnPostSaveModel; \n" + "- Path = '#{model.path}' \n" + "- Title = '#{model.title}' \n" + "- Dir.pwd = '#{Dir.pwd}'" UI.messagebox(msg) end end
When you attach an istance of the MyModelObserver to the model, with:
Sketchup.active_model.add_observer(MyModelObserver.new)
Everytime the SKU file is saved, the onPostSaveModel method is executed.
Here for debugging I'm just checking the model.path value showing it with the messagebox, but in real code I do all the things needed to create the xml data and save it using the model.path (if only it would contain the correct data!)
For the Dir.pwd check for yourself if you dont trust me
Inside the onPostSaveModel method it return the folder where the model has been saved.
But Model.path and Model.title don't.Thanks for all the patience and effort you are putting on helping me.
-
Unfortunately the onPostSaveModel method returns the model.path and model.title as it was BEFORE the save !
It is no different from the onPreSave... and onSave... methodsThis recoded way ensures that your code waits for half a second before kicking in - at that point the recently saved model path and title ARE accessible
class MyModelObserver < Sketchup;;ModelObserver def onPostSaveModel(model) tid=UI.start_timer(0.5,false){ puts("OnPostSaveModel;\n- Path = '#{Sketchup.active_model.path}'\n- Title = '#{Sketchup.active_model.title}'\n- Dir.pwd = '#{Dir.pwd}'") UI.stop_timer(tid) } end end
Note that I used a puts in the test as a UI.messagebox will make multiple instances of the dialog until you OK it! A puts just does the one report in the Ruby Console.
Your code [or a mthod invoking it] needs to go into the {} of the start_timer.
I think you can get away with the stop_timer line...Also you CANNOT rely on the Dir.pwd to give you the correct path.
If you do a 'save' on a SKP that has never been saved before or a 'save_as' then Dir.pwd does return the folder where the SKP now resides, BUT if you do a 'save' on a previously saved SKP that just been reopened then Dir.pwd will return the path to the Plugins folder
However, with the timer fix you can now get the correct path/title anyway.Note that the model-observer is only attached to the model that is active when you launch Sketchup and subsequent new/existing SKPs opened from the menu will not get the observer. As explained earlier an AppObserver can watch for Sketchup doing this and then it can attach your onPostSave observer to the newly opened SKP too.
-
Hi TIG,
thanks a lot, your workaround is great, and you really saved my life!
Thank you also for the detailed explanation of the unreliability of the Dir.pwd.
About the AppObserver, I already use it to attach the model observer to the model, as you wrote, so non problems with that .As I said, the whole observer set should be revised. Look at some oddities:
- We have the onNewModel and onOpenModel, but where is the onCloseModel?
- The onQuit is useless, because when fired the active_model is already gone with the wind...
- The Model observer has onBeforeComponentSaveAs and onAfterComponentSaveAs, but also onPreSaveModel, onSaveModel and onPostSaveModel: they used the words "Before" and "After" but also "Pre" and "Post". This is non consistent and show that there isn't a coherent and organic view of the complete set.
I do hope that version 9 will do a complete redesign of events and observers.
We need more control on what the user do, also to prevent him on doing some things. I'm developing a program where I need to prevent the user to edit some component definitions and there is no simple way of doing that. But this is another story...
Anyway, thanks again for your precious help.
-
After some experiments, I'd like to add two things:
-
The Timer seems to ignore the no-repeat flag, so if the code (a delegate, tech speaking ) use more time than the timer interval, the timer start a new execution of the code. That's why the UI.messagebox create such a mess...
-
The solution is to move the stop.timer execution at the very begin of the code:
class MyModelObserver < Sketchup;;ModelObserver def onPostSaveModel(model) timer_id = UI.start_timer(0.5,false) do UI.stop_timer(timer_id) msg = "OnPostSaveModel; \n" + "- Path = '#{model.path}' \n" + "- Title = '#{model.title}' \n" + "- Dir.pwd = '#{Dir.pwd}'" UI.messagebox(msg) # Generate and save xml report # ... end end end
Thanks again.
-
-
@tig said:
Unfortunately the onPostSaveModel method returns the model.path and model.title as it was BEFORE the save !
It is no different from the onPreSave... and onSave... methodsObserver bug?
-
@thomthom said:
Observer bug?
Hi thomthom, can you please remove the question mark?
I've spent (lost...) two days to find a solution, and wrote a lot about it. Thanks god TIG helped me finding a workaround.
But now we can surely say that is a bug.
And I've already filled the form you pinned for it. It's a pity that we can't track the bug, nor vote for it, otherwise I'd begged you for a vote!
(Ok, this reply was only an excuse to thank TIG one more time!)
and... ops! also the timer seems to have a bug because it doesn't stop even if the repeat flag is false
-
The timer should [will] stop when given a 'false' repeat argument, if the process only involves a 'puts' or other non-interruptive code.
BUT if it involves a UI.messagebox it keeps firing repeatedly until the dialog is closed - probably another bug -
-
Hey,
I ran into the same problem as Nick60 today and was glad I found this thread with an nice solution.
However there's still one use case with a problem:
when the user saves the model with "Save copy as..." the side-car file will be saved under the wrong name.
Any suggestions how this could be fixed?
Advertisement