This is Controller.m in view mode; [Download] [Up]
/* Controller.m -- Controller object for MailHelper application.
Copyright 1991, Izumi Ohzawa and Manuel Alberto Ricart, All rights reserved.
3-17-91 V1.0 (IO)
* Starting project.
* Some codes are borrowed from AtYourService NeXT demo application.
4-6-91 V1.0 (IO)
* Bug fix: fclose(fpin); was missing in method insertSignature.
9-18-91 V1.1 (MAR)
* Preferences panel and use of default database to store them.
Joint venture with Izumi? Perhaps. Izumi sent me his code
for MailHelper. I told him I implement some basic prefs for him.
9-22-91 V1.1 (IO)
* Defaults now written out as soon as OK button in Pref panel is pressed.
* Signature insertion now adds a separator '---' within the code to
remove requirement of having it in signature file itself (to make MailHelper
conform with other programs which use .signature).
* RTF signature insertion added.
10-9-91 V1.2 (Mitsuhiro Kishimoto)
* Japanese re-format routine: needed to handle mixed ASCII and 2-byte EUC code.
Original "Kin-soku" (forbidden line break) code was written
by Masatoshi Kurihara.
9-10-93 V1.3 Mike O'Neill (emo@mitre.org) added .rtfd support, grayed rtf selection, and 3.0 colorized icon and compiled FAT
To implement:
User selectable command keys for various functions.
*/
#import "Controller.h"
#import <appkit/appkit.h>
@implementation Controller
/* Modified Izumi's code to load the defaults at startup.
* It also sets up the default values on the prefs panel.
*/
- appDidInit:sender
{
static NXDefaultsVector MailHelperDefaults = {
{WIDTH,"62"},
{QUOTE,"> "},
{SIGFILE,SIGFILENAME},
{RTFSIGFILE,RTFSIGFILENAME},
{RTFDSIGFILE,RTFDSIGFILENAME},
{NULL}
};
myListener = [NXApp appListener];
[myListener setServicesDelegate: self];
NXRegisterDefaults(APPNAME, MailHelperDefaults);
wrapWidth = atoi(NXGetDefaultValue(APPNAME, WIDTH));
[gWrapWidth setIntValue:wrapWidth];
[gWrapScroller setIntValue:wrapWidth];
quoteString =(char *) NXGetDefaultValue(APPNAME, QUOTE);
[gQuoteString setStringValue:quoteString];
sigFile =(char *) NXGetDefaultValue(APPNAME, SIGFILE);
[gSigFileName setStringValue:sigFile];
rtfSigFile =(char *) NXGetDefaultValue(APPNAME, RTFSIGFILE);
[gRtfSigFileName setStringValue:rtfSigFile];
rtfdSigFile =(char *) NXGetDefaultValue(APPNAME, RTFDSIGFILE);
[gRtfdSigFileName setStringValue:rtfdSigFile];
// [gRtfdText setGraphicsImportEnabled:YES];
return self;
}
/* Brings up the Info panel. Not done on startup because it's in a separate
* interface file. Saves startup time for the user if we do this when they ask
* for it, and not before.
* "infoPanel" and "helpPanel" are defined in "Info.nib".
*/
- infoPanel:sender
{
if( ! infoPanel ){
[NXApp loadNibSection:"Info.nib" owner:self];
}
[infoPanel makeKeyAndOrderFront:sender];
return self;
}
// Records the prefsPanel values into the global variables
/* [izumi] Moved from delegate method -appWillTerminate:, because it is
* not apparently called if user is logging out from Workspace --
* this is how MailHelper gets terminated (MailHelper is almost never
* exited via Quit from menu.).
*/
- prefsOK:sender
{
char buf[20];
wrapWidth = (int)[gWrapWidth intValue];
quoteString = (char *)[gQuoteString stringValue];
sigFile = (char *)[gSigFileName stringValue];
rtfSigFile = (char *)[gRtfSigFileName stringValue];
sprintf(buf, "%d", wrapWidth);
NXWriteDefault(APPNAME, WIDTH, buf);
NXWriteDefault(APPNAME, QUOTE, quoteString);
NXWriteDefault(APPNAME, SIGFILE, sigFile);
NXWriteDefault(APPNAME, RTFSIGFILE, rtfSigFile);
return self;
}
- prefsCancel:sender
{
[gWrapWidth setIntValue:wrapWidth];
[gWrapWidth display];
[gWrapScroller setIntValue:wrapWidth];
[gWrapScroller display];
[gQuoteString setStringValue:quoteString];
[gQuoteString display];
[gSigFileName setStringValue:sigFile];
[gSigFileName display];
[gRtfSigFileName setStringValue:rtfSigFile];
[gRtfSigFileName display];
return self;
}
/*
* Brings up the Help panel (as above)
*/
- helpPanel:sender
{
if( ! helpPanel ){
[NXApp loadNibSection:"Info.nib" owner:self];
}
[helpPanel makeKeyAndOrderFront:sender];
return self;
}
/* Reformats selected text so that it fits into a specified column width.
* Alberto's Modifications:
* initialized colLimit to wrapWidth global variable.
*/
- reformatSelection:(id)pbid userData:(const char *)udata error:(char **)errmsg
{
char *data;
int length;
const char *const *types;
int hasAscii, i;
types = [pbid types]; /* get a list of pasteboard types */
hasAscii = 0;
for(i=0; !hasAscii && types[i]; i++)
if(!strcmp(types[i], NXAsciiPboardType)) hasAscii = 1;
if(hasAscii)
{
[pbid readType:NXAsciiPboardType data:&data length:&length];
if(data && length)
{
char *returnData, *dataptr, *endptr;
char *retptr;
int col;
unsigned char c1, c2;
col = 0;
returnData=malloc(length+10);
dataptr = data;
endptr = dataptr+length;
retptr = returnData;
while (dataptr < endptr) {
c1 = *dataptr++;
c2 = (iskanji (c1) ? *dataptr++ : *dataptr);
switch (c1) {
case '\n':
if ( c2 == '\n')
col = 0;
else if (iskanji (c2))
goto skip_char;
else
c1 = ' ';
break;
case '\t':
col = (col + 8) &~ 7;
break;
case '\b':
col = col ? col - 1 : 0;
break;
default:
col = col + (iskanji (c1) ? 2 : 1);
}
if (col > wrapWidth) {
if ( ! iskanji (c1)) {
for (i = 1; 0 < col - i; i++) {
c2 = *(retptr - i);
if ( iskanji (c2) ) {
dataptr -= i;
retptr -= (i - 1);
*retptr++ = '\n';
col = 0;
goto skip_char;
} else if ( isspace (c2) ) {
dataptr -= i;
retptr -= i;
*retptr++ = '\n';
col = 0;
goto skip_char;
}
}
*retptr++ = '\n';
col = 1;
} else if (iskanji (c1) && ! KINSOKU (c1, c2)) {
*retptr++ = '\n';
col = 2;
}
}
*retptr++= c1;
if (iskanji (c1))
*retptr++= c2;
else if (c1 == '\n' && c2 == '\n') {
*retptr++= c2;
dataptr++;
}
skip_char:
;
}
*retptr++= '\n';
*retptr = '\0';
[pbid declareTypes:&NXAsciiPboardType num:1 owner:self];
[pbid writeType:NXAsciiPboardType data:returnData length:strlen(returnData)];
free(returnData);
} /* end if(data && length) */
else
*errmsg = "Selection is empty.";
} /* end if(hasAscii) */
else
*errmsg = "No ASCII text found in your selection.";
return self;
}
/* Adds quotation marks "> " to the head of each line of selected text.
* Alberto's Modification:
* Only changed the definition of quotestr to point to the quoteString global.
*/
- quoteSelection:(id)pbid userData:(const char *)udata error:(char **)errmsg
{
char *data;
int length;
const char *const *types;
char *quotestr = quoteString;
int hasAscii, i, quotelen;
quotelen = strlen(quotestr);
types = [pbid types]; /* get a list of pasteboard types */
hasAscii = 0;
for(i=0; !hasAscii && types[i]; i++)
if(!strcmp(types[i], NXAsciiPboardType)) hasAscii = 1;
if(hasAscii)
{
[pbid readType:NXAsciiPboardType data:&data length:&length];
if(data && length)
{
int numlines;
char ch;
char *returnData, *dataptr, *endptr, *outptr;
numlines = 1;
dataptr = data; /* ptr to original data */
endptr = data+length; /* ptr to end of data */
while(dataptr < endptr) /* count the number of lines */
if(*dataptr++ == '\n')
numlines++;
returnData=malloc(length+numlines*quotelen+10);
dataptr = data; /* reinitialize ptr to orig data */
outptr = returnData;
for(i=0;i<quotelen;i++)
*outptr++ = quotestr[i];
while(dataptr < endptr)
{
if((ch = *dataptr++) == '\n')
{
*outptr++ = ch;
for(i=0;i<quotelen;i++)
*outptr++ = quotestr[i];
}
else
*outptr++ = ch;
}
*outptr = '\n';
*(outptr+1) = '\0';
[pbid declareTypes:&NXAsciiPboardType num:1 owner:self];
[pbid writeType:NXAsciiPboardType data:returnData length:strlen(returnData)];
free(returnData);
} /* end if(data && length) */
else
*errmsg = "Selection is empty.";
} /* end if(hasAscii) */
else
*errmsg = "No ASCII text found in your selection.";
return self;
}
// Adds the content of ~/.signature at the current cursor location.
- insertSignature:(id)pbid userData:(const char *)udata error:(char **)errmsg
{
char *data, *dataptr;
char *signaturefile = sigFile;
char signaturepath[256];
int length, i;
struct stat filestat;
FILE *fpin;
sprintf(signaturepath, "%s/%s", NXHomeDirectory(), signaturefile);
if(stat(signaturepath, &filestat))
{
data = "";
length = 0;
*errmsg = "No signature file found in your home directory.";
}
else
{
length = filestat.st_size;
if((fpin = fopen(signaturepath, "r")) != NULL)
{
dataptr = data = malloc(length+NUMSIGDASH+10); /* data remains unchanged */
for(i=0; i<NUMSIGDASH; i++) /* Add '---' signature separator here */
*dataptr++ = '-';
*dataptr++ = '\n';
fread((void *)dataptr, 1, length, fpin);
fclose(fpin); /* This was missing in V1.0 release */
*(dataptr+length) = '\0';
[pbid declareTypes:&NXAsciiPboardType num:1 owner:self];
[pbid writeType:NXAsciiPboardType data:data length:strlen(data)];
free(data);
}
else
*errmsg = "Cannot open signature file.";
}
return self;
}
// Adds the content of ~/.signature.rtf at the current cursor location.
// RTF signature insertion method.
- insertRtfSignature:(id)pbid userData:(const char *)udata error:(char **)errmsg
{
char *data;
char *signaturefile = rtfSigFile;
char signaturepath[256];
int length;
struct stat filestat;
FILE *fpin;
sprintf(signaturepath, "%s/%s", NXHomeDirectory(), signaturefile);
if(stat(signaturepath, &filestat))
{
data = "";
length = 0;
*errmsg = "No RTF signature file found in your home directory.";
}
else
{
length = filestat.st_size;
if((fpin = fopen(signaturepath, "r")) != NULL)
{
data = malloc(length+10);
fread((void *)data, 1, length, fpin);
fclose(fpin);
*(data+length) = '\0';
[pbid declareTypes:&NXRTFPboardType num:1 owner:self];
[pbid writeType:NXRTFPboardType data:data length:strlen(data)];
free(data);
}
else
*errmsg = "Cannot open RTF signature file.";
}
return self;
}
// Adds the content of ~/.signature.rtfd at the current cursor location.
// RTFD signature insertion method.
- insertRtfdSignature:(id)pbid userData:(const char *)udata error:(char **)errmsg
{
char *data;
char *signaturefile = rtfdSigFile;
char signaturepath[256];
int length;
struct stat filestat;
sprintf(signaturepath, "%s/%s", NXHomeDirectory(), signaturefile);
if(stat(signaturepath, &filestat))
{
data = "";
length = 0;
*errmsg = "No RTFD signature found in your home directory.";
}
else
{
if(![gRtfdText openRTFDFrom:signaturepath])
{
[tempText selectAll:self]; // This bit of code is necessary because
[tempText paste:self]; // while Edit, Mail and Text all support RTFD
[gRtfdText selectAll:self]; // there is as yet no proper NXAtom for the
[gRtfdText copy:self]; // pasteboard type. So I use the copy and
[gRtfdText writeSelectionToPasteboard:pbid types:(NXAtom *)[[Pasteboard newName:NXGeneralPboard] types]];
[tempText selectAll:self]; // to put the text on the general pboard,
[tempText copy:self]; //from whence I then get the types!
}
else
*errmsg = "Cannot open RTFD signature.";
}
return self;
}
// quote an RTF selection by graying it out
- grayRTFSelection:(id)pbid userData:(const char *)udata error:(char **)errmsg
{
NXAtom pbtype[] = {NXRTFPboardType, 0};
[tempText selectAll:self];
[tempText readSelectionFromPasteboard:pbid];
[tempText setSelGray:NX_DKGRAY];
[tempText writeSelectionToPasteboard:pbid types:pbtype];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.