This is DecoderController.m in view mode; [Download] [Up]
#import <appkit/appkit.h>
#import <misckit/MiscSortedList.h>
#import <misckit/MiscAppDefaults.h>
#import "../Preferences.subproj/preferences.h"
#import "decode.h"
#import "NiftyMatrix.h"
#import "DecodeCell.h"
#import "NNTP.h"
#import "MainWindowControl.h"
#import "ArticleSetMatrix.h"
#import "ArticleSet.h"
#import "Article.h"
#import "MatrixScroller.h"
#import "DecoderController.h"
#import "descriptors.h"
@implementation DecoderController : Object
- (void) doDecoding:sender
// Sender is the MainWindowControl. This is activated after the user
// chooses Tools->UUdecode from the menu.
{
int articlesSelected;
// Keep the main window control around cause we'll need it.
mainWindowControl = sender;
articlesSelected = [[mainWindowControl articleSet] numSelCells];
// If multiple articles are selected then we have to do the
// modal panel.
setDecodeDepositPathname([NXApp defaultValue:DEFAULT_SAVE_PATH]);
if (articlesSelected > 1) {
[self showDecodePanel:self];
}
else
// If only a single article is selected then we can grab
// the text from the text object.
if (articlesSelected == 1) {
Text *articleText = [sender articleText];
NXStream *textStream;
int status;
textStream = [articleText stream];
NXSeek(textStream,0,NX_FROMSTART);
uud_start();
status = uudecode(textStream);
if (status == -1) {
NXRunAlertPanel("UUdecode Error",
"Could not decode the selected article.", "OK", NULL, NULL);
}
else
if (status == 0 && uudecode_state() == SKIP_LEADING) {
NXRunAlertPanel("UUdecode Error",
"Could not find the end of article.", "OK", NULL, NULL);
}
decode_end();
}
}
- (void) uudecodeMultipleArticles
// Begin the uudecoding.
{
DecodeCell * selectedArticleCell;
int selectedArticleCount;
int i;
[decodeAndAbortButton setEnabled:NO];
continueDecoding = YES;
// Start with the first cell that isn't decoded. Usually that's the first
// one, but if the user clicks the "Abort" button and then decides to
// continue...
// currentDecodeIndex = 0;
selectedArticleCount = [selectedArticleMatrix cellCount];
for (i=0; i<selectedArticleCount; i++) {
selectedArticleCell = [selectedArticleMatrix cellAt:i :0];
if ([selectedArticleCell decodeStatus] == NOT_DECODED) {
break;
}
}
currentDecodeIndex = i;
// This starts the chain of decoding. If there are more articles
// and the abort button is not clicked then they will get done in turn.
if (currentDecodeIndex < selectedArticleCount) {
uud_start();
[self uudecodeArticle:[[selectedArticleMatrix cellAt:
currentDecodeIndex :0] articleIndex]];
}
}
- (void) uudecodeArticle:(int)articleIndex
// This method uudecodes the given article (the articleIndex is it's place in
// the articleMatrix in the main window), then primes (delay performs) the next
// not yet decoded article if the abort button hasn't been clicked.
// This is just so you have something like multithreading without actually
// having to write it.
{
// Has the abort button been clicked?
if (continueDecoding) {
id nntpServer = [mainWindowControl nntpServer];
Article * article;
char * body;
int selectedArticleCount;
// Get and load the article.
article = [[mainWindowControl articleMatrix] cellAt:articleIndex :0];
[nntpServer loadArticleBody:article toString:&body];
if (body) {
// It's probably not the most efficient thing to put the article
// in a stream, but that's how the uudecode function now expects
// it.
NXStream * articleStream = NXOpenMemory(body, strlen(body),
NX_READONLY);
DecodeCell * currentCell;
int currentStatus;
int px,py;
currentStatus = uudecode(articleStream);
NXCloseMemory(articleStream, NX_FREEBUFFER);
// Should it only be setRead if it's successful? For now as you
// can see it marks it read regardless.
//[article setRead];
// Set the image in the cell to show success or failure.
currentCell = [selectedArticleMatrix cellAt:currentDecodeIndex :0];
[currentCell setDecodeStatus:(currentStatus == 0) ?
DECODE_SUCCESSFUL : DECODE_FAILED];
[selectedArticleMatrix getRow:&px andCol:&py ofCell:currentCell];
[selectedArticleMatrix drawCellAt:px :py];
[selectedArticleMatrix scrollCellToVisible:px upperOffset:1.5 lowerOffset:1.5];
//stop if error
if(currentStatus){
decode_end();
return;
}
}
// Set the next cell for uudecoding if there are any more.
selectedArticleCount = [selectedArticleMatrix cellCount];
currentDecodeIndex++;
if (currentDecodeIndex < selectedArticleCount) {
DecodeCell * nextCell;
nextCell = [selectedArticleMatrix cellAt:currentDecodeIndex :0];
// This is probably bad (passing an int to the with argument).
[self perform:_cmd with:(void*)[nextCell articleIndex]
afterDelay:0.0 cancelPrevious:NO];
}
// We are done decoding so set the button back to say "Decode".
else {
//[decodeAndAbortButton setState:0];
continueDecoding = NO;
decode_end();
[panel close];
[(ArticleSet *)mainWindowControl markRead:self];
[NXApp abortModal];
}
}
}
- (void) showDecodePanel:sender
{
if (panel == nil) {
[NXApp loadNibSection:"ModalDecodingPanel.nib" owner:self];
[self setupDecodePanel];
}
[decodeAndAbortButton setState:0];
[decodeAndAbortButton setEnabled:YES];
[self loadMatrixWithArticles];
[panel orderFront:self];
[NXApp runModalFor:panel];
}
- (void) setupDecodePanel
// This is called only the first time the nib is loaded so we can swap
// the matrix with a nifty matrix.
{
NiftyMatrix * niftyMatrix;
ScrollView * scrollView = [[selectedArticleMatrix superview] superview];
NXRect scrollBoundsRect;
NXSize interCellSpacing;
NXSize cellSize;
// Determine the Matrix bounds.
[scrollView getBounds:&scrollBoundsRect];
// Prepare a NiftyMatrix to go inside the ScrollView.
niftyMatrix = [[NiftyMatrix alloc] initFrame:&scrollBoundsRect
mode:NX_RADIOMODE cellClass:[DecodeCell class]
numRows:5 numCols:1];
// Eliminate intercell spacing.
interCellSpacing.height = 0.0;
interCellSpacing.width = 0.0;
[niftyMatrix setIntercell:&interCellSpacing];
// Set the Cell size to the width of the ScrollView's bounds rect.
[niftyMatrix getCellSize:&cellSize];
cellSize.width = NX_WIDTH (&scrollBoundsRect);
[niftyMatrix setCellSize:&cellSize];
[niftyMatrix sizeToCells];
// Set NiftyMatrix sizing parameters.
[niftyMatrix setAutosizeCells:YES];
[[niftyMatrix superview] setAutoresizeSubviews:YES];
[niftyMatrix setAutosizing:NX_WIDTHSIZABLE];
// Scroll when the user clicks in the EnhancedNiftyMatrix and then
// drags the mouse out of contentView.
[niftyMatrix setAutoscroll:YES];
// Stick the matrix in the ScrollView.
[scrollView setDocView:niftyMatrix];
[niftyMatrix display];
[selectedArticleMatrix free];
selectedArticleMatrix = niftyMatrix;
}
- (void) loadMatrixWithArticles
// Loads the nifty matrix with the selected cells from the article matrix.
// We also sort them so that multipart pics will probably be in the correct
// order.
{
List * articleList = [[mainWindowControl articleMatrix] cellList];
MiscSortedList * sortedArticleList = [[MiscSortedList alloc] init];
Article * articleCell;
DecodeCell * sortedArticleCell;
int i;
int sortedArticleCount;
int oldSortType=[Article sortType];
// Get the selected articles and sort them.
[sortedArticleList setSortEnabled:NO];
sortedArticleList = [[mainWindowControl articleMatrix]
getSelectedCells:sortedArticleList];
[Article setSortType:SORT_BY_SUBJECT];
[sortedArticleList sort];
[Article setSortType:oldSortType];
// Resize our matrix so it will hold the new selected cells.
sortedArticleCount = [sortedArticleList count];
[selectedArticleMatrix renewRows:sortedArticleCount cols:1];
// Fill the matrix.
for (i=0; i<sortedArticleCount; i++) {
sortedArticleCell = [selectedArticleMatrix cellAt:i :0];
articleCell = [sortedArticleList objectAt:i];
// The article index is the index of the article in the articleMatrix.
[sortedArticleCell setArticleIndex:[articleList indexOf:articleCell]];
[sortedArticleCell setStringValue:
[articleCell header]->fieldBody[SUBJECT]];
// Since we might be reusing cells we should set this explicitly.
[sortedArticleCell setDecodeStatus:NOT_DECODED];
}
// Scroll to the top and redisplay.
// [[selectedArticleMatrix window] disableFlushWindow];
[selectedArticleMatrix scrollCellToVisible:0 :0];
[selectedArticleMatrix sizeToCells];
[selectedArticleMatrix display];
// [[selectedArticleMatrix window] reenableFlushWindow];
// [[selectedArticleMatrix window] flushWindow];
// Set our counter to display the number of selected articles.
[numArticlesTF setIntValue:[selectedArticleMatrix cellCount]];
}
- decodeOrAbortButtonClicked:sender
// The sender is the "Decode" or "Abort" button (the same button with
// a title and alt-title).
{
// The "Decode" button was clicked.
if ([sender state] == 1) {
[self uudecodeMultipleArticles];
}
// The "Abort" button was clicked.
else {
continueDecoding = NO;
}
return self;
}
- cancelModalPanel:sender
// The cancel button was clicked
{
continueDecoding = NO;
decode_end();
[NXApp stopModal];
[panel close];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.