home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-06-15 | 8.3 KB | 325 lines | [TEXT/MMCC] |
- // ===========================================================================
- // SCScriptsMenu.cp -- handle the scripts menu
- // ===========================================================================
- // © 1995 James Kaput, Jeremy Roschelle SimCalc Project
-
- // This source code may be compiled into a commercial or non-commercial application
- // providing that the hmnu resource 140 is included and the following help balloon appears
- // when the user points at the script menu with Balloon help enabled:
-
- //ScriptMenu
- //Copyright © 1995
- //By Jeremy Roschelle
- //Use this menu to run scripts.
-
- // Comment:
- // the scripts menu is actually just an attachment that can be added to the
- // application. The attachment handles commands coming from the scripts menu
- // by dispatching to an appropriate scripts menu item
-
- #include "SCScriptsMenu.h"
- #include "UScripting.h"
- #include "SCFinderUtility.h"
- #include "UEventUtils.h"
-
- SCScriptsMenuHandler::SCScriptsMenuHandler(ResIDT inMenuID,
- short inVRefNum,
- long inParID,
- Int16 inMax)
- : LAttachment(msg_AnyMessage,true), mMenuID(inMenuID)
- {
- // appends menu items for each script in the designated folder
- if (inVRefNum != 0) {
- // set up data for iteration
- Int16 count = 0;
- Str255 scriptFileName;
- HFileParam fInfo;
- fInfo.ioNamePtr = scriptFileName;
-
- // iterate through each item in the folder, inserting scripts
- StFolderIterator iter(inVRefNum, inParID);
- while ((count++ < inMax) && iter.Next(fInfo)) {
- if (fInfo.ioFlFndrInfo.fdType == kOSAFileType) {
- FSSpec spec;
- FSMakeFSSpec(inVRefNum, inParID, scriptFileName, &spec);
- AppendScript(spec);
- }
- }
- }
- }
-
-
- SCScriptsMenuHandler::~SCScriptsMenuHandler()
- {
- LListIterator iter(mScripts,iterate_FromStart);
- SCScriptsMenuItem *item;
- while (iter.Next(&item)) delete item;
- }
-
- void
- SCScriptsMenuHandler::PurgeScripts()
- {
- LListIterator iter(mScripts,iterate_FromStart);
- SCScriptsMenuItem *item;
- while (iter.Next(&item)) item->PurgeScript();
- }
-
- // we have to execute on 2 kinds of message, a status message and command message
- void
- SCScriptsMenuHandler::ExecuteSelf(MessageT inMessage, void *ioParam)
- {
- mExecuteHost = true;
- // update status
- if (inMessage == msg_CommandStatus) {
- SCommandStatus *status = (SCommandStatus *)ioParam;
- if (HiWord(- status->command) == mMenuID) {
- *status->enabled = true;
- *status->usesMark = false;
- mExecuteHost = false; // we handled it
- }
- }
- // handle menu comand
- else if (HiWord(-inMessage) == mMenuID) {
- Int16 index = LoWord(-inMessage);
- if (index > mScripts.GetCount()) // attach a new script
- AttachScriptDialog();
- else { // execute an existing script
- SCScriptsMenuItem *item;
- if (mScripts.FetchItemAt(index, &item)) {
- if (cmdKey & UEventUtils::GetModifiers())
- item->OpenScript(); // open on command key
- else item->RunScript();
- mExecuteHost = false; // we handled it
- }
- }
- }
- }
-
- void
- SCScriptsMenuHandler::AttachScriptDialog()
- {
- // get the file to attach
- OSType scriptFileType = kOSAFileType;
- StandardFileReply reply;
- ::StandardGetFile(nil,1,&scriptFileType,&reply);
-
- if (reply.sfGood) AppendScript(reply.sfFile);
- }
-
- void
- SCScriptsMenuHandler::AppendScript(FSSpec &inScriptFile)
- {
- MenuHandle menu = ::GetMenu(mMenuID);
- if (! menu) return;
-
- SCScriptsMenuItem *item = new SCScriptsMenuItem(inScriptFile);
-
- // insert into the menu
- ::InsertMenuItem(menu,inScriptFile.name,mScripts.GetCount());
-
- // insert the corresponding class instance into the list
- mScripts.InsertItemsAt(1,arrayIndex_Last,&item);
-
- // insert balloon help into resource
- AttachBalloonHelp(inScriptFile, mScripts.GetCount());
- }
-
- void
- SCScriptsMenuHandler::AttachBalloonHelp(FSSpec &inScriptFile,Int16 inIndex)
- {
- Str255 text;
- { // get the text
- Int16 fRefNum = ::FSpOpenResFile(&inScriptFile,fsRdPerm);
- if (ResError()) return;
-
- // the first text resource has the description of the script (if any)
- Handle outText = ::Get1IndResource('TEXT',1);
- if (outText) UFinder::Handle2PStr(outText,text);
- else *text = 0;
-
- ::CloseResFile(fRefNum);
- }
-
- { // add the help
- char buffer[500];
- MakeBalloonData(text,buffer);
- InsertBalloonData(inIndex,buffer);
- }
- }
-
- void
- SCScriptsMenuHandler::MakeBalloonData(Str255 inHelp, char *ioBuffer)
- {
- Int16 mark = 2, // leave room to write number of bytes to end
- data;
- Int32 zeros = 0;
-
- if (*inHelp == 0) { // no data
- data = 0x0100; // skip this item
- ::BlockMoveData(&data,&ioBuffer[mark],sizeof(Int16));
- mark += sizeof(Int16);
- }
- else {
- data = 0x0001; // direct string type
- ::BlockMoveData(&data,&ioBuffer[mark],sizeof(Int16));
- mark += sizeof(Int16);
-
- // write out the string
- ::BlockMoveData(inHelp,&ioBuffer[mark],1 + *inHelp);
- mark += 1 + *inHelp;
-
- // write out three zeros for the other strings
- ::BlockMoveData(&zeros,&ioBuffer[mark],3);
- mark += 3;
- }
-
- // align buffer to an even word boundary
- if (mark & 0x0001) ++mark;
-
- // add size to first word of buffer
- ::BlockMoveData(&mark,ioBuffer,sizeof(mark));
- }
- void
- SCScriptsMenuHandler::InsertBalloonData(Int16 inIndex, char *inBuffer)
- {
- Handle hmnu = ::Get1Resource('hmnu',mMenuID);
- if (! hmnu) return;
-
- Int16 len = *(short *)inBuffer;
-
- // make some room in the handle
- ::SetHandleSize(hmnu, ::GetHandleSize(hmnu) + len);
- if (::MemError()) return;
-
- StHandleLocker lock(hmnu); // lock it down so we can safely dereference it
- char *help = *hmnu;
-
- // increment number of items
- ++*(short *)(help + 0x0A); // @ help + 0x0A
-
- // skip over existing items
- {
- Int16 itemsToSkip = inIndex + 2 - 1; // skip default and title resource, don't skip self
- help += 0x0C; // location of first msg record
- do {
- help += *(Int16 *)help; // add the number of bytes to skip
- } while (--itemsToSkip);
- }
-
- // shift data out of the way
- {
- char *dest, *end;
- dest = help + len;
- end = ((char *)*hmnu + ::GetHandleSize(hmnu));
- ::BlockMoveData(help, dest, end - dest);
- }
- // copy help data in
- ::BlockMoveData(inBuffer, help, len);
-
- // we're done!
- // we don't release the resource, because we don't want it to be purged
- // we don't mark it as changed, because we don't want it written out
- //::ChangedResource(hmnu);
- }
-
- void
- SCScriptsMenuHandler::RemoveScript(Int16 inIndex)
- {
- SCScriptsMenuItem *item;
- MenuHandle menu = ::GetMenu(mMenuID);
- if (! menu) return;
-
- if (mScripts.FetchItemAt(inIndex,&item) ) {
- delete item;
- mScripts.RemoveItemsAt(1,inIndex);
-
- ::DeleteMenuItem(menu,inIndex);
- }
- RemoveBalloonHelp(inIndex);
- }
-
- void
- SCScriptsMenuHandler::RemoveBalloonHelp(Int16 inIndex)
- {
- Handle hmnu = ::Get1Resource('hmnu',mMenuID);
- if (! hmnu) return;
-
- Int16 itemSize;
- Int32 hSize = ::GetHandleSize(hmnu);
-
- {
- StHandleLocker lock(hmnu); // lock it down so we can safely dereference it
- char *help = *hmnu;
-
- // decrement number of items
- --*(short *)(help + 0x0A); // @ help + 0x0A
-
- // skip over existing items
- Int16 itemsToSkip = inIndex + 2 - 1; // skip default and title resource, don't skip self
- help += 0x0C; // location of first msg record
- do {
- help += *(Int16 *)help; // add the number of bytes to skip
- } while (--itemsToSkip);
-
- // shift data to close the gap
- itemSize = *(short *)help;
- char *end = (char *)*hmnu + hSize;
- ::BlockMoveData(help + itemSize, help, (end - help - itemSize));
- }
-
- // make Handle shorter
- ::SetHandleSize(hmnu,hSize - itemSize);
- }
-
-
-
- SCScriptsMenuItem::~SCScriptsMenuItem()
- {
- PurgeScript();
- }
-
- void
- SCScriptsMenuItem::PurgeScript()
- {
- // dispose the script id token
- if (mScriptID != kOSANullScript && noErr == UScripting::DisposeScript(mScriptID))
- mScriptID = kOSANullScript;
- }
-
- OSErr
- SCScriptsMenuItem::OpenScript()
- {
- PurgeScript(); // if the user is opening it, they probably will change it
- return UFinder::SendFinderAEOpen(mFileSpec);
- }
-
- OSErr
- SCScriptsMenuItem::RunScript()
- {
- OSErr err = noErr;
- // load the script if its not available yet
- if (mScriptID == kOSANullScript) {
- Handle script = nil, text = nil;
- short fRefNum = -1;
-
- Try_ {
- // open resource fork
- fRefNum = ::FSpOpenResFile(&mFileSpec,fsRdPerm);
- ThrowIfResError_();
- // get the first script resource in the file
- script = ::Get1IndResource('scpt',1);
- FailNIL_(script);
- // Load it
- UScripting::LoadScript(script,mScriptID);
- }
- Catch_(catchErr) {
- err = catchErr;
- SysBeep(0);
- }
- EndCatch_
- if (fRefNum != -1) ::CloseResFile(fRefNum);
- }
- if (err == noErr) new URun1Script(mScriptID);
- return err;
- }
-