home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.mactech.com 2010
/
ftp.mactech.com.tar
/
ftp.mactech.com
/
machack
/
Hacks96
/
StockTalk.sit
/
StockTalk
/
Source
/
StockPlugIn.cp
< prev
next >
Wrap
Text File
|
1996-06-22
|
20KB
|
747 lines
#include "ArrangeCallbacks.h"
#include "PluginLibrary.h"
#include <Dialogs.h>
#include <OSA.h>
#include <Resources.h>
#include <AERegistry.h>
#if defined (__MWERKS__) && defined (PLUGIN_GLOBALS)
#include "A4Stuff.h"
#endif
/* This file defines a "generic" plugin module for Arrange 2.0. To
* use it, you should modify the Plugin class definition by adding
* new fields and private functions, and make corresponding changes in the
* "Plugin" section at the bottom of the file. You should not have to
* look at or make any changes to the "Main entry point" section in the middle
* of the file. This section contains code to create an instance of
* Plugin when the module is loaded, and forward hook calls from Arrange to
* the appropriate Plugin functions.
*
* There is an associated Rez file, GenericPlugin.r, which defines the
* 'MDdf' resource needed for each Arrange plugin module. To create a plugin
* module, compile GenericPlugin.r to produce an 'MDdf' resource, and
* compile and link this file to produce an 'MDcd' resource with the same ID.
*
* This version of GenericPlugin.cp was written by Steve Newman on 12/24/93.
* Last updated 7/15/94.
*/
#define ModuleRsrcID -0x8000
#define OurModuleID 0x70000000 // Unique module ID; replace with a value
// obtained from CE Software.
#define baseCmdCode OurModuleID
#define pluginName "Stock Quote Plugin" // controls our name in the About menu
#define pluginAboutMenuText "About Stock Quote Plugin"
#define aboutCmdCode (baseCmdCode + 0)
#define updateQuoteCmdCode (baseCmdCode + 1)
#if defined (__MWERKS__) && defined (PLUGIN_GLOBALS)
#define SetupA4 long lOldA4 = SetCurrentA4 ();
#define TearDownA4 SetA4 (lOldA4);
#define UnloadSegs UnloadSegsFunc ();
static void UnloadSegsFunc ();
#else
#define SetupA4
#define TearDownA4
#define UnloadSegs
#endif //__MWERKS__
typedef struct {
Str255 cURLAddress;
Str255 cComment;
Str255 cTitle;
arDocumentPtr whichDoc;
const ArrangeCallbackTbl* calls;
arNoteID cTheTourNote;
short whichNote;
} myprefs;
typedef struct {
arFieldID lTitleField;
arFieldID lValueField;
arFieldID lIndexField;
arFieldID lChangeField;
} sIDList;
class Plugin
{
public:
Plugin(const ArrangeCallbackTbl* theCalls);
~Plugin();
arHookResult ClickNotify( arClickLocation loc, Point where, Short modifiers,
Short clickCount, arNoteID note, arFieldID field,
arPathID path );
arHookResult KeyNotify ( Short theChar, Short key, Short modifiers );
arHookResult MenuNotify ( Integer commandCode, Integer commandParam,
Short modifiers );
arHookResult FieldNotify( arNoteID note, arFieldID field, arFieldAction action,
const char* choiceText );
void TopicNotify( arTopicID newTopic, arWindowID newWindow,
arTopicAction action );
void TickNotify ( );
arHookResult FileNotify ( arFileAction action );
arHookResult QuitNotify ( );
void ATMNotify ( );
private:
const ArrangeCallbackTbl* calls; // callback table
short mQuotes;
myprefs theprefs;
ComponentInstance scriptingComponent;
void UpdateTheQuotes ();
void UpdateNote(arNoteID);
OSErr InitComponent();
OSErr GetQuote(ConstStr255Param, StringPtr, StringPtr, StringPtr);
void SetChange(arNoteID selNote, short index, StringPtr newValue);
}; // Plugin
/*************************************************************************/
/**************************** Main entry point ***************************/
/*************************************************************************/
/* Root entry point for the module - must be the first function in the
* file, so that the linker will place it first in the code segment.
* This is the routine which Arrange calls at application startup time
* (and again at quit time).
*
* Most plug-ins will not need to modify this routine or the Hook functions
* immediately following. All customization can be done in the "Plugin"
* section (below).
*/
extern "C" Integer main( ModuleParamBlock *pb, pModuleRootAction action,
Integer /*p1*/ ENDP )
{
SetupA4;
Integer lResult = 0;
/* Extract the callback table from our parameter block, and coerce it
* to the extended Arrange table.
*/
ArrangeCallbackTbl* calls = (ArrangeCallbackTbl*)(pb->calls);
Assert (sizeof (Byte) == 1);
Assert (sizeof (Short) == 2);
Assert (sizeof (Integer) == 4);
Assert (sizeof (Float) == 8);
switch (action)
{
case mrLoad:
{
// Allocate memory and create a new Plugin object.
void* storage = calls->mem->AllocMem( sizeof(Plugin),
amFreeStore | amErrIfNoMem );
pb->moduleRefcon = uInteger(new(storage) Plugin(calls));
lResult = 1;
}
break;
case mrUnload:
{
/* Dispose of the Plugin object and release the memory
* it occupies.
*/
delete (Plugin*)(pb->moduleRefcon);
calls->mem->DeallocMem((void*)(pb->moduleRefcon), amFreeStore);
lResult = 0;
}
break;
case mrFindEntry:
default:
{
/* This module contains no extended entry points, so we always
* return 0 for the mrFindEntry message. Most plug-ins will not
* use extended entry points.
*/
lResult = 0;
}
break;
} // switch (action)
UnloadSegs;
TearDownA4;
return lResult;
} // main
#if defined (__MWERKS__) && defined (PLUGIN_GLOBALS)
#pragma segment PluginLib
static void PluginLibSeg (void)
{
}
#pragma segment Main
static void UnloadSegsFunc ()
{
// Put segment unloading code here.
// Do NOT use UnloadSeg!
UnloadA4Seg (PluginLibSeg);
}
#endif //__MWERKS__ && PLUGIN_GLOBALS
/* These hook functions simply pass control to the appropriate function
* in the Plugin object.
*/
static arHookResult OurClickHook( ModuleParamBlock* pb, arClickLocation loc,
Point where, pShort modifiers, pShort clickCount,
arNoteID note, arFieldID field,
arPathID path ENDP )
{
SetupA4;
arHookResult eResult = ((Plugin*)(pb->moduleRefcon))->ClickNotify( loc, where, modifiers,
clickCount, note, field,
path );
UnloadSegs;
TearDownA4;
return eResult;
}
static arHookResult OurKeyHook( ModuleParamBlock* pb, pShort theChar, pShort key,
pShort modifiers ENDP )
{
SetupA4;
arHookResult eResult = ((Plugin*)(pb->moduleRefcon))->KeyNotify(theChar, key, modifiers);
UnloadSegs;
TearDownA4;
return eResult;
}
static arHookResult OurMenuHook( ModuleParamBlock* pb, Integer commandCode,
Integer commandParam, pShort modifiers ENDP )
{
SetupA4;
arHookResult eResult = ((Plugin*)(pb->moduleRefcon))->MenuNotify( commandCode, commandParam,
modifiers );
UnloadSegs;
TearDownA4;
return eResult;
}
static arHookResult OurFieldHook( ModuleParamBlock* pb, arNoteID note,
arFieldID field, arFieldAction action,
const char* choiceText ENDP )
{
SetupA4;
arHookResult eResult = ((Plugin*)(pb->moduleRefcon))->FieldNotify( note, field, action,
choiceText );
UnloadSegs;
TearDownA4;
return eResult;
}
static void OurTopicHook( ModuleParamBlock* pb, arTopicID newTopic,
arWindowID newWindow, arTopicAction action ENDP )
{
SetupA4;
((Plugin*)(pb->moduleRefcon))->TopicNotify(newTopic, newWindow, action);
UnloadSegs;
TearDownA4;
}
static void OurTickHook(ModuleParamBlock* pb ENDP)
{
SetupA4;
((Plugin*)(pb->moduleRefcon))->TickNotify();
UnloadSegs;
TearDownA4;
}
static arHookResult OurFileHook(ModuleParamBlock* pb, arFileAction action ENDP)
{
SetupA4;
arHookResult eResult = ((Plugin*)(pb->moduleRefcon))->FileNotify(action);
UnloadSegs;
TearDownA4;
return eResult;
}
static arHookResult OurQuitHook(ModuleParamBlock* pb ENDP)
{
SetupA4;
arHookResult eResult = ((Plugin*)(pb->moduleRefcon))->QuitNotify();
UnloadSegs;
TearDownA4;
return eResult;
}
static void OurATMHook(ModuleParamBlock* pb ENDP)
{
SetupA4;
((Plugin*)(pb->moduleRefcon))->ATMNotify();
UnloadSegs;
TearDownA4;
}
/*************************************************************************/
/********************************* Plugin ********************************/
/*************************************************************************/
/* Construct a Plugin object. This is called once, from the OurModuleRoot
* function, when the module is initialized (i.e. at application startup time).
*/
Plugin::Plugin(const ArrangeCallbackTbl* theCalls)
{
// Record the callback table for future use.
calls = theCalls;
/* These commands, if un-commented-out, register this plugin to be called
* by Arrange when various events occur. For example, if you un-comment-out
* the call to SetClickHook, then Plugin::ClickNotify will be called
* whenever the user clicks in any of the locations described in the
* arClickLocation enum.
*/
// calls->ui->SetClickHook(OurClickHook, 0, true);
// calls->ui->SetKeyHook (OurKeyHook, 0, true, charFilter, keyFilter, modFilter);
// calls->ui->SetMenuHook (OurMenuHook, 0, true, whichCommand);
// calls->ui->SetFieldHook(OurFieldHook, 0, true, whichField);
// calls->ui->SetTopicHook(OurTopicHook, 0, true);
// calls->ui->SetTickHook (OurTickHook, 0, true);
// calls->ui->SetFileHook (OurFileHook, 0, true);
// calls->ui->SetQuitHook (OurQuitHook, 0, true);
// calls->ui->SetATMHook (OurATMHook, 0, true);
// Add an item to the About Plugins menu for this plugin.
calls->ui->AddMenuItem(mPluginAbout, pluginAboutMenuText, 0, aboutCmdCode, 0);
calls->ui->AddMenuItem(mTools, "Update Quote", 0, updateQuoteCmdCode,2);
calls->ui->SetMenuHook(OurMenuHook, 1, true, aboutCmdCode);
calls->ui->SetMenuHook(OurMenuHook, 2, true, updateQuoteCmdCode);
InitComponent();
} // Plugin constructor
/* Dispose of a Plugin object. This is called when Arrange terminates. You
* should free up any data structures which you allocation in the Plugin
* constructor (above).
*/
Plugin::~Plugin()
{
} // ~Plugin
/* This function is called whenever the user clicks in an "interesting place"
* in a document window. It should return true if we handle the click, false
* (the normal case) when the click should be passed along to other plug-ins
* or to Arrange's normal event processing. See the documentation for
* SetClickHook for more details.
*/
arHookResult Plugin::ClickNotify( arClickLocation loc, Point where,
Short modifiers, Short clickCount,
arNoteID note, arFieldID field,
arPathID path )
{
return false; // Let Arrange handle the event
} // ClickNotify
/* This function is called whenever the user types a key which matches the
* filters we pass to SetKeyHook in Plugin's constructor. It should return
* true if we handle the event, false (the normal case) when the event
* should be passed along to other plug-ins or to Arrange's normal event
* processing. See the documentation for SetKeyHook for more details.
*/
arHookResult Plugin::KeyNotify(Short theChar, Short key, Short modifiers)
{
return false; // Let Arrange handle the event
} // KeyNotify
/* This function is called whenever the user chooses a menu item for which
* we have registered (via the SetMenuHook function). It should return true
* if we handle the command, false (the normal case) when the command should
* be passed along to other plug-ins or to Arrange's normal event processing.
* See the documentation for SetMenuHook for more details.
*/
arHookResult Plugin::MenuNotify( Integer commandCode, Integer commandParam,
Short modifiers )
{
/* If this is our About menu item, display our about-box dialog and return
* true to indicate we handled the command.
*/
if (commandCode == aboutCmdCode)
{
Alert(ModuleRsrcID, nil);
return true;
}
else if (commandCode == updateQuoteCmdCode)
{
UpdateTheQuotes();
return true;
}
else
return false; // Let Arrange handle the event
} // MenuNotify
/* If we register to recieve events for a field by calling SetFieldHook, this
* function will be called for any events in that field. It should return
* false in almost all cases. See the documentation for SetFieldHook for
* more details.
*/
arHookResult Plugin::FieldNotify( arNoteID note, arFieldID field,
arFieldAction action, const char* choiceText )
{
return false;
} // FieldNotify
/* This function is called whenever the user switches windows or changes
* the current folder/topic/view in the front window. See the documentation
* for SetTopicHook for more details.
*/
void Plugin::TopicNotify( arTopicID newTopic, arWindowID newWindow,
arTopicAction action )
{
} // TopicNotify
/* This function is called periodically, whenever Arrange recieves a null
* event from the Event Manager.
*/
void Plugin::TickNotify()
{
} // TickNotify
/* This function is called whenever various file-level events occur. It
* should return true in almost all cases. See the documentation for
* SetFileHook for more details.
*/
arHookResult Plugin::FileNotify(arFileAction action)
{
return true;
} // FileNotify
/* This function is called if the user voluntarily quits Arrange. It should
* return true to allow the user to quit, false to prevent it. See the
* documentation for SetQuitHook for more details.
*/
arHookResult Plugin::QuitNotify()
{
return true;
} // QuitNotify
/* This function is called whenever the user clicks in the menu bar or types
* a command key, just before processing the event. It should do any fixing
* up of menus which might be necessary based on the current state of affairs.
* See the documentation for SetATMHook for more details.
*/
void Plugin::ATMNotify()
{
} // ATMNotify
/*Boolean Plugin::GetMyIDs(sIDList *theIDs)
{
char topic[13] = "Stock Quotes";
char title[6] = "Title";
char index[6] = "Index";
char value[6] = "Value";
char change[7] = "Change";
theIDs->lTitleField = calls->sysObj->LookupObjectName ( arTopic,(char*) (&topic), true);
if(!theIDs->lTitleField)
return false;
theIDs->lTopicContentsFieldID = calls->sysObj->GetBuiltInObject (boTopicContentsField);
if (!theIDs->lTopicContentsFieldID)
{
return false;
}
theIDs->lTitleField = calls->sysObj->LookupObjectName ( arField,(char*) (&title), true);
if(!theIDs->lTitleField)
return false;
theIDs->lIndexField = calls->sysObj->LookupObjectName ( arField,(char*) (&index), true);
if(!theIDs->lTitleField)
return false;
theIDs->lValueField = calls->sysObj->LookupObjectName ( arField,(char*) (&value), true);
if(!theIDs->lTitleField)
return false;
theIDs->lChangeField = calls->sysObj->LookupObjectName ( arField,(char*) (&change), true);
if(!theIDs->lTitleField)
return false;
return true;
}
*/
void Plugin::UpdateTheQuotes ( )
{
Integer i;
short whichnote;
// Determine whether there is a selection and how many notes it contains.
Integer selCount;
arNoteID selNote;
arNoteID parentNote;
arFieldID selField;
Integer selStart;
Integer selEnd;
short thecount;
arFieldID theField;
arNoteInfo thetopicinfo;
short thelength;
Str255 tempstr;
Ptr theptr;
char TheName[32]="Reformatting";
Boolean firstchange = true;
Str31 promptstr = "\pRetrieving the quote...";
if (!calls->sel->FlushSelection(false))
{
return;
}
switch (calls->sel->GetSelection(&selNote, &selField, &selStart, &selEnd))
{
case stNote:
case stFieldContents:
case stMultipleNotes:
case stMultipleFields:
case stField:
case stText: // selected text is treated specially
default:
calls->dlg->DisplayNotify( (const char*)&promptstr[1], nfShowImmediately);
UpdateNote(selNote);
calls->dlg->ClearNotify();
return;
} // switch (GetSelection result)
return;
}
void Plugin::UpdateNote(arNoteID selNote)
{
arFieldID theField = calls->notes->GetNoteField(selNote, 1);
if(!theField)
DebugStr("\pno field");
if (theField!=nil)
{
arFieldInfo info;
info.versNum = 1;
calls->sysObj->GetFieldInfo(theField, &info);
if(info.type!=arFTText)
DebugStr("\pnot a text");
if (info.type==arFTText)
{
Str255 index;
index[0] = calls->data->GetFieldTextLen(selNote, theField);
if (index[0])
{
Str255 price = "\p", change = "\p", name = "\p";
index[0] = calls->data->GetFieldText(selNote, theField, index[0]+1, (char*)(index + 1));
OSErr err = GetQuote(index, price, name, change);
if(!err)
{
SetChange(selNote, 0, name);
SetChange(selNote, 2, price);
SetChange(selNote, 3, change);
calls->sel->FlushSelection(false);
}
}
}
}
}
void Plugin::SetChange(arNoteID selNote,
short index,
StringPtr newValue)
{
arFieldID theField = calls->notes->GetNoteField(selNote, index);
if(theField)
calls->data->SetFieldText( selNote,
theField,
(char *)(newValue + 1),
newValue[0],
0);
}
OSErr Plugin::GetQuote(ConstStr255Param index,
StringPtr price, StringPtr name, StringPtr change)
{
AEDesc target = {typeNull, nil};
AppleEvent theEvent;
OSErr err = AECreateAppleEvent( 'core',
'clos',
&target,
kAutoGenerateReturnID,
0,
&theEvent);
err = AEPutParamPtr( &theEvent,
keyDirectObject,
typeChar,
index + 1,
index[0]);
AEDesc scriptData = {typeNull, 0};
scriptData.dataHandle = GetResource('scpt', 128);
scriptData.descriptorType = 'scpt';
if(scriptData.dataHandle == 0)
DebugStr("\pNo data");
OSAID scriptID;
err = OSALoad( scriptingComponent,
&scriptData,
kOSAModePreventGetSource,
&scriptID);
if(err)
DebugStr("\pcould not load script");
if(!err)
{
AppleEvent reply = { typeNull, 0};
OSAID result;
err = OSAExecuteEvent( scriptingComponent,
&theEvent,
scriptID,
kOSAModeNull,
&result);
if(err)
DebugStr("\pcould not execute event");
AEDescList resultList = { typeNull, 0};
if(!err)
{
/*err = AEGetParamDesc(&reply,
keyAEResult,
typeAEList,
&resultList);*/
err = OSACoerceToDesc( scriptingComponent,
result,
typeAEList,
kOSAModeNull,
&resultList);
long size;
AEKeyword key;
DescType type;
if(!err)
{
err = AEGetNthPtr( &resultList,
1,
typeChar,
&key,
&type,
name + 1,
255,
&size);
name[0] = size;
err = AEGetNthPtr( &resultList,
2,
typeChar,
&key,
&type,
price + 1,
255,
&size);
price[0] = size;
err = AEGetNthPtr( &resultList,
3,
typeChar,
&key,
&type,
change + 1,
255,
&size);
change[0] = size;
}
}
}
return err;
}
OSErr Plugin::InitComponent()
{
OSAError err = 0;
ComponentDescription descr;
Component aComponent;
ComponentInstance aScriptingComponent;
descr.componentType = kOSAComponentType;
descr.componentSubType = (OSType) 0;
descr.componentManufacturer = (OSType) 0;
descr.componentFlags = kOSASupportsCompiling +
kOSASupportsGetSource +
kOSASupportsConvenience +
kOSASupportsEventHandling;
descr.componentFlagsMask = descr.componentFlags;
aComponent = FindNextComponent(nil, &descr);
if (!aComponent)
err = paramErr;
else
{
aScriptingComponent = OpenComponent(aComponent);
if (!aScriptingComponent)
err = paramErr;
else if (aScriptingComponent)
err = OSASetActiveProc(aScriptingComponent, 0, 0);
}
scriptingComponent = aScriptingComponent;
if(err)
DebugStr("\pCould not init component");
return err;
}