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.