This is IAppDelegate.m in view mode; [Download] [Up]
/*$Copyright:
* Copyright (C) 1992.5.22. Recruit Co.,Ltd.
* Institute for Supercomputing Research
* All rights reserved.
* NewsBase by ISR, Kazuto MIYAI, Gary ARAKAKI, Katsunori SUZUKI, Kok-meng Lue
*
* You may freely copy, distribute and reuse the code in this program under
* following conditions.
* - to include this notice in the source code, if it is to be distributed
* with source code.
* - to add the file named "COPYING" within the code, which shall include
* GNU GENERAL PUBLIC LICENSE(*).
* - to display an acknowledgement in binary code as follows: "This product
* includes software developed by Recruit Co.,Ltd., ISR."
* - to display a notice which shall state that the users may freely copy,
* distribute and reuse the code in this program under GNU GENERAL PUBLIC
* LICENSE(*)
* - to indicate the way to access the copy of GNU GENERAL PUBLIC LICENSE(*)
*
* (*)GNU GENERAL PUBLIC LICENSE is stored in the file named COPYING
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
$*/
/* IAppDelegate.m connects the user interface and WorkSpace Manager
to/from the editor/viewer. */
#import "IAppDelegate.h"
#import "IMediaTable.h"
#import <appkit/Application.h>
#import <appkit/Window.h>
#import <appkit/Panel.h>
#import <appkit/PopUpList.h>
#import <mach_init.h>
#import <objc/List.h>
#import <appkit/MenuCell.h>
#import <appkit/publicWraps.h>
#import <sys/dir.h>
#import <defaults.h>
#import <mach.h>
#import <libc.h>
#import <ctype.h>
#import "ILocalFileD.h"
#import "INewsD.h"
#import "IMMEditor.h"
#import "IBinaryD.h"
#import "ITextD.h"
#import "IOrderedListD.h"
#import "IReceiveListener.h"
#import "IReceiveSpeaker.h"
#import "data_types.h"
#import "errdebug.h"
#import "Localization.h"
#import "IConvertMIME.h"
#import "IArticleD.h"
#import "IHelp.h"
#import "InfoPanel.h"
#define LoStr(key) doLocalString(NULL,key,NULL)
struct windowDef {
@defs(Window)
};
extern char *ioBaseClassNameTable[];
static BOOL launchedFromDoubleClickOnFile = NO;
// ## REWRITE! ## Really shouldn't use an extern for this better to send message
HashTable *listOfTempFiles = nil;
// these tags must match the tags of the menu cell (really not a good way!)
// but IB doesn't gives us better!
#define MENU_TAG_SAVE 701
#define MENU_TAG_POST 703
#define MENU_TAG_RECURSIVE_SAVE 702
#define MENU_TAG_RECURSIVE_POST 704
#define MENU_TAG_SAVE_AS_MIME 705
#define FIND_NEXT_TAG 110
#define FIND_PREVIOUS_TAG 111
#define FIND_ENTER_SELECTION 113
@implementation IAppDelegate
- init
{
[super init];
iHelpPanel = nil;
iInfoPanel = nil;
listOfTempFiles = [[HashTable alloc] initKeyDesc:"*"];
return(self);
}
-(int)receiveArticle:(char *)data length:(int)length
{
const char *articleBuffer;
articleBuffer = NXCopyInputData(0);
DBG(10,fprintf(stderr, "***** start of article *****\n"));
DBG(10,fputs(articleBuffer, stderr));
DBG(10,fprintf(stderr, "***** end of article *****\n"));
[INewsD openArticle:articleBuffer length:length];
return(0);
}
- sendArticle:sender
{
IMMEditor *sendEditor;
IArticleD *article;
sendEditor = [[NXApp keyWindow] delegate];
if ([sendEditor class] == [IMMEditor class]) {
if ((article = [sendEditor sendArticle]) != nil) {
if ([[article dataForKey:HEADER_INFO]
infoForKey:GROUPNAME] == NULL) {
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Newsgroups field is missing, Please enter."),
NULL,NULL,NULL);
return (self);
}
// post article
[INewsD save:article];
}
} else {
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("key window is not an Editor window"),NULL,NULL,NULL);
}
return(self);
}
- openArticle:sender
{
[ILocalFileD open];
return(self);
}
- saveArticle:sender
{
IMMEditor *theEditor;
IArticleD *article;
theEditor = [[NXApp keyWindow] delegate];
if ([theEditor class] == [IMMEditor class]) {
if ((article = [theEditor sendArticle]) != nil) {
if ([[article dataForKey:HEADER_INFO]
infoForKey:GROUPNAME] == NULL) {
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Newsgroups field is missing, Please enter."),
NULL,NULL,NULL);
return (self);
}
[ILocalFileD save:article];
}
} else {
NXRunAlertPanel(LoStr("NewsBase"),LoStr("key window is not an Editor"
" window"), NULL, NULL, NULL);
}
return(self);
}
- postArticle:(const char *)articleBuffer length:(int)length
{
port_t port;
int returnCode;
port = NXPortFromName("NewsBase", NULL);
[[NXApp appSpeaker] setSendPort:port];
if ((returnCode = [[NXApp appSpeaker] receiveArticle:articleBuffer
length:length]) != 0) {
NXRunAlertPanel([self name],LoStr("cannot contact NewsBase"),
LoStr("OK"),NULL,NULL);
}
return(self);
}
- sendArticleFrom:sender toIOClass:(Class)ioClass
{
IMMEditor *sendEditor;
IOrderedListD *article;
sendEditor = [[NXApp keyWindow] delegate];
if ([sendEditor class] != [IMMEditor class]) {
NXRunAlertPanel(LoStr("NewsBase"),LoStr("key window is not an Editor window"),NULL,NULL,NULL);
return(self);
}
if ((article = [sendEditor sendArticle]) != nil) {
}
return(self);
}
// recursiveSendArticle is the common method for saves, posts, recursive
// saves and recursive posts; menu tags will differentiate the actual
// requests
- recursiveSendArticle:sender
{
IMMEditor *sendEditor;
IArticleD *article;
int i;
id externalObject;
const char *multipleViewerFlag;
sendEditor = [[NXApp keyWindow] delegate];
if ([sendEditor class] != [IMMEditor class]) {
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("key window is not an Editor window"),NULL,NULL,NULL);
return(self);
}
if ((article = [sendEditor sendArticle]) != nil) {
if ([[article dataForKey:HEADER_INFO]
infoForKey:GROUPNAME] == NULL) {
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Newsgroups field is missing, Please enter."),
NULL,NULL,NULL);
return (self);
}
switch ([[sender selectedCell] tag]) {
case MENU_TAG_SAVE:
case MENU_TAG_POST:
// check if there exists hyper links
if ([[article externalsList] count] > 0) {
if (NXRunAlertPanel(LoStr(MMEDITOR),
LoStr("Article has externally linked articles "
"which will not be recursively saved."), LoStr("OK"),
LoStr("Cancel"), NULL) == NX_ALERTDEFAULT) {
break;
} else {
return(self);
}
}
break;
default:
break;
}
switch ([[sender selectedCell] tag]) {
case MENU_TAG_SAVE:
[ILocalFileD save:article];
break;
case MENU_TAG_POST:
[INewsD save:article];
break;
case MENU_TAG_RECURSIVE_SAVE:
// recursive save requires multiple viewer mode so temporarily
// set multiple viewer mode
multipleViewerFlag = NXGetDefaultValue(OWNER, MULTIPLEVIEWERFLAG);
NXSetDefault(OWNER, MULTIPLEVIEWERFLAG, "Yes");
[article recursiveSaveToDomain:[ILocalFileD domain]];
NXSetDefault(OWNER, MULTIPLEVIEWERFLAG, multipleViewerFlag);
break;
case MENU_TAG_RECURSIVE_POST:
// recursive save requires multiple viewer mode so temporarily
// set multiple viewer mode
multipleViewerFlag = NXGetDefaultValue(OWNER, MULTIPLEVIEWERFLAG);
NXSetDefault(OWNER, MULTIPLEVIEWERFLAG, "Yes");
[article recursiveSaveToDomain:[INewsD domain]];
NXSetDefault(OWNER, MULTIPLEVIEWERFLAG, multipleViewerFlag);
break;
case MENU_TAG_SAVE_AS_MIME:
[ILocalFileD saveAsMIME:article];
break;
}
}
return(self);
}
- printArticle:sender
{
IMMEditor *printEditor;
printEditor = [[NXApp keyWindow] delegate];
if ([printEditor class] == [IMMEditor class]) {
[printEditor printArticle];
} else {
NXRunAlertPanel(LoStr("NewsBase"),LoStr("key window is not an Editor window"),NULL,NULL,NULL);
}
return(self);
}
- redisplayArticle:sender
{
IMMEditor *redisplayEditor;
redisplayEditor = [[NXApp keyWindow] delegate];
if ([redisplayEditor class] == [IMMEditor class]) {
[redisplayEditor redisplayArticle];
} else {
NXRunAlertPanel(LoStr("NewsBase"),LoStr("key window is not an Editor window"),NULL,NULL,NULL);
}
return(self);
}
- getReferenceListOfArticle:sender
{
IMMEditor *currentEditor;
MenuCell *menucell;
const char *referenceList, *sptr;
char messageId[512], *tptr;
currentEditor = [[NXApp keyWindow] delegate];
if (currentEditor == nil) {
currentEditor = sender;
}
if ([currentEditor class] == [IMMEditor class]) {
if ((referenceList = [currentEditor getReferenceList]) != NULL) {
sptr = referenceList;
while (*sptr != '\0') {
for (; *sptr != '\0' && *sptr != '<'; ++sptr);
if (*sptr != '<') {
break;
}
getNextMessageId:
messageId[0] = '<';
for (++sptr, tptr = messageId + 1; *sptr != '\0' && *sptr != '>'
&& *sptr != '<'; ++sptr, ++tptr) {
*tptr = *sptr;
}
if (*sptr == '<') {
// error message id did not end and new begins
goto getNextMessageId;
}
if (*sptr != '>') {
break;
}
*tptr++ = *sptr++;
*tptr = '\0';
menucell = [[oEditorGetReMenuCell target] addItem:messageId
action:@selector(getArticleWithMessageID:)
keyEquivalent:'\0'];
[menucell setTarget:self];
}
}
// } else {
// NXRunAlertPanel(LoStr("NewsBase"),LoStr("key window is not an Editor window"),NULL,NULL,NULL);
}
return(self);
}
- getArticleWithMessageID:sender
{
[INewsD loadFromName:[[sender selectedCell] title] inZone:NULL];
return(self);
}
- closeAllEditorWindows:sender
{
List *windowList;
Window *window;
int i;
windowList = [NXApp windowList];
for (i = 0; (window = [windowList objectAt:i]) != nil; ++i) {
if ([[window delegate] class] == [IMMEditor class]) {
if ([[window delegate] windowWillClose:self] != nil) {
[window close];
}
}
}
return(self);
}
- openEditor:sender
{
IArticleD *article;
id openPanel;
const char *types[2] = {"mime", NULL};
NXStream *stream;
id articleItem;
id conv;
switch ([[sender selectedCell] tag]) {
case 0:
// new editor window
LoadLocalNib("MMRTFEditor.nib",self,NO,NULL);
/*
[NXApp loadNibSection:"MMRTFEditor.nib" owner:self withNames:NO
fromZone:NXCreateZone(vm_page_size, vm_page_size, YES)];
*/
[editor editNewArticle];
break;
case 1:
// post response
editor = [[NXApp keyWindow] delegate];
if ([editor class] == [IMMEditor class]) {
if ((article = [editor sendArticle]) != nil) {
LoadLocalNib("MMRTFEditor.nib",self,NO,NULL);
/*
[NXApp loadNibSection:"MMRTFEditor.nib" owner:self withNames:NO
fromZone:NXCreateZone(vm_page_size, vm_page_size, YES)];
*/
[editor postResponseToArticle:article];
}
} else {
NXRunAlertPanel(LoStr("NewsBase"),LoStr("key window is not an Editor window"),NULL,NULL,NULL);
}
break;
/*
case 2:
openPanel = [OpenPanel new];
[openPanel allowMultipleFiles:NO];
if ([openPanel runModalForTypes:types]) {
stream = NXMapFile([openPanel filename], NX_READONLY);
LoadLocalNib("MMRTFEditor.nib",self,NO,[self zone]);
conv = [[IConvertMIME alloc] init];
articleItem = [conv convertToItem:stream];
[editor displayArticle:articleItem];
NXCloseMemory(stream, NX_FREEBUFFER);
}
*/
}
return(self);
}
- openHelpPanel:sender
{
if (iHelpPanel == nil) {
iHelpPanel = [[IHelp allocFromZone:[self zone]] init];
}
[iHelpPanel openHelpPanel:sender];
return self;
}
- openInfoPanel:sender
{
if (iInfoPanel == nil) {
iInfoPanel = [[InfoPanel allocFromZone:[self zone]] init];
}
[iInfoPanel openInfoPanel:sender];
return self;
}
- appWillInit:sender
{
[NXApp setAppListener:[[IReceiveListener alloc] init]];
[NXApp setAppSpeaker:[[IReceiveSpeaker alloc] init]];
return(self);
}
- appDidInit:sender
{
// initialize IMMEditor class to prevent lockup with workspace manager
[IMMEditor class];
return(self);
}
- appWillTerminate:sender
{
int n;
Window *window;
List *windowList;
Class isA;
NXHashState state;
const char *filename;
id value;
char command[512];
windowList = [NXApp windowList];
for (n = 0; window = [windowList objectAt:n]; ++n) {
if (NXZoneFromPtr(window) == 0) {
DBG(1, fprintf(stderr, "NXZoneFromPtr(window = %#x) = %#x\n",
window, NXZoneFromPtr(window)););
[windowList removeObject:window];
--n;
continue;
}
if ((isA = ((struct windowDef *)window)->isa) != (Class)[Window class]
&& isA != (Class)[Panel class] && isA != (Class)[Menu class] &&
isA != (Class)[PopUpList class]) {
DBG(1, fprintf(stderr, "(window = %#x)->isa = %#x\n",
window, ((struct windowDef *)window)->isa););
[windowList removeObject:window];
--n;
}
}
// remove all temporary files
state = [listOfTempFiles initState];
while ([listOfTempFiles nextState:&state key:(const void **)&filename
value:(void **)&value] == YES) {
sprintf(command, "rm -r %.505s", (const char *)filename);
system(command);
}
return(self);
}
- (BOOL)appAcceptsAnotherFile:sender
{
DBG(1, ;);
return(YES);
}
- (BOOL)app:sender openFile:(const char *)filename type:(const char *)type
{
DBG(1, ;);
launchedFromDoubleClickOnFile = YES;
// initialize IMMEditor class to prevent lockup with workspace manager
[IMMEditor class];
return([ILocalFileD openFromName:filename]);
}
- editorDidBecomeKey:sender
{
Menu *oEditorGetReSubMenu;
Matrix *oEditorGetReSubMenuItemList;
int nrows, ncols, i;
[oEditorReMenuCell setEnabled:YES];
[oSaveMenuCell setEnabled:YES];
[oRecursiveSaveMenuCell setEnabled:YES];
[oSaveAsMenuCell setEnabled:YES];
[oPostMenuCell setEnabled:YES];
[oRecursivePostMenuCell setEnabled:YES];
[oPrintMenuCell setEnabled:YES];
[oFindMenuCell setEnabled:YES];
[oEditMenuCell setEnabled:YES];
[oCloseMenuCell setEnabled:YES];
[oRedisplayMenuCell setEnabled:YES];
oEditorGetReSubMenu = [oEditorGetReMenuCell target];
oEditorGetReSubMenuItemList = [oEditorGetReSubMenu itemList];
[oEditorGetReSubMenuItemList getNumRows:&nrows numCols:&ncols];
for (i = 0; i < nrows; ++i) {
[oEditorGetReSubMenuItemList removeRowAt:i andFree:YES];
}
[oEditorReMenuCell setEnabled:YES];
[self getReferenceListOfArticle:sender];
oEditorGetReSubMenu = [oEditorGetReMenuCell target];
[[oEditorGetReSubMenu itemList] sizeToCells];
[oEditorGetReSubMenu sizeToFit];
[oEditorGetReMenuCell setEnabled:YES];
return(self);
}
- editorDidResignKey:sender
{
Menu *oEditorGetReSubMenu;
Matrix *oEditorGetReSubMenuItemList;
int nrows, ncols, i;
[oEditorReMenuCell setEnabled:NO];
[oSaveMenuCell setEnabled:NO];
[oRecursiveSaveMenuCell setEnabled:NO];
[oSaveAsMenuCell setEnabled:NO];
[oPostMenuCell setEnabled:NO];
[oRecursivePostMenuCell setEnabled:NO];
[oPrintMenuCell setEnabled:NO];
[oFindMenuCell setEnabled:NO];
[oEditMenuCell setEnabled:YES];
[oCloseMenuCell setEnabled:NO];
[oRedisplayMenuCell setEnabled:NO];
[oEditorGetReMenuCell setEnabled:NO];
oEditorGetReSubMenu = [oEditorGetReMenuCell target];
oEditorGetReSubMenuItemList = [oEditorGetReSubMenu itemList];
[oEditorGetReSubMenuItemList getNumRows:&nrows numCols:&ncols];
for (i = 0; i < nrows; ++i) {
[oEditorGetReSubMenuItemList removeRowAt:i andFree:YES];
}
[oEditorGetReSubMenuItemList sizeToCells];
[oEditorGetReSubMenu sizeToFit];
return(self);
}
static Window *iconEnteredWindow;
- (int)iconEntered:(int)windowNum at:(double)x :(double)y
iconWindow:(int)iconWindowNum iconX:(double)iconX iconY:(double)iconY
iconWidth:(double)iconWidth iconHeight:(double)iconHeight
pathList:(const char *)pathList
{
unsigned int iconEnteredWindowNum;
// ## REWRITE! ## would be nice if this uniformly redirected the
// message to the windows delegate
NXConvertGlobalToWinNum(windowNum, &iconEnteredWindowNum);
iconEnteredWindow = [NXApp findWindow:iconEnteredWindowNum];
[iconEnteredWindow makeKeyAndOrderFront:self];
if ([[iconEnteredWindow delegate] class] == [IMMEditor class]) {
return([[[iconEnteredWindow delegate] text] iconEntered:windowNum
at:x :y iconWindow:iconWindowNum iconX:iconX iconY:iconY
iconWidth:iconWidth iconHeight:iconHeight pathList:pathList]);
}
return(0);
}
- (int)iconReleasedAt:(double)x :(double)y ok:(int *)flag
{
if ([[iconEnteredWindow delegate] class] == [IMMEditor class]) {
return([[[iconEnteredWindow delegate] text]
iconReleasedAt:x :y ok:flag]);
}
return(0);
}
- (int)iconExitedAt:(double)x :(double)y
{
if ([[iconEnteredWindow delegate] class] == [IMMEditor class]) {
return([[[iconEnteredWindow delegate] text] iconExitedAt:x :y]);
}
return(0);
}
- setOEditorReMenuCell:editorReMenuCell
{
oEditorReMenuCell = editorReMenuCell;
[oEditorReMenuCell setEnabled:NO];
return(self);
}
- setOEditorGetReMenuCell:editorGetReMenuCell
{
oEditorGetReMenuCell = editorGetReMenuCell;
[oEditorGetReMenuCell setEnabled:NO];
[[oEditorGetReMenuCell target] setTitle:"Message ID's"];
[[oEditorGetReMenuCell target] setDelegate:self];
return(self);
}
- (int)requestForPost:(char *) newsgroups sourceWindow:(int)wnum
{
IMMEditor *sendEditor;
IArticleD *article;
char *groupName;
unsigned int lwnum;
id sourceWin;
DBG(1,fprintf(stderr," ============ requestForPost %s\t %d",
newsgroups, wnum));
[NXApp activateSelf:YES];
NXConvertGlobalToWinNum(wnum, &lwnum);
if ((sourceWin=[NXApp findWindow:lwnum]) == nil) {
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("err occured when posting, try again"),NULL,NULL,NULL);
return(-1);
}
[sourceWin makeKeyAndOrderFront:self];
sendEditor = [sourceWin delegate];
if ([sendEditor class] != [IMMEditor class]) {
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("key window is not an Editor window"),NULL,NULL,NULL);
return(-1);
}
if ((article = [sendEditor sendArticle]) != nil) {
// check if there exists hyper links
if ([[article externalsList] count] > 0) {
if (NXRunAlertPanel(LoStr(MMEDITOR),
LoStr("Article has externally linked articles "
"which will not be recursively saved."), LoStr("OK"),
LoStr("Cancel"), NULL) != NX_ALERTDEFAULT) {
return (-1);
}
}
if ((groupName=[[article dataForKey:HEADER_INFO]
infoForKey:GROUPNAME]) != NULL) {
// article header has "Newsgroups:"
if (strncmp(newsgroups,"",strlen(newsgroups))==0) {
// Newstoups: is in editor header
[INewsD save:article];
return (0);
} else if (strncmp(groupName,newsgroups,strlen(groupName))==0) {
// group name is same
[INewsD save:article];
return (0);
} else {
// groupname is different
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Newsgroups: is not matched"),NULL,NULL,NULL);
return(-1);
}
} else {
// header does not have "Newsgroups:"
if (strncmp(newsgroups,"",strlen(newsgroups))==0) {
// posted to nextStation icon, so should have "Newsgroups:"
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Newsgroups field is missing, Please enter."),
NULL,NULL,NULL);
return (-1);
}
[[article dataForKey:HEADER_INFO]
addInfoString:(const char *)newsgroups key:GROUPNAME];
[INewsD save:article];
return (0);
}
}
return (0);
}
// save previous context which is usually NewsBase
- setPreviousContext:(int)context
{
if (context != myContext) {
previousContext = context;
}
return(self);
}
// probably NewsBase
- (int)previousContext
{
return(previousContext);
}
- setMyContext:(int)context
{
myContext = context;
return(self);
}
- (int)myContext
{
return(myContext);
}
// find distributes find menu selections to the appropriate editor
- find:sender
{
IMMEditor *findEditor;
findEditor = [[NXApp mainWindow] delegate];
if ([findEditor class] != [IMMEditor class]) {
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("key window is not an Editor window"),NULL,NULL,NULL);
return(self);
}
switch ([[sender selectedCell] tag]) {
case FIND_NEXT_TAG:
[[findEditor view] find:[oFindText stringValue] forward:YES
ignoreCase:[oFindCase state]];
break;
case FIND_PREVIOUS_TAG:
[[findEditor view] find:[oFindText stringValue] forward:NO
ignoreCase:[oFindCase state]];
break;
case FIND_ENTER_SELECTION:
[oFindText setStringValue:[[findEditor view] selection]];
break;
}
return(self);
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.