Replace or influence the Save and SaveAs methods

Is there a good way to either mimic the Save and SaveAs methods or at least influence the existing methods to inject path and filename?

I have tried using the Rhino.UI.SaveFileDialog which I can fully control the path and filename, and I have also subscribed to the Rhino.Commands.Command.BeginCommand event. Each of these pose issues I can’t seem to find my way around.

With creating a substitute dialog I then need to actually save the file itself to disk. This only seems to more-or-less operate as an export where the active document remains open and unnamed. It also relies on users remembering to use this new command in lieu of the Save and SaveAs commands.

With subscribing to the event I can run lines of code before or after the original Save or SaveAs but I see no way to provide the path and filename it uses.

Please let me know if I am missing something.

Thank you,
Jeff

Hey @Jeffrey_Ries,

Are you trying to change where Rhino saves? What exactly are you trying to do.

Would either;

achieve what you need?

– cs

Thanks for your response @csykes

Yes, I am trying to fill-in-the-blanks of the save dialog before it is shown. Both filename and save location path would need to be changed.

Per your suggestions I looked at BeginSave event but cannot yet figure out how to use the BinaryArchiveWriter. I also just looked at the WriteDocument method but at first glance the filename property is read-only there too.

Still poking at it with a stick,
Jeff

Hey @Jeffrey_Ries,

So you want to, by default, whenever Save is called within Rhino, default the FileDialog to a path that you’ll determine? None of my solutions will achieve this.

I feel compelled to ask, as I want to help solve this, and avoid XY problems, why do you want to do this?

– cs

We have many Rhino users throughout many offices and would like to enforce file naming and folder structure standards. This will enable any of these users to better navigate each others projects.

Jeff

1 Like

That’s a very good reason.

I’ve had a poke around, and I can’t find anything that would do this, macros nor code-wise.

You could of course prompt users in a new, unsaved file to save it somewhere with a custom prompt that validates the name. But I don’t feel like this is a particularly good solution.

– cs

Hi @Jeffrey_Ries,

The behavior of Rhino’s Save/SaveAs command cannot be modified.

But, you can write your own custom Save/SaveAs commands using a plug-in.

– Dale

Hey @dale

Yes, I have already written my own Save/SaveAs commands which do most of what I want. However, when I get the result of the dialog and apply them to a WriteFile/WriteDocument/Doc.Save/Doc.SaveAs it treats it more like an export leaving the original document unnamed, unsaved and active. I feel this will be very confusing to the end users who will most likely continue working in the open document which they will eventually save again and wonder what is going on.

Do you know of any way to save the active document in-place where the user can then continue working?

This is why I experimented with subscribing to the Save & SaveAs events since they already do what I want. I just merely want to front load the filename and path.

Thanks,
Jeff

Hi @Jeffrey_Ries,

Once you have your path string built, I’d just script either the _-Save or _-SaveAs command.

– Dale

1 Like

Thank you @dale

You have gotten me so close to the finish line.

Protected Overrides Function RunCommand(ByVal doc As RhinoDoc, ByVal mode As RunMode) As Result
        Dim thisSelectEnEDialog As New SelectExhibitorAndEvent
        Dim thisSelectEnEDialogResult As Boolean = thisSelectEnEDialog.ShowDialog()

        If thisSelectEnEDialogResult Then
            ' Create Directory Structure
            Dim ExhibitorDir As IO.DirectoryInfo = Utilities.Directories.CreateDesignExhibitorDirs(thisSelectEnEDialog.ExhibitorName)
            Dim EventDir As IO.DirectoryInfo = Utilities.Directories.CreateDesignShowDirs(ExhibitorDir, CInt(Today.ToString("yyyy")), thisSelectEnEDialog.EventName)

            Dim thisActiveDoc As RhinoDoc = Rhino.RhinoDoc.ActiveDoc
            Dim thisSaveDialog As New Rhino.UI.SaveFileDialog With {
                .Title = "Smart Save",
                .DefaultExt = "3dm",
                .Filter = ".3dm",
                .InitialDirectory = EventDir.FullName & "\3D Design",
                .FileName = thisSelectEnEDialog.EventName & "_" & "V1"
            }
            If thisSaveDialog.ShowSaveDialog() Then
                Dim SaveScript As String = "_-SaveAs """ & thisSaveDialog.FileName.Substring(0, thisSaveDialog.FileName.Length - 4) & """"
                Rhino.RhinoApp.RunScript(SaveScript, True)
                RhinoApp.WriteLine("New file saved.")
            End If
        End If

        Return Result.Success
    End Function

The SaveScript variable returns the following:

"_-SaveAs ""\\det-fs3\Design\Client\Exhibitor\1_Shows and Events\2022-2023\Show Name 2023\3D Design\Show Name 2023_V1"""

However, it does not save the file. No feedback or errors either.

If I open Rhino manually and run _-SaveAs and paste the below excerpt of that string it works fine.

"\\det-fs3\Design\Client\Exhibitor\1_Shows and Events\2022-2023\Show Name 2023\3D Design\Show Name 2023_V1"

Also, if I hardcode the path it works. It just doesn’t seem to like a concatenated string.

Any ideas why this might be?

Thanks,
Jeff

Hi @Jeffrey_Ries,

