Autodesk Maya project changed event (signal) - pyside

I am writing a project manager for Maya in PySide. It's purpose is to navigate through projects contents for quick accessibility. So I would like it to rescan newly set project directory automaticaly. As far as I know, there is no event like "Project Changed" in maya ScriptJob command. Any advices would be appreciated!

You're right, as there is not any "Project Changed" event in Maya's scriptJob command, you have to somewhat hack this. The following answer implies modifying Maya's file. So, if you need to deploy your project manager on multiple computers, you'll also have to deploy modifications made on Maya's files.
There might be an easier solution, but couldn't found out how to do it efficiently using the existing events.
Note:
I'm using Maya 2014, so change the path provided according to your actual version.
Solution 1 - PyMel based:
Goto C:\Program Files\Autodesk\Maya2014\Python\Lib\site-packages\pymel\core
Open system.py in your favorite editor
Search for the Workspace class (#547 in my system.py)
Edit the chdir function (#621):
#classmethod
def chdir(self, newdir):
_OpenMaya.MUserEventMessage.postUserEvent('ProjectChanged')
return cmds.workspace( dir=newdir )
Open a new Maya (Maya needs to be restarted so the modifications are effective)
Run this code in your script editor:
import maya.OpenMaya as om
#Register a new event (IE: Tell maya that this event really exists)
om.MUserEventMessage.registerUserEvent('ProjectChanged')
from pymel.all import *
#This function will be called when the project will be changed
#Do your real stuff inside
def myCallbackFunction(data):
print('Got a ChangedProject event!')
#Tell Maya to run myCallbackFunction when ProjectCHanged occurs
callbackId = om.MUserEventMessage.addUserEventCallback('ProjectChanged', myCallbackFunction)
#Whange your project directory:
# - The ProjectChanged signal will be sent
# - Maya will catch it and execute myCallbackFunction
# - This will print 'Got a ChangedProject event!'
workspace.chdir(r"C:\Users\dhasselhoff\Documents\maya\projects\hookedonafeeling")
If you want to remove the callback function when done: om.MUserEventMessage.removeCallback(callbackId)
Solution 2 - MEL based:
Goto C:\Program Files\Autodesk\Maya2014\scripts\others
Open setProject.mel in your favorite editor
Edit the setProject function (#359):
...
// Restore the current directory. The project may have changed, but the cur dir
// need not
workspace -dir $oldCurrentDir;
python("import maya.OpenMaya as om\nom.MUserEventMessage.postUserEvent('ProjectChanged')");
}
// Try to set it directly from the name given
else
{
sp_setLocalWorkspaceWithoutPopupDialog $newProject;
python("import maya.OpenMaya as om\nom.MUserEventMessage.postUserEvent('ProjectChanged')");
}
Open a new Maya (Maya needs to be restarted so the modifications are effective)
Run this code in your script editor:
import maya.OpenMaya as om
#Register a new event (IE: Tell maya that this event really exists)
om.MUserEventMessage.registerUserEvent('ProjectChanged')
#This function will be called when the project will be changed
#Do your real stuff inside
def myCallbackFunction(data):
print('Got a ChangedProject event!')
#Tell Maya to run myCallbackFunction when ProjectCHanged occurs
callbackId = om.MUserEventMessage.addUserEventCallback('ProjectChanged', myCallbackFunction)
#Whange your project directory:
# - The ProjectChanged signal will be sent
# - Maya will catch it and execute myCallbackFunction
# - This will print 'Got a ChangedProject event!'
mel.eval('setProject("C:\Users\dhasselhoff\Documents\maya\projects\hookedonafeeling");')
If you want to remove the callback function when done: om.MUserEventMessage.removeCallback(callbackId)

Related

Updating the tab/file status after saving in a Sublime Text Plugin

This may be an old bug; I found this report. I'm using Sublime 3 but I think this code also works on 2.
When I call self.view.run_command('save') within a plugin, the save does happen -- I can type the file in a console window and see the results. The dirty flag seems to get cleared. But the tab for the file contains a dot rather than an x, indicating the file hasn't been saved. And sure enough, if you try to close it, it asks if you want to save the file.
Is there any way to refresh the file window so it recognizes that the file has been saved?
Here's my plugin code: (This is my first plugin so please excuse obvious style issues)
# Sublime Text plugin to insert output in the OUTPUT_SHOULD_BE comment
# Bind to key with:
# { "keys": ["f12"], "command": "insert_output" },
import sublime, sublime_plugin, pprint, os, re
class InsertOutputCommand(sublime_plugin.TextCommand):
def run(self, edit):
outfile = self.view.file_name().rsplit('.')[0] + ".out"
if not os.path.exists(outfile):
sublime.error_message("Not Found: " + outfile)
return
out_data = open(outfile).read().strip()
region = self.view.find(r"/\* OUTPUT_SHOULD_BE\n", 0)
if region:
self.view.insert(edit, region.end(), out_data)
self.view.run_command('save')
self.view.window().focus_view(self.view)
else:
sublime.error_message("Not Found: OUTPUT_SHOULD_BE")
I'm sure this is probably a terrible hack, but it works:
self.view.run_command("save")
# Refresh the buffer and clear the dirty flag:
sublime.set_timeout(lambda: self.view.run_command("revert"), 10)
The revert command, which must be delayed in order to work, simply brings back whatever is stored in the file. Since the file was successfully saved on disk, this is just the same file that we already see on the screen. In the process, the dirty flag is cleared and the dot on the file tab becomes an x.
Feels very hacky to me and I'd love a more proper solution. But at least it works, ugly or not.

after opening a file check if the file was modified on close

I am wondering if I am doing it the correct way.
def checkout
clone = system( "svn export #{file} tmp/" )
open_file = system( "start tmp/#{#file}" )
end
Now, I am able to open the file I want with the default editor but how to record if the file was modified before close.
Should I create a Process and do Process.wait or something?
Thanks for your help
Use File::mtime method for the same.
Returns the modification time for the named file as a Time object.
file_time_before_opening = File.mtime('your file/path')
# do file operation as you like
file_time_after_closing = File.mtime('your file/path')
# now compare file_time_before_opening and file_time_after_closing to know
# if it is modified or not.
If you mean you are using start in Windows, use /wait or /w option to make it wait until the editor termination.
Use IO::read to check file content modification. (before, after the editor execution).
before = IO.read('tmp/#{#file}', {mode: 'rb'})
system("start /wait tmp/#{#file}")
after = IO.read('tmp/#{#file}', {mode: 'rb'})
# Check the file content modification.
if before != after:
# File changed!
If you're editing a huge file, IO::read will consume memroy accordingly. Use File::mtime as Arup Rakshit suggested, if there's such huge file in your repository. (cons: false positive alarm for save without modification)

Reopening closed file: Lua

I have a file called backup.lua, which the program should write to every so often in order to backup its status, in case of a failure.
The problem is that the program writes the backup.lua file completely fine first-time round, but any other times it refuses to write to the file.
I tried removing the file while the program was still open but Windows told me that the file was in use by 'CrysisWarsDedicatedServer.exe', which is the program. I have told the host Lua function to close the backup.lua file, so why isn't it letting me modify the file at will after it has been closed?
I can't find anything on the internet (Google actually tried to correct my search) and the secondary programmer on the project doesn't know either.
So I'm wondering if any of you folks know what we are doing wrong here?
Host function code:
function ServerBackup(todo)
local write, read;
if todo=="write" then
write = true;
else
read = true;
end
if (write) then
local source = io.open(Root().."Mods/Infinity/System/Read/backup.lua", "w");
System.Log(TeamInstantAction:GetTeamScore(2).." for 2, and for 1: "..TeamInstantAction:GetTeamScore(1))
System.LogAlways("[System] Backing up serverdata to file 'backup.lua'");
source:write("--[[ The server is dependent on this file; editing it will lead to serious problems.If there is a problem with this file, please re-write it by accessing the backup system ingame.--]]");
source:write("Backup = {};Backup.Time = '"..os.date("%H:%M").."';Backup.Date = '"..os.date("%d/%m/%Y").."';");
source:write(XFormat("TeamInstantAction:SetTeamScore(2, %d);TeamInstantAction:SetTeamScore(1, %d);TeamInstantAction:UpdateScores();",TeamInstantAction:GetTeamScore(2), TeamInstantAction:GetTeamScore(1) ));
source:close();
for i,player in pairs(g_gameRules.game:GetPlayers() or {}) do
if (IsModerator(player)) then
CMPlayer(player, "[!backup] Completed server backup.");
end
end
end
--local source = io.open(Root().."Mods/Infinity/System/Read/backup.lua", "r"); Can the file be open here and by the Lua scriptloader too?
if (read) then
System.LogAlways("[System] Restoring serverdata from file 'backup.lua'");
--source:close();
Backup = {};
Script.LoadScript(Root().."Mods/Infinity/System/Read/backup.lua");
if not Backup or #Backup < 1 then
System.LogAlways("[System] Error restoring serverdata from file 'backup.lua'");
end
end
end
Thanks all :).
Edit:
Although the file is now written to the disk fine, the system fails to read the dumped file.
So, now the problem is that the "LoadScript" function isn't doing what you expect:
Because I'm psychic, i have divined that you're writing a Crysis plugin, and are attempting to use it's LoadScript API call.
(Please don't assume everyone here would guess this, or be bothered to look for it. It's vital information that must form part of your questions)
The script you're writing attempts to set Backup - but your script, as written - does not separate lines with newline characters. As the first line is a comment, the entire script will be ignored.
Basicallty the script you've written looks like this, which is all treated as a comment.
--[[ comment ]]--Backup="Hello!"
You need to write a "\n" after the comment (and, I'd recommend in other places too) to make it like this. In fact, you don't really need block comments at all.
-- comment
Backup="Hello!"

Uncaught Throw generated by JLink or UseFrontEnd

This example routine generates two Throw::nocatch warning messages in the kernel window. Can they be handled somehow?
The example consists of this code in a file "test.m" created in C:\Temp:
Needs["JLink`"];
$FrontEndLaunchCommand = "Mathematica.exe";
UseFrontEnd[NotebookWrite[CreateDocument[], "Testing"]];
Then these commands pasted and run at the Windows Command Prompt:
PATH = C:\Program Files\Wolfram Research\Mathematica\8.0\;%PATH%
start MathKernel -noprompt -initfile "C:\Temp\test.m"
Addendum
The reason for using UseFrontEnd as opposed to UsingFrontEnd is that an interactive front end may be required to preserve output and messages from notebooks that are usually run interactively. For example, with C:\Temp\test.m modified like so:
Needs["JLink`"];
$FrontEndLaunchCommand="Mathematica.exe";
UseFrontEnd[
nb = NotebookOpen["C:\\Temp\\run.nb"];
SelectionMove[nb, Next, Cell];
SelectionEvaluate[nb];
];
Pause[10];
CloseFrontEnd[];
and a notebook C:\Temp\run.nb created with a single cell containing:
x1 = 0; While[x1 < 1000000,
If[Mod[x1, 100000] == 0,
Print["x1=" <> ToString[x1]]]; x1++];
NotebookSave[EvaluationNotebook[]];
NotebookClose[EvaluationNotebook[]];
this code, launched from a Windows Command Prompt, will run interactively and save its output. This is not possible to achieve using UsingFrontEnd or MathKernel -script "C:\Temp\test.m".
During the initialization, the kernel code is in a mode which prevents aborts.
Throw/Catch are implemented with Abort, therefore they do not work during initialization.
A simple example that shows the problem is to put this in your test.m file:
Catch[Throw[test]];
Similarly, functions like TimeConstrained, MemoryConstrained, Break, the Trace family, Abort and those that depend upon it (like certain data paclets) will have problems like this during initialization.
A possible solution to your problem might be to consider the -script option:
math.exe -script test.m
Also, note that in version 8 there is a documented function called UsingFrontEnd, which does what UseFrontEnd did, but is auto-configured, so this:
Needs["JLink`"];
UsingFrontEnd[NotebookWrite[CreateDocument[], "Testing"]];
should be all you need in your test.m file.
See also: Mathematica Scripts
Addendum
One possible solution to use the -script and UsingFrontEnd is to use the 'run.m script
included below. This does require setting up a 'Test' kernel in the kernel configuration options (basically a clone of the 'Local' kernel settings).
The script includes two utility functions, NotebookEvaluatingQ and NotebookPauseForEvaluation, which help the script to wait for the client notebook to finish evaluating before saving it. The upside of this approach is that all the evaluation control code is in the 'run.m' script, so the client notebook does not need to have a NotebookSave[EvaluationNotebook[]] statement at the end.
NotebookPauseForEvaluation[nb_] := Module[{},While[NotebookEvaluatingQ[nb],Pause[.25]]]
NotebookEvaluatingQ[nb_]:=Module[{},
SelectionMove[nb,All,Notebook];
Or##Map["Evaluating"/.#&,Developer`CellInformation[nb]]
]
UsingFrontEnd[
nb = NotebookOpen["c:\\users\\arnoudb\\run.nb"];
SetOptions[nb,Evaluator->"Test"];
SelectionMove[nb,All,Notebook];
SelectionEvaluate[nb];
NotebookPauseForEvaluation[nb];
NotebookSave[nb];
]
I hope this is useful in some way to you. It could use a few more improvements like resetting the notebook's kernel to its original and closing the notebook after saving it,
but this code should work for this particular purpose.
On a side note, I tried one other approach, using this:
UsingFrontEnd[ NotebookEvaluate[ "c:\\users\\arnoudb\\run.nb", InsertResults->True ] ]
But this is kicking the kernel terminal session into a dialog mode, which seems like a bug
to me (I'll check into this and get this reported if this is a valid issue).

Startup Items - Creating a basic one

Please save me from a potential nervous breakdown!
I've been following Apples documentation (see below) on how to create a Startup Item. Currently I'm just trying to get my script to print something to the console, much less actually run my app.
Here are my two scripts, one is the startup executable, the other is the plist:
#!/bin/sh
. /etc/rc.common
# The start subroutine
StartService() {
# Insert your start command below. For example:
echo "hey Eric we've started"
# End example.
}
# The stop subroutine
StopService() {
# Insert your stop command(s) below. For example:
echo "STOPPED ERIC"
# End example.
}
# The restart subroutine
RestartService() {
# Insert your start command below. For example:
echo "RESTART ERIC"
# End example.
}
RunService "$1"
{
Description = "Software Update service";
Provides = ("SoftwareUpdateServer");
Requires = ("Network");
Uses = ("Network");
OrderPreference = "Late";
Messages =
{
start = "Starting Software Update service";
stop = "Stopping Software Update service";
};
}
Using terminal I tried to set the permissions as closely as possible as to how it is documented in the example in the link below. The odd thing was that the files didn't show the 'root' aspect to their ownership.
I then ran SystemStarter start theApp and nothing happens. Absolutely nothing.
Any help?
http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/StartupItems.html
You should not create a Startup Item any more. It's a legacy mechanism and superseded by launchd. Write a plist for launchd instead. I know this is not the help you wanted, but sadly with Apple, you need to follow the mothership...
Read this section of the same document instead.
See the document just you quoted yourself:
Note: The launchd facility is he preferred mechanism for launching daemons in Mac OS X v10.4 and higher. Unless your software requires compatibility with Mac OS X v10.3 or earlier, you should use the launchd facility instead of writing a startup item. For more information, see “Guidelines for Creating and Launching Daemons.”
Note that v10.4 become available in 2005.

Resources