This is ToDoItem.m in view mode; [Download] [Up]
/*
* ToDoItem - implementation of ToDoItem, the basic unit of information
* for the ToDoList program. The method -adjustPriority implements
* the dynamic priority mechanism.
*
* You may freely copy, distribute and reuse the code in this example.
* This code is provided AS IS without warranty of any kind, expressed
* or implied, as to its fitness for any particular use.
*
* Copyright 1995 Ralph Zazula (rzazula@next.com). All Rights Reserved.
*
*/
#import "ToDoItem.h"
#import "RZ.h"
#import <appkit/appkit.h>
#import <math.h>
typedef struct _toDoItemFlags {
#ifdef __BIG_ENDIAN__
unsigned int type:8;
unsigned int private:1;
unsigned int completed:1;
unsigned int _RESERVED:22;
#else
unsigned int _RESERVED:22;
unsigned int completed:1;
unsigned int private:1;
unsigned int type:8;
#endif
} toDoItemFlags;
#define _flags ((toDoItemFlags *)_reservedToDoItem1)
@implementation ToDoItem
+ initialize
{
if([self class] == [ToDoItem class]) {
[self setVersion:4];
}
return self;
}
- initSubject:(char *)subj startDate:(long)start dueDate:(long)due
completeDate:(long)completed type:(char)type isPrivate:(BOOL)privateFlag
isCompleted:(BOOL)completeFlag data:(char *)buf dataLen:(int)len
{
if(self = [super init]) {
_flags = (toDoItemFlags *)calloc(1, sizeof(toDoItemFlags));
[self setSubject:subj];
[self setStartDate:start];
[self setDueDate:due];
[self setType:type];
[self setPrivate:privateFlag];
/* don't want auto-calc of completion so don't use setCompleted: */
dateCompleted = completed ? completed : 0;
_flags->completed = completeFlag;
[self setData:buf];
}
return self;
}
- initFromItem:(id <ToDoItems>)anItem
{
char *buf;
int len;
[anItem getData:&buf length:&len];
return [self initSubject:[anItem subject] startDate:[anItem startDate]
dueDate:[anItem dueDate] completeDate:[anItem dateCompleted]
type:[anItem type] isPrivate:[anItem isPrivate]
isCompleted:[anItem isCompleted] data:buf dataLen:len];
}
- init
{
return [self initSubject:NULL startDate:time(NULL) dueDate:(time(NULL)+60)
completeDate:0 type:TODO_TYPE_NORMAL isPrivate:NO isCompleted:NO
data:NULL dataLen:0];
}
- free
{
if(subject) {
NX_FREE(subject);
subject = NULL;
}
if(data) {
NX_FREE(data);
data = NULL;
dataLen = 0;
}
free(_flags);
return [super free];
}
- (char *)subject { return subject; }
- (long)priority { return priority; }
- (long)startDate { return startDate; }
- (long)dueDate { return dueDate; }
- (long)dateCompleted { return dateCompleted; }
- (char)type { return _flags->type; }
- (BOOL)isPrivate { return _flags->private; }
- (BOOL)isCompleted { return _flags->completed; }
- (const char *)asciiStartDate
{
static char buf[40];
if(!startDate) {
return NULL;
}
strftime(buf, 40, "%m/%d/%y", localtime(&startDate));
return buf;
}
- (const char *)asciiCompletedDate
{
static char buf[40];
if(!dateCompleted) {
return NULL;
}
strftime(buf, 40, "%m/%d/%y", localtime(&dateCompleted));
return buf;
}
- (const char *)asciiDueDate
{
static char buf[40];
switch(_flags->type) {
case TODO_TYPE_NORMAL :
case TODO_TYPE_APPOINTMENT :
strftime(buf, 40, "%m/%d/%y", localtime(&dueDate));
break;
case TODO_TYPE_HIGHPRIORITY :
sprintf(buf, "ASAP!");
break;
case TODO_TYPE_LOWPRIORITY :
sprintf(buf, "LATER");
break;
}
return buf;
}
- getData:(char **)d length:(int *)len
{
*d = data;
*len = dataLen;
return self;
}
- setSubject:(const char *)s
{
subject = RZReplaceStringBuffer(&subject, s);
return self;
}
- setPriority:(long)p
{
priority = p;
return self;
}
- setStartDate:(long)newDate
{
startDate = newDate;
return self;
}
- setDueDate:(long)newDate
{
dueDate = newDate;
[self adjustPriority];
return self;
}
- setType:(char)newType
{
_flags->type = newType;
priority = 0;
return self;
}
- setPrivate:(BOOL)flag
{
_flags->private = flag;
return self;
}
- setCompleted:(BOOL)flag
{
_flags->completed = flag;
dateCompleted = flag ? time(NULL) : 0;
return self;
}
- setData:(const char *)d
{
RZReplaceStringBuffer(&data, d);
dataLen = data ? strlen(data) + 1 : 0;
return self;
}
- setDataFromText:aText
{
NXStream *stream;
BOOL failed = NO;
stream = NXOpenMemory(NULL, 0, NX_READWRITE);
NX_DURING
[aText writeRichText:stream];
NX_HANDLER
failed = YES;
NX_ENDHANDLER
if(!failed) {
[self setDataFromStream:stream];
NXCloseMemory(stream, NX_FREEBUFFER);
}
return self;
}
- setDataFromStream:(NXStream *)stream
{
char *_data;
int _dataLen, _maxLen;
NXGetMemoryBuffer(stream, &_data, &_dataLen, &_maxLen);
[self setData:_data];
return self;
}
- writeToStream:(NXStream *)stream
{
static id dummyText = nil;
NXPrintf(stream, "Subject: %s\n",[self subject]);
switch(_flags->type) {
case TODO_TYPE_NORMAL :
NXPrintf(stream, "Type: Normal\n");
break;
case TODO_TYPE_APPOINTMENT :
NXPrintf(stream, "Type: Appointment\n");
break;
case TODO_TYPE_LOWPRIORITY :
NXPrintf(stream, "Type: Low Priority\n");
break;
case TODO_TYPE_HIGHPRIORITY :
NXPrintf(stream, "Type: High Priority\n");
break;
}
NXPrintf(stream, "Created: %s\n",[self asciiStartDate]);
NXPrintf(stream, "Due on: %s\n",[self asciiDueDate]);
if(_flags->completed) {
NXPrintf(stream, "Completed: %s\n",[self asciiCompletedDate]);
}
NXPrintf(stream, "\n");
if(dataLen) {
NXStream *_stream;
if(!dummyText) {
dummyText = [[Text alloc] init];
}
_stream = NXOpenMemory(NULL, 0, NX_READWRITE);
NXWrite(_stream, data, dataLen);
NXSeek(_stream, 0, NX_FROMSTART);
[dummyText readRichText:_stream];
NXCloseMemory(_stream, NX_FREEBUFFER);
[dummyText writeText:stream];
}
return self;
}
#define LOW_PRIORITY_BASE 0
#define LOW_PRIORITY_SIZE 256
#define LOW_PRIORITY_MAX (LOW_PRIORITY_BASE + LOW_PRIORITY_SIZE)
#define NORMAL_PRIORITY_BASE (LOW_PRIORITY_MAX + 1)
#define NORMAL_PRIORITY_SIZE 512
#define NORMAL_PRIORITY_MAX (NORMAL_PRIORITY_BASE + NORMAL_PRIORITY_SIZE)
#define HIGH_PRIORITY_BASE (NORMAL_PRIORITY_MAX + 1)
#define HIGH_PRIORITY_SIZE 256
#define HIGH_PRIORITY_MAX (HIGH_PRIORITY_BASE + HIGH_PRIORITY_SIZE)
#define ONE_DAY (60*60*24)
#define ONE_YEAR (60*60*24*365)
#define OLDEST_ITEM ONE_YEAR
- adjustPriority
/*
* priority quantizer - I've decided to quantize priorities in the
* range 0 - 1023 (if you have more than 1K of stuff to do, you're
* in trouble :-) The priority space is divided into three regions:
* 0 - 255 LOW PRIORITY ITEMS
* 256 - 767 NORMAL PRIORITY ITEMS
* 768 - 1023 HIGH PRIORITY ITEMS
*/
{
long age = time(NULL) - startDate;
long deadline = dueDate - time(NULL);
if(_flags->completed) {
priority = -dateCompleted;
return self;
}
switch(_flags->type) {
case TODO_TYPE_LOWPRIORITY :
/* accrue priority over time but never get above LOW_PRIORITY_MAX */
priority = LOW_PRIORITY_BASE +
LOW_PRIORITY_SIZE*((float)age/(float)OLDEST_ITEM);
priority = MIN(priority, LOW_PRIORITY_MAX);
break;
case TODO_TYPE_NORMAL :
/* increase priority as we get nearer the deadline */
if(deadline > 0) {
/* quantize the time until the deadline */
priority = NORMAL_PRIORITY_MAX -
NORMAL_PRIORITY_SIZE*((float)deadline/(float)OLDEST_ITEM);
} else {
/* past the due date, make max priority */
priority = NORMAL_PRIORITY_MAX;
}
priority = MIN(priority, NORMAL_PRIORITY_MAX);
break;
case TODO_TYPE_HIGHPRIORITY :
/* accrue priority over time but never get above HIGH_PRIORITY_MAX */
priority = HIGH_PRIORITY_BASE +
HIGH_PRIORITY_SIZE*((float)age/(float)OLDEST_ITEM);
priority = MIN(priority, HIGH_PRIORITY_MAX);
break;
case TODO_TYPE_APPOINTMENT :
/* drop into an appropriate slot based on the appointment date */
if(deadline > 10*ONE_DAY) {
priority = LOW_PRIORITY_MAX;
} else if(deadline < 2*ONE_DAY) {
priority = HIGH_PRIORITY_MAX;
} else {
priority = NORMAL_PRIORITY_MAX;
}
break;
}
return self;
}
- awake
{
[self adjustPriority];
return self;
}
- read:(NXTypedStream *)ts
{
[super read:ts];
_flags = (toDoItemFlags *)calloc(1,sizeof(toDoItemFlags));
switch(NXTypedStreamClassVersion(ts, [[self class] name])) {
case 4 :
NXReadTypes(ts, "*llll*iI",
&subject, &priority, &startDate, &dueDate, &dateCompleted,
&data, &dataLen, _flags);
break;
case 3 :
NXReadTypes(ts, "*llll*ii",
&subject, &priority, &startDate, &dueDate, &dateCompleted,
&data, &dataLen, _flags);
break;
case 2 :
NXReadTypes(ts, "*lll*ii",
&subject, &priority, &startDate, &dueDate, &data, &dataLen, _flags);
break;
case 1 :
NXReadTypes(ts, "*lll*ic",
&subject, &priority, &startDate, &dueDate, &data, &dataLen, &_flags->type);
break;
case 0 :
NXReadTypes(ts, "*lll*i",
&subject, &priority, &startDate, &dueDate, &data, &dataLen);
break;
}
return self;
}
- write:(NXTypedStream *)ts
{
[super write:ts];
NXWriteTypes(ts, "*llll*iI",
&subject, &priority, &startDate, &dueDate, &dateCompleted,
&data, &dataLen, _flags);
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.