/* Copyright (c) 2017, Computer History Museum All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "filtwin.h" /************************************************************************ * Filters window - Copyright (C) 1994 QUALCOMM Incorporated ************************************************************************/ #define FILE_NUM 67 #ifdef TWO #pragma segment FilterWin #define MIN_ACTION_WI (35*Win->hPitch) #define MIN_MATCH_HI (13*Win->vPitch) #define MAX_MATCH_HI (15*Win->vPitch) #define MIN_ACTION_HI (GROW_SIZE + 3*INSET + 5*MIN_ACT1_HI) #define MIN_ACT1_HI (24) #define MAX_ACT1_HI (3*Win->vPitch) #define MAX_MATCHPOP_WI (25*Win->hPitch) #define BUTTON_REASONABLE (24*Win->hPitch) #define POP_V_ADJUST (-3) #define POP_H_ADJUST INSET #define FILT_DRAG_DATA_TYPE 'Eufl' /************************************************************************ * Filter globals ************************************************************************/ typedef enum { flNewButton=0, flRemoveButton, flIncoming, flOutgoing, flManual, flMatchOnePop, flMatchTwoPop, flConjunction, flAct1, flAct2, flAct3, flAct4, flAct5, flAccel1, flAccel2, flNickFilePop1, flNickFilePop2, flActionGroup, flMatchGroup, flLimit } FilterControlEnum; #define fl1stLimit flAct1 #define fl2ndLimit flActionGroup typedef enum { flrVBar, flrAccel1, flrAccel2, flrMatch, flrAction, flrList, flrMatch1, flrMatch2, flrAct1, flrAct2, flrAct3, flrAct4, flrAct5, flrDate, flrVal1, flrVal2, flrLimit } FilterRectEnum; typedef struct { PETEHandle headerPTE; PETEHandle valuePTE; Point labelPoint; } MatchBlock, *MBlockPtr, **MBlockHandle; typedef struct { ControlHandle controls[flLimit]; Rect rects[flrLimit]; short actSpace; short actHi; MatchBlock blocks[2]; short selected; MyWindowPtr win; ListHandle lHand; Boolean multiple; Boolean hasTwo; Boolean currentDirty; RgnHandle actRgn; MenuHandle actionMenu; DragReference oldDrag; Boolean dragInteresting; Boolean dragFromMe; } FilterGlobalRec; FilterGlobalRec **FLG; #define DragInteresting (*FLG)->dragInteresting #define DragFromMe (*FLG)->dragFromMe #define OldDrag (*FLG)->oldDrag #define Controls (*FLG)->controls #define Rects (*FLG)->rects #define Blocks (*FLG)->blocks #define ActSpace (*FLG)->actSpace #define ActHi (*FLG)->actHi #define Selected (*FLG)->selected #define Win (*FLG)->win #define LHand (*FLG)->lHand #define Points (*FLG)->points #define Multiple (*FLG)->multiple #define CurrentDirty (*FLG)->currentDirty #define CurrentLabel (*FLG)->currentLabel #define RemoveButton Controls[flRemoveButton] #define NewButton Controls[flNewButton] #define MatchGroup Controls[flMatchGroup] #define ActionGroup Controls[flActionGroup] #define Block0 (*FLG)->blocks[0] #define Block1 (*FLG)->blocks[1] #define HasTwo (*FLG)->hasTwo #define ActRgn (*FLG)->actRgn #define ActionMenu (*FLG)->actionMenu #define STEList Win->steList /********************************************************************** * Prototypes **********************************************************************/ void FilterHelp(MyWindowPtr win,Point mouse); OSErr FiltDragHandler(MyWindowPtr win,DragTrackingMessage which,DragReference drag); void FilterClick(MyWindowPtr win, EventRecord *event); short FilterListWidth(short total); short FilterMatchHeight(short total); void FilterDidResize(MyWindowPtr win, Rect *oldContR); short MatchBlockHeight(short total); void FiltersSetGreys(void); Boolean FiltersClose(MyWindowPtr win); OSErr FillFilters(short startingFrom); void FiltersUpdate(MyWindowPtr win); void SetFASpacings(short total); void FAPopup(Rect *r); void FAPopupValueFit(Rect *r,ControlHandle popup); void AccelPopUp(PETEHandle pte,ControlHandle verbCntl,short top,short left); void ActOnFilterSelect(void); void DisplaySelectedFilter(void); void InvalMatch2(void); void FActionPopUp(Point pt,ControlHandle cntl); void AdjustActionMenu (MenuHandle theMenu); void NewAction(short n,FActionHandle fa,FilterKeywordEnum action); void FASingleRect(Rect *inRect, Rect *r,short hi); void FilterButton(MyWindowPtr win,ControlHandle button,long modifiers,short part); void FilterSwap(short i, short j); void RemoveFilter(short which); void AddFilter(short n); Boolean FilterActionButton(ControlHandle button,short modifiers); void FilterSelect(short which); void FilterTextChanged(MyWindowPtr win, TEHandle teh, short oldNl, short newNl, Boolean scroll); OSErr FiltSetAndShowNickPop(FilterControlEnum pop,PStr value,Rect *r); void InvalAct(short i); short ActOf(FActionHandle fa); Boolean FilterKey(MyWindowPtr win, EventRecord *event); void FilterActivate(MyWindowPtr win); Boolean FilterMenu(MyWindowPtr win, int menu, int item, short modifiers); Boolean FilterApp1(MyWindowPtr win,EventRecord *event); Boolean AppearInFilter(PStr what,short which,Boolean caseSens); Boolean AppearInTerm(PStr what,MTPtr term); void FAMultRect(Rect *inRect, Rect *r,short *spacing,short hi,short n); Boolean AppearInActions(PStr what,FActionHandle fa); Boolean AppearInAction(PStr what,FActionHandle fa); void FiltDragDivider(Point where); void FilterCursor(Point mouse); OSErr PrintFilters(Boolean selected,Boolean now); void FiltRedoList(short startSel,short nSel); OSErr FiltDrop(short stice,DragReference drag); OSErr FiltDropFile(short stice,DragReference drag); OSErr MoveSelectedFilters(short stice); #ifdef DEBUG #ifdef GRIDLINES void ControlGridlines(ControlHandle cntl); #endif #endif FActionProc FAflkNone, FAflkPrint, FAflkStop, FAflkCopy, FAflkSubject, FAflkLabel, FAflkSound, FAflkOpenMessage, FAflkOpenMailbox, FAflkPriority, FAflkForward, FAflkRedirect, FAflkReply, FAflkNotifyApp, FAflkNotifyUser, FAflkServerOpts, FAflkTransfer, FAflkAttachments, FAflkTranslit, FAflkStatus, FAflkPersonality,FAflkJunk, //#ifdef SPEECH_ENABLED FAflkSpeak, //#endif FAflkAddHistory, FAflkMoveAttach; OSErr PrintAFilter(short i, Rect *uRect, short *v, short *page,PMPrintContext printContext); short FiltPrintLines(short which,Rect *uRect); void FiltPrintTerm(MTPtr term); void FAPopActRect(Rect *inRect, Rect *r); OSErr FiltDoDrag(EventRecord *event); void FiltClickHook(short cell,ListHandle lHand); void RemoveSelectedFilters(void); void RemoveFilterLo(short which); void DrawFilterDate(void); #ifdef GX_PRINTING OSErr GXPrintFilters(Boolean selected, Boolean now); OSErr GXPrintAFilter(CGrafPtr GXPortPtr, short i, Rect *uRect, gxRectangle *GXuRect, short *v, short *page, long firstPage, long numPages); short FilterToPrintFirst(long firstPage, Rect *uRect); #endif //GX_PRINTING short SelectFiltersBasedOnWindow(WindowPtr winWP); Boolean FilterFind(MyWindowPtr win,PStr what); pascal OSErr FilterChanged(PETEHandle pte,long start,long stop); pascal OSErr FiltDragSend(FlavorType flavor, void *dragSendRefCon, ItemReference theItemRef, DragReference drag); void FiltDragFilename(PStr name); void FiltEnableVerb(ControlHandle popUpCntl,PStr head); void FiltEnableVerbAll(void); Boolean FilterScrollWheel(MyWindowPtr win,Point pt,short h,short v); /********************************************************************** * FilterChanged - set the dirty bit on the window when an edit region changes **********************************************************************/ pascal OSErr FilterChanged(PETEHandle pte,long start,long stop) { #pragma unused(pte,start,stop) CurrentDirty = True; return noErr; } /************************************************************************ * OpenFiltersWindow - open the window ************************************************************************/ OSErr OpenFiltersWindow(void) { WindowPtr winWP=nil; short err = noErr; void *grumble; MyWindowPtr win=nil; Rect r; Point cSize; Rect bounds; short i; Str255 not; DECLARE_UPP(FiltListDef,ListDef); INIT_UPP(FiltListDef,ListDef); CycleBalls(); NotifyHelpers(0,eFilterWin,nil); if (PrefIsSet(PREF_MA)) return(noErr); /* * open already? */ if (SelectOpenWazoo(FILT_WIN)) ; else if (FLG) UserSelectWindow(GetMyWindowWindowPtr(Win)); else { /* * allocate space */ if (!(FLG = NewZH(FilterGlobalRec))) {WarnUser(MEM_ERR,err=MemError()); goto fail;} /* * make the window */ if (!(win=GetNewMyWindow(FILT_WIND,nil,nil,BehindModal,False,False,FILT_WIN))) { WarnUser(MEM_ERR,err=MemError()); goto fail; } Win = win; winWP = GetMyWindowWindowPtr(win); ConfigFontSetup(Win); //MySetThemeWindowBackground(win,kThemeListViewBackgroundBrush,False); /* * regenerate the list of filters */ if (err=RegenerateFilters()) goto fail; /* * and all the controls */ for (i=0;iframe = True; (*PeteExtra(grumble))->infinitelyWide = True; Block0.headerPTE = grumble; PETESetCallback(PETE,Block0.headerPTE,(void*)FilterChanged,peDocChanged); BMD(not,(*PeteExtra(Block0.headerPTE))->not,sizeof(not)); /* value 1 */ if (err = PeteCreate(Win,&grumble,0,nil)) {WarnUser(MEM_ERR,err); goto fail;} PeteFontAndSize(grumble,GetPortTextFont(GetQDGlobalsThePort()),GetPortTextSize(GetQDGlobalsThePort())); (*PeteExtra(grumble))->frame = True; (*PeteExtra(grumble))->infinitelyWide = True; Block0.valuePTE = grumble; PETESetCallback(PETE,Block0.valuePTE,(void*)FilterChanged,peDocChanged); /* header 2 */ if (err = PeteCreate(Win,&grumble,0,nil)) {WarnUser(MEM_ERR,err); goto fail;} (*PeteExtra(grumble))->frame = True; (*PeteExtra(grumble))->infinitelyWide = True; PeteFontAndSize(grumble,GetPortTextFont(GetQDGlobalsThePort()),GetPortTextSize(GetQDGlobalsThePort())); Block1.headerPTE = grumble; PETESetCallback(PETE,Block1.headerPTE,(void*)FilterChanged,peDocChanged); /* value 2 */ if (err = PeteCreate(Win,&grumble,0,nil)) {WarnUser(MEM_ERR,err); goto fail;} PeteFontAndSize(grumble,GetPortTextFont(GetQDGlobalsThePort()),GetPortTextSize(GetQDGlobalsThePort())); (*PeteExtra(grumble))->frame = True; (*PeteExtra(grumble))->infinitelyWide = True; Block1.valuePTE = grumble; PETESetCallback(PETE,Block1.valuePTE,(void*)FilterChanged,peDocChanged); /* * list handle */ SetRect(&bounds,0,0,1,0); cSize.h = cSize.v = 1; #ifdef FANCY_FILT_LDEF grumble = (void *)CreateNewList(FiltListDefUPP,FILT_LDEF,&r,&bounds,cSize,winWP,True,False,False,True); #else grumble = (void *)LNew(&r,&bounds,cSize,nil,winWP,True,False,False,True); #endif if (!grumble) {WarnUser(MEM_ERR,err=MemError()); goto fail;} LHand = (ListHandle)grumble; (*LHand)->indent.h = INSET; //(*LHand)->selFlags = lOnlyOne; /* * install handlers */ Win->help = FilterHelp; Win->cursor = FilterCursor; Win->activate = FilterActivate; Win->app1 = FilterApp1; Win->menu = FilterMenu; Win->key = FilterKey; Win->textChanged = FilterTextChanged; Win->button = FilterButton; Win->click = FilterClick; Win->close = FiltersClose; Win->position = PositionPrefsTitle; Win->update = FiltersUpdate; Win->didResize = FilterDidResize; Win->dontControl = True; Win->drag = FiltDragHandler; Win->find = FilterFind; Win->scrollWheel = FilterScrollWheel; Win->userSave = true; FiltersSetGreys(); grumble = (Handle)NewRgn(); if (!grumble) {err=WarnUser(MEM_ERR,MemError()); goto fail;} ActRgn = (RgnHandle)grumble; grumble = (Handle)GetMenu(FLA_HI_MENU); if (!grumble) {err=WarnUser(MEM_ERR,MemError()); goto fail;} ActionMenu = (MenuHandle)grumble; AdjustActionMenu (ActionMenu); InsertMenu(ActionMenu,-1); /* * fill the list */ if (err = FillFilters(0)) goto fail; MyWindowDidResize(Win,&Win->contR); ShowMyWindow(winWP); } if (MainEvent.modifiers & shiftKey) { for (winWP = GetNextWindow (winWP); winWP && !IsWindowVisible (winWP); winWP = GetNextWindow (winWP)); if (winWP) SelectFiltersBasedOnWindow(winWP); } //WinGreyBG(Win); return(noErr); fail: FiltersClose(win); if (winWP) CloseMyWindow(winWP); return(err); } #pragma segment FilterWin /************************************************************************ * SelectFiltersBasedOnWindow - select the filters that match a window ************************************************************************/ short SelectFiltersBasedOnWindow(WindowPtr winWP) { MyWindowPtr win = GetWindowMyWindowPtr(winWP); short count = 0; TOCHandle tocH = nil; short sumNum; Point c; if (winWP) { switch (GetWindowKind(winWP)) { case MESS_WIN: case COMP_WIN: tocH = (*Win2MessH(win))->tocH; sumNum = (*Win2MessH(win))->sumNum; break; case MBOX_WIN: case CBOX_WIN: tocH = (TOCHandle) GetWindowPrivateData (winWP); sumNum = FirstMsgSelected(tocH); if (sumNum<0) tocH = nil; break; } if (tocH) { c.h = 0; for (c.v=0;c.vpteList,mouse)) return; else for (i=0,fa=FR[Selected-1].actions;fa;fa=(*fa)->next,i++) { r = Rects[flrAct1+i]; if (PtInSlopRect(mouse,Rects[flrAct1+i],2)) { ((*(FActionProc*)FATable((*fa)->action)))(faeCursor,fa,(Rect*)&mouse,&cursor); break; } } } SetMyCursor(cursor); } /********************************************************************** * FilterFind - find in the filters window **********************************************************************/ Boolean FilterFind(MyWindowPtr win,PStr what) { WindowPtr WinWP = GetMyWindowWindowPtr (Win); CGrafPtr winPort = GetMyWindowCGrafPtr (win); Boolean found = False; short spot; short stop; Boolean wrapped; SelectWindow_(WinWP); SetPort_(GetWindowPort(WinWP)); LActivate(True,LHand); wrapped = False; spot = -1; stop = 0; if (Selected) spot = stop = Selected-1; // Don't let any drawing occur during find SetEmptyClipRgn(winPort); win->noUpdates = true; do { MiniEvents(); if (CommandPeriod || EjectBuckaroo) break; spot++; if (spot>=NFilters) {spot=0;wrapped = True;} FilterSelect(spot); if (spot==stop && wrapped) break; found = AppearInFilter(what,spot,PrefIsSet(PREF_SENSITIVE)); } while (!found); win->noUpdates = false; InfiniteClip(winPort); // Restore clipping region InvalContent(win); return found; } /********************************************************************** * FilterScrollWheel - handle scroll wheel events for filter list **********************************************************************/ Boolean FilterScrollWheel(MyWindowPtr win,Point pt,short h,short v) { Rect rList; GetListViewBounds (LHand, &rList); if (PtInRect(pt,&rList)) { LScroll(0,-v,LHand); return true; } return false; } /********************************************************************** * MatchInFilter - does a string appear in a filter? **********************************************************************/ Boolean AppearInFilter(PStr what,short which,Boolean caseSens) { #pragma unused(caseSens) Boolean found; Str255 scratch; LDRef(Filters); found = nil!=PFindSub(what,FR[which].name); found = found || AppearInTerm(what,&FR[which].terms[0]); found = found || FR[which].conjunction!=cjIgnore && AppearInTerm(what,&FR[which].terms[1]); found = found || PFindSub(what,GetRString(scratch,CONJ_STRN+FR[which].conjunction)); found = found || AppearInActions(what,FR[which].actions); UL(Filters); return(found); } /********************************************************************** * AppearInActions - does a string appear in any of the actions? **********************************************************************/ Boolean AppearInActions(PStr what,FActionHandle fa) { for (;fa;fa = (*fa)->next) if (AppearInAction(what,fa)) return(True); return(False); } /********************************************************************** * AppearInAction - does a string appear in an action? **********************************************************************/ Boolean AppearInAction(PStr what,FActionHandle fa) { Str255 scratch; GetMenuItemText(ActionMenu,(*fa)->action,scratch); if (PFindSub(what,scratch)) return(True); return(CallAction(faeFind,fa,nil,what)); } /********************************************************************** * AppearInTerm - does a string appear in a term? **********************************************************************/ Boolean AppearInTerm(PStr what,MTPtr term) { Str255 verb; return ( PFindSub(what,term->header) || PFindSub(what,term->value) || PFindSub(what,GetRString(verb,VERB_STRN+term->verb)) || 0 ); } /************************************************************************ * FilterKey - handle keystrokes in the filter window ************************************************************************/ Boolean FilterKey(MyWindowPtr win, EventRecord *event) { #pragma unused(win) short key = event->message&0xff; if (event->modifiers & cmdKey) {return(False);} /* no command keys! */ switch(key) { case upArrowChar: FilterSelect(MAX(0,Selected-2)); return(True); case downArrowChar: FilterSelect(MIN(Selected,NFilters-1)); return(True); } if (!Win->pte) return(False); if (key=='\t' || key=='\015') { if (event->modifiers&shiftKey) PeteFocusPrevious(Win); else PeteFocusNext(Win); PeteSelectAll(Win,Win->pte); FiltEnableVerbAll(); } else if (key==enterChar) { PeteSelectAll(Win,Win->pte); SaveCurrentFilter(); FiltEnableVerbAll(); } else { return(False); } return(True); } /************************************************************************ * FilterApp1 - handle App1 event for filter ************************************************************************/ Boolean FilterApp1(MyWindowPtr win,EventRecord *event) { #pragma unused(win) return(ListApp1(event,LHand)); } /************************************************************************ * FilterActivate - handle activation and deactivation ************************************************************************/ void FilterActivate(MyWindowPtr win) { #pragma unused(win) LActivate(Win->isActive,LHand); if (!Win->isActive) SaveCurrentFilter(); } /********************************************************************** * FiltersUpdate - update the filters window **********************************************************************/ void FiltersUpdate(MyWindowPtr win) { CGrafPtr WinPort = GetMyWindowCGrafPtr (Win); Rect r; Str63 s; short i; FActionHandle fa; short wi; //RaisedWindowRect(win); ConfigFontSetup(win); r = Rects[flrList]; InsetRect(&r,1,1); DrawThemeListBoxFrame(&r,kThemeStateActive); for (i=flrMatch1;i<=flrAct5;i++) { r = Rects[i]; DrawThemeSecondaryGroup(&r,kThemeStateActive); } TextMode(srcOr); GetRString(s,HEADER_LABEL); if (!Selected || Multiple) TextMode(grayishTextOr); MoveTo(Block0.labelPoint.h,Block0.labelPoint.v); DrawString(s); if (!HasTwo) TextMode(grayishTextOr); MoveTo(Block1.labelPoint.h,Block1.labelPoint.v); DrawString(s); TextMode(srcOr); TextFace(0); DrawFilterDate(); r = Rects[flrVBar]; DrawDivider(&r,True); LUpdate(MyGetPortVisibleRegion(WinPort),LHand); wi = ControlWi(Controls[flMatchOnePop]); if (Selected && !Multiple) { for (i=0,fa=FR[Selected-1].actions;fa && inext) { r = Rects[flrAct1+i]; (*(FActionProc*)FATable((*fa)->action))(faeDraw,fa,&r,nil); } } } /********************************************************************** * DrawFilterDate - draw the last use date of a filter **********************************************************************/ void DrawFilterDate(void) { Str255 string; Str63 date; Rect r; long secs; r = Rects[flrDate]; EraseRect(&r); if (Selected && !Multiple) { if (secs = FilterLastMatchHi(Selected-1)) { DateString(secs+ZoneSecs(),shortDate,date,nil); ComposeRString(string,FILT_DATE_LABEL,date); MoveTo(r.right-StringWidth(string),r.bottom); DrawString(string); } } } /************************************************************************ * FiltersMenu - handle our paltry menu item ************************************************************************/ Boolean FilterMenu(MyWindowPtr win, int menu, int item, short modifiers) { switch (menu) { case FILE_MENU: switch(item) { case FILE_SAVE_ITEM: if (win->isDirty) SaveFilters(); return(True); break; case FILE_PRINT_ITEM: case FILE_PRINT_ONE_ITEM: #ifdef GX_PRINTING if (gGXIsPresent) GXPrintFilters((modifiers&shiftKey)!=0, item==FILE_PRINT_ONE_ITEM); else #endif //GX_PRINTING PrintFilters((modifiers&shiftKey)!=0, item==FILE_PRINT_ONE_ITEM); return(True); break; } break; } return(False); } /********************************************************************** * ActOf - get the number of an action **********************************************************************/ short ActOf(FActionHandle action) { short i; FActionHandle fa; for (i=0,fa=FR[Selected-1].actions;fa;fa=(*fa)->next,i++) if (fa==action) break; return(i); } /********************************************************************** * FAPopup - find the popup for a given FAction rectangle **********************************************************************/ void FAPopup(Rect *r) { short v = r->top; short h = r->left; short diff; GetControlBounds(Controls[flMatchOnePop],r); OffsetRect(r,h+INSET-r->left,v+INSET-r->top-1); // how much space is there? diff = ActHi-RectHi(*r); if (r->top>v+diff/2) // if space is tight, center OffsetRect(r,0,v+diff/2-r->top); } /************************************************************************ * FAPopupValueFit - fit a popup control for a value in a filter action ************************************************************************/ void FAPopupValueFit(Rect *r,ControlHandle popup) { Rect controlR; short over; // figure out how big it wants to be ButtonFit(popup); // figure out how big we think it should be FAPopActRect(r,&controlR); // if it's too tall, move it up a bit over = controlR.top + ControlHi(popup) - r->bottom; if (over>0) OffsetRect(&controlR,0,-over-2); // move the control into place MoveMyCntl(popup,controlR.left,controlR.top,MIN(ControlWi(popup),RectWi(controlR)),0); } /************************************************************************ * FillFilters - fill the list box ************************************************************************/ OSErr FillFilters(short startingFrom) { Str255 name; short n = NFilters; Point c; c.h = 0; LSetDrawingMode(False,LHand); LAddRow(n-startingFrom,n,LHand); for (c.v=startingFrom;c.vvPitch+2; SetWinMinSize(Win,120+55*Win->hPitch,MIN_MATCH_HI+MIN_ACTION_HI+2*INSET+Win->vPitch); /* Size the buttons early on */ ButtonFit(NewButton); ButtonFit(RemoveButton); /* * begin by figuring out the big rectangles */ listR = win->contR; InsetRect(&listR,GROW_SIZE,INSET); /* leave a decent margin */ matchR = actionR = listR; /* list rectangle needs room for a row of buttons along the bottom */ listR.bottom -= (2*INSET+ControlHi(NewButton)); /* list rectangle width */ listR.right = listR.left + FilterListWidth(RectWi(listR)); /* match & action offset from list */ matchR.left = actionR.left = listR.right + GROW_SIZE; /* bit of room off the top */ matchR.top += Win->vPitch/2+4; /* figure out relative heights of the two areas */ matchR.bottom = matchR.top + FilterMatchHeight(RectHi(matchR)); actionR.top = matchR.bottom + Win->vPitch + 2 + 4; /* leave room near grow box if possible */ if (actionR.bottom-actionR.top>MIN_ACTION_HI+(GROW_SIZE-INSET)) actionR.bottom -= GROW_SIZE-INSET; Rects[flrMatch] = matchR; Rects[flrAction] = actionR; Rects[flrList] = listR; r = actionR; r.top -= GROW_SIZE; MySetCntlRect(ActionGroup,&r); r = matchR; r.top -= GROW_SIZE; MySetCntlRect(MatchGroup,&r); /* * new and remove buttons along the bottom */ MoveMyCntl(NewButton,listR.left,listR.bottom+INSET,0,0); MoveMyCntl(RemoveButton,listR.right-ControlWi(RemoveButton),listR.bottom+INSET,0,0); /* * set up the rectangle for the vertical separator bar */ SET_RECT(&Rects[flrVBar],listR.right+INSET,win->contR.top+INSET,listR.right+INSET+2,actionR.bottom); /* * the match rectangles */ mblHeight = MatchBlockHeight(RectHi(matchR)); SET_RECT(&Rects[flrMatch1],matchR.left+GROW_SIZE,matchR.top+INSET+(3*GROW_SIZE)/2, matchR.right-GROW_SIZE,matchR.top+INSET+mblHeight); Rects[flrMatch2] = Rects[flrMatch1]; OFFSET_RECT(&Rects[flrMatch2],0,matchR.bottom - INSET - Rects[flrMatch1].bottom); dateR = actionR; dateR.bottom = dateR.top-4; dateR.top = dateR.bottom - (SmallSysFontSize()*12)/10; dateR.right = Rects[flrMatch1].right; dateR.left = (dateR.left+dateR.right)/2; Rects[flrDate] = dateR; /* * place match controls */ x = (3*RectWi(Rects[flrMatch1]))/8; x = MIN(x,MAX_MATCHPOP_WI); x += Rects[flrMatch1].left; y = RectHi(Rects[flrMatch1])/2 + Rects[flrMatch1].top; MoveMyCntl(Controls[flMatchOnePop],Rects[flrMatch1].left+INSET,y+MAX_APPEAR_RIM, x-Rects[flrMatch1].left-INSET-1, lineH+2*TE_VMARGIN); GetControlBounds(Controls[flMatchOnePop],&rCntl); OFFSET_RECT(&rCntl,0, Rects[flrMatch2].bottom-Rects[flrMatch1].bottom); SetControlBounds(Controls[flMatchTwoPop],&rCntl); SetControlBounds(Controls[flConjunction],&rCntl); MoveControl(Controls[flConjunction],x-RectWi(rCntl)/2, (Rects[flrMatch2].top+Rects[flrMatch1].bottom-RectHi(rCntl))/2); /* * Place match STE's */ SetRect(&hiddenRect,-100,-100,-100,-100); /* value 1 */ GetControlBounds(Controls[flMatchOnePop],&r); r.left = r.right+MIN_APPEAR_SPACE; r.right = Rects[flrMatch1].right-INSET; r.top += ((r.bottom-r.top)-ONE_LINE_HI(Win))/2; r.bottom = r.top+ONE_LINE_HI(Win); Rects[flrVal1] = r; popupValue = GetControlValue(Controls[flMatchOnePop]); if (popupValue == mbmAppears || popupValue == mbmNotAppears || popupValue == mbmIntersectsFile || popupValue == mbmNotIntersectsFile) { PeteDidResize(Block0.valuePTE,&hiddenRect); if (popupValue == mbmIntersectsFile || popupValue == mbmNotIntersectsFile) FiltSetAndShowNickPop(flNickFilePop1,nil,&r); else HideControl(Controls[flNickFilePop1]); } else { HideControl(Controls[flNickFilePop1]); PeteDidResize(Block0.valuePTE,&r); } /* value 2 */ popupValue = GetControlValue(Controls[flMatchTwoPop]); OffsetRect(&r,0,Rects[flrMatch2].bottom-Rects[flrMatch1].bottom); if (popupValue == mbmAppears || popupValue == mbmNotAppears || popupValue == mbmIntersectsFile || popupValue == mbmNotIntersectsFile) { PeteDidResize(Block1.valuePTE,&hiddenRect); if (popupValue == mbmIntersectsFile || popupValue == mbmNotIntersectsFile) FiltSetAndShowNickPop(flNickFilePop2,nil,&r); else HideControl(Controls[flNickFilePop1]); } else { HideControl(Controls[flNickFilePop2]); PeteDidResize(Block1.valuePTE,&r); } Rects[flrVal2] = r; /* header 2 */ OffsetRect(&r,0,y-Rects[flrMatch1].bottom+3); r.right = r.left + (2*(r.right-r.left))/3; PeteDidResize(Block1.headerPTE,&r); Block1.labelPoint.h = x-StringWidth(GetRString(s,HEADER_LABEL))-2; Block1.labelPoint.v = r.top+SmallSysFontSize()+TE_VMARGIN; /* header 1 */ OffsetRect(&r,0,Rects[flrMatch1].bottom-Rects[flrMatch2].bottom); PeteDidResize(Block0.headerPTE,&r); Block0.labelPoint = Block1.labelPoint; Block0.labelPoint.v += Rects[flrMatch1].bottom-Rects[flrMatch2].bottom; /* accel 1 */ r.left = r.right+4; r.right = r.left+GROW_SIZE; r.bottom = r.top+GROW_SIZE; InsetRect(&r,0,4); Rects[flrAccel1] = r; MySetCntlRect(Controls[flAccel1],&r); //ShowControl(Controls[flAccel1]); /* accel 2 */ OffsetRect(&r,0,Rects[flrMatch2].bottom-Rects[flrMatch1].bottom); Rects[flrAccel2] = r; MySetCntlRect(Controls[flAccel2],&r); //ShowControl(Controls[flAccel2]); /* * incoming, outgoing, and manual buttons */ x = Rects[flrMatch1].left; wi = (Rects[flrMatch1].right-x-2*INSET)/3; y = matchR.top+INSET; MoveMyCntl(Controls[flIncoming],x,y,wi,lineH); MoveMyCntl(Controls[flOutgoing],x+wi+INSET,y,wi,lineH); MoveMyCntl(Controls[flManual],x+2*(wi+INSET),y,wi,lineH); /* * list itself */ r = Rects[flrList]; r.right -= GROW_SIZE; InsetRect(&r,1,1); cSize.h = r.right-r.left; cSize.v = lineH; r.bottom = r.top + (RectHi(r)/lineH)*lineH; ResizeList(LHand,&r,cSize); r.right += GROW_SIZE; InsetRect(&r,-1,-1); Rects[flrList] = r; /* * action rectangles */ r = Rects[flrMatch1]; SetFASpacings(Rects[flrAction].bottom-Rects[flrAction].top); r.top = Rects[flrAction].top + ActSpace; r.bottom = r.top + ActHi; for (i=flrAct1;iv+diff/2) // if space is tight, center OffsetRect(&r2,0,v+diff/2-r2.top); } MySetCntlRect(Controls[flAct1+i-flrAct1],&r2); } if (ActRgn) { /* big box */ r = Rects[flrAct1]; InsetRect(&r,1,1); RectRgn(ActRgn,&r); /* outside of little box */ r = Rects[flrAct1]; FAPopup(&r); InsetRect(&r,-1,-1); r.bottom += 1; RgnMinusRect(ActRgn,&r); /* inside of little box */ InsetRect(&r,2,3); r.top -= 1; RgnPlusRect(ActRgn,&r); } ForAllActionsDo(faeResize,nil); /* * wipe it */ for (i=0;iisDirty) { which = WannaSave(Win); if (which==CANCEL_ITEM || which == WANNA_SAVE_SAVE && SaveFilters()) return(False); } if (which==WANNA_SAVE_DISCARD) { FiltersRefCount = 0; ZapFilters(); } } if (ActionMenu) { DeleteMenu(FLA_MENU); ReleaseResource_(ActionMenu); } LDRef(FLG); if (LHand) LDispose(LHand); FiltersDecRef(); if (ActRgn) DisposeRgn(ActRgn); ZapHandle(FLG); } return(True); } /********************************************************************** * FilterWindowClean - set the clean of the fitler window **********************************************************************/ void FilterWindowClean(Boolean clean) { if (FLG && Win) Win->isDirty = !clean; } #pragma segment FilterWin /********************************************************************** * **********************************************************************/ Boolean FiltWinOpen(void) { return(FLG && Win); } /********************************************************************** * FilterIsSelected - is a filter selected? **********************************************************************/ Boolean FilterIsSelected(short which) { return FLG && Cell1Selected(which+1,LHand); } /********************************************************************** * **********************************************************************/ void FiltClickHook(short cell,ListHandle lHand) { Point c; short oldCell; if (cell && cell<=(*lHand)->dataBounds.bottom) { if (MainEvent.modifiers&cmdKey) { c.h = 0; c.v = cell-1; LSetSelect(!Cell1Selected(cell,lHand),c,lHand); ActOnFilterSelect(); } else if (!Cell1Selected(cell,lHand)) { if (MainEvent.modifiers&shiftKey) { oldCell = Next1Selected(0,lHand); if (oldCell && oldCellcell) { c.v = cell-1; cell = oldCell-1; oldCell = c.v; } else oldCell = --cell; c.h = 0; for (c.v=oldCell;c.vwhere; Rect r; PETEHandle pte = nil; FActionHandle fa; short i; Boolean drag; ControlHandle cntl; long controlId = -1; GlobalToLocal(&pt); r = Rects[flrAction]; if (PtInRect(pt,&r)) { ForAllActionsDo(faeMouseGoingDown,nil); } r = Rects[flrList]; if (PtInRect(pt,&r)) { LClickWDrag(pt,event->modifiers,LHand,&drag,FiltClickHook); if (drag) FiltDoDrag(event); ActOnFilterSelect(); } else if ((r = Rects[flrVBar]),PtInSloppyRect(pt,&r,1)) { FiltDragDivider(pt); } else if (FindControl(pt,winWP,&cntl) && (GetControlReference(cntl)&0xffffff00)=='act\0') { FActionPopUp(pt,cntl); controlId = GetControlReference(cntl); } else if (HandleControl(pt,win)) ; else if (Selected && !Multiple) { if ((r=Rects[flrAccel1]),PtInRect(pt,&r)) { AccelPopUp(Block0.headerPTE,Controls[flMatchOnePop],r.top,r.left); controlId = AUDITCONTROLID(GetWindowKind(winWP),flAccel1); } else if (HasTwo && ((r=Rects[flrAccel2]),PtInRect(pt,&r))) { AccelPopUp(Block1.headerPTE,Controls[flMatchTwoPop],r.top,r.left); controlId = AUDITCONTROLID(GetWindowKind(winWP),flAccel2); } else if (PtInPETE(pt,Block0.headerPTE)) pte = Block0.headerPTE; else if (PtInPETE(pt,Block0.valuePTE)) pte = Block0.valuePTE; else if (HasTwo && PtInPETE(pt,Block1.headerPTE)) pte = Block1.headerPTE; else if (HasTwo && PtInPETE(pt,Block1.valuePTE)) pte = Block1.valuePTE; else for (i=0,fa=FR[Selected-1].actions;fa;fa=(*fa)->next,i++) { r = Rects[flrAct1+i]; if (PtInRect(pt,&r)) { ((*(FActionProc*)FATable((*fa)->action)))(faeClick,fa,(Rect*)&pt,event); break; } } if (pte) PeteEditWFocus(Win,pte,peeEvent,(void*)event,nil); } FiltEnableVerbAll(); if (controlId >= 0) AuditHit((event->modifiers&shiftKey)!=0, (event->modifiers&controlKey)!=0, (event->modifiers&optionKey)!=0, (event->modifiers&cmdKey)!=0, false, GetWindowKind(winWP), controlId, event->what); } /********************************************************************** * FiltDoDrag - drag some filters **********************************************************************/ OSErr FiltDoDrag(EventRecord *event) { Point p = event->where; short theCell; short n = NFilters; DragReference drag; OSErr err = noErr; Handle data; RgnHandle rgn; PromiseHFSFlavor promise; FSSpec spec; // we may write here DECLARE_UPP(FiltDragSend,DragSendData); INIT_UPP(FiltDragSend,DragSendData); GlobalToLocal(&p); theCell = InWhich1Cell(p,LHand); if (theCell>n) LClick(p,event->modifiers,LHand); else { if (!Cell1Selected(theCell,LHand)) FilterSelect(theCell-1); if (!(err=MyNewDrag(Win,&drag))) { if (!(data=NuHTempBetter(0))) err = MemError(); else if (!(rgn=MyLDragRgn(LHand))) err = MemError(); else { for (theCell=0;theCell=Next1Selected(theCell,LHand);) if (err=PtrPlusHand(&theCell,data,sizeof(theCell))) break; // Setup the promiseHFS Zero(promise); promise.fileType = FILTER_FTYPE; promise.fileCreator = CREATOR; promise.promisedFlavor = SPEC_FLAVOR; Zero(spec); if (!(err=FinderDragVoodoo(drag))) // bad finder. bad. if (!err) { // add the cell data for internal drags err = AddDragItemFlavor(drag,1,FILT_DRAG_DATA_TYPE, LDRef(data),GetHandleSize(data), flavorSenderOnly|flavorNotSaved); ZapHandle(data); if (!err) // add the promiseHFS if (!(err=AddDragItemFlavor(drag,1,flavorTypePromiseHFS,&promise,sizeof(promise),0))) // add an flavor to hold the spec we're supposed to write to if (!(err=AddDragItemFlavor(drag,1,SPEC_FLAVOR,nil,0,0))) // now the proc that really does the work if somebody takes us up on our promise if (!(err=SetDragSendProc(drag,FiltDragSendUPP,(void*)&spec))) { // finally actually track the drag if (!(err=MyTrackDrag(drag,event,rgn))) { if (*spec.name) { // We need to write selected filters to this file err = SaveFiltersLo(&spec,false,false); } } } DisposeRgn(rgn); } } MyDisposeDrag(drag); } } return(err); } /********************************************************************** * FiltDragSend - drag data proc for filters **********************************************************************/ pascal OSErr FiltDragSend(FlavorType flavor, void *dragSendRefCon, ItemReference theItemRef, DragReference drag) { AEDesc dropLocation; OSErr err=cantGetFlavorErr; FSSpecPtr spec = (FSSpecPtr)dragSendRefCon; /* * return the filename */ if (flavor==SPEC_FLAVOR) { NullADList(&dropLocation,nil); if (!(err=GetDropLocation(drag,&dropLocation))) if (!(err=GetDropLocationDirectory(&dropLocation,&spec->vRefNum,&spec->parID))) { FiltDragFilename(spec->name); UniqueSpec(spec,31); FSpCreateResFile(spec,CREATOR,FILTER_FTYPE,smSystemScript); WhackFinder(spec); if (!(err = ResError())) err = MySetDragItemFlavorData(drag,1,SPEC_FLAVOR,spec,sizeof(FSSpec)); } DisposeADList(&dropLocation,nil); } return(err); } /********************************************************************** * FiltDragFilename - setup a filename for the target of a filter drag **********************************************************************/ void FiltDragFilename(PStr name) { #ifdef TO_DO #pragma warning Need to write better naming function for filter drags #endif GetRString(name,FILTERS_NAME); } /********************************************************************** * FiltDragHandler - drag handler for filters window **********************************************************************/ OSErr FiltDragHandler(MyWindowPtr win,DragTrackingMessage which,DragReference drag) { OSErr err=noErr; Point mouse; Rect r; short stice; static short flags; if (drag!=OldDrag) { Boolean interesting, me, draggingFile; interesting = DragIsInteresting(drag,FILT_DRAG_DATA_TYPE,nil); if (!interesting) draggingFile = interesting = DragIsInterestingFileType(drag,nil,FILTER_FTYPE,nil); else draggingFile = false; flags = ldtInterstice; if (draggingFile) flags |= ldtIgnoreSelection; me = DragSource==win; DragInteresting = interesting; OldDrag = drag; DragFromMe = me; } if (!DragInteresting) return(Selected ? dragNotAcceptedErr:1); if (which==0xfff) HideDragHilite(drag); SetPort(GetMyWindowCGrafPtr(Win)); GetDragMouse(drag,&mouse,nil); GlobalToLocal(&mouse); switch (which) { case 0xfff: case kDragTrackingInWindow: if (DragInteresting) { r = Rects[flrList]; r.right -= GROW_SIZE; InsetRect(&r,0,-GROW_SIZE); if (PtInRect(mouse,&r)) { stice = MyLDragTracker(drag,mouse,flags,LHand); if (stice==-1) err = dragNotAcceptedErr; else if (which==0xfff) { HideDragHilite(drag); if (DragInteresting) err = FiltDrop(stice,drag); else err == dragNotAcceptedErr; } } } break; case kDragTrackingLeaveWindow: HideDragHilite(drag); break; } return(err); } /********************************************************************** * FiltDrop - handle a drop onto filters **********************************************************************/ OSErr FiltDrop(short stice,DragReference drag) { short n = NFilters; short **data; FRHandle fr = nil; OSErr err; ASSERT(MyCountDragItems(drag)==1); SaveCurrentFilter(); if (!(err=MyGetDragItemData(drag,1,FILT_DRAG_DATA_TYPE,(Handle*)&data))) { ZapHandle(data); err = MoveSelectedFilters(stice); } else err = FiltDropFile(stice,drag); return(err); } /********************************************************************** * **********************************************************************/ OSErr FiltDropFile(short stice,DragReference drag) { short item; OSErr err=noErr; HFSFlavor **data; FSSpec spec; short n = MyCountDragItems(drag); short oldN = NFilters; // Add the filters to the filter structure for (item=1;item<=n && !err;item++) // loop through each item { if (!(err=MyGetDragItemData(drag,item,flavorTypeHFS,(void*)&data))) { spec = (*data)->fileSpec; ZapHandle(data); err = ReadFilters(Filters,spec.vRefNum,spec.parID,spec.name); } } // Add the filters to the list in the window n = NFilters - oldN; if (n>0) { FillFilters(oldN); FiltRedoList(oldN,n); MoveSelectedFilters(stice); } return(err); } /********************************************************************** * FiltSetAndShowNickPop - populate the nickname file popup and move it into place **********************************************************************/ OSErr FiltSetAndShowNickPop(FilterControlEnum pop,PStr value,Rect *r) { // if we're passed with a string, set the contents // of the menu and its value if (value) { MenuHandle mh; short ab; Str63 name; short val = 1; if (mh = GetControlPopupMenuHandle(Controls[pop])) { TrashMenu(mh,1); // The address book menu will consist of only the following: // Eudora Nicknames // Regular Address Books // History List // ÇAnyÈ GetRString(name,ANY_ALIAS_FILE); MyAppendMenu(mh,name); for (ab = 0; ab < NAliases; ++ab) if (IsEudoraAddressBook (ab) || IsRegularAddressBook (ab) || IsHistoryAddressBook (ab)) { PCopy(name,(*Aliases)[ab].spec.name); MyAppendMenu (mh,name); if (StringSame(name,value)) val = CountMenuItems(mh); } SetControlMaximum (Controls[pop], CountMenuItems (mh)); SetControlMinimum (Controls[pop], 1); SetControlValue (Controls[pop], val); } } MySetCntlRect(Controls[pop],r); ShowControl(Controls[pop]); return noErr; } /********************************************************************** * **********************************************************************/ OSErr MoveSelectedFilters(short stice) { short fNum; short nSelected=0; FRHandle fr=nil; short i; short spot; short goodSpot; short n = NFilters; for (fNum=0;fNum=spot+nSelected;fNum--) { if (FR[fNum].kill) continue; //will be overwritten if (fNum!=goodSpot) FR[goodSpot] = FR[fNum]; //filter ok, copy into place goodSpot--; //found another good one } /* * now, move them into place */ BMD(*fr,&FR[spot],nSelected*sizeof(FilterRecord)); ZapHandle(fr); /* * cleanup */ if (nSelected==1 && Selected && !Multiple) Selected = spot+1; FiltRedoList(spot,nSelected); return noErr; } return MemError(); } /********************************************************************** * **********************************************************************/ void FiltRedoList(short startSel,short nSel) { Point c; short n = NFilters; Str255 title; c.h = 0; /* * retitle every cell */ for (c.v=0;c.visDirty = True; } /********************************************************************** * **********************************************************************/ void FiltDragDivider(Point pt) { Rect div, bounds; Point newPt; div = Rects[flrVBar]; bounds = Win->contR; bounds.right = RectWi(Win->contR)-MIN_ACTION_WI; bounds.left = (GetRLong(FILT_LIST_MIN)*Win->minSize.h)/100; newPt = DragDivider(pt,&div,&bounds,Win); /* * resize? */ if (newPt.h) { SetPrefLong(PREF_F_LIST_WIDE,newPt.h-GROW_SIZE-INSET); MyWindowDidResize(Win,nil); } } /************************************************************************ * FilterButton - handle hits on the buttons. ************************************************************************/ void FilterButton(MyWindowPtr win,ControlHandle button,long modifiers,short part) { #pragma unused(modifiers,part) FilterControlEnum which; Rect r,hiddenRect; short popupValue; Boolean wasFilterActionButton = false; SetRect(&hiddenRect,-100,-100,-100,ONE_LINE_HI(Win)-100); for (which=flNewButton;whichisDirty = CurrentDirty = True; break; case flMatchOnePop: Win->isDirty = CurrentDirty = True; /* value 1 */ r = Rects[flrVal1]; popupValue = GetControlValue(Controls[flMatchOnePop]); if (popupValue == mbmAppears || popupValue == mbmNotAppears || popupValue == mbmIntersectsFile || popupValue == mbmNotIntersectsFile) { PeteDidResize(Block0.valuePTE,&hiddenRect); if (popupValue == mbmIntersectsFile || popupValue == mbmNotIntersectsFile) FiltSetAndShowNickPop(flNickFilePop1,"",&r); else HideControl(Controls[flNickFilePop1]); } else { HideControl(Controls[flNickFilePop1]); PeteDidResize(Block0.valuePTE,&r); } InsetRect(&r,-3,-3); InvalWindowRect(GetMyWindowWindowPtr(win),&r); break; case flMatchTwoPop: Win->isDirty = CurrentDirty = True; /* value 2 */ popupValue = GetControlValue(Controls[flMatchTwoPop]); r = Rects[flrVal2]; if (popupValue == mbmAppears || popupValue == mbmNotAppears || popupValue == mbmIntersectsFile || popupValue == mbmNotIntersectsFile) { PeteDidResize(Block1.valuePTE,&hiddenRect); if (popupValue == mbmIntersectsFile || popupValue == mbmNotIntersectsFile) FiltSetAndShowNickPop(flNickFilePop2,"",&r); else HideControl(Controls[flNickFilePop2]); } else { HideControl(Controls[flNickFilePop2]); PeteDidResize(Block1.valuePTE,&r); } InsetRect(&r,-3,-3); InvalWindowRect(GetMyWindowWindowPtr(win),&r); break; case flNickFilePop1: case flNickFilePop2: Win->isDirty = CurrentDirty = True; break; case flConjunction: if (HasTwo != (GetControlValue(Controls[flConjunction])!=cjIgnore)) { InvalMatch2(); HasTwo = !HasTwo; FiltersSetGreys(); if (!HasTwo && (Win->pte==Block1.headerPTE || Win->pte==Block1.valuePTE)) { PeteFocus(Win,Block0.headerPTE,True); PeteSelectAll(Win,Win->pte); Win->hasSelection = MyWinHasSelection(Win); } } Win->isDirty = CurrentDirty = True; break; default: if (FilterActionButton(button,modifiers)) Win->isDirty = CurrentDirty = True; wasFilterActionButton = true; break; } // Audit the non-filter action button controls. if (!wasFilterActionButton) AuditHit((modifiers&shiftKey)!=0, (modifiers&controlKey)!=0, (modifiers&optionKey)!=0, (modifiers&cmdKey)!=0, false, GetWindowKind (GetMyWindowWindowPtr (win)), AUDITCONTROLID(GetWindowKind (GetMyWindowWindowPtr (win)),which), mouseDown); } /********************************************************************** * RemoveSelectedFilters - remove the current set of filters **********************************************************************/ void RemoveSelectedFilters(void) { short cell; short selectMe=0; Rect r; cell=1; while (cell=Next1Selected(cell-1,LHand)) { RemoveFilterLo(cell-1); if (!selectMe) selectMe = cell; } if (NFilters) FilterSelect(selectMe-1); else { FilterSelect(0); DisplaySelectedFilter(); FiltersSetGreys(); r = Win->contR; InvalWindowRect(GetMyWindowWindowPtr(Win),&r); } } /********************************************************************** * FilterActionButton - is the given click in one of an action's buttons? **********************************************************************/ Boolean FilterActionButton(ControlHandle button,short modifiers) { Boolean retVal = False; FActionHandle fa; short i; Point pt; Rect r; GetControlBounds(button,&r); pt.h = (r.left+r.right)/2; pt.v = (r.top+r.bottom)/2; if (Selected && !Multiple) { for (i=0,fa=FR[Selected-1].actions;fa && inext,i++) { r = Rects[flrAct1+i]; if (PtInRect(pt,&r)) { (*(FActionProc*)FATable((*fa)->action))(faeButton,fa,(void*)&modifiers,button); return(True); } } } return retVal; } /************************************************************************ * FilterSwap - swap two filters ************************************************************************/ void FilterSwap(short i, short j) { FilterRecord fi,fj; Point pi, pj; Boolean iSelect, jSelect; /* * make local copies */ pi.h = pj.h = 0; pi.v = i; pj.v = j; fi = FR[i]; fj = FR[j]; iSelect = LGetSelect(False,&pi,LHand); jSelect = LGetSelect(False,&pj,LHand); /* * swap data in the handle */ FR[j] = fi; FR[i] = fj; /* * swap data in the list */ LSetCell(fj.name+1,*fj.name,pi,LHand); LSetSelect(jSelect,pi,LHand); LSetCell(fi.name+1,*fi.name,pj,LHand); LSetSelect(iSelect,pj,LHand); Win->isDirty = True; } /************************************************************************ * FilterTextChanged - the te routines did something to our text ************************************************************************/ void FilterTextChanged(MyWindowPtr win, TEHandle teh, short oldNl, short newNl, Boolean scroll) { CurrentDirty = True; } /************************************************************************ * RemoveFilter - get rid of a filter ************************************************************************/ void RemoveFilter(short which) { short n = NFilters; RemoveFilterLo(which); if (FLG && *FLG && Win) { if (which==Selected-1) { Selected = 0; if (NFilters) FilterSelect(which); else { DisplaySelectedFilter(); FiltersSetGreys(); } } } } void RemoveFilterLo(short which) { short n = NFilters; if (FLG && *FLG && Win && which==Selected-1 && !Multiple) ForAllActionsDo(faeClose,nil); Selected = Multiple = 0; if (which<--n) BMD(&FR[which+1],&FR[which],(n-which)*sizeof(FilterRecord)); SetHandleBig_(Filters,n*sizeof(FilterRecord)); if (FLG && *FLG && Win) { LDelRow(1,which,LHand); Win->isDirty = CurrentDirty = True; } } /************************************************************************ * AddFilter - add a filter. n is filter should be ************************************************************************/ void AddFilter(short n) { Point c; FilterRecord fr; short i; FActionHandle fa; FRInit(&fr); fr.incoming = True; fr.fu.id = FilterNewId(); GetRString(fr.name,UNTITLED); SetHandleBig_(Filters,(NFilters+1)*sizeof(fr)); if (MemError()) {WarnUser(MEM_ERR,MemError()); return;} for (i=MAX_ACTIONS;i;i--) { fa = NewZH(FAction); if (!fa) {WarnUser(MEM_ERR,MemError()); break;} (*fa)->action = flkNone; LL_Push(fr.actions,fa); } if (i) SetHandleBig_(Filters,NFilters*sizeof(fr)); if (nisDirty = CurrentDirty = True; PopGWorld(); } } /************************************************************************ * FilterSelect - select a given cell ************************************************************************/ void FilterSelect(short which) { if (which>0) which = MIN(which,NFilters-1); SaveCurrentFilter(); SelectSingleCell(which,LHand); LAutoScroll(LHand); ActOnFilterSelect(); } /************************************************************************ * ActOnFilterSelect - we have selected a filter; do something about it ************************************************************************/ void ActOnFilterSelect(void) { short which, next; Rect r; short i; FActionHandle fa; which = Next1Selected(0,LHand); next = Next1Selected(which,LHand); if (Multiple && next) return; /* still a multiple selection */ if (which==Selected && !next) return; /* same single selection */ SaveCurrentFilter(); if (Multiple) for (i=0;inext) if ((*fa)->action!=flkNone) InvalAct(i); ForAllActionsDo(faeClose,nil); if ((Multiple==0)!=(next==0) || (Selected==0)!=(which==0)) { r = Win->contR; r.left = Rects[flrVBar].right+1; InvalWindowRect(GetMyWindowWindowPtr(Win),&r); } else if (which && Selected && (FR[which-1].conjunction==cjIgnore)!=HasTwo) InvalMatch2(); r = Rects[flrDate]; InvalWindowRect(GetMyWindowWindowPtr(Win),&r); Selected = which; Multiple = next; if (Multiple) for (i=0;inext) if ((*fa)->action!=flkNone) InvalAct(i); if (!Selected || Multiple) for (i=0;inext; /* * enable the items */ CheckNone(ActionMenu); item = GetControlValue(cntl); for (i=CountMenuItems(ActionMenu);i;i--) { GetMenuItemText(ActionMenu,i,s); if (*s>1) { //Enhanced Filters - disable and mark the Pro-only filter feature set (already done at this point) if (enable = (HasFeature (featureEudoraPro) || !FAProOnly (i))) if (!FAMultiple(i) && i!=(*fa)->action) { for (other=FR[Selected-1].actions;other;other=(*other)->next) if (other!=fa && (*other)->action==i) { DisableItem (ActionMenu,i); goto loop; } } EnableIf (ActionMenu, i, enable); if (item==i) SetItemMark (ActionMenu, item, diamondChar); } loop:; } if (TrackControl(cntl,pt,nil)) { short newItem; newItem = GetControlValue(cntl); if (newItem != item) NewAction(n,fa,newItem); } } /************************************************************************ * AdjustActionMenu - enable/disable items in the action menu ************************************************************************/ void AdjustActionMenu (MenuHandle theMenu) { // Disable any non-pro features (lamer than it should be...) SetMenuItemBasedOnFeature (theMenu, flkLabel, featureFilterLabel, true); SetMenuItemBasedOnFeature (theMenu, flkPersonality, featureFilterPersonality, true); SetMenuItemBasedOnFeature (theMenu, flkSound, featureFilterSound, true); SetMenuItemBasedOnFeature (theMenu, flkSpeak, featureFilterSpeak, SpeechAvailable ()); SetMenuItemBasedOnFeature (theMenu, flkOpenMessage, featureFilterOpen, true); SetMenuItemBasedOnFeature (theMenu, flkPrint, featureFilterPrint, true); SetMenuItemBasedOnFeature (theMenu, flkAddHistory, featureFilterAddHistory, true); SetMenuItemBasedOnFeature (theMenu, flkForward, featureFilterForward, true); SetMenuItemBasedOnFeature (theMenu, flkRedirect, featureFilterRedirect, true); SetMenuItemBasedOnFeature (theMenu, flkReply, featureFilterReply, true); SetMenuItemBasedOnFeature (theMenu, flkServerOpts, featureFilterServerOptions, true); SetMenuItemBasedOnFeature (theMenu, flkJunk, featureJunk, true); } /************************************************************************ * AccelPopUp - pop up a menu for choosing a header quickly ************************************************************************/ void AccelPopUp(PETEHandle pte,ControlHandle verbCntl,short top,short left) { MenuHandle mh; Str255 value; short item; long sel; Point pt; pt.h = left; pt.v = top; LocalToGlobal(&pt); if (mh=GetMenu(HEAD_ACCEL_MENU)) { if (PersCount()>1) MyAppendMenu(mh,GetRString(value,FiltMetaLocalStrn+fmlPersonality)); GetRString(value,FiltMetaLocalStrn+fmlJunk); if (*value && (item=FindItemByName(mh,value))) SetMenuItemBasedOnFeature(mh,item,featureJunk,true); item = 0; PeteSString(value,pte); if (*value && !(item=FindItemByName(mh,value))) { AppendMenu(mh,"\p-"); DisableItem(mh,CountMenuItems(mh)); MyAppendMenu(mh,value); item = CountMenuItems(mh); } InsertMenu(mh,-1); sel = AFPopUpMenuSelect(mh,pt.v,pt.h,item); if (sel&0xffff && sel&0xff && (sel&0xff)!=item) { MyGetItem(mh,sel&0xff,value); PeteSetTextPtr(pte,value+1,*value); Win->isDirty = CurrentDirty = True; FiltEnableVerb(verbCntl,value); } DeleteMenu(HEAD_ACCEL_MENU); ReleaseResource_(mh); } } /********************************************************************** * NewAction - change an action **********************************************************************/ void NewAction(short n,FActionHandle fa,FilterKeywordEnum action) { FActionProc *old, *new; Rect r; old = (FActionProc *)FATable((*fa)->action); new = (FActionProc *)FATable(action); if (old) { (*old)(faeDispose,fa,nil,nil); if ((*fa)->data) ZapHandle((*fa)->data); } Win->isDirty = CurrentDirty = True; (*fa)->action = action; r = Rects[flrAct1+n]; InvalAct(n); if (new) if (!(*new)(faeRead,fa,nil,nil)) if (!(*new)(faeInit,fa,&r,nil)); (*new)(faeNew,fa,&r,nil); } /************************************************************************ * DisplaySelectedFilter - display a filter ************************************************************************/ void DisplaySelectedFilter(void) { FilterRecord fr; Rect r,hiddenRect; Str255 s; short i; FActionHandle fa; SetRect(&hiddenRect,-100,-100,-100,ONE_LINE_HI(Win)-100); if (Selected && !Multiple) fr = FR[Selected-1]; else FRInit(&fr); MySetCtlValue(Controls[flIncoming],fr.incoming); MySetCtlValue(Controls[flOutgoing],fr.outgoing); MySetCtlValue(Controls[flManual],fr.manual); #ifdef NEVER CurrentLabel = fr.label; DrawLabel(); DrawFilterDate(); #endif MySetCtlValue(Controls[flConjunction],fr.conjunction); MySetCtlValue(Controls[flMatchOnePop],fr.terms[0].verb); MySetCtlValue(Controls[flMatchTwoPop],fr.terms[1].verb); /* value 1 */ r = Rects[flrVal1]; FiltEnableVerb(Controls[flMatchOnePop],fr.terms[0].header); if (fr.terms[0].verb == mbmAppears || fr.terms[0].verb == mbmNotAppears || fr.terms[0].verb == mbmIntersectsFile || fr.terms[0].verb == mbmNotIntersectsFile) { PeteDidResize(Block0.valuePTE,&hiddenRect); if (fr.terms[0].verb == mbmIntersectsFile || fr.terms[0].verb == mbmNotIntersectsFile) FiltSetAndShowNickPop(flNickFilePop1,fr.terms[0].value,&r); else HideControl(Controls[flNickFilePop1]); } else { HideControl(Controls[flNickFilePop1]); PeteDidResize(Block0.valuePTE,&r); } /* value 2 */ r = Rects[flrVal2]; FiltEnableVerb(Controls[flMatchTwoPop],fr.terms[1].header); if (fr.terms[1].verb == mbmAppears || fr.terms[1].verb == mbmNotAppears || fr.terms[1].verb == mbmIntersectsFile || fr.terms[1].verb == mbmNotIntersectsFile) { PeteDidResize(Block1.valuePTE,&hiddenRect); if (fr.terms[1].verb == mbmIntersectsFile || fr.terms[1].verb == mbmNotIntersectsFile) FiltSetAndShowNickPop(flNickFilePop2,fr.terms[1].value,&r); else HideControl(Controls[flNickFilePop1]); } else { HideControl(Controls[flNickFilePop2]); PeteDidResize(Block1.valuePTE,&r); } PeteSetString(Transmogrify(s,FiltMetaLocalStrn,fr.terms[0].header,FiltMetaEnglishStrn),Block0.headerPTE); PeteSetString(fr.terms[0].value,Block0.valuePTE); PeteSetString(Transmogrify(s,FiltMetaLocalStrn,fr.terms[1].header,FiltMetaEnglishStrn),Block1.headerPTE); PeteSetString(fr.terms[1].value,Block1.valuePTE); if (HasTwo != (fr.conjunction!=cjIgnore)) { HasTwo = !HasTwo; InvalMatch2(); } ForAllActionsDo(faeInit,nil); if (Selected && !Multiple) { PeteFocus(Win,Block0.headerPTE,True); PeteSelectAll(Win,Win->pte); for (i=0,fa=FR[Selected-1].actions;inext) { SetControlValue(Controls[flAct1+i],fa?(*fa)->action:flkNone); ShowControl(Controls[flAct1+i]); } } else PeteFocus(Win,nil,True); PeteCleanList(Win->pteList); } /********************************************************************** * FiltEnableVerbAll - enable all the verb popups in the filters window **********************************************************************/ void FiltEnableVerbAll(void) { Str63 s; PeteSString(s,Block0.headerPTE); FiltEnableVerb(Controls[flMatchOnePop],s); PeteSString(s,Block1.headerPTE); FiltEnableVerb(Controls[flMatchTwoPop],s); } /********************************************************************** * FiltEnableVerb - enable one of the verb popups **********************************************************************/ void FiltEnableVerb(ControlHandle popUpCntl,PStr head) { Boolean junkScore = EqualStrRes(head,FiltMetaEnglishStrn+fmeJunk) || EqualStrRes(head,FiltMetaLocalStrn+fmlJunk); short i; MenuHandle mh = PopUpMenuH(popUpCntl); // enable only a few things if we're searching on junk score for (i=mbmContains;inext) { r = Rects[flrAct1+i]; err = (*(FActionProc*)FATable((*fa)->action))(callType,fa,&r,dataPtr); if (err) anyErr = err; } } return(anyErr); } /************************************************************************ * SaveCurrentFilter - save the current filter ************************************************************************/ void SaveCurrentFilter(void) { Str31 scratch; Str255 name; Str31 head; Boolean dirty = FLG && Win && PeteIsDirtyList(Win->pteList); if (FLG) CurrentDirty = dirty || CurrentDirty; if (FLG && Selected && !Multiple && CurrentDirty) { FilterRecord fr; FilterUse fu = FR[Selected-1].fu; Str31 idStr; FRInit(&fr); fr.fu = fu; fr.actions = FR[Selected-1].actions; fr.incoming = GetControlValue(Controls[flIncoming]); fr.outgoing = GetControlValue(Controls[flOutgoing]); fr.manual = GetControlValue(Controls[flManual]); fr.conjunction = GetControlValue(Controls[flConjunction]); fr.terms[0].verb = GetControlValue(Controls[flMatchOnePop]); PeteSString(fr.terms[0].header,Block0.headerPTE); if (fr.terms[0].verb==mbmIntersectsFile || fr.terms[0].verb==mbmNotIntersectsFile) MyGetItem(PopUpMenuH (Controls[flNickFilePop1]),GetControlValue(Controls[flNickFilePop1]),fr.terms[0].value); else if (fr.terms[0].verb==mbmAppears || fr.terms[0].verb==mbmNotAppears) *fr.terms[0].value = 0; else PeteSString(fr.terms[0].value,Block0.valuePTE); if (HasTwo) { fr.terms[1].verb = GetControlValue(Controls[flMatchTwoPop]); PeteSString(fr.terms[1].header,Block1.headerPTE); if (fr.terms[1].verb==mbmIntersectsFile || fr.terms[1].verb==mbmNotIntersectsFile) MyGetItem(PopUpMenuH (Controls[flNickFilePop2]),GetControlValue(Controls[flNickFilePop2]),fr.terms[1].value); else if (fr.terms[1].verb==mbmAppears || fr.terms[1].verb==mbmNotAppears) *fr.terms[1].value = 0; else PeteSString(fr.terms[1].value,Block1.valuePTE); } TrimWhite(fr.terms[0].header); TrimWhite(fr.terms[1].header); TrimInitialWhite(fr.terms[0].header); TrimInitialWhite(fr.terms[1].header); /* * build the name BEFORE transmogrification */ if (*fr.terms[0].header || *fr.terms[0].value) { NumToString(fr.fu.id,idStr); PSCopy(head,fr.terms[0].header); if (head[*head]==':') --*head; utl_PlugParams(GetRString(scratch,FILTER_NAME),name, head,fr.terms[0].value,idStr,nil); PSCopy(fr.name,name); } else GetRString(fr.name,UNTITLED); Transmogrify(fr.terms[0].header,FiltMetaEnglishStrn,fr.terms[0].header,FiltMetaLocalStrn); Transmogrify(fr.terms[1].header,FiltMetaEnglishStrn,fr.terms[1].header,FiltMetaLocalStrn); /* * save the actions */ ForAllActionsDo(faeSave,nil); /* * study it */ StudyFilter(&fr); /* * save it */ LDRef(Filters); { Point c; c.h = 0; c.v = Selected-1; FR[Selected-1] = fr; Win->isDirty = True; LSetCell(fr.name+1,*fr.name,c,LHand); } UL(Filters); CurrentDirty = False; PeteCleanList(Win->pteList); } } #pragma segment Print /********************************************************************** * PrintFilters - print the filter list **********************************************************************/ OSErr PrintFilters(Boolean selected,Boolean now) { OSErr err; PMPrintContext printContext; Rect uRect; short page = 0; short n = NFilters; short i; short v; PushGWorld(); if (!(err = PrintPreamble(&printContext,&uRect,now))) { for (i=0;ileft + (GetRLong(NICK_PRINT_NICK_PER)*RectWi(*uRect))/100; FActionHandle fa; Point penLoc; FilterRecord fr = FR[which]; /* * need new page? */ if (*page==0 || *v+FiltPrintLines(which,uRect)*Win->vPitch>uRect->bottom-GetRLong(PRINT_H_MAR)) { GetWTitle(GetMyWindowWindowPtr(Win),scratch); if (*page!=0) { PrintBottomHeader(*page,uRect); PMEndPage(printContext); } PMBeginPage(printContext,nil); *v = uRect->top+GetRLong(PRINT_H_MAR); PrintMessageHeader(scratch,++*page,GetRLong(PRINT_H_MAR),*v,uRect->left,uRect->right); } /* * print the name & types */ *v += Win->vPitch; MoveTo(uRect->left,*v); BoldString(fr.name); if (GetPortPenLocation(GetQDGlobalsThePort(),&penLoc)->hvPitch; /* * print the terms */ MoveTo(h,*v); FiltPrintTerm(fr.terms); if (fr.conjunction!=cjIgnore) { *v += Win->vPitch; MoveTo(h,*v); DrawChar(' '); BoldRString(FiltConjPrintStrn+fr.conjunction); DrawChar(' '); FiltPrintTerm(fr.terms+1); } MoveTo(h,*v+(Win->vPitch*2)/3); Hairline(True); Line(72,0); Hairline(False); *v += Win->vPitch; /* * print the actions */ for (fa=fr.actions;fa;fa=(*fa)->next) { if ((*fa)->action==flkNone) continue; *v += Win->vPitch; MoveTo(h,*v); GetMenuItemText(ActionMenu,(*fa)->action,scratch); BoldString(scratch); DrawChar(' '); CallAction(faePrint,fa,nil,nil); } /* * and leave a blank line */ *v += Win->vPitch; return(err); } #ifdef GX_PRINTING /********************************************************************** * GXPrintFilters - print the filter list, Quickdraw GX version **********************************************************************/ OSErr GXPrintFilters(Boolean selected, Boolean now) { OSErr err = noErr; gxRectangle GXuRect; Rect uRect; short i = 0, v = 0, page = 0; Str255 scratch; CGrafPort GXPort; long firstPage, numPages; GrafPtr oldPort; GetWTitle(GetMyWindowWindowPtr(Win), scratch); if ((err = GXPrintPreamble(&GXuRect, scratch, &firstPage, &numPages, now)) == noErr) { GetPort(&oldPort); OpenCPort(&GXPort); SetPort((GrafPtr)&GXPort); GXRectToRect(&GXuRect, &uRect); for (i = FilterToPrintFirst(firstPage, &uRect); i < NFilters && !err; i++) err = GXPrintAFilter(&GXPort, i, &uRect, &GXuRect, &v, &page, firstPage, numPages); //finish final page if ((page) && (err==noErr)) { MyGXInstallQDTranslator(&GXPort, &GXuRect, &gGXPrintViewPort, true); PrintBottomHeader(page, &uRect); MyGXRemoveQDTranslator(&GXPort); GXFinishPage(GXPageSetup); } #ifdef DEBUG { GrafPtr test; GetPort(&test); ASSERT(test == (GrafPtr)&GXPort); } #endif //DEBUG CloseCPort(&GXPort); SetPort(oldPort); err = GXPrintCleanup(); } return(err); } /********************************************************************** * FilterToPrintFirst - return which filter to print first. Return the * first filter that shows up on the first page in the page range. **********************************************************************/ short FilterToPrintFirst(long firstPage, Rect *uRect) { short filtNum = 0; short pageNum = 1; FActionHandle fa; FilterRecord fr; short v = 0; while (pageNum < firstPage) { fr = FR[filtNum]; //"draw" the filter v += 4*(Win->vPitch); if (fr.conjunction!=cjIgnore) { v += Win->vPitch; } for (fa=fr.actions;fa;fa=(*fa)->next) { if ((*fa)->action==flkNone) continue; v += Win->vPitch; } //we skipped this filter. filtNum++; //have we "filled" a page? if (v+FiltPrintLines(filtNum,uRect)*Win->vPitch>uRect->bottom-GetRLong(PRINT_H_MAR)) { pageNum++; v = uRect->top+GetRLong(PRINT_H_MAR); } } return (filtNum); } /********************************************************************** * GXPrintAFilter - print a single filter, GX version. This sets the * port to GXPortPtr. **********************************************************************/ OSErr GXPrintAFilter(CGrafPtr GXPortPtr, short which, Rect *uRect, gxRectangle *GXuRect, short *v, short *page, long firstPage, long numPages) { Str255 scratch, string; OSErr err = noErr; short h = uRect->left + (GetRLong(NICK_PRINT_NICK_PER)*RectWi(*uRect))/100; FActionHandle fa; FilterRecord fr = FR[which]; gxFormat pageFormat = GXGetJobFormat(GXPageSetup, 1); Point penLoc; //This will allow cmd-. to stop printing. GXIdleJob(GXPageSetup); MiniEvents(); if (CommandPeriod) return(errEndOfDocument); SetPort((GrafPtr)GXPortPtr); //all printing will be done to this port ... /* * need new page? */ if (*page == 0 || *v+FiltPrintLines(which,uRect)*Win->vPitch>uRect->bottom-GetRLong(PRINT_H_MAR)) { GetWTitle(GetMyWindowWindowPtr(Win), scratch); //finish current page if (*page != 0) { MyGXInstallQDTranslator(GXPortPtr, GXuRect, &gGXPrintViewPort, true); PrintBottomHeader(*page + firstPage - 1, uRect); MyGXRemoveQDTranslator(GXPortPtr); GXFinishPage(GXPageSetup); } //return if the next page is past the last page in the page range if ((numPages < INT_MAX) && (*page + firstPage > firstPage + numPages - 1)) return (errEndOfDocument); //start new page GXStartPage(GXPageSetup, (*page)+firstPage, pageFormat, 1, &gGXPrintViewPort); err = GXGetJobError(GXPageSetup); if (err != noErr) return (err); (*page)++; *v = uRect->top+GetRLong(PRINT_H_MAR); MyGXInstallQDTranslator(GXPortPtr, GXuRect, &gGXPrintViewPort, true); PrintMessageHeader(scratch, *page + firstPage - 1, GetRLong(PRINT_H_MAR), *v, uRect->left, uRect->right); MyGXRemoveQDTranslator(GXPortPtr); } /* * print the name & types */ MyGXInstallQDTranslator(GXPortPtr, GXuRect, &gGXPrintViewPort, true); *v += Win->vPitch; MoveTo(uRect->left,*v); BoldString(fr.name); if (GetPortPenLocation(GetQDGlobalsThePort(),&penLoc)->hvPitch; /* * print the terms */ MoveTo(h,*v); FiltPrintTerm(fr.terms); if (fr.conjunction!=cjIgnore) { *v += Win->vPitch; MoveTo(h,*v); DrawChar(' '); BoldRString(FiltConjPrintStrn+fr.conjunction); DrawChar(' '); FiltPrintTerm(fr.terms+1); } MoveTo(h,*v+(Win->vPitch*2)/3); Hairline(True); Line(72,0); Hairline(False); *v += Win->vPitch; /* * print the actions */ for (fa=fr.actions;fa;fa=(*fa)->next) { if ((*fa)->action==flkNone) continue; *v += Win->vPitch; MoveTo(h,*v); GetMenuItemText(ActionMenu,(*fa)->action,scratch); BoldString(scratch); DrawChar(' '); CallAction(faePrint,fa,nil,nil); } /* * and leave a blank line */ *v += Win->vPitch; MyGXRemoveQDTranslator(GXPortPtr); return(err); } #endif //GX_PRINTING /********************************************************************** * **********************************************************************/ void FiltPrintTerm(MTPtr term) { if (!EqualStrRes(term->header,FILTER_ANY) && !EqualStrRes(term->header,FILTER_ADDRESSEE) && !EqualStrRes(term->header,FILTER_BODY)) { BoldRString(JUST_PLAIN_HEADER); DrawChar(' '); } DrawString(term->header); DrawChar(' '); BoldRString(FiltVerbPrintStrn+term->verb); DrawChar(' '); if (term->verb!=mbmAppears && term->verb!=mbmNotAppears) DrawString(term->value); } /********************************************************************** * FiltPrintLines - how many lines will a filter take? **********************************************************************/ short FiltPrintLines(short which,Rect *uRect) { short lines = 3; // filter name & condition FActionHandle fa; Str255 name; PCopy(name,FR[which].name); if (FR[which].conjunction!=cjIgnore) lines++; for (fa=FR[which].actions;fa;fa=(*fa)->next) if ((*fa)->action!=flkNone) lines++; return(lines); } #pragma segment Balloon typedef enum { fhFirstTwo=1, /* descriptions of the first four controls; up, down, new, remove */ fhFilterTypes=3, /* in, out, manual */ fhList=9, /* list box */ fhHeader, /* header text boxes */ fhValue, /* value text boxes */ fhGreyNoSel, /* something is grey because no selection */ fhGreyOne, /* something is grey because only one term in use */ fhMatchType, /* match type help base */ fhConjunction=fhMatchType+mbmLimit-1, /* help for the conjunction */ fhDate=fhConjunction+cjLimit-1, /* date rectangle */ fhNone, fhAction, } FilterHelpEnum; /************************************************************************ * FilterHelp - balloon help for the filter window ************************************************************************/ void FilterHelp(MyWindowPtr win,Point mouse) { #pragma unused(win) Rect r; FilterHelpEnum fh=0; FilterHelpEnum greyFH=0; short part; ControlHandle cntl; short cNum; Str255 message; Str255 grey; FActionHandle fa; short i; short percent = 80; *message = 0; greyFH = Selected ? fhGreyOne : fhGreyNoSel; /* * help on controls */ if (part=FindControl(mouse,GetMyWindowWindowPtr(win),&cntl)) { for (cNum=0;cNumnext) { r = Rects[flrAct1+i]; if (PtInRect(mouse,&r)) { if ((*fa)->action==flkNone) fh = fhNone; else { *message = 0; CallAction(faeHelp,fa,&r,message); fh = fhAction+1; if (!*message) {percent=20; GetIndString(message,526,(*fa)->action);} //Dprintf("\p1 %d.%d %d.%d <%d> Ò%pÓ;g",r.left,r.top,r.right,r.bottom,fh,message); } goto display; } } } return; } display: if (fh==fhList) { MyBalloon(&r,90,0,0,FILT_LIST_HELP_PICT,nil); } else if (fh) { if (!*message) { GetRString(message,FILT_HELP_STRN+fh); if (greyFH) { GetRString(grey,FILT_HELP_STRN+greyFH); PSCat(message,grey); } } //Dprintf("\p2 %d.%d %d.%d <%d> Ò%pÓ;g",r.left,r.top,r.right,r.bottom,fh,message); MyBalloon(&r,percent,0,0,0,message); } } /********************************************************************** * FAflkNone - no action **********************************************************************/ short FAflkNone(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { return(noErr); } /********************************************************************** * FAflkStop - stop filtering now **********************************************************************/ short FAflkStop(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { switch (callType) { case faeInit: case faeResize: case faeDraw: case faeClose: case faeDispose: case faeRead: break; case faeWrite: return(FWriteBool(*(short*)dataPtr,(*action)->action,True)); case faeButton: case faeClick: case faeSave: break; #ifdef FANCY_FILT_LDEF case faeListDraw: { Point old; GetPortPenLocation(GetQDGlobalsThePort(),&old); r->right -= 10; MoveTo(r->right+2,old.v); PlotTinyIconAtPenID(ttNone,STOP_ICON); MoveTo(old.h,old.v); break; } #endif case faeDo: return(euFilterStop); break; } return(noErr); } /********************************************************************** * FAflkJunk - junk the current message **********************************************************************/ short FAflkJunk(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { OSErr err = noErr; FilterPBPtr fpb = (FilterPBPtr)dataPtr; TOCHandle junkTOC = NULL; switch (callType) { case faeInit: case faeResize: case faeDraw: case faeClose: case faeDispose: case faeRead: break; case faeWrite: return(FWriteBool(*(short*)dataPtr,(*action)->action,True)); case faeButton: case faeClick: case faeSave: break; #ifdef FANCY_FILT_LDEF case faeListDraw: { Point old; GetPortPenLocation(GetQDGlobalsThePort(),&old); r->right -= 10; MoveTo(r->right+2,old.v); PlotTinyIconAtPenID(ttNone,STOP_ICON); MoveTo(old.h,old.v); break; } #endif case faeDo: if (HasFeature (featureJunk)) { // locate proper Junk mailbox if ((*fpb->tocH)->imapTOC) junkTOC = LocateIMAPJunkToc(fpb->tocH, true,true); else junkTOC = GetSpecialTOC(JUNK); if (junkTOC) { UseFeature (featureJunk); err = Junk(fpb->tocH,fpb->sumNum,true,false); if (!err && ((fpb->tocH)!=junkTOC)) { if (junkTOC) { fpb->spec = GetMailboxSpec(junkTOC,-1); fpb->xferred = True; fpb->dontUser = true; } err = euFilterXfered; } } if (err && err!=euFilterXfered) err = euFilterStop; // continue filtering rest of messages in spite of error } return(err); break; } return(noErr); } /********************************************************************** * FAflkPrint - print one **********************************************************************/ short FAflkPrint(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FilterPBPtr fpb = (FilterPBPtr)dataPtr; switch (callType) { case faeInit: case faeResize: case faeDraw: case faeClose: case faeDispose: case faeRead: break; case faeWrite: return(FWriteBool(*(short*)dataPtr,(*action)->action,True)); case faeButton: case faeClick: case faeSave: break; case faeDo: //Enhanced Filters - the print filter action is not supported in Light if (HasFeature (featureFilterPrint)) { UseFeature (featureFilterPrint); #ifdef IMAP // if this is an IMAP message, make sure it's been downloaded. if ((*fpb->tocH)->imapTOC) { Boolean filteringUnderway = IMAPFilteringUnderway(); if (filteringUnderway) IMAPStopFiltering(false); EnsureMsgDownloaded(fpb->tocH, fpb->sumNum, false); if (filteringUnderway) IMAPStartFiltering(fpb->tocH, true); } #endif fpb->print = True; } break; } return(noErr); } /********************************************************************** * FAFlkTransfer - transfer message to another mailbox **********************************************************************/ typedef struct { ControlHandle button; FSSpec spec; Boolean brandNew; } FDflkTransfer, *FDflkTransferPtr, **FDflkTransferHandle; short FAflkTransfer(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FDflkTransfer f; OSErr err = noErr; Str255 s; FDflkTransferHandle data = (FDflkTransferHandle)(*action)->data; Rect tempR; Boolean copy = (*action)->action==flkCopy; FilterPBPtr fpb = (FilterPBPtr)dataPtr; FSSpec curSpec; TOCHandle toTocH; switch (callType) { /* * initialize for the window */ case faeInit: f.button = GetNewControlSmall(FILT_CNTL_BASE+flNewButton,GetMyWindowWindowPtr(Win)); if (!f.button) { err = ResError(); break; } (*data)->button = f.button; f.spec = (*data)->spec; MailboxSpecAlias(&f.spec,s); SetControlTitle(f.button,s); EmbedControl(f.button,ActionGroup); /* fall-through */ case faeResize: f.button = (*data)->button; ButtonFit(f.button); FASingleRect(r,&tempR,ControlHi(f.button)); if (RectWi(tempR)>BUTTON_REASONABLE) tempR.right = tempR.left+BUTTON_REASONABLE; MoveMyCntl(f.button,tempR.left,tempR.top,RectWi(tempR),0); ShowControl(f.button); if ((*data)->brandNew) goto buttonHit; break; /* * close for window */ case faeDispose: case faeClose: if (data) { if ((*data)->button) DisposeControl((*data)->button); (*data)->button = nil; } break; /* * do we care that a mailbox was renamed? */ case faeMBWillRename: curSpec = (*data)->spec; if (SameSpec(&curSpec,&((MBRenamePBPtr)dataPtr)->oldSpec)) err = 1; break; case faeMBDidRename: curSpec = (*data)->spec; if (SameSpec(&curSpec,&((MBRenamePBPtr)dataPtr)->oldSpec)) { (*data)->spec = ((MBRenamePBPtr)dataPtr)->newSpec; if (FLG && Win && (*data)->button) SetControlTitle((*data)->button,((MBRenamePBPtr)dataPtr)->newSpec.name); } break; /* * read in data */ case faeRead: Zero(f); if (dataPtr) { BoxSpecByName(&f.spec,dataPtr); f.brandNew = False; } else f.brandNew = True; data = NewZH(FDflkTransfer); if (!data) err = MemError(); else { **data = f; (*action)->data = (Handle)data; } break; /* * find */ case faeFind: PCopy(s,(*data)->spec.name); err = PFindSub(dataPtr,s)!=nil; break; #ifdef FANCY_FILT_LDEF /* * draw the item */ case faeListDraw: { Point old; GetPortPenLocation(GetQDGlobalsThePort(),&old); r->right -= 10; MoveTo(r->right+2,old.v); PlotTinyIconAtPenID(ttNone,copy?COPY_ICON:TRANSFER_ICON); if ((*action)->action==flkTransfer) FAflkStop(callType,action,r,dataPtr); MoveTo(old.h,old.v); break; } #endif /* * print */ case faePrint: PCopy(s,(*data)->spec.name); DrawString(s); break; /* * write it out */ case faeWrite: f.spec = (*data)->spec; if (Box2Path(&f.spec,s)) PCopy(s,(*data)->spec.name); if (*s) err = FWriteKey(*(short*)dataPtr,(*action)->action,s); break; /* * button */ case faeButton: f.button = (ControlHandle)dataPtr; if (f.button==(*data)->button) { buttonHit: if ((*data)->brandNew) UpdateMyWindow(GetMyWindowWindowPtr(Win)); (*data)->brandNew = False; if (ChooseMailbox(TRANSFER_MENU,CHOOSE_MBOX_TRANSFER,&f.spec)) { SetControlTitle(f.button,MailboxSpecAlias(&f.spec,s)); (*data)->spec = f.spec; Win->isDirty = CurrentDirty = True; } return(True); } break; case faeHelp: if (MouseInControl((*data)->button)) { GetControlBounds((*data)->button,r); GetIndString(dataPtr,526,((*action)->action==flkTransfer ? flkhTransfer:flkhCopy)); } break; case faeDo: if (!(*data)->spec.name) return(0); /* failure */ f = **data; curSpec = GetMailboxSpec(fpb->tocH,-1); if (SameSpec(&curSpec,&f.spec)) return(euFilterStop); if (!copy && fpb->openMessage) (*fpb->tocH)->sums[fpb->sumNum].opts |= OPT_OPEN; if (!copy && fpb->print) { short oldstat = (*fpb->tocH)->sums[fpb->sumNum].state; #ifdef IMAP // if this is an IMAP message, make sure it's been downloaded before we try to print it if ((*fpb->tocH)->imapTOC) { Boolean filteringUnderway = IMAPFilteringUnderway(); if (filteringUnderway) IMAPStopFiltering(false); EnsureMsgDownloaded(fpb->tocH, fpb->sumNum, false); if (filteringUnderway) IMAPStartFiltering(fpb->tocH, true); } #endif PrintClosedMessage(fpb->tocH,fpb->sumNum,True); SetState(fpb->tocH,fpb->sumNum,oldstat); } (*fpb->tocH)->sums[fpb->sumNum].flags |= FLAG_SKIPWARN; // if this is a transfer to or from an IMAP mailbox, do the transfer in the foreground. toTocH = TOCBySpec(&f.spec); if (((*fpb->tocH)->imapTOC) || (toTocH && (*toTocH)->imapTOC)) { err = IMAPMoveMessageDuringFiltering(fpb->tocH, fpb->sumNum, toTocH, (*action)->action==flkCopy, fpb); } else err = MoveMessageLo(fpb->tocH,fpb->sumNum,&f.spec,(*action)->action==flkCopy,false,true); if (!err) { if (!copy) { fpb->xferred = True; #ifdef IMAP if ((*fpb->tocH)->imapTOC) fpb->xferredFromIMAP = True; #endif fpb->spec = f.spec; err = euFilterXfered; } else if ((fpb->doReport || PrefIsSet(PREF_REPORT)) && !fpb->dontReport) AddSpecToList(&f.spec,fpb->report); } if (err && err!=euFilterXfered) err = euFilterStop; // continue filtering rest of messages in spite of error break; } return(err); } /********************************************************************** * FAflkMoveAttach - move attachments **********************************************************************/ typedef struct { ControlHandle button; FSSpec spec; Boolean brandNew; } FDflkMVA, *FDflkMVAPtr, **FDflkMVAHandle; short FAflkMoveAttach(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FDflkMVA f; OSErr err = noErr; Str255 s; FDflkMVAHandle data = (FDflkMVAHandle)(*action)->data; Rect tempR; FilterPBPtr fpb = (FilterPBPtr)dataPtr; switch (callType) { /* * initialize for the window */ case faeInit: f.button = GetNewControlSmall(FILT_CNTL_BASE+flNewButton,GetMyWindowWindowPtr(Win)); if (!f.button) { err = ResError(); break; } (*data)->button = f.button; f.spec = (*data)->spec; if ((*data)->brandNew || GetDirName(nil,f.spec.vRefNum,f.spec.parID,s)) *s = 0; SetControlTitle(f.button,s); EmbedControl(f.button,ActionGroup); /* fall-through */ case faeResize: f.button = (*data)->button; ButtonFit(f.button); FASingleRect(r,&tempR,ControlHi(f.button)); if (RectWi(tempR)>BUTTON_REASONABLE) tempR.right = tempR.left+BUTTON_REASONABLE; MoveMyCntl(f.button,tempR.left,tempR.top,RectWi(tempR),0); ShowControl(f.button); if ((*data)->brandNew) goto buttonHit; break; /* * close for window */ case faeDispose: case faeClose: if (data) { if ((*data)->button) DisposeControl((*data)->button); (*data)->button = nil; } break; /* * do we care that a mailbox was renamed? */ case faeMBWillRename: break; case faeMBDidRename: break; /* * read in data */ case faeRead: Zero(f); f.spec = AttFolderSpec; if (dataPtr) { StringToNum(dataPtr,&f.spec.parID); f.brandNew = False; if (GetDirName(nil,f.spec.vRefNum,f.spec.parID,s)) f.spec = AttFolderSpec; } else f.brandNew = True; data = NewZH(FDflkMVA); if (!data) err = MemError(); else { **data = f; (*action)->data = (Handle)data; } break; /* * find */ case faeFind: PCopy(s,(*data)->spec.name); err = PFindSub(dataPtr,s)!=nil; break; #ifdef FANCY_FILT_LDEF /* * draw the item */ case faeListDraw: break; #endif /* * print */ case faePrint: PCopy(s,(*data)->spec.name); DrawString(s); break; /* * write it out */ case faeWrite: f.spec = (*data)->spec; NumToString(f.spec.parID,s); if (*s) err = FWriteKey(*(short*)dataPtr,(*action)->action,s); break; /* * button */ case faeButton: f.button = (ControlHandle)dataPtr; if (f.button==(*data)->button) { buttonHit: (*data)->brandNew = False; if (GetFolder(s,&f.spec.vRefNum,&f.spec.parID,True,True,True,True)) { if (f.spec.vRefNum!=AttFolderSpec.vRefNum) { WarnUser(SAME_VOLUME_DUMMY,0); goto buttonHit; } *f.spec.name = 0; GetDirName(nil,f.spec.vRefNum,f.spec.parID,s); SetControlTitle(f.button,s); (*data)->spec = f.spec; Win->isDirty = CurrentDirty = True; } return(True); } break; case faeHelp: if (MouseInControl((*data)->button)) { GetControlBounds((*data)->button,r); GetIndString(dataPtr,526,((*action)->action==flkTransfer ? flkhTransfer:flkhCopy)); } break; case faeDo: f = **data; if ((*fpb->tocH)->sums[fpb->sumNum].flags&FLAG_HAS_ATT) #ifdef IMAP { if ((*fpb->tocH)->imapTOC) { Boolean filteringUnderway = IMAPFilteringUnderway(); // deselect the current message. It may or may not go away, and it will just confuse the filtering process to keep it highlighted. (*fpb->tocH)->sums[fpb->sumNum].selected = false; InvalSum(fpb->tocH,fpb->sumNum); // Filtering takes place in the foreground. Free up the connection for the upcoming transfer if (filteringUnderway) IMAPStopFiltering(false); EnsureMsgDownloaded(fpb->tocH, fpb->sumNum, false); if (FetchAllIMAPAttachments(fpb->tocH, fpb->sumNum, true)) { MovingAttachmentsLo(fpb->tocH,fpb->sumNum,True,False,False,false,nil,&f.spec); } // go back to filtering if (filteringUnderway) IMAPStartFiltering(fpb->tocH, true); } else #endif MovingAttachmentsLo(fpb->tocH,fpb->sumNum,True,False,False,false,nil,&f.spec); #ifdef IMAP } #endif break; } return(err); } /************************************************************************ * SetNewAndOther - enable/disable "New" and/or "Other" mailbox menu items ************************************************************************/ static void SetNewAndOther(short menu,short newItem,short firstUserItem,Boolean disableNew,Boolean disableOther) { MenuHandle mh; short menuCount,subID,item; if (mh = GetMHandle(menu)) { EnableIf(mh,newItem,!disableNew); EnableIf(mh,newItem+1,!disableOther); // Other item menuCount = CountMenuItems(mh); for(item=firstUserItem;item<=menuCount;item++) if (subID = SubmenuId(mh,item)) // Do submenu with recursion SetNewAndOther(subID,1,3,disableNew,disableOther); } } /************************************************************************ * DisableRemoteMailboxes - disable IMAP mailbox menu items ************************************************************************/ static void DisableRemoteMailboxes(short menu, Boolean restore) { MenuHandle mh; short c; PersHandle p; Boolean disable; Str255 itemText; short vRef; long dirId; short it; if (mh = GetMHandle(menu)) { // the caller has asked for a local mailbox. Disable IMAP malboxes in this menu. for (c = 1; c <= CountMenuItems(mh); c++) { MyGetItem(mh,c,itemText); disable = false; for (p = PersList; p && !disable; p = (*p)->next) { if (StringSame((*p)->name,itemText) && IsIMAPPers(p)) { // This item has the same name as an IMAP personality it = SubmenuId(mh,c); if (it) { MenuID2VD(it,&vRef,&dirId); if (IsIMAPVD(vRef, dirId)) { // this item *is* an IMAP personality menu disable = true; } } } } if (disable) EnableIf(mh, c, restore); } } } /************************************************************************ * ChooseMailboxLo - select a mailbox from Mailboxes or Transfer menu * Allow disabling of new and other mailboxes ************************************************************************/ Boolean ChooseMailboxLo(short menu, PStr msgStr, FSSpecPtr spec, Boolean disableNew, Boolean disableOther, Boolean disableRemote) { short mId; WindowPtr theWindow; EventRecord event; DialogPtr dgPtr; MyWindowPtr dgPtrWin; Boolean rslt = False; PushGWorld(); /* * put up message and disable all but transfer */ for (mId=APPLE_MENU;mId>16)&0xffff; itm = mSelect & 0xffff; if (mnu==menu || IsMailboxSubmenu(mnu)) { rslt=GetTransferParams(mnu,itm,spec,nil); } HiliteMenu(0); } } DisposDialog_(dgPtr); EnableMenus(FrontWindow_(),False); DirtyHackForChooseMailbox = false; if (disableNew || disableOther) // Restore "New" and "Other" mailbox menu items SetNewAndOther(menu,MAILBOX_NEW_ITEM,MAILBOX_FIRST_USER_ITEM,false,false); if (disableRemote) // The caller has asked for local mailboxes only. DisableRemoteMailboxes(menu, true); PopGWorld(); return(rslt); } /************************************************************************ * ChooseMailbox - select a mailbox from Mailboxes or Transfer menu ************************************************************************/ Boolean ChooseMailbox(short menu, short msg, FSSpecPtr spec) { Str255 msgStr; return ChooseMailboxLo(menu,GetRString(msgStr,msg),spec,false,false,false); } /********************************************************************** * FASingleRect - size a single rectangle in an action area **********************************************************************/ void FASingleRect(Rect *inRect, Rect *r,short hi) { Rect popup = *inRect; short lines; FAPopup(&popup); lines = (RectHi(*inRect)-3*INSET)/Win->vPitch; if (lines<=1 || hi) { *r = popup; r->left = popup.right+2*INSET; r->right = inRect->right - 2*INSET; if (hi) r->bottom = r->top+hi; } else { hi = Win->vPitch*((RectHi(*inRect)-Win->vPitch-2*INSET)/Win->vPitch) + 2*TE_VMARGIN; r->top = popup.bottom + (inRect->bottom-popup.bottom-hi)/2; SetRect(r,popup.left+GROW_SIZE,r->top,inRect->right-GROW_SIZE,r->top+hi); } } /********************************************************************** * **********************************************************************/ void FAPopActRect(Rect *inRect, Rect *r) { short wi; *r = *inRect; FAPopup(r); wi = RectWi(*r); r->left = r->right + 2*INSET; r->right = inRect->right - 2*INSET; } /********************************************************************** * FAMultRect - size multiple rectangles in an action area **********************************************************************/ void FAMultRect(Rect *inRect, Rect *r,short *spacing,short hi,short n) { Rect overall; FASingleRect(inRect,&overall,0); *spacing = (RectHi(overall)>2*Win->vPitch) ? 2*INSET : INSET; if (hi) { OffsetRect(&overall,0,(RectHi(overall)-hi)/2); overall.bottom = overall.top + hi; } overall.right = overall.left + (RectWi(overall)-(n-1)*(*spacing))/n; *r = overall; } #pragma segment FiltActions /********************************************************************** * **********************************************************************/ short FAflkCopy(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { return(FAflkTransfer(callType,action,r,dataPtr)); } /********************************************************************** * **********************************************************************/ short FAflkTranslit(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { return(noErr); } typedef struct { Rect r; long status; ControlHandle popup; } FDflkStatus, **FDflkStatusHandle; /********************************************************************** * **********************************************************************/ short FAflkStatus(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FDflkStatusHandle data; FDflkStatus f; Str255 s; OSErr err = noErr; FilterPBPtr fpb = (FilterPBPtr)dataPtr; short item; Rect controlR; data = (void*)(*action)->data; switch (callType) { case faeInit: f = **data; f.popup = GetNewControlSmall(FILT_STATUS_POP,GetMyWindowWindowPtr(Win)); if (!f.popup) { FAflkStatus(faeDispose,action,nil,nil); return(MEM_ERR); } item = Status2Item(f.status); MySetCtlValue(f.popup,item); EmbedControl(f.popup,ActionGroup); **data = f; // fall-through case faeResize: f = **data; FAPopupValueFit(r,f.popup); ShowControl(f.popup); break; case faeHelp: FAPopActRect(r,&controlR); if (MouseInRect(&controlR)) { *r = controlR; GetIndString(dataPtr,526,flkhStatus); } break; case faeDraw: f = **data; if (f.popup) { MenuHandle mh = GetMHandle(STATE_HIER_MENU); CGrafPtr WinPort = GetMyWindowCGrafPtr (Win); EnableItem(mh,0); Update1Control(f.popup,MyGetPortVisibleRegion(WinPort)); #ifdef GRIDLINES ControlGridlines(f.popup); #endif } break; case faeRead: data = NuHandleClear(sizeof(FDflkStatus)); /* if we can't find a dozen bytes, we're dead */ if (!data) return(MemError()); (*action)->data = (void*)data; if (dataPtr) { StringToNum(dataPtr,&f.status); (*data)->status = f.status; } else (*data)->status = UNREAD; // gotta be something break; case faePrint: MyGetItem(GetMHandle(STATE_HIER_MENU),Status2Item((*data)->status),s); DrawString(s); break; case faeWrite: NumToString((*data)->status,s); err = FWriteKey(*(short*)dataPtr,flkStatus,s); break; case faeButton: f = **data; item = GetControlValue(f.popup); item = Item2Status(item); if (item!=f.status) { f.status = item; Win->isDirty = CurrentDirty = True; **data = f; } break; case faeFind: MyGetItem(GetMHandle(STATE_HIER_MENU),(*data)->status,s); err = PFindSub(dataPtr,s)!=nil; break; case faeClick: break; case faeClose: case faeDispose: if (data) { f = **data; if (f.popup) DisposeControl(f.popup); f.popup = nil; **data = f; } break; case faeDo: SetState(fpb->tocH,fpb->sumNum,(*data)->status); break; } return(err); } /********************************************************************** * FAflkSubject - change a subject **********************************************************************/ typedef struct FDflkSubject **FDflkSubjectHandle; typedef struct FDflkSubject { PETEHandle pte; Str255 subject; } FDflkSubject; short FAflkSubject(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FDflkSubjectHandle data = (FDflkSubjectHandle)(*action)->data; FDflkSubject f; Rect textR; OSErr err = noErr; Str255 s; FilterPBPtr fpb = (FilterPBPtr)dataPtr; switch (callType) { case faeInit: SetRect(&textR,0,0,0,0); if (err=PeteCreate(Win,&f.pte,0,nil)) return(WarnUser(PETE_ERR,err)); PeteFontAndSize(f.pte,GetPortTextFont(GetQDGlobalsThePort()),GetPortTextSize(GetQDGlobalsThePort())); (*PeteExtra(f.pte))->frame = True; (*PeteExtra(f.pte))->infinitelyWide = True; PCopy(s,(*data)->subject); PeteSetString(s,f.pte); (*data)->pte = f.pte; PETESetCallback(PETE,f.pte,(void*)FilterChanged,peDocChanged); /* fall through */ case faeResize: FASingleRect(r,&textR,ONE_LINE_HI(Win)); PeteDidResize((*data)->pte,&textR); break; case faeNew: PeteFocus(Win,(*data)->pte,true); break; case faeDraw: break; case faeFind: err = PeteFindString(dataPtr,0,(*data)->pte)>=0; break; case faePrint: PCopy(s,(*data)->subject); DrawString(s); break; case faeCursor: if (PtInPETE(*(Point*)r,(*data)->pte)) *(short*)dataPtr = iBeamCursor; else *(short*)dataPtr = arrowCursor; break; case faeDispose: case faeClose: if (data) { PeteDispose(Win,(*data)->pte); (*data)->pte = nil; } break; case faeRead: data = NewZH(FDflkSubject); if (!data) return(WarnUser(MEM_ERR,MemError())); else { (*action)->data = (void*)data; if (dataPtr) PCopy((*data)->subject,(UPtr)dataPtr); } break; case faeWrite: PCopy(s,(*data)->subject); if (*s) err = FWriteKey(*(short*)dataPtr,flkSubject,s); break; case faeHelp: if (MouseInPTE((*data)->pte)) { PeteRect((*data)->pte,r); GetIndString(dataPtr,526,flkhSubject); } break; case faeClick: if (PtInPETE(*(Point*)r,(*data)->pte)) { PeteEditWFocus(Win,(*data)->pte,peeEvent,dataPtr,nil); err = True; /* actually, not an error, but... */ } break; case faeSave: PeteSString(s,(*data)->pte); PCopy((*data)->subject,s); break; case faeDo: PCopy(s,(*data)->subject); NonSequitur(s,fpb->tocH,fpb->sumNum); break; } return(err); } /********************************************************************** * FAflkLabel - set the label for a message **********************************************************************/ typedef struct FDflkLabel **FDflkLabelHandle; typedef struct FDflkLabel { long color; Rect r; ControlHandle popup; } FDflkLabel; short FAflkLabel(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FDflkLabelHandle data; FDflkLabel f; RGBColor oldColor,color; Str255 s; OSErr err = noErr; FilterPBPtr fpb = (FilterPBPtr)dataPtr; short item; data = (void*)(*action)->data; switch (callType) { case faeInit: f = **data; f.popup = GetNewControlSmall(FILT_LABEL_POP,GetMyWindowWindowPtr(Win)); if (!f.popup) { FAflkStatus(faeDispose,action,nil,nil); return(MEM_ERR); } **data = f; FAflkLabel(faeMouseGoingDown,action,r,dataPtr); MySetCtlValue(f.popup,Label2Menu(f.color)); EmbedControl(f.popup,ActionGroup); // fall-through case faeResize: f = **data; FAPopupValueFit(r,f.popup); ShowControl(f.popup); break; case faeClose: case faeDispose: if (data) { f = **data; if (f.popup) DisposeControl(f.popup); f.popup = nil; **data = f; } break; case faeButton: f = **data; item = GetControlValue(f.popup); item = Menu2Label(item); if (item!=f.color) { f.color = item; Win->isDirty = CurrentDirty = True; **data = f; } break; case faeMouseGoingDown: { MenuHandle mh; f = **data; if (f.popup && (mh = GetControlPopupMenuHandle(f.popup))) { TrashMenu(mh,3); AddFinderItems(mh); SetItemMark(mh,1,noMark); SetItemMark(mh,GetControlValue(f.popup),diamondChar); EnableItem(mh,0); SetControlMaximum(f.popup,CountMenuItems(mh)); } break; } case faeHelp: FAPopActRect(r,&f.r); if (MouseInRect(&f.r)) { *r = f.r; GetIndString(dataPtr,526,flkhLabel); } break; case faeDraw: f = **data; if (f.popup) { CGrafPtr WinPort = GetMyWindowCGrafPtr (Win); MenuHandle mh = GetMHandle(LABEL_HIER_MENU); EnableItem(mh,0); Update1Control(f.popup,MyGetPortVisibleRegion(WinPort)); #ifdef GRIDLINES ControlGridlines(f.popup); #endif } break; case faeRead: data = NewZH(FDflkLabel); /* if we can't find a dozen bytes, we're dead */ if (!data) return(MemError()); (*action)->data = (void*)data; if (dataPtr) { StringToNum(dataPtr,&f.color); (*data)->color = f.color; } break; case faePrint: //No labels in Light, no label menu if (HasFeature (featureFilterLabel)) { MyGetLabel((*data)->color,&color,s); if (ThereIsColor) { GetForeColor(&oldColor); RGBForeColor(&color); } DrawString(s); if (ThereIsColor) RGBForeColor(&oldColor); } break; case faeWrite: NumToString((*data)->color,s); err = FWriteKey(*(short*)dataPtr,flkLabel,s); break; case faeFind: //No labels in Light, no label menu if (HasFeature (featureFilterLabel)) { MyGetLabel((*data)->color,&color,s); err = PFindSub(dataPtr,s)!=nil; } break; #ifdef FANCY_FILT_LDEF case faeListDraw: //No labels in Light, no label menu if (HasFeature (featureFilterLabel)) { MyGetLabel((*data)->color,&color,s); if (ThereIsColor && !BlackWhite(&color)) RGBForeColor(DarkenColor(&color,GetRLong(TEXT_DARKER))); } break; #endif case faeDo: //No labels in Light, no label menu if (HasFeature (featureFilterLabel)) { UseFeature (featureFilterLabel); SetSumColor(fpb->tocH,fpb->sumNum,(*data)->color); } break; } return(err); } /********************************************************************** * FAflkPersonality - set the label for a message **********************************************************************/ typedef struct FDflkPers **FDflkPersHandle; typedef struct FDflkPers { long persId; Rect r; ControlHandle popup; } FDflkPers; short FAflkPersonality(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { OSErr err = noErr; Str255 s; FilterPBPtr fpb; PersHandle pers; uLong persId; Rect localR; FDflkPersHandle data; FDflkPers f; short item; if (!HasFeature (featureFilterPersonality)) return (err); fpb = (FilterPBPtr)dataPtr; data = (FDflkPersHandle)(*action)->data; if (data) { persId = (uLong)(*data)->persId; pers = PERS_FORCE(FindPersById(persId)); f = **data; } switch (callType) { case faeInit: f = **data; f.popup = GetNewControlSmall(FILT_PERS_POP,GetMyWindowWindowPtr(Win)); if (!f.popup) { FAflkPersonality(faeDispose,action,nil,nil); return(MEM_ERR); } **data = f; FAflkPersonality(faeMouseGoingDown,action,r,dataPtr); item = Pers2Index(pers); if (item>0) item+=2; else item+=1; MySetCtlValue(f.popup,item); EmbedControl(f.popup,ActionGroup); // fall-through case faeResize: f = **data; FAPopupValueFit(r,f.popup); ShowControl(f.popup); break; case faeDraw: f = **data; if (f.popup) { MenuHandle mh = GetMHandle(PERS_HIER_MENU); CGrafPtr WinPort = GetMyWindowCGrafPtr (Win); EnableItem(mh,0); Update1Control(f.popup,MyGetPortVisibleRegion(WinPort)); #ifdef GRIDLINES ControlGridlines(f.popup); #endif } break; case faeClose: case faeDispose: if (data) { f = **data; if (f.popup) DisposeControl(f.popup); f.popup = nil; **data = f; } break; case faeButton: f = **data; item = Pers2Index(pers); if (item) item += 2; else item++; if (item!=GetControlValue(f.popup)) { item = GetControlValue(f.popup); item--; if (item) item--; f.persId = (*Index2Pers(item))->persId; Win->isDirty = CurrentDirty = True; **data = f; } break; case faeMouseGoingDown: { MenuHandle mh; Str255 string; f = **data; if (f.popup && (mh = GetControlPopupMenuHandle(f.popup))) { TrashMenu(mh,3); for (pers=(*PersList)->next;pers;pers=(*pers)->next) MyAppendMenu(mh,PCopy(string,(*pers)->name)); SetItemMark(mh,1,noMark); SetItemMark(mh,GetControlValue(f.popup),diamondChar); EnableItem(mh,0); SetControlMaximum(f.popup,CountMenuItems(mh)); } } case faeHelp: FAPopActRect(r,&localR); if (MouseInRect(&localR)) { *r = localR; GetIndString(dataPtr,526,flkhPersonality); } break; case faeRead: data = NewZH(FDflkPers); /* if we can't find a dozen bytes, we're dead */ if (!data) return(MemError()); (*action)->data = (void*)data; if (dataPtr && *(UPtr)dataPtr) persId = (*PERS_FORCE(FindPersByName(dataPtr)))->persId; else persId = 0; (*data)->persId = persId; break; case faePrint: PSCopy(s,(*pers)->name); DrawString(s); break; case faeWrite: if (pers==PersList) *s = 0; else PSCopy(s,(*pers)->name); if (*s) err = FWriteKey(*(short*)dataPtr,flkPersonality,s); else err = FWriteBool(*(short*)dataPtr,flkPersonality,True); break; case faeFind: PSCopy(s,(*pers)->name); err = PFindSub(dataPtr,s)!=nil; break; case faeDo: //Enhanced Filters - the personalities action is not supported in Light if (HasFeature (featureMultiplePersonalities)) { if (pers != PersList) UseFeature (featureFilterPersonality); SetPers(fpb->tocH,fpb->sumNum,pers,False); } break; } return(err); } /********************************************************************** * **********************************************************************/ typedef struct FDflkSound **FDflkSoundHandle; typedef struct FDflkSound { ControlHandle popup; Str255 name; } FDflkSound; short FAflkSound(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FDflkSoundHandle data; FDflkSound f; Str255 s; OSErr err = noErr; FilterPBPtr fpb = (FilterPBPtr)dataPtr; short item; MenuHandle mh; data = (void*)(*action)->data; switch (callType) { case faeInit: f = **data; f.popup = GetNewControlSmall(FILT_SOUND_CNTL,GetMyWindowWindowPtr(Win)); if (!f.popup) { FAflkSound(faeDispose,action,nil,nil); return(MEM_ERR); } mh = (MenuHandle)GetControlPopupMenuHandle(f.popup); AddSoundsToMenu(mh); SetControlMaximum(f.popup,CountMenuItems(mh)); item = FindItemByName(mh,f.name); if (!item) { item = 1; GetMenuItemText(mh,item,f.name); } MySetCtlValue(f.popup,item); EmbedControl(f.popup,ActionGroup); **data = f; /* fall-through */ case faeResize: f = **data; FAPopupValueFit(r,f.popup); ShowControl(f.popup); break; case faeHelp: if (MouseInControl((*data)->popup)) { GetControlBounds((*data)->popup,r); GetIndString(dataPtr,526,flkhSound); } break; case faeDraw: break; case faeRead: data = NewZH(FDflkSound); /* if we can't find a dozen bytes, we're dead */ if (!data) return(MemError()); (*action)->data = (void*)data; if (dataPtr) PCopy((*data)->name,(UPtr)dataPtr); break; case faeWrite: PCopy(f.name,(*data)->name); if (*f.name) err = FWriteKey(*(short*)dataPtr,flkSound,f.name); break; case faeFind: PCopy(f.name,(*data)->name); err = PFindSub(dataPtr,f.name)!=nil; break; case faeButton: f = **data; item = GetControlValue(f.popup); GetMenuItemText((MenuHandle)GetControlPopupMenuHandle(f.popup),item,s); if (*s) PlayNamedSound(s); if (!StringSame(f.name,s)) { Win->isDirty = CurrentDirty = True; PCopy(f.name,s); **data = f; } break; case faeClose: case faeDispose: if (data) { f = **data; if (f.popup) DisposeControl(f.popup); f.popup = nil; **data = f; } break; case faePrint: f = **data; DrawString(f.name); break; case faeDo: //Enhanced Filters - the sound filter action is not supported in Light if (HasFeature (featureFilterSound)) { UseFeature (featureFilterSound); f = **data; if (*f.name) PlayNamedSound(f.name); } break; } return(err); } /********************************************************************** * **********************************************************************/ typedef struct FDflkOpen **FDflkOpenHandle; typedef struct FDflkOpen { long flags; ControlHandle message; ControlHandle mailbox; } FDflkOpen; short FAflkOpenMessage(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FDflkOpenHandle data = (FDflkOpenHandle)(*action)->data; FDflkOpen f; Rect controlR; short spacing; short val; WindowPtr WinWP; ControlHandle button = (ControlHandle)dataPtr; Str63 s; FilterPBPtr fpb = (FilterPBPtr)dataPtr; long flag; switch (callType) { case faeInit: WinWP = GetMyWindowWindowPtr (Win); f.mailbox = GetNewControlSmall(OPEN_BOX_CNTL,WinWP); f.message = GetNewControlSmall(OPEN_MESSAGE_CNTL,WinWP); if (!f.mailbox || !f.message) { FAflkOpenMessage(faeDispose,action,nil,nil); return(MEM_ERR); } f.flags = (*data)->flags; **data = f; MySetCtlValue(f.mailbox,0!=(f.flags&afbOpenMailbox)); MySetCtlValue(f.message,0!=(f.flags&afbOpenMessage)); EmbedControl(f.mailbox,ActionGroup); EmbedControl(f.message,ActionGroup); /* fall-through */ case faeResize: f = **data; ButtonFit(f.mailbox); ButtonFit(f.message); FAMultRect(r,&controlR,&spacing,ControlHi(f.mailbox),2); MoveMyCntl(f.mailbox,controlR.left,controlR.top,RectWi(controlR),0); OffsetRect(&controlR,RectWi(controlR)+spacing,0); MoveMyCntl(f.message,controlR.left,controlR.top,RectWi(controlR),0); ShowControl(f.message); ShowControl(f.mailbox); break; case faeClose: case faeDispose: if (data) { f = **data; if (f.message) DisposeControl(f.message); if (f.mailbox) DisposeControl(f.mailbox); f.mailbox = f.message = nil; **data = f; } break; case faeRead: data = NewZH(FDflkOpen); /* if we can't find a dozen bytes, we're dead */ if (!data) return(MemError()); (*action)->data = (void*)data; if (dataPtr) StringToNum(dataPtr,&f.flags); else f.flags = 0; (*data)->flags = f.flags; break; case faePrint: if ((*data)->flags&afbOpenMailbox) { DrawRString(MAILBOX_PRINT); if ((*data)->flags&afbOpenMessage) { DrawRString(AND_PRINT); DrawRString(MESSAGE_PRINT); } } else if ((*data)->flags&afbOpenMessage) { DrawRString(MESSAGE_PRINT); } break; case faeWrite: NumToString((*data)->flags,s); return(FWriteKey(*(short*)dataPtr,(*action)->action,s)); break; case faeButton: f = **data; val = !GetControlValue(button); MySetCtlValue(button,val); flag = (button==f.mailbox) ? afbOpenMailbox : afbOpenMessage; if (val) (*data)->flags |= flag; else (*data)->flags &= ~flag; break; case faeHelp: f = **data; if (MouseInControl(f.mailbox)) { GetIndString(dataPtr,526,flkhOpenBox); GetControlBounds(f.mailbox,r); } if (MouseInControl(f.message)) { GetIndString(dataPtr,526,flkhOpenMess); GetControlBounds(f.message,r); } break; case faeDo: //Enhanced Filters - the open message filter action is not supported in Light if (HasFeature (featureFilterOpen)) { UseFeature (featureFilterOpen); fpb->openMailbox = 0!=((*data)->flags&afbOpenMailbox); fpb->openMessage = 0!=((*data)->flags&afbOpenMessage); ComposeLogS(LOG_FILT,nil,"\pOpen %d %d",fpb->openMailbox,fpb->openMessage); } break; } return(noErr); } /********************************************************************** * **********************************************************************/ typedef struct FDflkPrior **FDflkPriorHandle; typedef struct FDflkPrior { long prior; Rect r; ControlHandle popup; } FDflkPrior; short FAflkPriority(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FDflkPriorHandle data; FDflkPrior f; Str255 s; OSErr err = noErr; FilterPBPtr fpb = (FilterPBPtr)dataPtr; Rect ir; short item; Point penLoc; data = (void*)(*action)->data; switch (callType) { case faeInit: f = **data; f.popup = GetNewControlSmall(FILT_PRIORITY_POP,GetMyWindowWindowPtr(Win)); if (!f.popup) { FAflkStatus(faeDispose,action,nil,nil); return(MEM_ERR); } item = f.prior ? f.prior : 3; MySetCtlValue(f.popup,item); **data = f; EmbedControl(f.popup,ActionGroup); // fall-through case faeResize: f = **data; FAPopupValueFit(r,f.popup); ShowControl(f.popup); break; case faeHelp: f.r = (*data)->r; if (MouseInRect(&f.r)) { *r = f.r; GetIndString(dataPtr,526,flkhPriority); } break; case faeDraw: f = **data; if (f.popup) { MenuHandle mh = GetMHandle(PRIOR_HIER_MENU); CGrafPtr WinPort = GetMyWindowCGrafPtr (Win); EnableItem(mh,0); Update1Control(f.popup,MyGetPortVisibleRegion(WinPort)); #ifdef GRIDLINES ControlGridlines(f.popup); #endif } break; case faeRead: data = NewZH(FDflkPrior); /* if we can't find a dozen bytes, we're dead */ if (!data) return(MemError()); (*action)->data = (void*)data; if (dataPtr) { StringToNum(dataPtr,&f.prior); (*data)->prior = f.prior; } break; case faeFind: GetRString(s,PRIOR_STRN+(*data)->prior); err = PFindSub(dataPtr,s)!=nil; break; case faeWrite: NumToString((*data)->prior,s); err = FWriteKey(*(short*)dataPtr,flkPriority,s); break; case faeButton: f = **data; item = GetControlValue(f.popup); if (item!=f.prior) { f.prior = item; Win->isDirty = CurrentDirty = True; **data = f; } break; case faeClose: case faeDispose: if (data) { f = **data; if (f.popup) DisposeControl(f.popup); f.popup = nil; **data = f; } break; case faePrint: f = **data; GetPortPenLocation(GetQDGlobalsThePort(),&penLoc); ir.top = penLoc.v-10; ir.left = penLoc.h; ir.bottom = ir.top +16; ir.right = ir.left+16; PlotIconID(&ir,atAbsoluteCenter, ttNone,PRIOR_SICN_BASE+f.prior-1); break; case faeDo: SetPriority(fpb->tocH,fpb->sumNum,NewPrior((*data)->prior, (*fpb->tocH)->sums[fpb->sumNum].priority)); break; } return(err); } /********************************************************************** * **********************************************************************/ typedef struct FDflkForward **FDflkForwardHandle; typedef struct FDflkForward { PETEHandle pte; Str255 addresses; } FDflkForward; short FAflkForward(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FDflkForwardHandle data = (FDflkForwardHandle)(*action)->data; FDflkForward f; Rect textR; OSErr err = noErr; Str255 s; FilterPBPtr fpb = (FilterPBPtr)dataPtr; switch (callType) { case faeInit: if (err=PeteCreate(Win,&f.pte,0,nil)) return(WarnUser(PETE_ERR,err)); (*PeteExtra(f.pte))->frame = True; (*PeteExtra(f.pte))->infinitelyWide = True; PeteFontAndSize(f.pte,GetPortTextFont(GetQDGlobalsThePort()),GetPortTextSize(GetQDGlobalsThePort())); PCopy(s,(*data)->addresses); PeteSetString(s,f.pte); (*data)->pte = f.pte; PETESetCallback(PETE,f.pte,(void*)FilterChanged,peDocChanged); /* fall through */ case faeResize: FASingleRect(r,&textR,ONE_LINE_HI(Win)); PeteDidResize((*data)->pte,&textR); break; case faeNew: PeteFocus(Win,(*data)->pte,true); break; case faeDraw: break; case faeDispose: case faeClose: FAflkSubject(callType,action,r,dataPtr); break; case faeFind: err = PeteFindString(dataPtr,0,(*data)->pte)>=0; break; case faeCursor: if (PtInPETE(*(Point*)r,(*data)->pte)) *(short*)dataPtr = iBeamCursor; else *(short*)dataPtr = arrowCursor; break; case faeRead: data = NewZH(FDflkForward); if (!data) return(WarnUser(MEM_ERR,MemError())); else { (*action)->data = (void*)data; if (dataPtr) PCopy((*data)->addresses,(UPtr)dataPtr); } break; case faeWrite: PCopy(s,(*data)->addresses); if (*s) err = FWriteKey(*(short*)dataPtr,(*action)->action,s); break; case faePrint: PCopy(s,(*data)->addresses); DrawString(s); break; case faeClick: if (PtInPETE(*(Point*)r,(*data)->pte)) { PeteEditWFocus(Win,(*data)->pte,peeEvent,dataPtr,nil); err = True; /* actually, not an error, but... */ } break; break; case faeSave: PeteSString(s,(*data)->pte); PCopy((*data)->addresses,s); break; case faeHelp: if (MouseInPTE((*data)->pte)) { PeteRect((*data)->pte,r); GetIndString(dataPtr,526,((*action)->action==flkForward?flkhForward:flkhRedirect)); } break; case faeDo: //Enhanced Filters - the forward filter action is not supported in Light //if ((*fpb->tocH)->which==OUT) return(noErr); /* don't do for out */ if (HasFeature (featureFilterForward)) { if (((*fpb->tocH)->sums[fpb->sumNum].opts&OPT_BULK)&&!PrefIsSet(PREF_BOMBS_AWAY)) return(noErr); /* don't do for bulk mail */ PCopy(s,(*data)->addresses); DoFordirectMessage(fpb->tocH,fpb->sumNum,(*action)->action,s,True); UseFeature (featureFilterForward); } break; } return(err); } /********************************************************************** * **********************************************************************/ short FAflkRedirect(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { return(FAflkForward(callType,action,r,dataPtr)); } /********************************************************************** * **********************************************************************/ typedef struct FDflkReply **FDflkReplyHandle; typedef struct FDflkReply { Str31 name; Rect r; ControlHandle popup; } FDflkReply; short FAflkReply(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { OSErr err = noErr; Str255 s; FilterPBPtr fpb = (FilterPBPtr)dataPtr; FDflkReplyHandle data = (FDflkReplyHandle)(*action)->data; short item; MenuHandle mh; FDflkReply f; switch (callType) { case faeInit: f = **data; f.popup = GetNewControlSmall(FILT_REPLY_POP,GetMyWindowWindowPtr(Win)); if (!f.popup) { FAflkReply(faeDispose,action,nil,nil); return(MEM_ERR); } **data = f; FAflkReply(faeMouseGoingDown,action,r,dataPtr); mh = GetControlPopupMenuHandle(f.popup); item = FindItemByName(mh,f.name); if (!item) { item = 1; MyGetItem(mh,item,f.name); PCopy((*data)->name,f.name); } MySetCtlValue(f.popup,item); EmbedControl(f.popup,ActionGroup); // fall-through case faeResize: f = **data; FAPopupValueFit(r,f.popup); ShowControl(f.popup); break; case faeClose: case faeDispose: if (data) { f = **data; if (f.popup) DisposeControl(f.popup); f.popup = nil; **data = f; } break; case faeButton: f = **data; mh = GetMHandle(REPLY_WITH_HIER_MENU); item = FindItemByName(mh,f.name); if (item!=GetControlValue(f.popup)) { item = GetControlValue(f.popup); MyGetItem(mh,item,f.name); Win->isDirty = CurrentDirty = True; **data = f; } break; case faeMouseGoingDown: { Str255 string; f = **data; if (f.popup && (mh = GetControlPopupMenuHandle(f.popup))) { MenuHandle otherMH = GetMHandle(NEW_WITH_HIER_MENU); short n; if (otherMH) { TrashMenu(mh,1); n = CountMenuItems(otherMH); for (item=1;item<=n;item++) { MyGetItem(otherMH,item,string); MyAppendMenu(mh,string); } SetItemMark(mh,GetControlValue(f.popup),diamondChar); EnableItem(mh,0); SetControlMaximum(f.popup,CountMenuItems(mh)); } } break; } case faeFind: PCopy(s,(*data)->name); err = PFindSub(dataPtr,s)!=nil; break; case faeRead: data = NewZH(FDflkReply); if (!data) return(WarnUser(MEM_ERR,MemError())); else { (*action)->data = (void*)data; if (dataPtr) PSCopy((*data)->name,(UPtr)dataPtr); } break; case faeWrite: PCopy(s,(*data)->name); if (*s) err = FWriteKey(*(short*)dataPtr,(*action)->action,s); break; case faePrint: PCopy(s,(*data)->name); DrawString(s); break; case faeDo: //We don't have a reply with menu, so we can't do this action in LIGHT if (HasFeature (featureFilterReply)) { short i; MenuHandle mh = GetMHandle(REPLY_WITH_HIER_MENU); //if ((*fpb->tocH)->which==OUT) return(noErr); /* don't do for out */ if (((*fpb->tocH)->sums[fpb->sumNum].opts&OPT_BULK)&&!PrefIsSet(PREF_BOMBS_AWAY)) return(noErr); /* don't do for bulk mail */ PCopy(s,*(*action)->data); if (mh && (i=FindItemByName(mh,s))) { UseFeature (featureFilterReply); DoReplyClosed(fpb->tocH,fpb->sumNum,False,False,False,True,i,True,True); } } break; } return(err); } /********************************************************************** * **********************************************************************/ short FAflkNotifyApp(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { return(noErr); } /********************************************************************** * **********************************************************************/ typedef struct FDflkNUser **FDflkNUserHandle; typedef struct FDflkNUser { long flags; ControlHandle user; ControlHandle report; } FDflkNUser; short FAflkNotifyUser(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FDflkNUserHandle data = (FDflkNUserHandle)(*action)->data; FDflkNUser f; Rect controlR; short spacing; short val; WindowPtr WinWP; ControlHandle button = (ControlHandle)dataPtr; Str63 s; FilterPBPtr fpb = (FilterPBPtr)dataPtr; long flag; switch (callType) { case faeInit: WinWP = GetMyWindowWindowPtr (Win); f.report = GetNewControlSmall(DO_FILTER_CNTL,WinWP); f.user = GetNewControlSmall(DO_USER_CNTL,WinWP); if (!f.user || !f.report) { FAflkNotifyUser(faeDispose,action,nil,nil); return(MEM_ERR); } f.flags = (*data)->flags; **data = f; MySetCtlValue(f.user,0!=(f.flags&afbUser)); MySetCtlValue(f.report,0!=(f.flags&afbReport)); EmbedControl(f.report,ActionGroup); EmbedControl(f.user,ActionGroup); /* fall-through */ case faeResize: f = **data; ButtonFit(f.user); ButtonFit(f.report); FAMultRect(r,&controlR,&spacing,ControlHi(f.user),2); MoveMyCntl(f.user,controlR.left,controlR.top,RectWi(controlR),0); OffsetRect(&controlR,RectWi(controlR)+spacing,0); MoveMyCntl(f.report,controlR.left,controlR.top,RectWi(controlR),0); ShowControl(f.user); ShowControl(f.report); break; case faeClose: case faeDispose: if (data) { f = **data; if (f.user) DisposeControl(f.user); if (f.report) DisposeControl(f.report); f.user = f.report = nil; **data = f; } break; case faeRead: data = NewZH(FDflkNUser); /* if we can't find a dozen bytes, we're dead */ (*action)->data = (void*)data; if (dataPtr) StringToNum(dataPtr,&f.flags); else f.flags = afbUser | (PrefIsSet(PREF_REPORT)?afbReport:0); (*data)->flags = f.flags; break; case faeWrite: NumToString((*data)->flags,s); return(FWriteKey(*(short*)dataPtr,(*action)->action,s)); break; case faeButton: f = **data; val = !GetControlValue(button); MySetCtlValue(button,val); Win->isDirty = CurrentDirty = True; flag = (button==f.user) ? afbUser : afbReport; if (val) (*data)->flags |= flag; else (*data)->flags &= ~flag; break; case faePrint: if ((*data)->flags&afbUser) { DrawRString(NOTIFY_NORM); if ((*data)->flags&afbReport) { DrawRString(AND_PRINT); DrawRString(NOTIFY_REPORT); } } else if ((*data)->flags&afbReport) { DrawRString(NOTIFY_REPORT); } break; case faeDo: if (0==((*data)->flags&afbUser)) fpb->dontUser = True; fpb->doReport = 0!=((*data)->flags&afbReport); fpb->dontReport = !fpb->doReport; break; case faeHelp: f = **data; if (MouseInControl(f.user)) { GetIndString(dataPtr,526,flkhNUser); GetControlBounds(f.user,r); } if (MouseInControl(f.report)) { GetIndString(dataPtr,526,flkhNReport); GetControlBounds(f.report,r); } break; } return(noErr); } /********************************************************************** * FAflkServerOpts - set server options **********************************************************************/ typedef struct FDflkSOpt **FDflkSOptHandle; typedef struct FDflkSOpt { long flags; ControlHandle fetch; ControlHandle trash; } FDflkSOpt; short FAflkServerOpts(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { FDflkSOptHandle data = (FDflkSOptHandle)(*action)->data; FDflkSOpt f; Rect controlR; short spacing; short val; WindowPtr WinWP; ControlHandle button = (ControlHandle)dataPtr; Str63 s; FilterPBPtr fpb = (FilterPBPtr)dataPtr; long flag; long uidHash; PersHandle pers; Boolean lmos; switch (callType) { case faeInit: WinWP = GetMyWindowWindowPtr (Win); f.fetch = GetNewControlSmall(DO_FETCH_CNTL,WinWP); f.trash = GetNewControlSmall(DO_TRASH_CNTL,WinWP); if (!f.fetch || !f.trash) { FAflkServerOpts(faeDispose,action,nil,nil); return(MEM_ERR); } f.flags = (*data)->flags; **data = f; MySetCtlValue(f.trash,0!=(f.flags&afbTrash)); MySetCtlValue(f.fetch,0!=(f.flags&afbFetch)); lmos = PrefIsSet(PREF_LMOS); if (!lmos&&(f.flags&afbFetch)) { HiliteControl(f.trash,255); (*data)->flags |= afbTrash; MySetCtlValue(f.trash,1); } else HiliteControl(f.trash,0); EmbedControl(f.trash,ActionGroup); EmbedControl(f.fetch,ActionGroup); /* fall-through */ case faeResize: f = **data; ButtonFit(f.fetch); ButtonFit(f.trash); FAMultRect(r,&controlR,&spacing,ControlHi(f.fetch),2); MoveMyCntl(f.fetch,controlR.left,controlR.top,RectWi(controlR),0); OffsetRect(&controlR,RectWi(controlR)+spacing,0); MoveMyCntl(f.trash,controlR.left,controlR.top,RectWi(controlR),0); ShowControl(f.fetch); ShowControl(f.trash); break; case faeClose: case faeDispose: if (data) { f = **data; if (f.trash) DisposeControl(f.trash); if (f.fetch) DisposeControl(f.fetch); f.fetch = f.trash = nil; **data = f; } break; case faeRead: data = NewZH(FDflkSOpt); /* if we can't find a dozen bytes, we're dead */ (*action)->data = (void*)data; if (dataPtr) StringToNum(dataPtr,&f.flags); else f.flags = 0; (*data)->flags = f.flags; break; case faeWrite: NumToString((*data)->flags,s); return(FWriteKey(*(short*)dataPtr,(*action)->action,s)); break; case faeButton: f = **data; val = !GetControlValue(button); MySetCtlValue(button,val); Win->isDirty = CurrentDirty = True; flag = (button==f.trash) ? afbTrash : afbFetch; if (val) f.flags |= flag; else f.flags &= ~flag; **data = f; lmos = PrefIsSet(PREF_LMOS); if (!lmos&&(f.flags&afbFetch)) { HiliteControl(f.trash,255); (*data)->flags |= afbTrash; MySetCtlValue(f.trash,1); } else HiliteControl(f.trash,0); break; case faeHelp: f = **data; if (MouseInControl(f.fetch)) { GetIndString(dataPtr,526,flkhFetch); GetControlBounds(f.fetch,r); } else if (MouseInControl(f.trash)) { GetIndString(dataPtr,526,flkhDelete); GetControlBounds(f.trash,r); } break; case faeDo: //Enhanced Filters - the Server Options filter actions is not supported in Light if (HasFeature (featureFilterServerOptions)) { UseFeature (featureFilterServerOptions); flag = (*data)->flags; uidHash = (*fpb->tocH)->sums[fpb->sumNum].uidHash; pers = TS_TO_PPERS(fpb->tocH,fpb->sumNum); #ifdef IMAP if ((*fpb->tocH)->imapTOC) { // This is an IMAP mailbox. Boolean filteringUnderway = IMAPFilteringUnderway(); // Make sure progress is displayed while doing the next bit ... if (filteringUnderway) IMAPStopFiltering(false); if (flag&afbFetch) { // Server Options -> Fetch. Download this message if it's not already present. if (!IMAPMessageDownloaded(fpb->tocH, fpb->sumNum) && !IMAPMessageBeingDownloaded(fpb->tocH, fpb->sumNum)) UIDDownloadMessage(fpb->tocH, uidHash, true, true); } else if (flag&afbTrash) { // Server Options -> Delete. Delete this message from the IMAP server. IMAPDeleteMessageDuringFiltering(fpb->tocH, pers, (*fpb->tocH)->sums[fpb->sumNum].uidHash); } // go back to filtering if (filteringUnderway) IMAPStartFiltering(fpb->tocH, true); } else { // This is a regular mailbox. #endif //if (IdIsOnPOPD(PERS_POPD_TYPE(pers),POPD_ID,uidHash)) // because of incremental filtering, we may not know it's on the server when we do this { Boolean skipped = ((*fpb->tocH)->sums[fpb->sumNum].flags & FLAG_SKIPPED)!=0; if ((flag&afbFetch) && skipped) AddIdToPOPD(PERS_POPD_TYPE(pers),FETCH_ID,uidHash,False); if (flag&afbTrash) { AddIdToPOPD(PERS_POPD_TYPE(pers),DELETE_ID,uidHash,False); TOCSetDirty(fpb->tocH,true); } if ((*fpb->tocH)->win) Fix1MessServerArea((*fpb->tocH)->win); if ((*fpb->tocH)->sums[fpb->sumNum].messH) Fix1MessServerArea((*(*fpb->tocH)->sums[fpb->sumNum].messH)->win); } #ifdef IMAP } #endif } break; case faePrint: if ((*data)->flags&afbFetch) { DrawRString(FETCH_PRINT); if ((*data)->flags&afbTrash) { DrawRString(AND_PRINT); DrawRString(DELETE_PRINT); } } else if ((*data)->flags&afbTrash) { DrawRString(DELETE_PRINT); } break; } return(noErr); } /********************************************************************** * **********************************************************************/ short FAflkAttachments(FACallEnum callType,FActionHandle action,Rect *r,void *dataPtr) { return(noErr); } #ifndef SPEECH_ENABLED short FAflkSpeak (FACallEnum callType, FActionHandle action, Rect *r, void *dataPtr) { // return noSynthFound; return noErr; } #else typedef struct FDflkSpeak **FDflkSpeakHandle; typedef struct FDflkSpeak { SpeakableParts speak; ControlHandle popup; ControlHandle sender; ControlHandle subject; VoiceSpec voice; } FDflkSpeak; /********************************************************************** * FAflkSpeak - speak the sender and/or subject **********************************************************************/ short FAflkSpeak (FACallEnum callType, FActionHandle action, Rect *r, void *dataPtr) { FDflkSpeakHandle data; FDflkSpeak filter; FilterPBPtr fpb; VoiceSpec voice; WindowPtr WinWP; ControlHandle theControl; Str255 sample; Str63 string; Rect controlR; UPtr spot; OSType creator, id; long speak; short spacing, value; Rect rCntl; SpeakableParts iHaveSpoken; data = (FDflkSpeakHandle) (*action)->data; switch (callType) { case faeInit: WinWP = GetMyWindowWindowPtr (Win); filter = **data; filter.speak = (*data)->speak; filter.sender = GetNewControlSmall (FILT_SPEAK_SENDER_CNTL, WinWP); filter.subject = GetNewControlSmall (FILT_SPEAK_SUBJECT_CNTL, WinWP); filter.popup = GetNewVoicePopupSmall (FILT_SPEAK_POPUP_CNTL, WinWP, &filter.voice); **data = filter; if (!filter.sender || !filter.subject) { FAflkSpeak (faeDispose, action, nil, nil); return (MEM_ERR); } MySetCtlValue (filter.sender, (filter.speak & speakSender) != 0); MySetCtlValue (filter.subject, (filter.speak & speakSubject) != 0); EmbedControl(filter.sender,ActionGroup); EmbedControl(filter.subject,ActionGroup); EmbedControl(filter.popup,ActionGroup); /* fall-through */ case faeResize: filter = **data; ButtonFit (filter.sender); ButtonFit (filter.subject); FAMultRect (r, &controlR, &spacing, ControlHi (filter.sender), 2); if (filter.popup) { ButtonFit (filter.popup); GetControlBounds(filter.popup,&rCntl); MoveMyCntl (filter.popup, controlR.left, controlR.top, MIN (RectWi (rCntl), RectWi (controlR)), 0); OffsetRect (&controlR, RectWi (controlR) + spacing, 0); controlR.right = controlR.left + RectWi (controlR) / 2; } MoveMyCntl (filter.sender, controlR.left, controlR.top, RectWi (controlR), 0); OffsetRect (&controlR, RectWi (controlR) + spacing, 0); MoveMyCntl (filter.subject, controlR.left, controlR.top, RectWi (controlR), 0); if (filter.popup) ShowControl (filter.popup); ShowControl (filter.sender); ShowControl (filter.subject); break; case faeClose: case faeDispose: if (data) { filter = **data; if (filter.sender) DisposeControl (filter.sender); if (filter.subject) DisposeControl (filter.subject); if (filter.popup) DisposeControl (filter.popup); filter.sender = filter.subject = filter.popup = nil; **data = filter; } break; case faeRead: // Stored as data = NewZH (FDflkSpeak); /* if we can't find a dozen or so bytes, we're dead */ (*action)->data = (void *) data; if (dataPtr) { spot = (UPtr) dataPtr + 1; if (PToken (dataPtr, string, &spot, " ")) MyStringToNum (string,&speak); if (PToken (dataPtr, string, &spot, " ")) MyStringToNum (string,&creator); if (PToken (dataPtr, string, &spot, " ")) MyStringToNum (string,&id); } else { speak = speakNothing; creator = 0; id = 0; } (*data)->speak = speak; if (SpeechAvailable ()) (void) MakeVoiceSpec (creator, id, &(*data)->voice); break; case faeWrite: // Written as NumToString ((*data)->speak, string); PLCat (string, (*data)->voice.creator); PLCat (string, (*data)->voice.id); return (FWriteKey (*(short *) dataPtr, (*action)->action, string)); break; case faeButton: filter = **data; theControl = (ControlHandle) dataPtr; value = GetControlValue (theControl); Win->isDirty = CurrentDirty = True; if (theControl == filter.popup) { GetMenuItemText (GetControlPopupMenuHandle(filter.popup), value, string); if (*string && !FindVoiceFromName (string, &voice)) { (*data)->voice = voice; GetRString (sample, SPEAK_SAMPLE_TEXT); (void) Speak (&voice, sample + 1, *sample); } } else { MySetCtlValue (theControl, !value); speak = (theControl == filter.sender) ? speakSender : speakSubject; if (!value) (*data)->speak |= speak; else (*data)->speak &= ~speak; } break; case faePrint: filter = **data; if (filter.speak) { iHaveSpoken = false; if (filter.speak & speakSender) { DrawRString (SPEAK_SENDERS_NAME); iHaveSpoken = true; } if (filter.speak & speakSubject) { if (iHaveSpoken) DrawRString(AND_PRINT); DrawRString (SPEAK_SUBJECT); iHaveSpoken = true; } } else DrawRString (SPEAK_NOTHING); DrawRString (SPEAK_USING); if (GetVoiceName (&filter.voice, string)) DrawRString (SPEAK_DEFAULT_VOICE); else DrawString (string); break; case faeDo: //Enhanced Filters - the speak filter action is not supported in Light if (HasFeature (featureFilterSpeak)) { UseFeature (featureFilterSpeak); filter = **data; fpb = (FilterPBPtr) dataPtr; // Speak now or forever hold your peace if (filter.speak) (void) SpeakMessage (&filter.voice, fpb->tocH, fpb->sumNum, filter.speak | speakSummary, false); } break; case faeHelp: filter = **data; if (MouseInControl (filter.popup)) { GetIndString (dataPtr, 526, flkhSpeak); GetControlBounds(filter.popup,r); } else if (MouseInControl (filter.sender)) { GetIndString (dataPtr, 526, flkhSpeakSender); GetControlBounds(filter.sender,r); } else if (MouseInControl (filter.subject)) { GetIndString (dataPtr, 526, flkhSpeakSubject); GetControlBounds(filter.subject,r); } break; } return (noErr); } #endif short FAflkAddHistory (FACallEnum callType, FActionHandle action, Rect *r, void *dataPtr) { FilterPBPtr fpb; switch (callType) { case faeInit: case faeResize: case faeClose: case faeDispose: break; case faeWrite: return(FWriteBool(*(short*)dataPtr,(*action)->action,True)); break; case faeButton: case faePrint: break; case faeDo: //Enhanced Filters - Add the sender to the nickname cache if (HasFeature (featureFilterAddHistory)) if (fpb = (FilterPBPtr) dataPtr) { TextAddrHandle addresses = nil; UseFeature (featureFilterAddHistory); if (!GatherBoxAddresses (fpb->tocH, 0, fpb->sumNum, fpb->sumNum, &addresses, false)) { CacheRecentNickname (LDRef (addresses)); UL (addresses); } } break; case faeHelp: break; } return (noErr); } #ifdef GRIDLINES /************************************************************************ * ControlGridlines - draw gridlines where a control is ************************************************************************/ void ControlGridlines(ControlHandle cntl) { Rect r; GetControlBounds(cntl,&r); MoveTo(r.left-10,r.top); Line(10,0); Line(0,-10); MoveTo(r.right+10,r.top); Line(-10,0); Line(0,-10); MoveTo(r.left-10,r.bottom); Line(10,0); Line(0,10); MoveTo(r.right+10,r.bottom); Line(-10,0); Line(0,10); } #endif /********************************************************************** * RefreshFiltersWindow - bring it to the front and select the last * filter if details is true. **********************************************************************/ void RefreshFiltersWindow(FilterRecord newFilter, Boolean details) { Point c; short n = NFilters - 1; if (FLG && *FLG && Win) { PushGWorld(); SetPort_(GetMyWindowCGrafPtr(Win)); LAddRow(1,n,LHand); c.h = 0; c.v = n; LSetCell(newFilter.name+1,*newFilter.name,c,LHand); PopGWorld(); } //open the filters window if the user hit "add details" if (details) { OpenFiltersWindow(); PushGWorld(); SetPort_(GetMyWindowCGrafPtr(Win)); FilterSelect(n); PopGWorld(); } } #endif