This is CharController.m in view mode; [Download] [Up]
/***********************************************************************
Controller class for Convert TEXT which converts between Mac and NeXT text.
Copyright (C) 1993 David John Burrowes
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author, David John Burrowes, can be reached at:
davidjohn@kira.net.netcom.com
David John Burrowes
1926 Ivy #10
San Mateo, CA 94403-1367
***********************************************************************/
#import "CharController.h"
#import "NeXTToMacText.h"
#import "MacToNeXTText.h"
#import "CRLFToNeXTText.h"
#import "NeXTToCRLFText.h"
#import "File.h"
#import <appkit/Cell.h>
#import <appkit/Matrix.h>
@implementation CharController
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Routine: init
// Parameters: none
// Returns: self
// Stores: none
// Description:
// This overrides the defalut init method. But it does little else.
// Other initializations done in AppDidInit, above...
// Note that subclasses should OVERRIDE this
// Bugs:
// History:
// 93.07.05 djb Reworked conversion preferences. Used tobe a boolean for yes or no
// to indicate mac vs. next source conversion. Now use a string to
// indicate what kinda conversion should be default. Non-intuitively,
// I've decided to leave the default name the same (DoMacConversio)
// and let it keep the old yes/no, as well as newer MacToNeXT, etc
// options. Icky, but provides some upward compat.. HOWEVER.
// This has taught me, I think, the lesson that: defaults names should
// be a bit general, and it's better if their options are meaningful rather
// than booleans. Both allow later changes without breaking things like
// this.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- init
{
//
// Get all the default values from the database
//
static NXDefaultsVector theDefaults =
{
{"UseCurlyQuotes", "NO"},
{"UseIMv1", "NO"},
{"DoMacConversion", "MacToNeXT"},
{NULL, NULL}
};
CString tempPreference;
[super init];
//
// Set up strings for the interface.
//
ConversionString = "Converting text files";
SourcePrompt = "Source file:";
DestPrompt = "Dest file:";
DestExtension = "";
DefaultsOwner = "MacToNeXTText";
NXRegisterDefaults(DefaultsOwner, theDefaults);
//
// Note that we completely ignore the old DoMacConversion preference.
// We neither read nor remove it.
//
UseCurlyQuotes = [self GetBoolPref: "UseCurlyQuotes"];
UseIMv1 = [self GetBoolPref: "UseIMv1"];
tempPreference = [self GetPref: "DoMacConversion"];
//
// New for 1.1. Get a more detailed conversion type from the defaults database,
// and set our new ConversionType flag appropriately.
//
if ((strcmp(tempPreference, "MacToNeXT") == 0) ||
(strcmp(tempPreference, "YES") == 0) )
DefaultConversion = MacToNeXT;
else if ((strcmp(tempPreference, "NeXTToMac") == 0) ||
(strcmp(tempPreference, "NO") == 0) )
DefaultConversion = NeXTToMac;
else if (strcmp(tempPreference, "CRLFToNeXT") == 0)
DefaultConversion = CRLFToNeXT;
else if (strcmp(tempPreference, "NeXTToCRLF") == 0)
DefaultConversion = NeXTToCRLF;
//
// Since we are pretending to be a converter as well as controller, define our manager
// And, then set ourselves up to recieve the messages we sent to a converter!
//
myManager = NullInstance;
converterInst = self;
//
// Set up default converter.
//
theConverter = NullInstance;
CurrentConversion = DefaultConversion;
return self;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Routine: displayPreferences:
// Parameters: the object that called us
// Returns: self
// Stores: none
// Description:
// This is called whenever we need to bring the preferences panel onto the screen.
// Using the value in our internal preference variables, then we set the buttons
// in the preference panel to reflect these, and then we show the panel.
// History:
// 93.07.05 djb Modified for 1.1's more complex default conversion choices.
// Bugs:
// Well, strictly speaking, this is only needed the first time this is called,
// because thereafter the buttons maintain their own highlite properly.
// Oh well. This whole scheme is a bit awkward, given my trivial use, and the fact
// that it really seems to be designed for bigger things.
// This doesn't set any ResultObject fields. =(
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-displayPreferences: sender
{
//
// Get the default preference values, and compare judge what buttons to
// highlight for the user.
//
if (UseIMv1 == YES)
[UseIMv1Button setIntValue: 1];
else
[UseIMv1Button setIntValue: 0];
if (UseCurlyQuotes == YES)
[UseCurlyQuotesButton setIntValue: 1];
else
[UseCurlyQuotesButton setIntValue: 0];
switch (DefaultConversion)
{
case MacToNeXT:
[DefaultConversionButton selectCellWithTag: MacToNeXT];
break;
case NeXTToMac:
[DefaultConversionButton selectCellWithTag: NeXTToMac];
break;
case CRLFToNeXT:
[DefaultConversionButton selectCellWithTag: CRLFToNeXT];
break;
case NeXTToCRLF:
[DefaultConversionButton selectCellWithTag: NeXTToCRLF];
break;
}
[prefPanel makeKeyAndOrderFront:self];
//
return self;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Routine: SetIMV1:
// Parameters: the object that called us
// Returns: self
// Stores: nothing!
// Description:
// This method gets called whenever the user clicks on a button to change
// the setting of whether we should use IMv1 when converting Mac files.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- SetIMV1: sender
{
if ( [sender intValue] == 1)
UseIMv1 = YES;
else
UseIMv1 = NO;
[self SetBoolPref: "UseIMv1" To: UseIMv1];
return self;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Routine: SetUseCurlyQuotes:
// Parameters: the object that called us
// Returns: self
// Stores: nothing!
// Description:
// This method gets called whenever the user clicks on a button to change
// the setting of whether we should convert to curly quotes when converting NeXT files.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-SetUseCurlyQuotes: sender
{
if ( [sender intValue] == 1)
UseCurlyQuotes = YES;
else
UseCurlyQuotes = NO;
[self SetBoolPref: "UseCurlyQuotes" To: UseCurlyQuotes];
return self;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Routine: SetDefaultConversion:
// Parameters: the object that called us
// Returns: self
// Stores: nothing!
// Description:
// This method gets called whenever the user clicks on a button to change
// the setting of whether we should assume files to be converted are Mac ones or not.
// History:
// 93.07.05 djb Modified for 1.1's richer conversion options. NOTE: This
// makes some assumptions that the sender's value will always be
// one of it's conversionvalues.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-SetDefaultConversion: sender
{
DefaultConversion = [[sender selectedCell] tag] ;
switch ( DefaultConversion )
{
case MacToNeXT:
[self SetPref: "DoMacConversion" To: "MacToNeXT"];
break;
case NeXTToMac:
[self SetPref: "DoMacConversion" To: "NeXTToMac"];
break;
case CRLFToNeXT:
[self SetPref: "DoMacConversion" To: "CRLFToNeXT"];
break;
case NeXTToCRLF:
[self SetPref: "DoMacConversion" To: "NeXTToCRLF"];
break;
}
CurrentConversion = DefaultConversion;
return self;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Method: PrepareToConvertMac
// Parameters: the object that send this message
// Returns: self
// Stores: nothing
// Description:
// Sets the flag for the kind of conversion to do (not a mac one), and convert a file.
// Bugs:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- PrepareToConvertMac:sender
{
CurrentConversion = MacToNeXT;
[self PrepareForConversion: self];
return self;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Method: PrepareToConvertNeXT
// Parameters: the object that send this message
// Returns: self
// Stores: nothing
// Description:
// Sets the flag for the kind of conversion to do (not a mac one), and convert a file.
// Bugs:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- PrepareToConvertNeXT:sender
{
CurrentConversion = NeXTToMac;
[self PrepareForConversion: self];
return self;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Method: PrepareToConvertCRLF
// Parameters: the object that send this message
// Returns: self
// Stores: nothing
// Description:
// Sets the flag for the kind of conversion to do (CRLF to NeXT) and does the
// conversion. We set the CurrentConversion flag here to override the default
// value it would have..
// Bugs:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- PrepareToConvertCRLF:sender
{
CurrentConversion = CRLFToNeXT;
[self PrepareForConversion: self];
return self;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Method: PrepareToConvertNeXTToCRLF
// Parameters: the object that send this message
// Returns: self
// Stores: nothing
// Description:
// Sets the flag for the kind of conversion to do (NeXT to CRLF) and does the
// conversion. We set the CurrentConversion flag here to override the default
// value it would have..
// Bugs:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- PrepareToConvertNeXTToCRLF:sender
{
CurrentConversion = CRLFToNeXT;
[self PrepareForConversion: self];
return self;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Method: ReportTo:
// Parameters: The caller
// Returns: none
// Stores: none
// Description:
// ConvertController's use this to tell the converter what object to report status
// to. That is, we must tell sender when we are, for example, 50% of the way
// done so it can let the user know what's going on. Subclasses should have no
// need of subclassing this. It will always be set up before a call to the main
// conversion routine.
// Bugs:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ReportTo: sender
{
myManager = sender;
return self;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Method: isThisAGoodFile:
// Parameters: A File instance
// Returns: YES if it is, NO if it isn't.
// Stores: none
// Description:
// A converter, in addition to converting a file X to a file Y, should be able to
// identify when a source file is a legitimate file for conversion. In the case of
// this abstract class, this method does nothing. A subclass, however, will
// subclass this method and have it examine the specified file, and determine
// if it's a legit file or not. It returns YES if the file is good, or NO if the file is
// questionable or bad.
// Bugs:
// We need to use the proposed Fact datatype here, instead of Boolean.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (Boolean) isThisAGoodFile: Instance
{
return YES;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Routine: ConvertFrom:To:
// Parameters: The file to be converted from, and the file to be converted to
// Returns: self
// Stores: error code
// Description:
// This uses the object stored in this object's instance variable theConverter
// to convert the contents of the source file to a new form, and writes them out
// into the destination file. Note that this assumes that the converter is a subclass
// of textConverter. Basiclally, loop until we find the eof, readin 512 byte chunks,
// converting, and writing out. In the last time through, we find Eof, and
// write out what we read in that was just before this eof, then quit when we
// loop around.
// History:
// 93.07.05 djb Modified for the now 4 types of conversions, rather than the older 2.
// Bugs
// We ignore errors that the file access might generate.
// (if we don't read 512 bytes, and we don't find eof, then we have an error.
// but we don't check for it either )
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ConvertFrom: sourceFile To: destinationFile
{
Pointer sourceBuffer = NewPointer(512);
Pointer destinationBuffer;
PositiveInteger numWritten,
bytesRead = 512;
Boolean eofFound = NO;
Real modifier = 100.0 / [sourceFile FileSize];
[super ConvertFrom: sourceFile To: destinationFile];
[MacConvertCommand setEnabled: NO];
[NextConvertCommand setEnabled: NO];
[CRLFConvertCommand setEnabled: NO];
[NeXT2CRLFConvertCommand setEnabled: NO];
[ConvertCommands setEnabled: NO];
//
// Kill any converter waiting around, then set up the proper one for this conversion.
//
if (theConverter != NullInstance)
[theConverter free];
switch ( CurrentConversion )
{
case MacToNeXT:
theConverter = [ [MacToNeXTText alloc] init ];
[theConverter UseIM1: UseIMv1];
ConversionString = "Converting Macintosh text to NeXT text";
break;
case NeXTToMac:
theConverter = [[NeXTToMacText alloc] init];
[theConverter ConvertSingleQuotes: UseCurlyQuotes];
ConversionString = "Converting NeXT text to Macintosh text";
break;
case CRLFToNeXT:
theConverter = [ [CRLFToNeXTText alloc] init ];
ConversionString = "Converting CRLF text to NeXT text";
break;
case NeXTToCRLF:
theConverter = [ [NeXTToCRLFText alloc] init ];
ConversionString = "Converting NeXT text to CRLF text";
break;
}
//
// With the converter set up, set the flag so it will do the default conversion
// (stored in DoMacConversion) next time if none other is specified.
// (that is, if someone drags a file onto our window, do the default conversion,
// and not the one we are actually about to do).
//
CurrentConversion = DefaultConversion;
[super ConvertFrom: sourceFile To: destinationFile];
while ((eofFound != YES) && (bytesRead == 512))
{
[sourceFile Read: 512 BytesInto: sourceBuffer];
bytesRead = [sourceFile GetPositiveInteger];
eofFound = [sourceFile GetBooleanFrom: SECOND_RESULT];
//
// If eof was found, then this is our last pass through the converter.
//
[theConverter ConvertString: sourceBuffer WithLength: bytesRead];
destinationBuffer = [theConverter GetPointer];
numWritten = [theConverter GetPositiveIntegerFrom: SECOND_RESULT];
[destinationFile Write: numWritten BytesFrom: destinationBuffer];
[myManager SetPercentageDone: modifier * [sourceFile GetCurrentPosition]];
}
[MacConvertCommand setEnabled: YES];
[NextConvertCommand setEnabled: YES];
[CRLFConvertCommand setEnabled: YES];
[NeXT2CRLFConvertCommand setEnabled: YES];
[ConvertCommands setEnabled: YES];
//
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.