This is IItemHeaderBrowser.m in view mode; [Download] [Up]
/*$Copyright: * Copyright (C) 1992.5.22. Recruit Co.,Ltd. * Institute for Supercomputing Research * All rights reserved. * NewsBase by ISR, Kazuto MIYAI, Gary ARAKAKI, Katsunori SUZUKI, Kok-meng Lue * * You may freely copy, distribute and reuse the code in this program under * following conditions. * - to include this notice in the source code, if it is to be distributed * with source code. * - to add the file named "COPYING" within the code, which shall include * GNU GENERAL PUBLIC LICENSE(*). * - to display an acknowledgement in binary code as follows: "This product * includes software developed by Recruit Co.,Ltd., ISR." * - to display a notice which shall state that the users may freely copy, * distribute and reuse the code in this program under GNU GENERAL PUBLIC * LICENSE(*) * - to indicate the way to access the copy of GNU GENERAL PUBLIC LICENSE(*) * * (*)GNU GENERAL PUBLIC LICENSE is stored in the file named COPYING * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. $*/ #import <appkit/appkit.h> #import <mach/mach_init.h> #import <string.h> #import <defaults/defaults.h> #import <dpsclient/event.h> #import <libc.h> #import "IItemHeaderBrowser.h" #import "INXBrowserCellWithLinkedObject.h" #import "IUifNode.h" #import "IOrderedListD.h" #import "InfoD.h" #import "INewsGroupTreeControl.h" #import "INewsgroupInfoD.h" #import "ITreeNodeD.h" #import "ITreeBrowserMatrix.h" #import "errdebug.h" #import "data_types.h" #import "Localization.h" #define MAX_NO_OF_TOKENS 256 #define MAXVISIBLECOL 2 #define MINCOLWIDTH 160 extern id currentNewsGroup; @implementation IItemHeaderBrowser - initFrame:(NXRect *)frameRect { [super initFrame:frameRect]; [self setMinColumnWidth:MINCOLWIDTH]; [self setMaxVisibleColumns:MAXVISIBLECOL]; [self setAction:@selector(singleClickLeafPreHandler:)]; [self setDoubleAction:@selector(doubleClickLeafPreHandler:)]; [self acceptArrowKeys:YES andSendActionMessages:NO]; return self; } - (BOOL)acceptsFirstResponder { return YES; } - loadColumnZero { // make self first responder when loading column and column has // any cells. if self(browser) has no column, then refuse to get // first responder. data group browser might get first responder. [super loadColumnZero]; if ([[[self matrixInColumn:0] cellList] count] > 0) { [window makeFirstResponder:self]; } return self; } /* The target object and action message of itemheader is IItemHeaderBrowser and articleHandler. I.e., articleHandler is called when a article is selected. */ - (void)singleClickLeafPreHandler:sender { ITreeBrowserMatrix *lastColumnMatrix; int keyFlag; lastColumnMatrix = [self matrixInColumn:[self lastColumn]]; if (((keyFlag=(int)[lastColumnMatrix flagsOfLastEvent]) & NX_COMMANDMASK) && (keyFlag & NX_CONTROLMASK)) { // 'command' + 'control' click // post cancel article if (NXRunAlertPanel(LoStr("NewsBase"), LoStr("Are you sure to cancel the article?"), LoStr("NO"),LoStr("YES"),NULL) == 0) { [lastColumnMatrix resetFlagsOfLastEvent]; [self cancelArticle]; return; } else { /* Cancel is clicked */ return; } } if (strcmp(NXGetDefaultValue(OWNER, ARTICLESELECT),SINGLECLICK)==0) { [self leafPreHandler:sender]; return; } else { // lastColumnMatrix = [self matrixInColumn:[self lastColumn]]; if (keyFlag & NX_CONTROLMASK) { DBG(1,fprintf(stderr,"-- IItemHeaderBrowser:singleClick")); // don't have to reset flags in matrix because "leafPreHander:" // will do it in next statement. [self leafPreHandler:sender]; return; } return; } } - (void)doubleClickLeafPreHandler:sender { if (strcmp(NXGetDefaultValue(OWNER, ARTICLESELECT),DOUBLECLICK)==0) { [self leafPreHandler:sender]; return; } else { return; } } - (void)leafHandler:sender { id selectedCell; id articleItem; id node; [window makeFirstResponder:self]; // set first responder to self selectedCell = [[self matrixInColumn:[self lastColumn]] selectedCell]; if ([selectedCell isLeaf]) { node = [selectedCell node]; if ((articleItem = [iIOmodule itemOf:node])==nil) { return; } /* set no active to cell */ if (([node active]==YES) && ([iIOmodule toggleActive:node]==YES)) { [selectedCell setActive:NO]; [node setActive:NO]; } [[self matrixInColumn:[self lastColumn]] display]; return; } return; } - directoryHandler:node { [window makeFirstResponder:self]; // set first responder to self return [iIOmodule itemHeadersOf:node]; } - keyDown:(NXEvent *)theEvent { unsigned int ch; id selectedCell; DBG(1,fprintf(stderr," keydown")); selectedCell = [[self matrixInColumn:[self selectedColumn]] selectedCell]; if ((ch=(theEvent->data).key.charCode) == NX_CR) { // "Return" key pressed DBG(1,fprintf(stderr," NX_CR")); // click selected cell if ([selectedCell isLeaf] ==YES) { [self leafHandler:self]; } return self; } if (ch == 0x20 || ch == 0x80) { // 0x20 : space // 0x80 : alt+space if ([self selectedColumn] == -1) { // no cell is selected so select first one [[self matrixInColumn:0] selectCellAt:0 :0]; } selectedCell = [[self matrixInColumn:[self selectedColumn]] selectedCell]; if ((theEvent->flags & NX_SHIFTMASK) == NO) { // select next cell if (theEvent->flags & NX_ALTERNATEMASK) { // alternate key is down, select next cell selectedCell = [self selectNextCell:selectedCell]; } else { // start loop for selecting next *active* *leaf* cell do { if ([selectedCell isLeaf] == YES && [[selectedCell node] active] == YES) { break; } selectedCell = [self selectNextCell:selectedCell]; } while (selectedCell != NULL); } } else { // select prev cell DBG(1,fprintf(stderr,"--- space+shift\n")); [self selectPrevCell:selectedCell]; } if (selectedCell != NULL) { if ((theEvent->flags & NX_ALTERNATEMASK)==NO && (theEvent->flags & NX_SHIFTMASK)==NO) { // cell is selected and alt key is not down, click cell [self leafHandler:self]; } return self; } else { // no more cells, so beep return ([super keyDown:theEvent]); } } // handle arrow keys in super class return ([super keyDown:theEvent]); } - selectNextCell:nowselectedCell { return([self _selectCell:nowselectedCell direct:(DirectFlag)FORWARD]); } - selectPrevCell:nowselectedCell { return([self _selectCell:nowselectedCell direct:(DirectFlag)BACKWARD]); } - _selectCell:nowselectedCell direct:(DirectFlag)dflag { unsigned int cellIndex; id selectedColumnMatrix; id rightColumnMatrix, leftColumnMatrix; int trow, tcol; // can not use cellList??? int tcellIndex; // cellList has old information and sometimes it points cell which // is alread deleted selectedColumnMatrix = [self matrixInColumn:[self selectedColumn]]; if ([nowselectedCell isLeaf] == YES) { // no right column cellIndex = [[selectedColumnMatrix cellList] indexOf:nowselectedCell]; [selectedColumnMatrix getNumRows:&trow numCols:&tcol]; // check if selectedCell is bottom(for FORWARD) or top(for BACKWORD) if ((dflag == FORWARD && cellIndex < (trow -1)) || (dflag == BACKWARD && cellIndex != 0)) { // select next cell if (dflag == FORWARD) { tcellIndex = cellIndex + 1; } else { tcellIndex = cellIndex - 1; } [selectedColumnMatrix selectCellAt:tcellIndex :0]; [self scrollToCellAt:tcellIndex matrix:selectedColumnMatrix]; } else { // this cell is bottom or top if ((leftColumnMatrix=[self matrixInColumn: ([self selectedColumn] -1)]) != nil) { // select next cell in left column cellIndex = [[leftColumnMatrix cellList] indexOf:[leftColumnMatrix selectedCell]]; [leftColumnMatrix getNumRows:&trow numCols:&tcol]; if ((dflag == FORWARD && cellIndex < (trow -1)) || (dflag == BACKWARD && cellIndex != 0)) { if (dflag == FORWARD) { tcellIndex = cellIndex + 1; } else { tcellIndex = cellIndex - 1; } [leftColumnMatrix selectCellAt:tcellIndex :0]; [self setLastColumn:0]; [self scrollToCellAt:tcellIndex matrix:leftColumnMatrix]; } else { // left cell is last one [self setLastColumn:0]; return NULL; } } else { // no left column // this cell is really end return NULL; } } } else { // there is right column, but no cell is selected // select first cell in right column [selectedColumnMatrix lockFocus]; [selectedColumnMatrix sendAction]; [selectedColumnMatrix unlockFocus]; rightColumnMatrix=[self matrixInColumn:([self selectedColumn] +1)]; if (dflag == FORWARD) { [rightColumnMatrix selectCellAt:0 :0]; } else { [rightColumnMatrix selectCellAt: ([rightColumnMatrix cellCount]-1) :0]; } } // return id of selectedCell return ([[self matrixInColumn:[self selectedColumn]] selectedCell]); } - scrollToCellAt:(int)row matrix:matrix { NXRect matrixRect, cellRect; id contView; // clipView id scrollView; // scollView of a column for NXBrowser NXRect contRect; NXRect scrollerRect; NXCoord cell_y, cont_y; contView = [matrix superview]; scrollView = [[matrix superview] superview]; [matrix getFrame:&matrixRect]; [matrix getCellFrame:&cellRect at:row :0]; [contView getFrame:&contRect]; cell_y = cellRect.origin.y + cellRect.size.height; cont_y = contRect.size.height - cellRect.size.height * 3; // 3 cells are always shown after cell in (int)row if (cont_y < cell_y) { contRect.origin.y = cell_y - cont_y; } [[scrollView vertScroller] getFrame:&scrollerRect]; contRect.origin.x = 0.0; [contView rawScroll:&(contRect.origin)]; [scrollView reflectScroll:contView]; return (self); } - cancelArticle { id selectedCell; id node; id header; const char *messageID; char *fromValue; char buf[256], *user_name; char *mailAddress; selectedCell = [[self matrixInColumn:[self lastColumn]] selectedCell]; node = [selectedCell node]; if ((header=[[node linkedData] dataForKey:HEADER_INFO]) == nil) { return (nil); } if ((fromValue=(char *)[header infoForKey:FROM]) == NULL) { return (nil); } // check authentication sscanf(fromValue, "%256[^@]", buf); DBG(1,fprintf(stderr," buf = %s\n", buf)); if ((user_name=getenv("USER")) == NULL) { return (nil); } if (strcmp(user_name,buf)!=0) { NXRunAlertPanel(LoStr("NewsBase"),LoStr("From: field value not matched. Can not cancel"),NULL,NULL,NULL); return (nil); } if ((messageID = (const char *)[header infoForKey:MESSAGE_ID]) == NULL) { return (nil); } if (NXGetDefaultValue(OWNER,FROM) != NULL) { mailAddress = NXCopyStringBuffer(NXGetDefaultValue(OWNER,FROM)); } else { // set default value mailAddress = [self getMailAddress]; } [iIOmodule cancelArticleMessageID:messageID from:mailAddress]; free(mailAddress); return self; } - (char *)getMailAddress { char *mail_address; char *user_name, machine_name[256], domain_name[257]; user_name = NXCopyStringBufferFromZone(getenv("USER"),[self zone]); gethostname(machine_name,sizeof(machine_name)); getdomainname(domain_name + 1, sizeof(domain_name) - 1); domain_name[sizeof(domain_name) - 1] = '\0'; if (domain_name[1] != '\0') { domain_name[0] = '.'; } else { domain_name[0] = '\0'; } mail_address = (char *)NXZoneMalloc([self zone], strlen(user_name)+strlen(machine_name)+strlen(domain_name)+3); (void)sprintf(mail_address,"%s@%s%s",user_name,machine_name, domain_name); return mail_address; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.