This is InformerWindow.m in view mode; [Download] [Up]
// InformerWindow.m
//
// Purpose :
// Handles the "document" windows, one instance per window.
//
// Structure :
// InformerWindow is a subclass of Object. It is the delegate of
// its "document" window. It is also the owner of InformerWindow.nib.
// It is the delegate of the Browser.
//
//
// History :
// 9.20.1992 : Created by Max Tardiveau
#import "InformerWindow.h"
@implementation InformerWindow
/////////////////////////////////////////////////
//
- init
{
NXRect tmpRect;
//int tmpInt;
[super init];
[NXApp loadNibSection:"InformerWindow.nib" owner:self];
[myInspectorView setVertScrollerRequired:NO];
[myInspectorView getBounds:&tmpRect];
[myInspectorView setDocCursor:NXArrow];
myEmptyView = [[EmptyView new] initFrame:&tmpRect];
[myInspectorView setDocView:myEmptyView];
[myBrowser setCellClass:[InformerCell class]];
[myBrowser useScrollButtons:YES];
[myBrowser loadColumnZero];
[myWindow makeKeyAndOrderFront:self];
updatePeriod = 0;
[updateText setEnabled:NO];
return self;
}
/////////////////////////////////////////////////
// Sets our dispatcher
- setDispatcher:sender
{
myDispatcher = sender;
return self;
}
/////////////////////////////////////////////////
// Target method for the Update TextItem
static void updateFunc(DPSTimedEntry teNumber, double now, char *userData)
{
id theCell;
id theObject;
theCell = (id)userData;
if ((theObject = [theCell updater]) != NIL)
[theObject doUpdateForCell:theCell];
}
/////////////////////////////////////////////////
// Target method for the Update TextItem and Scroller
- setUpdate:sender
{
id CurrentCell;
updatePeriod = [sender intValue];
[updateScroller setIntValue:updatePeriod];
[updateText setIntValue:updatePeriod];
if (updatePeriod <= 1)
[updateTextSeconds setStringValue:"second"];
else
[updateTextSeconds setStringValue:"seconds"];
if (myTimedEntry)
{
DPSRemoveTimedEntry(myTimedEntry);
myTimedEntry = 0;
}
CurrentCell = [[myBrowser matrixInColumn:[myBrowser selectedColumn]]
selectedCell];
if (updatePeriod && CurrentCell)
myTimedEntry = DPSAddTimedEntry(updatePeriod,
(DPSTimedEntryProc)updateFunc, CurrentCell, NX_BASETHRESHOLD);
return self;
}
////////////////////////////////////////////////////////////////////////
// Target method for the Help button
// This can only be called if a Help file exists for
// the current cell.
- helpClicked:sender
{
id CurrentCell;
char tmpchar[256];
NXStream *textStream;
if ([[myHelpText docView] textLength] == 0) // Not yet loaded
{
CurrentCell = [[myBrowser matrixInColumn:
[myBrowser selectedColumn]] selectedCell];
sprintf(tmpchar, "%s/%s", [CurrentCell getDir], "HELP.rtf");
textStream = NXMapFile(tmpchar, NX_READONLY);
if (textStream == NIL)
{
[myDispatcher showError:"Error (2) opening HELP.rtf file."];
return self;
}
[[myHelpText docView] readRichText:textStream];
[[myHelpText docView] setSel:0 :0];
[[myHelpText docView] scrollSelToVisible];
NXCloseMemory(textStream, NX_FREEBUFFER);
}
[myHelpPanel makeKeyAndOrderFront:self];
return self;
}
////////////////////////////////////////////////////////////////////////
// Called by modules to put up messages.
- addMessage:(char *)theMessage
{
[[messageScrollView docView] setSel:1000000 :1000000];
[[[messageScrollView docView] replaceSel:theMessage] scrollSelToVisible];
return self;
}
////////////////////////////////////////////////////////////////////////
// Target method for the Clear button. Clears out all messages.
- clearMessages:sender
{
[[messageScrollView docView] setText:""];
return self;
}
///////////////////////////////////////////////////////////////////////////
// This method is used by modules to run functions that do not work when
// called from a dynamically loaded module. Functions having this problem :
// PScountscreenlist(), PScountwindowlist(), PSostype() and probably others.
- (int *) runFunction:(int * (*)())theFunction
{
return theFunction();
}
///////////////////////////////////////////////////////////////////////////
// Target method for the browser.
//
// When the user clicks on a cell in the browser, it can either be a
// leaf or a branch cell. If it is a branch, then we put back the Text
// in the ScrollView.
// If it is a leaf, then we load the Main.o file in the .inform directory,
// first alone, and then with /lib/libsys_s.a if it fails. We then create
// an instance of the class, which returns its view. We finally put that
// view as the DocView of our ScrollView.
- cellClicked:sender
{
id CurrentCell;
id theObject;
id theView;
id theClass;
char tmpchar[256];
struct stat myStat;
CurrentCell = [[sender matrixInColumn:[sender selectedColumn]] selectedCell];
// If there is a help file, enable Help button, else hide help window
sprintf(tmpchar, "%s/%s", [CurrentCell getDir], "HELP.rtf");
if (stat(tmpchar, &myStat) == 0)
[helpButton setEnabled:YES];
else
[helpButton setEnabled:NO];
[myHelpPanel performClose:self];
[[myHelpText docView] setText:""];
if (myTimedEntry)
{
DPSRemoveTimedEntry(myTimedEntry);
myTimedEntry = 0;
}
[updateTextSeconds setStringValue:"second"];
[updateScroller setIntValue:0];
[updateText setIntValue:0];
[updateScroller setEnabled:NO];
[updateText setEnabled:NO];
updatePeriod = 0;
if ((theObject = [CurrentCell updater]) != NIL)
{
[myWindow disableFlushWindow];
if ([theObject doUpdateForCell:CurrentCell])
{
[myInspectorView setDocView:[theObject mainView]];
updatePeriod = [theObject updateInterval];
[updateScroller setIntValue:updatePeriod];
[updateText setIntValue:updatePeriod];
if (updatePeriod <= 1)
[updateTextSeconds setStringValue:"second"];
else
[updateTextSeconds setStringValue:"seconds"];
if (updatePeriod)
{
[updateScroller setEnabled:YES];
[updateText setEnabled:YES];
}
else
{
[updateScroller setEnabled:NO];
[updateText setEnabled:NO];
}
if (updatePeriod)
myTimedEntry = DPSAddTimedEntry(updatePeriod,
(DPSTimedEntryProc)updateFunc, CurrentCell, NX_BASETHRESHOLD);
}
else
[myInspectorView setDocView:myEmptyView];
[[myWindow reenableFlushWindow] flushWindow];
return self;
}
if ( ! [CurrentCell isLeaf]) // it's only a directory
{
[myInspectorView setDocView:myEmptyView];
return self;
}
if ( ! [CurrentCell getMasterInstance])
{
theClass = [myDispatcher loadClassFromCell:CurrentCell];
if (theClass) // load was successful
theObject = [theClass new];
else
{
[self addMessage:"InformerWindow : could not create instance.\n"];
return self;
}
theView = [theObject loadEverythingFrom:[CurrentCell getDir]];
[theObject setMaster:self];
updatePeriod = [theObject updateInterval];
[updateScroller setIntValue:updatePeriod];
[updateText setIntValue:updatePeriod];
if (updatePeriod <= 1)
[updateTextSeconds setStringValue:"second"];
else
[updateTextSeconds setStringValue:"seconds"];
if (updatePeriod)
{
[updateScroller setEnabled:YES];
[updateText setEnabled:YES];
}
else
{
[updateScroller setEnabled:NO];
[updateText setEnabled:NO];
}
[theView removeFromSuperview];
[myInspectorView setDocView:theView];
}
else
theObject = [CurrentCell getMasterInstance];
[myWindow disableFlushWindow];
if ([theObject doUpdateForCell:CurrentCell])
{
if (updatePeriod)
myTimedEntry = DPSAddTimedEntry(updatePeriod,
(DPSTimedEntryProc)updateFunc, CurrentCell, NX_BASETHRESHOLD);
}
else
[myInspectorView setDocView:myEmptyView];
[[myWindow reenableFlushWindow] flushWindow];
return self;
}
//////////////////////////////////////////////////////////////////////////////
//
- window
{
return myWindow;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Delegate method for the browser
- (int)browser:sender fillMatrix:matrix inColumn:(int)column
{
DIR *myDirStream;
struct direct *myDir;
id CurrentCell;
id tmpCell;
char tmpChar[512];
char tmpName[256];
char *tmpcharptr;
char *cellDir;
struct stat myStat;
//NXStream *myStream;
int isList;
id updater;
id theObject;
id theClass;
if ( ! [[sender cellPrototype] isMemberOf:[InformerCell class]])
return 0;
if (column == 0) // First column
{
cellDir = baseDir;
isList = NO;
updater = NULL;
[sender setTitle:"Informer" ofColumn:0];
}
else // Not the first column
{
CurrentCell=[[sender matrixInColumn:[sender selectedColumn]] selectedCell];
cellDir = [CurrentCell getDir];
isList = [CurrentCell isList];
updater = [CurrentCell updater];
}
if (updater)
{
[updater fillList:matrix fromCell:CurrentCell];
}
else if (isList) // Ask the new class to fill the matrix
{
if ( ! [CurrentCell getMasterInstance])
{
theClass = [myDispatcher loadClassFromCell:CurrentCell];
if (theClass) // load was successful
{
theObject = [theClass new];
[theObject loadEverythingFrom:[CurrentCell getDir]];
[theObject setMaster:self];
[[theObject mainView] removeFromSuperview];
}
}
else
theObject = [CurrentCell getMasterInstance];
[theObject fillList:matrix fromCell:CurrentCell];
}
else // for plain directories
{
myDirStream = opendir(cellDir);
if (myDirStream == NIL)
{
[myDispatcher showError:"Could not find base directory."];
[self addMessage:"InformerWindow : could not find base directory.\n"];
return 0;
}
for (myDir = readdir(myDirStream); myDir != NULL;
myDir = readdir(myDirStream))
{
if (myDir->d_name[0] == '.') // Don't display "." and ".."
continue;
sprintf(tmpChar, "%s/%s", cellDir, myDir->d_name);
stat(tmpChar, &myStat);
if (myStat.st_mode & S_IFDIR) // It is a directory
{
[matrix addRow];
strncpy(tmpName, myDir->d_name, 511); // The name for now
tmpCell = [matrix cellAt:([matrix cellCount] -1) :0];
if (strlen(myDir->d_name) > 5) // Check if .item dir
{
strncpy(tmpChar, myDir->d_name, 255);
tmpcharptr = tmpChar;
tmpcharptr += (strlen(tmpcharptr) - 5);
if ( ! strncmp(tmpcharptr, ".item", 5)) // It is a .item
{
[tmpCell setLeaf:YES];
*tmpcharptr = '\0'; // Remove .item ending
strncpy(tmpName, tmpChar, 255);
}
else if ( ! strncmp(tmpcharptr, ".list", 5)) // It is a .list
{
[tmpCell setIsList:YES];
*tmpcharptr = '\0'; // Remove .list ending
strncpy(tmpName, tmpChar, 255);
}
}
sprintf(tmpChar, "%s/%s", cellDir, myDir->d_name);
[tmpCell setDir:tmpChar];
[tmpCell setStringValue:tmpName]; // Give the cell its name
}
}
}
return [matrix cellCount];
}
//////////////////////////////////////////////////////////////////////////////
// Delegate methods for the window
//
/////////////////////////////////////////////////
// Called when our window becomes the main window.
- windowDidBecomeMain:sender
{
[myDispatcher newFrontWindow:self];
return self;
}
/////////////////////////////////////////////////
// Called when our window becomes the key window.
- windowDidBecomeKey:sender
{
[myDispatcher newFrontWindow:self];
return self;
}
/////////////////////////////////////////////////
// Called when our window has stopped being the key window.
- windowDidResignKey:sender
{
[myDispatcher oldFrontWindow:self];
return self;
}
/////////////////////////////////////////////////
// Called when our window is going to close.
- windowWillClose:sender
{
[myDispatcher oldFrontWindow:self];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.