Make sure your path string includes a file extension (e.g. ".3dm’).

Also, you might want to take advantage of .NET’s Path class for manipulating path strings.

– Dale

Hey @dale

I added the extension back in - no difference.

I then tried testing for finding that extension and rooted path with the System.IO.Path tests you suggested. - No difference.

I also replaced the manual double quotes with Char(34) - no difference.

Lastly, I mapped the network drive to replace UNC path - no difference.

If I programmatically run a script with a path it simply ignores it and fails. If I paste _-SaveAs and then separately paste the single-quoted path into Rhino’s command line the file saves as expected.

Will you please attempt this last test from your end and see if you get the same result?

"_-SaveAs ""C:\Test\File Name.3dm"""

Sorry to be a pest, but I have run out of ideas on my end.

Thanks,
Jeff

it must be something related to string manipulation/escaping in vb or the rhino save file dialog; try this in your python editor just to prove that scripting SaveAs works fine in your environment

import Rhino
import System

sfd = System.Windows.Forms.SaveFileDialog()
if sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK:
    # split the path and put it back together just to prove it works fine
    dir = System.IO.Path.GetDirectoryName(sfd.FileName)
    file = System.IO.Path.GetFileName(sfd.FileName)
    path = System.IO.Path.Combine(dir, file)
    Rhino.RhinoApp.RunScript('-_SaveAs "' + path + '"', True)

Hey @jdhill

The python script you provided runs fine and the file saves as expected.

I noticed a slight difference in your example so I tried switching from two double quotes to two single quotes - no difference.

I even tried switching over to the Windows form in lieu of the Rhino one - no difference.

Protected Overrides Function RunCommand(ByVal doc As RhinoDoc, ByVal mode As RunMode) As Result
        Dim thisSelectEnEDialog As New SelectExhibitorAndEvent
        Dim thisSelectEnEDialogResult As Boolean = thisSelectEnEDialog.ShowDialog()

        If thisSelectEnEDialogResult Then
            ' Create Directory Structure
            Dim ExhibitorDir As IO.DirectoryInfo = Utilities.Directories.CreateDesignExhibitorDirs(thisSelectEnEDialog.ExhibitorName)
            Dim EventDir As IO.DirectoryInfo = Utilities.Directories.CreateDesignShowDirs(ExhibitorDir, CInt(Today.ToString("yyyy")), thisSelectEnEDialog.EventName)

            Dim thisActiveDoc As RhinoDoc = Rhino.RhinoDoc.ActiveDoc
            Dim thisDate As String = Today.ToString("yyyyMMdd")

            Dim thisSaveFileDialog As New System.Windows.Forms.SaveFileDialog With {
                .Title = "Smart Save",
                .DefaultExt = "3dm",
                .Filter = "Rhino files (*.3dm)|*.3dm|All files (*.*)|*.*",
                .InitialDirectory = EventDir.FullName & "\3D Design",
                .FileName = thisDate & "_" & thisSelectEnEDialog.EventName & "_" & "V1"
            }

            If thisSaveFileDialog.ShowDialog() = Windows.Forms.DialogResult.OK Then
                Dim thisDir As String = System.IO.Path.GetDirectoryName(thisSaveFileDialog.FileName)
                Dim thisFileName As String = System.IO.Path.GetFileName(thisSaveFileDialog.FileName)
                Dim thisPath As String = System.IO.Path.Combine(thisDir, thisFileName)
                Dim SaveScript As String = "_-SaveAs """ & thisPath & """"
                Rhino.RhinoApp.RunScript(SaveScript, True)
            End If
        End If

        Return Result.Success
    End Function

While doing so I noticed that your script uses -_SaveAs (dash, then underscore) rather than _-SaveAs (underscore, then dash). Tried it - no difference.

I then created a new command and narrowed it down to just the scripting portion.

Protected Overrides Function RunCommand(ByVal doc As RhinoDoc, ByVal mode As RunMode) As Result
        Dim SaveScriptHC As String = "_-SaveAs ""C:\Test\File Name.3dm"""
        Rhino.RhinoApp.RunScript(SaveScriptHC, True)

        ' TODO: complete command.
        Return Result.Success

    End Function

It still does not save the file.

Could I be the first to attempt this in VB?

Jeff

it’s been a very long time since touched vb so I can’t comment much on that, but I would just focus on using the last command example you gave to get the command to work, and then go from there

I use the _ to make sure I am calling SaveAs by its english command name, so the dash goes before it; on an english system I guess it will work either way, with the underscore just being pointless (a rhino dev could comment in more detail on this)

beyond that, I would just say to remove variables by confirming you are writing to a path where you have permission (try writing a text file there directly, from code, but not by asking rhino to do it), and remove extra directories & spaces from the filename

I don’t find reason to raise suspicion of of any vb-specific limitation, since this all compiles to IL and gets executed by the framework

Hi @Jeffrey_Ries,

Here is something you can start with.

TestVbSaveCommand.zip (904 Bytes)

– Dale

Thanks @dale

I couldn’t see the forest through the trees. I was missing the <CommandStyle(Style.ScriptRunner)> line at the Class level.

Thank you Dale for sorting me out. And thank you to @jdhill . Your examples helped me to better rewrite portions of my code as well.
Jeff