GridCtrl.cpp 183 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259
  1. // GridCtrl.cpp : implementation file
  2. //
  3. // MFC Grid Control v2.23
  4. //
  5. // Written by Chris Maunder <cmaunder@mail.com>
  6. // Copyright (c) 1998-2001. All Rights Reserved.
  7. //
  8. // The code contained in this file is based on the original
  9. // WorldCom Grid control written by Joe Willcoxson,
  10. // mailto:chinajoe@aol.com
  11. // http://users.aol.com/chinajoe
  12. // (These addresses may be out of date) The code has gone through
  13. // so many modifications that I'm not sure if there is even a single
  14. // original line of code. In any case Joe's code was a great
  15. // framework on which to build.
  16. //
  17. // This code may be used in compiled form in any way you desire. This
  18. // file may be redistributed unmodified by any means PROVIDING it is
  19. // not sold for profit without the authors written consent, and
  20. // providing that this notice and the authors name and all copyright
  21. // notices remains intact.
  22. //
  23. // An email letting me know how you are using it would be nice as well.
  24. //
  25. // This file is provided "as is" with no expressed or implied warranty.
  26. // The author accepts no liability for any damage/loss of business that
  27. // this product may cause.
  28. //
  29. // Expect bugs!
  30. //
  31. // Please use and enjoy, and let me know of any bugs/mods/improvements
  32. // that you have found/implemented and I will fix/incorporate them into
  33. // this file.
  34. //
  35. // History:
  36. // --------
  37. // This control is constantly evolving, sometimes due to new features that I
  38. // feel are necessary, and sometimes due to existing bugs. Where possible I
  39. // have credited the changes to those who contributed code corrections or
  40. // enhancements (names in brackets) or code suggestions (suggested by...)
  41. //
  42. // 1.0 - 1.13 20 Feb 1998 - 6 May 1999
  43. // First release version. Progressed from being a basic
  44. // grid based on the original WorldCom Grid control
  45. // written by Joe Willcoxson (mailto:chinajoe@aol.com,
  46. // http://users.aol.com/chinajoe) to something a little
  47. // more feature rich. Rewritten so many times I doubt
  48. // there is a single line of Joe's code left. Many, many,
  49. // MANY people sent in bug reports and fixes. Thank you
  50. // all.
  51. //
  52. // 2.0 1 Feb 2000
  53. // Rewritten to make the grid more object oriented, in
  54. // that the CGridCell class now takes care of cell-specific
  55. // tasks. This makes the code more robust, but more
  56. // importantly it allows the simple insertion of other
  57. // types of cells.
  58. //
  59. // 2.01 20 Feb 2000 - Eric Woodruff
  60. // Added better support for printing grids and
  61. // also fixed some other minor problems.
  62. //
  63. // 2.02 29 Feb 2000 - Brian V. Shifrin, Scot Reed,
  64. // Fixes to reduce flicker, fix font selection bug,
  65. // Fixed SetFixed[Row/Col]Count bug
  66. //
  67. // 2.03 28 Mar 2000 - Aqiruse (marked with //FNA)
  68. // Titletips now use cell color
  69. //
  70. // 2.10 11 Mar 2000 - Ken Bertelson and Chris Maunder
  71. // - Additions for virtual CGridCell support of embedded tree
  72. // & cell buttons implementation
  73. // - Optional WYSIWYG printing
  74. // - Awareness of hidden (0 width/height) rows and columns for
  75. // key movements, cut, copy, paste, and autosizing
  76. // - CGridCell can make title tips display any text rather than
  77. // cell text only
  78. // - Minor vis bug fixes
  79. // - CGridCtrl now works with CGridCellBase instead of CGridCell
  80. // This is a taste of things to come.
  81. //
  82. // 2.11 19 May 2000 - Chris Maunder
  83. // - Increasing fixed cells clashed with selected cells (Ivan Ilinov)
  84. // - AutoSizeRows obvous bug fixed
  85. // - OnLButtonDown fix (Ken Bertelson)
  86. // - ExpandToFit bug fixed (scrollbar space) (Igor Proskuriakov)
  87. // - List mode selection/deselection fixed
  88. // - Keyboard cell movement improved. You can now see the cells!
  89. // - m_nBarState MS madness fixed (Phil K)
  90. //
  91. // 2.12 26 May 2000 - Martin Richter
  92. // - If using TRY/CATCH (winCE) instead of try/catch (win32),
  93. // e->Delete is not called
  94. // - EnsureVisible "fix" was fixed properly.
  95. //
  96. // 2.20 30 Jul 2000 - Chris Maunder
  97. // - Font storage optimised (suggested by Martin Richter)
  98. // - AutoSizeColumn works on either column header, data or both
  99. // - EnsureVisible. The saga continues... (Ken)
  100. // - Rewrote exception handling
  101. // - Added TrackFocusCell and FrameFocusCell properties, as well as
  102. // ExpandLastColumn (suggested by Bruce E. Stemplewski).
  103. // - InsertColumn now allows you to insert columns at the end of the
  104. // column range (David Weibel)
  105. // - Shift-cell-selection more intuitive
  106. // - API change: Set/GetGridColor now Set/GetGridLineColor
  107. // - API change: Set/GetBkColor now Set/GetGridBkColor
  108. // - API change: Set/GetTextColor, Set/GetTextBkColor depricated
  109. // - API change: Set/GetFixedTextColor, Set/GetFixedBkColor depricated
  110. // - Stupid DDX_GridControl workaround removed.
  111. // - Added "virtual mode" via Set/GetVirtualMode
  112. // - Added SetCallbackFunc to allow callback functions in virtual mode
  113. // - Added Set/GetAutoSizeStyle
  114. // - AutoSize() bug fixed
  115. // - added GVIS_FIXEDROW, GVIS_FIXEDCOL states
  116. // - added Get/SetFixed[Row|Column]Selection
  117. // - cell "Get" methods now const'd. Sorry folks...
  118. // - GetMouseScrollLines now uses win98/W2K friendly code
  119. // - WS_EX_CLIENTEDGE style now implicit
  120. //
  121. // 2.21 29 Aug 2000 - Chris Maunder
  122. // - re-jigged OLE initialisation and drag/drop registration
  123. // - Cut and Paste bug fixed (empty cells not being treated correctly)
  124. // - Added "bExpandFixed" parameter to Expand*ToFit functions (Hans-Peter Werner)
  125. // - SetRedraw bug fixed
  126. // - Resizing 0-width last row and column now works
  127. // - Fixed CreateCell SetFormat bug (Loic Baudry)
  128. // - Fixed GetFixedTextColor typo (raybie@Exabyte.COM)
  129. // - Modified EnableScrollBars calls in Expand*ToFit functions (Simon Hughes)
  130. // - GetCellFromPt now public
  131. // - GV_CACHEHINT sent more appropriately, and also sent with -1 cellrange
  132. // at the end of operations (so App can discard data - Martin Richter)
  133. // - CGridCellBase::operator= checks for NULL font before setting (Martin Richter)
  134. // - After drag/drop, mouse button was still marked as "down". Fixed.
  135. //
  136. // 2.22 1 Jan 2001 - Chris Maunder
  137. // - SetModified bug in SetItem (Keith Worden)
  138. // - ifdef around SetItemTextFmt corrected for win32
  139. // - Save() bug fixed (row 0 saved twice)
  140. // - GetTopleftNonFixedCell, GetUnobstructedNonFixedCellRange and
  141. // GetVisibleNonFixedCellRange have optional parameter to force recalc.
  142. // - added virtual ValidateEdit.
  143. // - if the return value from the SendMessage operation for
  144. // GVN_ENDLABELEDIT or GVN_BEGINLABELEDIT is < 0 then the
  145. // edit, or the attempt to edit (respectively) is rejected.
  146. // - Added GetEditWnd to CGridCellBase
  147. // - Fixed the paste bug for cells being edited (Gary Lyben).
  148. // - GVN_SELCHANGING/GVN_SELCHANGED messages now sent correctly
  149. // - OnRButtonUp was not handling clicks on fixed cells correctly
  150. // - SB_ENDSCROLL message now sent on keypress initiated scroll
  151. // - GetCellTextExtent bug fixed (Elco)
  152. // - SetSelectedRange inefficiency fixed by huangchaoyi <ahaa007@263.net>
  153. // - DT_NOCLIP removed from CGridCellBase::Paint
  154. // - SetRowCount returns correct value on OOM condition (asigal@hotmail.com)
  155. // - Bug when editing using Japanese characters fixed (Michael Dunn)
  156. // - Fixed columns and rows printed correctly (fletch - untested)
  157. // - Added the "ClearCells" function
  158. //
  159. // TODO: 1) Implement sparse grids (super easy now)
  160. // 2) Fix it so that as you drag select, the speed of selection increases
  161. // with time.
  162. // 3) Scrolling is still a little dodgy (too much grey area). I know there
  163. // is a simple fix but it's been a low priority5
  164. // 4) Get some sleep
  165. //
  166. // ISSUES: 1) Crashes in the HPC/Pro emulation - but works fine on a device. ???
  167. // 2) WindowFromPoint seems to do weird things in W2K. Causing problems for
  168. // the rigt-click-on-titletip code.
  169. //
  170. /////////////////////////////////////////////////////////////////////////////
  171. #include "stdafx.h"
  172. #include "MemDC.h"
  173. #include "GridCtrl.h"
  174. // OLE stuff for clipboard operations
  175. #include <afxadv.h> // For CSharedFile
  176. #include <afxconv.h> // For LPTSTR -> LPSTR macros
  177. #ifdef _DEBUG
  178. #define new DEBUG_NEW
  179. #undef THIS_FILE
  180. static char THIS_FILE[] = __FILE__;
  181. #endif
  182. // Spit out some messages as a sanity check for programmers
  183. #ifdef GRIDCONTROL_NO_TITLETIPS
  184. #pragma message(" -- CGridCtrl: No titletips for cells with large data")
  185. #endif
  186. #ifdef GRIDCONTROL_NO_DRAGDROP
  187. #pragma message(" -- CGridCtrl: No OLE drag and drop")
  188. #endif
  189. #ifdef GRIDCONTROL_NO_CLIPBOARD
  190. #pragma message(" -- CGridCtrl: No clipboard support")
  191. #endif
  192. #ifdef GRIDCONTROL_NO_PRINTING
  193. #pragma message(" -- CGridCtrl: No printing support")
  194. #endif
  195. IMPLEMENT_DYNCREATE(CGridCtrl, CWnd)
  196. // Get the number of lines to scroll with each mouse wheel notch
  197. // Why doesn't windows give us this function???
  198. UINT GetMouseScrollLines()
  199. {
  200. int nScrollLines = 3; // reasonable default
  201. #ifndef _WIN32_WCE
  202. // Do things the hard way in win95
  203. OSVERSIONINFO VersionInfo;
  204. VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  205. if (!GetVersionEx(&VersionInfo) ||
  206. (VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && VersionInfo.dwMinorVersion == 0))
  207. {
  208. HKEY hKey;
  209. if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"),
  210. 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
  211. {
  212. TCHAR szData[128];
  213. DWORD dwKeyDataType;
  214. DWORD dwDataBufSize = sizeof(szData);
  215. if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
  216. (LPBYTE)&szData, &dwDataBufSize) == ERROR_SUCCESS)
  217. {
  218. nScrollLines = _tcstoul(szData, NULL, 10);
  219. }
  220. RegCloseKey(hKey);
  221. }
  222. }
  223. // win98 or greater
  224. else
  225. SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);
  226. #endif
  227. return nScrollLines;
  228. }
  229. /////////////////////////////////////////////////////////////////////////////
  230. // CGridCtrl
  231. CGridCtrl::CGridCtrl(int nRows, int nCols, int nFixedRows, int nFixedCols)
  232. {
  233. RegisterWindowClass();
  234. #if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
  235. _AFX_THREAD_STATE* pState = AfxGetThreadState();
  236. if (!pState->m_bNeedTerm && !AfxOleInit())
  237. AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
  238. #endif
  239. // Store the system colours in case they change. The gridctrl uses
  240. // these colours, and in OnSysColorChange we can check to see if
  241. // the gridctrl colours have been changed from the system colours.
  242. // If they have, then leave them, otherwise change them to reflect
  243. // the new system colours.
  244. m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
  245. m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
  246. m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
  247. m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
  248. m_crGridLineColour = RGB(192, 192, 192);
  249. m_nRows = 0;
  250. m_nCols = 0;
  251. m_nFixedRows = 0;
  252. m_nFixedCols = 0;
  253. m_bVirtualMode = FALSE;
  254. m_pfnCallback = NULL;
  255. m_nVScrollMax = 0; // Scroll position
  256. m_nHScrollMax = 0;
  257. m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
  258. // per mouse wheel notch to scroll
  259. m_nBarState = GVL_NONE;
  260. m_MouseMode = MOUSE_NOTHING;
  261. m_nGridLines = GVL_BOTH;
  262. m_bEditable = TRUE;
  263. m_bListMode = FALSE;
  264. m_bSingleRowSelection = FALSE;
  265. m_bSingleColSelection = FALSE;
  266. m_bLMouseButtonDown = FALSE;
  267. m_bRMouseButtonDown = FALSE;
  268. m_bAllowDraw = TRUE; // allow draw updates
  269. m_bEnableSelection = TRUE;
  270. m_bFixedColumnSelection = TRUE;
  271. m_bFixedRowSelection = TRUE;
  272. m_bAllowRowResize = TRUE;
  273. m_bAllowColumnResize = TRUE;
  274. m_bSortOnClick = FALSE; // Sort on header row click
  275. m_bHandleTabKey = TRUE;
  276. #ifdef _WIN32_WCE
  277. m_bDoubleBuffer = FALSE; // Use double buffering to avoid flicker?
  278. #else
  279. m_bDoubleBuffer = TRUE; // Use double buffering to avoid flicker?
  280. #endif
  281. m_bTitleTips = TRUE; // show cell title tips
  282. m_bWysiwygPrinting = FALSE; // use size-to-width printing
  283. m_bHiddenColUnhide = TRUE; // 0-width columns can be expanded via mouse
  284. m_bHiddenRowUnhide = TRUE; // 0-Height rows can be expanded via mouse
  285. m_bAllowColHide = TRUE; // Columns can be contracted to 0-width via mouse
  286. m_bAllowRowHide = TRUE; // Rows can be contracted to 0-height via mouse
  287. m_bAscending = TRUE; // sorting stuff
  288. m_nSortColumn = -1;
  289. m_pfnCompare = NULL;
  290. m_nAutoSizeColumnStyle = GVS_BOTH; // Autosize grid using header and data info
  291. m_nTimerID = 0; // For drag-selection
  292. m_nTimerInterval = 25; // (in milliseconds)
  293. m_nResizeCaptureRange = 3; // When resizing columns/row, the cursor has to be
  294. // within +/-3 pixels of the dividing line for
  295. // resizing to be possible
  296. m_pImageList = NULL; // Images in the grid
  297. m_bAllowDragAndDrop = FALSE; // for drag and drop - EFW - off by default
  298. m_bTrackFocusCell = TRUE; // Track Focus cell?
  299. m_bFrameFocus = TRUE; // Frame the selected cell?
  300. m_pRtcDefault = RUNTIME_CLASS(CGridCell);
  301. SetupDefaultCells();
  302. SetGridBkColor(m_crShadow);
  303. // Set up the initial grid size
  304. SetRowCount(nRows);
  305. SetColumnCount(nCols);
  306. SetFixedRowCount(nFixedRows);
  307. SetFixedColumnCount(nFixedCols);
  308. SetTitleTipTextClr(CLR_DEFAULT); //FNA
  309. SetTitleTipBackClr(CLR_DEFAULT);
  310. // set initial selection range (ie. none)
  311. m_SelectedCellMap.RemoveAll();
  312. m_PrevSelectedCellMap.RemoveAll();
  313. #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  314. // EFW - Added to support shaded/unshaded printout and
  315. // user-definable margins.
  316. m_bShadedPrintOut = TRUE;
  317. SetPrintMarginInfo(2, 2, 4, 4, 1, 1, 1);
  318. #endif
  319. }
  320. CGridCtrl::~CGridCtrl()
  321. {
  322. DeleteAllItems();
  323. #ifndef GRIDCONTROL_NO_TITLETIPS
  324. if (m_bTitleTips && ::IsWindow(m_TitleTip.GetSafeHwnd()))
  325. m_TitleTip.DestroyWindow();
  326. #endif
  327. DestroyWindow();
  328. #if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
  329. // BUG FIX - EFW
  330. COleDataSource *pSource = COleDataSource::GetClipboardOwner();
  331. if (pSource)
  332. COleDataSource::FlushClipboard();
  333. #endif
  334. }
  335. // Register the window class if it has not already been registered.
  336. BOOL CGridCtrl::RegisterWindowClass(HINSTANCE hInstance)
  337. {
  338. WNDCLASS wndcls;
  339. //HINSTANCE hInst = AfxGetInstanceHandle();
  340. //HINSTANCE hInst = AfxGetResourceHandle();
  341. HINSTANCE hInst = hInstance ? hInstance : AfxGetInstanceHandle();
  342. if (!(::GetClassInfo(hInst, GRIDCTRL_CLASSNAME, &wndcls)))
  343. {
  344. // otherwise we need to register a new class
  345. wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  346. wndcls.lpfnWndProc = ::DefWindowProc;
  347. wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
  348. wndcls.hInstance = hInst;
  349. wndcls.hIcon = NULL;
  350. #ifndef _WIN32_WCE_NO_CURSOR
  351. wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
  352. #else
  353. wndcls.hCursor = 0;
  354. #endif
  355. wndcls.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
  356. wndcls.lpszMenuName = NULL;
  357. wndcls.lpszClassName = GRIDCTRL_CLASSNAME;
  358. if (!AfxRegisterClass(&wndcls))
  359. {
  360. AfxThrowResourceException();
  361. return FALSE;
  362. }
  363. }
  364. return TRUE;
  365. }
  366. BOOL CGridCtrl::Initialise()
  367. {
  368. // Stop re-entry problems
  369. static BOOL bInProcedure = FALSE;
  370. if (bInProcedure)
  371. return FALSE;
  372. bInProcedure = TRUE;
  373. #ifndef GRIDCONTROL_NO_TITLETIPS
  374. m_TitleTip.SetParentWnd(this);
  375. #endif
  376. if (::IsWindow(m_hWnd))
  377. ModifyStyleEx(0, WS_EX_CLIENTEDGE, 0);
  378. bInProcedure = FALSE;
  379. return TRUE;
  380. }
  381. // creates the control - use like any other window create control
  382. BOOL CGridCtrl::Create(const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwStyle)
  383. {
  384. ASSERT(pParentWnd->GetSafeHwnd());
  385. if (!CWnd::Create(GRIDCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID))
  386. return FALSE;
  387. //Initialise();
  388. // The number of rows and columns will only be non-zero if the constructor
  389. // was called with non-zero initialising parameters. If this window was created
  390. // using a dialog template then the number of rows and columns will be 0 (which
  391. // means that the code below will not be needed - which is lucky 'cause it ain't
  392. // gonna get called in a dialog-template-type-situation.
  393. TRY
  394. {
  395. m_arRowHeights.SetSize(m_nRows); // initialize row heights
  396. m_arColWidths.SetSize(m_nCols); // initialize column widths
  397. }
  398. CATCH(CMemoryException, e)
  399. {
  400. e->ReportError();
  401. return FALSE;
  402. }
  403. END_CATCH
  404. int i;
  405. for (i = 0; i < m_nRows; i++)
  406. m_arRowHeights[i] = m_cellDefault.GetHeight();
  407. for (i = 0; i < m_nCols; i++)
  408. m_arColWidths[i] = m_cellDefault.GetWidth();
  409. ResetScrollBars(); //- called in OnSize anyway
  410. return TRUE;
  411. }
  412. void CGridCtrl::SetupDefaultCells()
  413. {
  414. m_cellDefault.SetGrid(this); // Normal editable cell
  415. m_cellFixedColDef.SetGrid(this); // Cell for fixed columns
  416. m_cellFixedRowDef.SetGrid(this); // Cell for fixed rows
  417. m_cellFixedRowColDef.SetGrid(this); // Cell for area overlapped by fixed columns/rows
  418. m_cellDefault.SetTextClr(m_crWindowText);
  419. m_cellDefault.SetBackClr(m_crWindowColour);
  420. m_cellFixedColDef.SetTextClr(m_crWindowText);
  421. m_cellFixedColDef.SetBackClr(m_cr3DFace);
  422. m_cellFixedRowDef.SetTextClr(m_crWindowText);
  423. m_cellFixedRowDef.SetBackClr(m_cr3DFace);
  424. m_cellFixedRowColDef.SetTextClr(m_crWindowText);
  425. m_cellFixedRowColDef.SetBackClr(m_cr3DFace);
  426. }
  427. void CGridCtrl::PreSubclassWindow()
  428. {
  429. CWnd::PreSubclassWindow();
  430. //HFONT hFont = ::CreateFontIndirect(m_cellDefault.GetFont());
  431. //OnSetFont((LPARAM)hFont, 0);
  432. //DeleteObject(hFont);
  433. Initialise();
  434. // ResetScrollBars(); - called in OnSize anyway
  435. }
  436. // Sends a message to the parent in the form of a WM_NOTIFY message with
  437. // a NM_GRIDVIEW structure attached
  438. LRESULT CGridCtrl::SendMessageToParent(int nRow, int nCol, int nMessage) const
  439. {
  440. if (!IsWindow(m_hWnd))
  441. return 0;
  442. NM_GRIDVIEW nmgv;
  443. nmgv.iRow = nRow;
  444. nmgv.iColumn = nCol;
  445. nmgv.hdr.hwndFrom = m_hWnd;
  446. nmgv.hdr.idFrom = GetDlgCtrlID();
  447. nmgv.hdr.code = nMessage;
  448. CWnd *pOwner = GetOwner();
  449. if (pOwner && IsWindow(pOwner->m_hWnd))
  450. return pOwner->SendMessage(WM_NOTIFY, nmgv.hdr.idFrom, (LPARAM)&nmgv);
  451. else
  452. return 0;
  453. }
  454. // Send a request to the parent to return information on a given cell
  455. LRESULT CGridCtrl::SendDisplayRequestToParent(GV_DISPINFO* pDisplayInfo) const
  456. {
  457. if (!IsWindow(m_hWnd))
  458. return 0;
  459. // Fix up the message headers
  460. pDisplayInfo->hdr.hwndFrom = m_hWnd;
  461. pDisplayInfo->hdr.idFrom = GetDlgCtrlID();
  462. pDisplayInfo->hdr.code = GVN_GETDISPINFO;
  463. // Send the message
  464. CWnd *pOwner = GetOwner();
  465. if (pOwner && IsWindow(pOwner->m_hWnd))
  466. return pOwner->SendMessage(WM_NOTIFY, pDisplayInfo->hdr.idFrom, (LPARAM)pDisplayInfo);
  467. else
  468. return 0;
  469. }
  470. // Send a hint to the parent about caching information
  471. LRESULT CGridCtrl::SendCacheHintToParent(const CCellRange& range) const
  472. {
  473. if (!IsWindow(m_hWnd))
  474. return 0;
  475. GV_CACHEHINT CacheHint;
  476. // Fix up the message headers
  477. CacheHint.hdr.hwndFrom = m_hWnd;
  478. CacheHint.hdr.idFrom = GetDlgCtrlID();
  479. CacheHint.hdr.code = GVN_ODCACHEHINT;
  480. CacheHint.range = range;
  481. // Send the message
  482. CWnd *pOwner = GetOwner();
  483. if (pOwner && IsWindow(pOwner->m_hWnd))
  484. return pOwner->SendMessage(WM_NOTIFY, CacheHint.hdr.idFrom, (LPARAM)&CacheHint);
  485. else
  486. return 0;
  487. }
  488. BEGIN_MESSAGE_MAP(CGridCtrl, CWnd)
  489. //EFW - Added ON_WM_RBUTTONUP
  490. //{{AFX_MSG_MAP(CGridCtrl)
  491. ON_WM_PAINT()
  492. ON_WM_HSCROLL()
  493. ON_WM_VSCROLL()
  494. ON_WM_SIZE()
  495. ON_WM_LBUTTONUP()
  496. ON_WM_LBUTTONDOWN()
  497. ON_WM_MOUSEMOVE()
  498. ON_WM_TIMER()
  499. ON_WM_GETDLGCODE()
  500. ON_WM_KEYDOWN()
  501. ON_WM_CHAR()
  502. ON_WM_LBUTTONDBLCLK()
  503. ON_WM_ERASEBKGND()
  504. ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateEditSelectAll)
  505. ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
  506. ON_WM_SYSKEYDOWN()
  507. //}}AFX_MSG_MAP
  508. #ifndef _WIN32_WCE_NO_CURSOR
  509. ON_WM_SETCURSOR()
  510. #endif
  511. #ifndef _WIN32_WCE
  512. ON_WM_RBUTTONUP()
  513. ON_WM_SYSCOLORCHANGE()
  514. ON_WM_CAPTURECHANGED()
  515. #endif
  516. #ifndef GRIDCONTROL_NO_CLIPBOARD
  517. ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  518. ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
  519. ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  520. ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)
  521. ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
  522. ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
  523. #endif
  524. #if (_WIN32_WCE >= 210)
  525. ON_WM_SETTINGCHANGE()
  526. #endif
  527. #if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
  528. ON_WM_MOUSEWHEEL()
  529. #endif
  530. ON_MESSAGE(WM_SETFONT, OnSetFont)
  531. ON_MESSAGE(WM_GETFONT, OnGetFont)
  532. ON_MESSAGE(WM_IME_CHAR, OnImeChar)
  533. ON_NOTIFY(GVN_ENDLABELEDIT, IDC_INPLACE_CONTROL, OnEndInPlaceEdit)
  534. END_MESSAGE_MAP()
  535. /////////////////////////////////////////////////////////////////////////////
  536. // CGridCtrl message handlers
  537. void CGridCtrl::OnPaint()
  538. {
  539. CPaintDC dc(this); // device context for painting
  540. if (m_bDoubleBuffer) // Use a memory DC to remove flicker
  541. {
  542. CMemDC MemDC(&dc);
  543. OnDraw(&MemDC);
  544. }
  545. else // Draw raw - this helps in debugging vis problems.
  546. OnDraw(&dc);
  547. }
  548. BOOL CGridCtrl::OnEraseBkgnd(CDC* /*pDC*/)
  549. {
  550. return TRUE; // Don't erase the background.
  551. }
  552. // Custom background erasure. This gets called from within the OnDraw function,
  553. // since we will (most likely) be using a memory DC to stop flicker. If we just
  554. // erase the background normally through OnEraseBkgnd, and didn't fill the memDC's
  555. // selected bitmap with colour, then all sorts of vis problems would occur
  556. void CGridCtrl::EraseBkgnd(CDC* pDC)
  557. {
  558. CRect VisRect, ClipRect, rect;
  559. CBrush FixedRowColBack(GetDefaultCell(TRUE, TRUE)->GetBackClr()),
  560. FixedRowBack(GetDefaultCell(TRUE, FALSE)->GetBackClr()),
  561. FixedColBack(GetDefaultCell(FALSE, TRUE)->GetBackClr()),
  562. TextBack(GetDefaultCell(FALSE, FALSE)->GetBackClr());
  563. CBrush Back(GetGridBkColor());
  564. //CBrush Back(GetTextBkColor());
  565. if (pDC->GetClipBox(ClipRect) == ERROR)
  566. return;
  567. GetVisibleNonFixedCellRange(VisRect);
  568. int nFixedColumnWidth = GetFixedColumnWidth();
  569. int nFixedRowHeight = GetFixedRowHeight();
  570. // Draw Fixed row/column background
  571. if (ClipRect.left < nFixedColumnWidth && ClipRect.top < nFixedRowHeight)
  572. pDC->FillRect(CRect(ClipRect.left, ClipRect.top,
  573. nFixedColumnWidth, nFixedRowHeight),
  574. &FixedRowColBack);
  575. // Draw Fixed columns background
  576. if (ClipRect.left < nFixedColumnWidth && ClipRect.top < VisRect.bottom)
  577. pDC->FillRect(CRect(ClipRect.left, ClipRect.top,
  578. nFixedColumnWidth, VisRect.bottom),
  579. &FixedColBack);
  580. // Draw Fixed rows background
  581. if (ClipRect.top < nFixedRowHeight &&
  582. ClipRect.right > nFixedColumnWidth && ClipRect.left < VisRect.right)
  583. pDC->FillRect(CRect(nFixedColumnWidth - 1, ClipRect.top,
  584. VisRect.right, nFixedRowHeight),
  585. &FixedRowBack);
  586. // Draw non-fixed cell background
  587. if (rect.IntersectRect(VisRect, ClipRect))
  588. {
  589. CRect CellRect(max(nFixedColumnWidth, rect.left),
  590. max(nFixedRowHeight, rect.top),
  591. rect.right, rect.bottom);
  592. pDC->FillRect(CellRect, &TextBack);
  593. }
  594. // Draw right hand side of window outside grid
  595. if (VisRect.right < ClipRect.right)
  596. pDC->FillRect(CRect(VisRect.right, ClipRect.top,
  597. ClipRect.right, ClipRect.bottom),
  598. &Back);
  599. // Draw bottom of window below grid
  600. if (VisRect.bottom < ClipRect.bottom && ClipRect.left < VisRect.right)
  601. pDC->FillRect(CRect(ClipRect.left, VisRect.bottom,
  602. VisRect.right, ClipRect.bottom),
  603. &Back);
  604. }
  605. void CGridCtrl::OnSize(UINT nType, int cx, int cy)
  606. {
  607. static BOOL bAlreadyInsideThisProcedure = FALSE;
  608. if (bAlreadyInsideThisProcedure)
  609. return;
  610. if (!::IsWindow(m_hWnd))
  611. return;
  612. // This hurts - but I need a place for initialisation for the drop target,
  613. // and the window must be created. "Create" is a good place - if one is
  614. // creating the window dynamically. If one is using a dialog template then
  615. // this is no good. Oh well...
  616. # ifndef GRIDCONTROL_NO_DRAGDROP
  617. m_DropTarget.Register(this);
  618. # endif
  619. // Start re-entry blocking
  620. bAlreadyInsideThisProcedure = TRUE;
  621. EndEditing(); // destroy any InPlaceEdit's
  622. CWnd::OnSize(nType, cx, cy);
  623. ResetScrollBars();
  624. // End re-entry blocking
  625. bAlreadyInsideThisProcedure = FALSE;
  626. }
  627. UINT CGridCtrl::OnGetDlgCode()
  628. {
  629. UINT nCode = DLGC_WANTARROWS | DLGC_WANTCHARS; // DLGC_WANTALLKEYS; //
  630. if (m_bHandleTabKey && !IsCTRLpressed())
  631. nCode |= DLGC_WANTTAB;
  632. return nCode;
  633. }
  634. #ifndef _WIN32_WCE
  635. // If system colours change, then redo colours
  636. void CGridCtrl::OnSysColorChange()
  637. {
  638. CWnd::OnSysColorChange();
  639. if (GetDefaultCell(FALSE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
  640. GetDefaultCell(FALSE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  641. if (GetDefaultCell(FALSE, FALSE)->GetBackClr() == m_crWindowColour)
  642. GetDefaultCell(FALSE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  643. if (GetDefaultCell(TRUE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
  644. GetDefaultCell(TRUE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  645. if (GetDefaultCell(TRUE, FALSE)->GetBackClr() == m_crWindowColour)
  646. GetDefaultCell(TRUE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  647. if (GetDefaultCell(FALSE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
  648. GetDefaultCell(FALSE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  649. if (GetDefaultCell(FALSE, TRUE)->GetBackClr() == m_crWindowColour)
  650. GetDefaultCell(FALSE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  651. if (GetDefaultCell(TRUE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
  652. GetDefaultCell(TRUE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  653. if (GetDefaultCell(TRUE, TRUE)->GetBackClr() == m_crWindowColour)
  654. GetDefaultCell(TRUE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  655. if (GetGridBkColor() == m_crShadow)
  656. SetGridBkColor(::GetSysColor(COLOR_3DSHADOW));
  657. m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
  658. m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
  659. m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
  660. m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
  661. }
  662. #endif
  663. #ifndef _WIN32_WCE_NO_CURSOR
  664. // If we are drag-selecting cells, or drag and dropping, stop now
  665. void CGridCtrl::OnCaptureChanged(CWnd *pWnd)
  666. {
  667. if (pWnd->GetSafeHwnd() == GetSafeHwnd())
  668. return;
  669. // kill timer if active
  670. if (m_nTimerID != 0)
  671. {
  672. KillTimer(m_nTimerID);
  673. m_nTimerID = 0;
  674. }
  675. #ifndef GRIDCONTROL_NO_DRAGDROP
  676. // Kill drag and drop if active
  677. if (m_MouseMode == MOUSE_DRAGGING)
  678. m_MouseMode = MOUSE_NOTHING;
  679. #endif
  680. }
  681. #endif
  682. #if (_MFC_VER >= 0x0421) || (_WIN32_WCE >= 210)
  683. // If system settings change, then redo colours
  684. void CGridCtrl::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
  685. {
  686. CWnd::OnSettingChange(uFlags, lpszSection);
  687. if (GetDefaultCell(FALSE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
  688. GetDefaultCell(FALSE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  689. if (GetDefaultCell(FALSE, FALSE)->GetBackClr() == m_crWindowColour)
  690. GetDefaultCell(FALSE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  691. if (GetDefaultCell(TRUE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
  692. GetDefaultCell(TRUE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  693. if (GetDefaultCell(TRUE, FALSE)->GetBackClr() == m_crWindowColour)
  694. GetDefaultCell(TRUE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  695. if (GetDefaultCell(FALSE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
  696. GetDefaultCell(FALSE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  697. if (GetDefaultCell(FALSE, TRUE)->GetBackClr() == m_crWindowColour)
  698. GetDefaultCell(FALSE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  699. if (GetDefaultCell(TRUE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
  700. GetDefaultCell(TRUE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  701. if (GetDefaultCell(TRUE, TRUE)->GetBackClr() == m_crWindowColour)
  702. GetDefaultCell(TRUE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  703. if (GetGridBkColor() == m_crShadow)
  704. SetGridBkColor(::GetSysColor(COLOR_3DSHADOW));
  705. m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
  706. m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
  707. m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
  708. m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
  709. m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
  710. }
  711. #endif
  712. // For drag-selection. Scrolls hidden cells into view
  713. // TODO: decrease timer interval over time to speed up selection over time
  714. void CGridCtrl::OnTimer(UINT nIDEvent)
  715. {
  716. ASSERT(nIDEvent == WM_LBUTTONDOWN);
  717. if (nIDEvent != WM_LBUTTONDOWN)
  718. return;
  719. CPoint pt, origPt;
  720. #ifdef _WIN32_WCE
  721. if (m_MouseMode == MOUSE_NOTHING)
  722. return;
  723. origPt = GetMessagePos();
  724. #else
  725. if (!GetCursorPos(&origPt))
  726. return;
  727. #endif
  728. ScreenToClient(&origPt);
  729. CRect rect;
  730. GetClientRect(rect);
  731. int nFixedRowHeight = GetFixedRowHeight();
  732. int nFixedColWidth = GetFixedColumnWidth();
  733. pt = origPt;
  734. if (pt.y > rect.bottom)
  735. {
  736. //SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  737. SendMessage(WM_KEYDOWN, VK_DOWN, 0);
  738. if (pt.x < rect.left)
  739. pt.x = rect.left;
  740. if (pt.x > rect.right)
  741. pt.x = rect.right;
  742. pt.y = rect.bottom;
  743. OnSelecting(GetCellFromPt(pt));
  744. }
  745. else if (pt.y < nFixedRowHeight)
  746. {
  747. //SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  748. SendMessage(WM_KEYDOWN, VK_UP, 0);
  749. if (pt.x < rect.left)
  750. pt.x = rect.left;
  751. if (pt.x > rect.right)
  752. pt.x = rect.right;
  753. pt.y = nFixedRowHeight + 1;
  754. OnSelecting(GetCellFromPt(pt));
  755. }
  756. pt = origPt;
  757. if (pt.x > rect.right)
  758. {
  759. // SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  760. SendMessage(WM_KEYDOWN, VK_RIGHT, 0);
  761. if (pt.y < rect.top)
  762. pt.y = rect.top;
  763. if (pt.y > rect.bottom)
  764. pt.y = rect.bottom;
  765. pt.x = rect.right;
  766. OnSelecting(GetCellFromPt(pt));
  767. }
  768. else if (pt.x < nFixedColWidth)
  769. {
  770. //SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  771. SendMessage(WM_KEYDOWN, VK_LEFT, 0);
  772. if (pt.y < rect.top)
  773. pt.y = rect.top;
  774. if (pt.y > rect.bottom)
  775. pt.y = rect.bottom;
  776. pt.x = nFixedColWidth + 1;
  777. OnSelecting(GetCellFromPt(pt));
  778. }
  779. }
  780. // move about with keyboard
  781. void CGridCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  782. {
  783. if (!IsValid(m_idCurrentCell))
  784. {
  785. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  786. return;
  787. }
  788. CCellID next = m_idCurrentCell;
  789. BOOL bChangeLine = FALSE;
  790. BOOL bHorzScrollAction = FALSE;
  791. BOOL bVertScrollAction = FALSE;
  792. if (IsCTRLpressed())
  793. {
  794. switch (nChar)
  795. {
  796. case 'A':
  797. OnEditSelectAll();
  798. break;
  799. #ifndef GRIDCONTROL_NO_CLIPBOARD
  800. case 'X':
  801. OnEditCut();
  802. break;
  803. case VK_INSERT:
  804. case 'C':
  805. OnEditCopy();
  806. break;
  807. case 'V':
  808. OnEditPaste();
  809. break;
  810. #endif
  811. }
  812. }
  813. #ifndef GRIDCONTROL_NO_CLIPBOARD
  814. if (IsSHIFTpressed() && (nChar == VK_INSERT))
  815. OnEditPaste();
  816. #endif
  817. BOOL bFoundVisible;
  818. int iOrig;
  819. if (nChar == VK_DELETE)
  820. {
  821. ValidateAndModifyCellContents(m_idCurrentCell.row, m_idCurrentCell.col, _T(""));
  822. }
  823. else if (nChar == VK_DOWN)
  824. {
  825. // don't let user go to a hidden row
  826. bFoundVisible = FALSE;
  827. iOrig = next.row;
  828. next.row++;
  829. while (next.row < GetRowCount())
  830. {
  831. if (GetRowHeight(next.row) > 0)
  832. {
  833. bFoundVisible = TRUE;
  834. break;
  835. }
  836. next.row++;
  837. }
  838. if (!bFoundVisible)
  839. next.row = iOrig;
  840. }
  841. else if (nChar == VK_UP)
  842. {
  843. // don't let user go to a hidden row
  844. bFoundVisible = FALSE;
  845. iOrig = next.row;
  846. next.row--;
  847. while (next.row >= m_nFixedRows)
  848. {
  849. if (GetRowHeight(next.row) > 0)
  850. {
  851. bFoundVisible = TRUE;
  852. break;
  853. }
  854. next.row--;
  855. }
  856. if (!bFoundVisible)
  857. next.row = iOrig;
  858. }
  859. else if (nChar == VK_RIGHT || (nChar == VK_TAB && !IsSHIFTpressed()))
  860. {
  861. // don't let user go to a hidden column
  862. bFoundVisible = FALSE;
  863. iOrig = next.col;
  864. next.col++;
  865. if (nChar == VK_TAB)
  866. {
  867. if (next.col == (GetColumnCount()) && next.row < (GetRowCount() - 1))
  868. {
  869. next.row++;
  870. next.col = m_nFixedCols;
  871. bChangeLine = TRUE;
  872. }
  873. else
  874. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  875. }
  876. while (next.col < GetColumnCount())
  877. {
  878. if (GetColumnWidth(next.col) > 0)
  879. {
  880. bFoundVisible = TRUE;
  881. break;
  882. }
  883. next.col++;
  884. }
  885. if (!bFoundVisible)
  886. next.col = iOrig;
  887. }
  888. else if (nChar == VK_LEFT || (nChar == VK_TAB && IsSHIFTpressed()))
  889. {
  890. // don't let user go to a hidden column
  891. bFoundVisible = FALSE;
  892. iOrig = next.col;
  893. next.col--;
  894. if (nChar == VK_TAB)
  895. {
  896. if (next.col == (GetFixedColumnCount() - 1) && next.row > GetFixedRowCount())
  897. {
  898. next.row--;
  899. next.col = GetColumnCount() - 1;
  900. bChangeLine = TRUE;
  901. }
  902. else
  903. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  904. }
  905. while (next.col >= m_nFixedCols)
  906. {
  907. if (GetColumnWidth(next.col) > 0)
  908. {
  909. bFoundVisible = TRUE;
  910. break;
  911. }
  912. next.col--;
  913. }
  914. if (!bFoundVisible)
  915. next.col = iOrig;
  916. }
  917. else if (nChar == VK_NEXT)
  918. {
  919. CCellID idOldTopLeft = GetTopleftNonFixedCell();
  920. SendMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
  921. bVertScrollAction = TRUE;
  922. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  923. int increment = idNewTopLeft.row - idOldTopLeft.row;
  924. if (increment)
  925. {
  926. next.row += increment;
  927. if (next.row > (GetRowCount() - 1))
  928. next.row = GetRowCount() - 1;
  929. }
  930. else
  931. next.row = GetRowCount() - 1;
  932. }
  933. else if (nChar == VK_PRIOR)
  934. {
  935. CCellID idOldTopLeft = GetTopleftNonFixedCell();
  936. SendMessage(WM_VSCROLL, SB_PAGEUP, 0);
  937. bVertScrollAction = TRUE;
  938. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  939. int increment = idNewTopLeft.row - idOldTopLeft.row;
  940. if (increment)
  941. {
  942. next.row += increment;
  943. if (next.row < m_nFixedRows)
  944. next.row = m_nFixedRows;
  945. }
  946. else
  947. next.row = m_nFixedRows;
  948. }
  949. else if (nChar == VK_HOME)
  950. {
  951. // Home and Ctrl-Home work more like Excel
  952. // and don't let user go to a hidden cell
  953. if (IsCTRLpressed())
  954. {
  955. SendMessage(WM_VSCROLL, SB_TOP, 0);
  956. SendMessage(WM_HSCROLL, SB_LEFT, 0);
  957. bVertScrollAction = TRUE;
  958. bHorzScrollAction = TRUE;
  959. next.row = m_nFixedRows;
  960. next.col = m_nFixedCols;
  961. }
  962. else
  963. {
  964. SendMessage(WM_HSCROLL, SB_LEFT, 0);
  965. bHorzScrollAction = TRUE;
  966. next.col = m_nFixedCols;
  967. }
  968. // adjust column to avoid hidden columns and rows
  969. while (next.col < GetColumnCount() - 1)
  970. {
  971. if (GetColumnWidth(next.col) > 0)
  972. break;
  973. next.col++;
  974. }
  975. while (next.row < GetRowCount() - 1)
  976. {
  977. if (GetRowHeight(next.row) > 0)
  978. break;
  979. next.row++;
  980. }
  981. }
  982. else if (nChar == VK_END)
  983. {
  984. // End and Ctrl-End work more like Excel
  985. // and don't let user go to a hidden cell
  986. if (IsCTRLpressed())
  987. {
  988. SendMessage(WM_VSCROLL, SB_BOTTOM, 0);
  989. SendMessage(WM_HSCROLL, SB_RIGHT, 0);
  990. bHorzScrollAction = TRUE;
  991. bVertScrollAction = TRUE;
  992. next.row = GetRowCount() - 1;
  993. next.col = GetColumnCount() - 1;
  994. }
  995. else
  996. {
  997. SendMessage(WM_HSCROLL, SB_RIGHT, 0);
  998. bHorzScrollAction = TRUE;
  999. next.col = GetColumnCount() - 1;
  1000. }
  1001. // adjust column to avoid hidden columns and rows
  1002. while (next.col > m_nFixedCols + 1)
  1003. {
  1004. if (GetColumnWidth(next.col) > 0)
  1005. break;
  1006. next.col--;
  1007. }
  1008. while (next.row > m_nFixedRows + 1)
  1009. {
  1010. if (GetRowHeight(next.row) > 0)
  1011. break;
  1012. next.row--;
  1013. }
  1014. }
  1015. else if (nChar == VK_F2)
  1016. {
  1017. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint(-1, -1), VK_LBUTTON);
  1018. }
  1019. else
  1020. {
  1021. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  1022. return;
  1023. }
  1024. if (next != m_idCurrentCell)
  1025. {
  1026. // While moving with the Cursorkeys the current ROW/CELL will get selected
  1027. // OR Selection will get expanded when SHIFT is pressed
  1028. // Cut n paste from OnLButtonDown - Franco Bez
  1029. // Added check for NULL mouse mode - Chris Maunder.
  1030. if (m_MouseMode == MOUSE_NOTHING)
  1031. {
  1032. m_PrevSelectedCellMap.RemoveAll();
  1033. m_MouseMode = m_bListMode ? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
  1034. if (!IsSHIFTpressed() || nChar == VK_TAB)
  1035. m_SelectionStartCell = next;
  1036. OnSelecting(next);
  1037. m_MouseMode = MOUSE_NOTHING;
  1038. }
  1039. SetFocusCell(next);
  1040. if (!IsCellVisible(next))
  1041. {
  1042. switch (nChar)
  1043. {
  1044. case VK_RIGHT:
  1045. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  1046. bHorzScrollAction = TRUE;
  1047. break;
  1048. case VK_LEFT:
  1049. SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  1050. bHorzScrollAction = TRUE;
  1051. break;
  1052. case VK_DOWN:
  1053. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  1054. bVertScrollAction = TRUE;
  1055. break;
  1056. case VK_UP:
  1057. SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  1058. bVertScrollAction = TRUE;
  1059. break;
  1060. case VK_TAB:
  1061. if (IsSHIFTpressed())
  1062. {
  1063. if (bChangeLine)
  1064. {
  1065. SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  1066. bVertScrollAction = TRUE;
  1067. SetScrollPos32(SB_HORZ, m_nHScrollMax);
  1068. break;
  1069. }
  1070. else
  1071. {
  1072. SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  1073. bHorzScrollAction = TRUE;
  1074. }
  1075. }
  1076. else
  1077. {
  1078. if (bChangeLine)
  1079. {
  1080. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  1081. bVertScrollAction = TRUE;
  1082. SetScrollPos32(SB_HORZ, 0);
  1083. break;
  1084. }
  1085. else
  1086. {
  1087. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  1088. bHorzScrollAction = TRUE;
  1089. }
  1090. }
  1091. break;
  1092. }
  1093. EnsureVisible(next); // Make sure cell is visible
  1094. Invalidate();
  1095. }
  1096. EnsureVisible(next); // Make sure cell is visible
  1097. if (bHorzScrollAction)
  1098. SendMessage(WM_HSCROLL, SB_ENDSCROLL, 0);
  1099. if (bVertScrollAction)
  1100. SendMessage(WM_VSCROLL, SB_ENDSCROLL, 0);
  1101. }
  1102. }
  1103. void CGridCtrl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  1104. {
  1105. CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
  1106. }
  1107. void CGridCtrl::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  1108. {
  1109. #ifdef GRIDCONTROL_USE_TITLETIPS
  1110. m_TitleTip.Hide(); // hide any titletips
  1111. #endif
  1112. CWnd::OnSysKeyDown(nChar, nRepCnt, nFlags);
  1113. }
  1114. // Instant editing of cells when keys are pressed
  1115. void CGridCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  1116. {
  1117. // EFW - BUG FIX
  1118. if (!IsCTRLpressed() && m_MouseMode == MOUSE_NOTHING && nChar != VK_ESCAPE)
  1119. {
  1120. if (!m_bHandleTabKey || (m_bHandleTabKey && nChar != VK_TAB))
  1121. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint(-1, -1), nChar);
  1122. }
  1123. CWnd::OnChar(nChar, nRepCnt, nFlags);
  1124. }
  1125. // Added by KiteFly
  1126. LRESULT CGridCtrl::OnImeChar(WPARAM wCharCode, LPARAM)
  1127. {
  1128. // EFW - BUG FIX
  1129. if (!IsCTRLpressed() && m_MouseMode == MOUSE_NOTHING && wCharCode != VK_ESCAPE)
  1130. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint(-1, -1), wCharCode);
  1131. return 0;
  1132. }
  1133. // Callback from any CInPlaceEdits that ended. This just calls OnEndEditCell,
  1134. // refreshes the edited cell and moves onto next cell if the return character
  1135. // from the edit says we should.
  1136. void CGridCtrl::OnEndInPlaceEdit(NMHDR* pNMHDR, LRESULT* pResult)
  1137. {
  1138. GV_DISPINFO *pgvDispInfo = (GV_DISPINFO *)pNMHDR;
  1139. GV_ITEM *pgvItem = &pgvDispInfo->item;
  1140. // In case OnEndInPlaceEdit called as window is being destroyed
  1141. if (!IsWindow(GetSafeHwnd()))
  1142. return;
  1143. OnEndEditCell(pgvItem->row, pgvItem->col, pgvItem->strText);
  1144. //InvalidateCellRect(CCellID(pgvItem->row, pgvItem->col));
  1145. switch (pgvItem->lParam)
  1146. {
  1147. case VK_TAB:
  1148. case VK_DOWN:
  1149. case VK_UP:
  1150. case VK_RIGHT:
  1151. case VK_LEFT:
  1152. case VK_NEXT:
  1153. case VK_PRIOR:
  1154. case VK_HOME:
  1155. case VK_END:
  1156. OnKeyDown(pgvItem->lParam, 0, 0);
  1157. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint(-1, -1), pgvItem->lParam);
  1158. }
  1159. *pResult = 0;
  1160. }
  1161. // Handle horz scrollbar notifications
  1162. void CGridCtrl::OnHScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
  1163. {
  1164. EndEditing();
  1165. #ifndef GRIDCONTROL_NO_TITLETIPS
  1166. m_TitleTip.Hide(); // hide any titletips
  1167. #endif
  1168. int scrollPos = GetScrollPos32(SB_HORZ);
  1169. CCellID idTopLeft = GetTopleftNonFixedCell();
  1170. CRect rect;
  1171. GetClientRect(rect);
  1172. switch (nSBCode)
  1173. {
  1174. case SB_LINERIGHT:
  1175. if (scrollPos < m_nHScrollMax)
  1176. {
  1177. // may have contiguous hidden columns. Blow by them
  1178. while (idTopLeft.col < (GetColumnCount() - 1)
  1179. && GetColumnWidth(idTopLeft.col) < 1)
  1180. {
  1181. idTopLeft.col++;
  1182. }
  1183. int xScroll = GetColumnWidth(idTopLeft.col);
  1184. SetScrollPos32(SB_HORZ, scrollPos + xScroll);
  1185. if (GetScrollPos32(SB_HORZ) == scrollPos)
  1186. break; // didn't work
  1187. rect.left = GetFixedColumnWidth();
  1188. //rect.left = GetFixedColumnWidth() + xScroll;
  1189. //ScrollWindow(-xScroll, 0, rect);
  1190. //rect.left = rect.right - xScroll;
  1191. InvalidateRect(rect);
  1192. }
  1193. break;
  1194. case SB_LINELEFT:
  1195. if (scrollPos > 0 && idTopLeft.col > GetFixedColumnCount())
  1196. {
  1197. int iColToUse = idTopLeft.col - 1;
  1198. // may have contiguous hidden columns. Blow by them
  1199. while (iColToUse > GetFixedColumnCount()
  1200. && GetColumnWidth(iColToUse) < 1)
  1201. {
  1202. iColToUse--;
  1203. }
  1204. int xScroll = GetColumnWidth(iColToUse);
  1205. SetScrollPos32(SB_HORZ, max(0, scrollPos - xScroll));
  1206. rect.left = GetFixedColumnWidth();
  1207. //ScrollWindow(xScroll, 0, rect);
  1208. //rect.right = rect.left + xScroll;
  1209. InvalidateRect(rect);
  1210. }
  1211. break;
  1212. case SB_PAGERIGHT:
  1213. if (scrollPos < m_nHScrollMax)
  1214. {
  1215. rect.left = GetFixedColumnWidth();
  1216. int offset = rect.Width();
  1217. int pos = min(m_nHScrollMax, scrollPos + offset);
  1218. SetScrollPos32(SB_HORZ, pos);
  1219. rect.left = GetFixedColumnWidth();
  1220. InvalidateRect(rect);
  1221. }
  1222. break;
  1223. case SB_PAGELEFT:
  1224. if (scrollPos > 0)
  1225. {
  1226. rect.left = GetFixedColumnWidth();
  1227. int offset = -rect.Width();
  1228. int pos = max(0, scrollPos + offset);
  1229. SetScrollPos32(SB_HORZ, pos);
  1230. rect.left = GetFixedColumnWidth();
  1231. InvalidateRect(rect);
  1232. }
  1233. break;
  1234. case SB_THUMBPOSITION:
  1235. case SB_THUMBTRACK:
  1236. {
  1237. SetScrollPos32(SB_HORZ, GetScrollPos32(SB_HORZ, TRUE));
  1238. m_idTopLeftCell.row = -1;
  1239. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  1240. if (idNewTopLeft != idTopLeft)
  1241. {
  1242. rect.left = GetFixedColumnWidth();
  1243. InvalidateRect(rect);
  1244. }
  1245. }
  1246. break;
  1247. case SB_LEFT:
  1248. if (scrollPos > 0)
  1249. {
  1250. SetScrollPos32(SB_HORZ, 0);
  1251. Invalidate();
  1252. }
  1253. break;
  1254. case SB_RIGHT:
  1255. if (scrollPos < m_nHScrollMax)
  1256. {
  1257. SetScrollPos32(SB_HORZ, m_nHScrollMax);
  1258. Invalidate();
  1259. }
  1260. break;
  1261. default:
  1262. break;
  1263. }
  1264. }
  1265. // Handle vert scrollbar notifications
  1266. void CGridCtrl::OnVScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
  1267. {
  1268. EndEditing();
  1269. #ifndef GRIDCONTROL_NO_TITLETIPS
  1270. m_TitleTip.Hide(); // hide any titletips
  1271. #endif
  1272. // Get the scroll position ourselves to ensure we get a 32 bit value
  1273. int scrollPos = GetScrollPos32(SB_VERT);
  1274. CCellID idTopLeft = GetTopleftNonFixedCell();
  1275. CRect rect;
  1276. GetClientRect(rect);
  1277. switch (nSBCode)
  1278. {
  1279. case SB_LINEDOWN:
  1280. if (scrollPos < m_nVScrollMax)
  1281. {
  1282. // may have contiguous hidden rows. Blow by them
  1283. while (idTopLeft.row < (GetRowCount() - 1)
  1284. && GetRowHeight(idTopLeft.row) < 1)
  1285. {
  1286. idTopLeft.row++;
  1287. }
  1288. int yScroll = GetRowHeight(idTopLeft.row);
  1289. SetScrollPos32(SB_VERT, scrollPos + yScroll);
  1290. if (GetScrollPos32(SB_VERT) == scrollPos)
  1291. break; // didn't work
  1292. rect.top = GetFixedRowHeight();
  1293. //rect.top = GetFixedRowHeight() + yScroll;
  1294. //ScrollWindow(0, -yScroll, rect);
  1295. //rect.top = rect.bottom - yScroll;
  1296. InvalidateRect(rect);
  1297. }
  1298. break;
  1299. case SB_LINEUP:
  1300. if (scrollPos > 0 && idTopLeft.row > GetFixedRowCount())
  1301. {
  1302. int iRowToUse = idTopLeft.row - 1;
  1303. // may have contiguous hidden rows. Blow by them
  1304. while (iRowToUse > GetFixedRowCount()
  1305. && GetRowHeight(iRowToUse) < 1)
  1306. {
  1307. iRowToUse--;
  1308. }
  1309. int yScroll = GetRowHeight(iRowToUse);
  1310. SetScrollPos32(SB_VERT, max(0, scrollPos - yScroll));
  1311. rect.top = GetFixedRowHeight();
  1312. //ScrollWindow(0, yScroll, rect);
  1313. //rect.bottom = rect.top + yScroll;
  1314. InvalidateRect(rect);
  1315. }
  1316. break;
  1317. case SB_PAGEDOWN:
  1318. if (scrollPos < m_nVScrollMax)
  1319. {
  1320. rect.top = GetFixedRowHeight();
  1321. scrollPos = min(m_nVScrollMax, scrollPos + rect.Height());
  1322. SetScrollPos32(SB_VERT, scrollPos);
  1323. rect.top = GetFixedRowHeight();
  1324. InvalidateRect(rect);
  1325. }
  1326. break;
  1327. case SB_PAGEUP:
  1328. if (scrollPos > 0)
  1329. {
  1330. rect.top = GetFixedRowHeight();
  1331. int offset = -rect.Height();
  1332. int pos = max(0, scrollPos + offset);
  1333. SetScrollPos32(SB_VERT, pos);
  1334. rect.top = GetFixedRowHeight();
  1335. InvalidateRect(rect);
  1336. }
  1337. break;
  1338. case SB_THUMBPOSITION:
  1339. case SB_THUMBTRACK:
  1340. {
  1341. SetScrollPos32(SB_VERT, GetScrollPos32(SB_VERT, TRUE));
  1342. m_idTopLeftCell.row = -1;
  1343. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  1344. if (idNewTopLeft != idTopLeft)
  1345. {
  1346. rect.top = GetFixedRowHeight();
  1347. InvalidateRect(rect);
  1348. }
  1349. }
  1350. break;
  1351. case SB_TOP:
  1352. if (scrollPos > 0)
  1353. {
  1354. SetScrollPos32(SB_VERT, 0);
  1355. Invalidate();
  1356. }
  1357. break;
  1358. case SB_BOTTOM:
  1359. if (scrollPos < m_nVScrollMax)
  1360. {
  1361. SetScrollPos32(SB_VERT, m_nVScrollMax);
  1362. Invalidate();
  1363. }
  1364. default:
  1365. break;
  1366. }
  1367. }
  1368. /////////////////////////////////////////////////////////////////////////////
  1369. // CGridCtrl implementation functions
  1370. void CGridCtrl::OnDraw(CDC* pDC)
  1371. {
  1372. if (!m_bAllowDraw)
  1373. return;
  1374. CRect clipRect;
  1375. if (pDC->GetClipBox(&clipRect) == ERROR)
  1376. return;
  1377. EraseBkgnd(pDC); // OnEraseBkgnd does nothing, so erase bkgnd here.
  1378. // This necessary since we may be using a Memory DC.
  1379. CRect rect;
  1380. int row, col;
  1381. CGridCellBase* pCell;
  1382. int nFixedRowHeight = GetFixedRowHeight();
  1383. int nFixedColWidth = GetFixedColumnWidth();
  1384. CCellID idTopLeft = GetTopleftNonFixedCell();
  1385. int minVisibleRow = idTopLeft.row,
  1386. minVisibleCol = idTopLeft.col;
  1387. CRect VisRect;
  1388. CCellRange VisCellRange = GetVisibleNonFixedCellRange(VisRect);
  1389. int maxVisibleRow = VisCellRange.GetMaxRow(),
  1390. maxVisibleCol = VisCellRange.GetMaxCol();
  1391. if (GetVirtualMode())
  1392. SendCacheHintToParent(VisCellRange);
  1393. // draw top-left cells 0..m_nFixedRows-1, 0..m_nFixedCols-1
  1394. rect.bottom = -1;
  1395. for (row = 0; row < m_nFixedRows; row++)
  1396. {
  1397. rect.top = rect.bottom + 1;
  1398. rect.bottom = rect.top + GetRowHeight(row) - 1;
  1399. rect.right = -1;
  1400. for (col = 0; col < m_nFixedCols; col++)
  1401. {
  1402. rect.left = rect.right + 1;
  1403. rect.right = rect.left + GetColumnWidth(col) - 1;
  1404. pCell = GetCell(row, col);
  1405. if (pCell)
  1406. pCell->Draw(pDC, row, col, rect, FALSE);
  1407. }
  1408. }
  1409. // draw fixed column cells: m_nFixedRows..n, 0..m_nFixedCols-1
  1410. rect.bottom = nFixedRowHeight - 1;
  1411. for (row = minVisibleRow; row <= maxVisibleRow; row++)
  1412. {
  1413. rect.top = rect.bottom + 1;
  1414. rect.bottom = rect.top + GetRowHeight(row) - 1;
  1415. // rect.bottom = bottom pixel of previous row
  1416. if (rect.top > clipRect.bottom)
  1417. break; // Gone past cliprect
  1418. if (rect.bottom < clipRect.top)
  1419. continue; // Reached cliprect yet?
  1420. rect.right = -1;
  1421. for (col = 0; col < m_nFixedCols; col++)
  1422. {
  1423. rect.left = rect.right + 1;
  1424. rect.right = rect.left + GetColumnWidth(col) - 1;
  1425. if (rect.left > clipRect.right)
  1426. break; // gone past cliprect
  1427. if (rect.right < clipRect.left)
  1428. continue; // Reached cliprect yet?
  1429. pCell = GetCell(row, col);
  1430. if (pCell)
  1431. pCell->Draw(pDC, row, col, rect, FALSE);
  1432. }
  1433. }
  1434. // draw fixed row cells 0..m_nFixedRows, m_nFixedCols..n
  1435. rect.bottom = -1;
  1436. for (row = 0; row < m_nFixedRows; row++)
  1437. {
  1438. rect.top = rect.bottom + 1;
  1439. rect.bottom = rect.top + GetRowHeight(row) - 1;
  1440. // rect.bottom = bottom pixel of previous row
  1441. if (rect.top > clipRect.bottom)
  1442. break; // Gone past cliprect
  1443. if (rect.bottom < clipRect.top)
  1444. continue; // Reached cliprect yet?
  1445. rect.right = nFixedColWidth - 1;
  1446. for (col = minVisibleCol; col <= maxVisibleCol; col++)
  1447. {
  1448. rect.left = rect.right + 1;
  1449. rect.right = rect.left + GetColumnWidth(col) - 1;
  1450. if (rect.left > clipRect.right)
  1451. break; // gone past cliprect
  1452. if (rect.right < clipRect.left)
  1453. continue; // Reached cliprect yet?
  1454. pCell = GetCell(row, col);
  1455. if (pCell)
  1456. pCell->Draw(pDC, row, col, rect, FALSE);
  1457. }
  1458. }
  1459. // draw rest of non-fixed cells
  1460. rect.bottom = nFixedRowHeight - 1;
  1461. for (row = minVisibleRow; row <= maxVisibleRow; row++)
  1462. {
  1463. rect.top = rect.bottom + 1;
  1464. rect.bottom = rect.top + GetRowHeight(row) - 1;
  1465. // rect.bottom = bottom pixel of previous row
  1466. if (rect.top > clipRect.bottom)
  1467. break; // Gone past cliprect
  1468. if (rect.bottom < clipRect.top)
  1469. continue; // Reached cliprect yet?
  1470. rect.right = nFixedColWidth - 1;
  1471. for (col = minVisibleCol; col <= maxVisibleCol; col++)
  1472. {
  1473. rect.left = rect.right + 1;
  1474. rect.right = rect.left + GetColumnWidth(col) - 1;
  1475. if (rect.left > clipRect.right)
  1476. break; // gone past cliprect
  1477. if (rect.right < clipRect.left)
  1478. continue; // Reached cliprect yet?
  1479. pCell = GetCell(row, col);
  1480. // TRACE(_T("Cell %d,%d type: %s\n"), row, col, pCell->GetRuntimeClass()->m_lpszClassName);
  1481. if (pCell)
  1482. pCell->Draw(pDC, row, col, rect, FALSE);
  1483. }
  1484. }
  1485. CPen pen;
  1486. pen.CreatePen(PS_SOLID, 0, m_crGridLineColour);
  1487. pDC->SelectObject(&pen);
  1488. // draw vertical lines (drawn at ends of cells)
  1489. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  1490. {
  1491. int x = nFixedColWidth;
  1492. for (col = minVisibleCol; col <= maxVisibleCol; col++)
  1493. {
  1494. x += GetColumnWidth(col);
  1495. pDC->MoveTo(x - 1, nFixedRowHeight);
  1496. pDC->LineTo(x - 1, VisRect.bottom);
  1497. }
  1498. }
  1499. // draw horizontal lines (drawn at bottom of each cell)
  1500. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  1501. {
  1502. int y = nFixedRowHeight;
  1503. for (row = minVisibleRow; row <= maxVisibleRow; row++)
  1504. {
  1505. y += GetRowHeight(row);
  1506. pDC->MoveTo(nFixedColWidth, y - 1);
  1507. pDC->LineTo(VisRect.right, y - 1);
  1508. }
  1509. }
  1510. pDC->SelectStockObject(NULL_PEN);
  1511. // Let parent know it can discard it's data if it needs to.
  1512. if (GetVirtualMode())
  1513. SendCacheHintToParent(CCellRange(-1, -1, -1, -1));
  1514. }
  1515. ////////////////////////////////////////////////////////////////////////////////////////
  1516. // CGridCtrl Cell selection stuff
  1517. // Is a given cell designation valid (ie within the bounds of our number
  1518. // of columns/rows)?
  1519. BOOL CGridCtrl::IsValid(int nRow, int nCol) const
  1520. {
  1521. return (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols);
  1522. }
  1523. BOOL CGridCtrl::IsValid(const CCellID& cell) const
  1524. {
  1525. return IsValid(cell.row, cell.col);
  1526. }
  1527. // Is a given cell range valid (ie within the bounds of our number
  1528. // of columns/rows)?
  1529. BOOL CGridCtrl::IsValid(const CCellRange& range) const
  1530. {
  1531. return (range.GetMinRow() >= 0 && range.GetMinCol() >= 0 &&
  1532. range.GetMaxRow() >= 0 && range.GetMaxCol() >= 0 &&
  1533. range.GetMaxRow() < m_nRows && range.GetMaxCol() < m_nCols &&
  1534. range.GetMinRow() <= range.GetMaxRow() && range.GetMinCol() <= range.GetMaxCol());
  1535. }
  1536. // Enables/Disables redraw for certain operations like columns auto-sizing etc,
  1537. // but not for user caused things such as selection changes.
  1538. void CGridCtrl::SetRedraw(BOOL bAllowDraw, BOOL bResetScrollBars /* = FALSE */)
  1539. {
  1540. // TRACE(_T("%s: Setting redraw to %s\n"),
  1541. // GetRuntimeClass()->m_lpszClassName, bAllowDraw? _T("TRUE") : _T("FALSE"));
  1542. if (bAllowDraw && !m_bAllowDraw)
  1543. {
  1544. m_bAllowDraw = TRUE;
  1545. Refresh();
  1546. }
  1547. m_bAllowDraw = bAllowDraw;
  1548. if (bResetScrollBars)
  1549. ResetScrollBars();
  1550. }
  1551. // Forces a redraw of a cell immediately (using a direct DC construction,
  1552. // or the supplied dc)
  1553. BOOL CGridCtrl::RedrawCell(const CCellID& cell, CDC* pDC /* = NULL */)
  1554. {
  1555. return RedrawCell(cell.row, cell.col, pDC);
  1556. }
  1557. BOOL CGridCtrl::RedrawCell(int nRow, int nCol, CDC* pDC /* = NULL */)
  1558. {
  1559. BOOL bResult = TRUE;
  1560. BOOL bMustReleaseDC = FALSE;
  1561. if (!m_bAllowDraw || !IsCellVisible(nRow, nCol))
  1562. return FALSE;
  1563. CRect rect;
  1564. if (!GetCellRect(nRow, nCol, rect))
  1565. return FALSE;
  1566. if (!pDC)
  1567. {
  1568. pDC = GetDC();
  1569. if (pDC)
  1570. bMustReleaseDC = TRUE;
  1571. }
  1572. if (pDC)
  1573. {
  1574. // Redraw cells directly
  1575. if (nRow < m_nFixedRows || nCol < m_nFixedCols)
  1576. {
  1577. CGridCellBase* pCell = GetCell(nRow, nCol);
  1578. if (pCell)
  1579. bResult = pCell->Draw(pDC, nRow, nCol, rect, TRUE);
  1580. }
  1581. else
  1582. {
  1583. CGridCellBase* pCell = GetCell(nRow, nCol);
  1584. if (pCell)
  1585. bResult = pCell->Draw(pDC, nRow, nCol, rect, TRUE);
  1586. // Since we have erased the background, we will need to redraw the gridlines
  1587. CPen pen;
  1588. pen.CreatePen(PS_SOLID, 0, m_crGridLineColour);
  1589. CPen* pOldPen = (CPen*)pDC->SelectObject(&pen);
  1590. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  1591. {
  1592. pDC->MoveTo(rect.left, rect.bottom);
  1593. pDC->LineTo(rect.right + 1, rect.bottom);
  1594. }
  1595. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  1596. {
  1597. pDC->MoveTo(rect.right, rect.top);
  1598. pDC->LineTo(rect.right, rect.bottom + 1);
  1599. }
  1600. pDC->SelectObject(pOldPen);
  1601. }
  1602. }
  1603. else
  1604. InvalidateRect(rect, TRUE); // Could not get a DC - invalidate it anyway
  1605. // and hope that OnPaint manages to get one
  1606. if (bMustReleaseDC)
  1607. ReleaseDC(pDC);
  1608. return bResult;
  1609. }
  1610. // redraw a complete row
  1611. BOOL CGridCtrl::RedrawRow(int row)
  1612. {
  1613. BOOL bResult = TRUE;
  1614. CDC* pDC = GetDC();
  1615. for (int col = 0; col < GetColumnCount(); col++)
  1616. bResult = RedrawCell(row, col, pDC) && bResult;
  1617. if (pDC)
  1618. ReleaseDC(pDC);
  1619. return bResult;
  1620. }
  1621. // redraw a complete column
  1622. BOOL CGridCtrl::RedrawColumn(int col)
  1623. {
  1624. BOOL bResult = TRUE;
  1625. CDC* pDC = GetDC();
  1626. for (int row = 0; row < GetRowCount(); row++)
  1627. bResult = RedrawCell(row, col, pDC) && bResult;
  1628. if (pDC)
  1629. ReleaseDC(pDC);
  1630. return bResult;
  1631. }
  1632. // Sets the currently selected cell, returning the previous current cell
  1633. CCellID CGridCtrl::SetFocusCell(int nRow, int nCol)
  1634. {
  1635. return SetFocusCell(CCellID(nRow, nCol));
  1636. }
  1637. CCellID CGridCtrl::SetFocusCell(CCellID cell)
  1638. {
  1639. if (cell == m_idCurrentCell)
  1640. return m_idCurrentCell;
  1641. CCellID idPrev = m_idCurrentCell;
  1642. // EFW - Bug Fix - Force focus to be in a non-fixed cell
  1643. if (cell.row != -1 && cell.row < GetFixedRowCount())
  1644. cell.row = GetFixedRowCount();
  1645. if (cell.col != -1 && cell.col < GetFixedColumnCount())
  1646. cell.col = GetFixedColumnCount();
  1647. m_idCurrentCell = cell;
  1648. if (IsValid(idPrev))
  1649. {
  1650. SetItemState(idPrev.row, idPrev.col,
  1651. GetItemState(idPrev.row, idPrev.col) & ~GVIS_FOCUSED);
  1652. RedrawCell(idPrev); // comment to reduce flicker
  1653. if (GetTrackFocusCell() && idPrev.col != m_idCurrentCell.col)
  1654. for (int row = 0; row < m_nFixedRows; row++)
  1655. RedrawCell(row, idPrev.col);
  1656. if (GetTrackFocusCell() && idPrev.row != m_idCurrentCell.row)
  1657. for (int col = 0; col < m_nFixedCols; col++)
  1658. RedrawCell(idPrev.row, col);
  1659. }
  1660. if (IsValid(m_idCurrentCell))
  1661. {
  1662. SetItemState(m_idCurrentCell.row, m_idCurrentCell.col,
  1663. GetItemState(m_idCurrentCell.row, m_idCurrentCell.col) | GVIS_FOCUSED);
  1664. RedrawCell(m_idCurrentCell); // comment to reduce flicker
  1665. if (GetTrackFocusCell() && idPrev.col != m_idCurrentCell.col)
  1666. for (int row = 0; row < m_nFixedRows; row++)
  1667. RedrawCell(row, m_idCurrentCell.col);
  1668. if (GetTrackFocusCell() && idPrev.row != m_idCurrentCell.row)
  1669. for (int col = 0; col < m_nFixedCols; col++)
  1670. RedrawCell(m_idCurrentCell.row, col);
  1671. // EFW - New addition. If in list mode, make sure the selected
  1672. // row highlight follows the cursor.
  1673. // Removed by C Maunder 27 May
  1674. //if (m_bListMode)
  1675. //{
  1676. // m_PrevSelectedCellMap.RemoveAll();
  1677. // m_MouseMode = MOUSE_SELECT_ROW;
  1678. // OnSelecting(m_idCurrentCell);
  1679. // Leave this off so that you can still drag the highlight around
  1680. // without selecting rows.
  1681. // m_MouseMode = MOUSE_NOTHING;
  1682. //}
  1683. }
  1684. return idPrev;
  1685. }
  1686. // Sets the range of currently selected cells
  1687. void CGridCtrl::SetSelectedRange(const CCellRange& Range,
  1688. BOOL bForceRepaint /* = FALSE */, BOOL bSelectCells/*=TRUE*/)
  1689. {
  1690. SetSelectedRange(Range.GetMinRow(), Range.GetMinCol(),
  1691. Range.GetMaxRow(), Range.GetMaxCol(),
  1692. bForceRepaint, bSelectCells);
  1693. }
  1694. void CGridCtrl::SetSelectedRange(int nMinRow, int nMinCol, int nMaxRow, int nMaxCol,
  1695. BOOL bForceRepaint /* = FALSE */, BOOL bSelectCells/*=TRUE*/)
  1696. {
  1697. if (!m_bEnableSelection)
  1698. return;
  1699. CDC* pDC = NULL;
  1700. if (bForceRepaint)
  1701. pDC = GetDC();
  1702. // Only redraw visible cells
  1703. CCellRange VisCellRange;
  1704. if (IsWindow(GetSafeHwnd()))
  1705. VisCellRange = GetVisibleNonFixedCellRange();
  1706. // EFW - Bug fix - Don't allow selection of fixed rows
  1707. if (nMinRow >= 0 && nMinRow < GetFixedRowCount())
  1708. nMinRow = GetFixedRowCount();
  1709. if (nMaxRow >= 0 && nMaxRow < GetFixedRowCount())
  1710. nMaxRow = GetFixedRowCount();
  1711. if (nMinCol >= 0 && nMinCol < GetFixedColumnCount())
  1712. nMinCol = GetFixedColumnCount();
  1713. if (nMaxCol >= 0 && nMaxCol < GetFixedColumnCount())
  1714. nMaxCol = GetFixedColumnCount();
  1715. // If we are selecting cells, then first clear out the list of currently selected cells, then
  1716. if (bSelectCells)
  1717. {
  1718. POSITION pos;
  1719. // Unselect all previously selected cells
  1720. for (pos = m_SelectedCellMap.GetStartPosition(); pos != NULL;)
  1721. {
  1722. DWORD key;
  1723. CCellID cell;
  1724. m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  1725. // Reset the selection flag on the cell
  1726. if (IsValid(cell))
  1727. {
  1728. // This will remove the cell from the m_SelectedCellMap map
  1729. SetItemState(cell.row, cell.col,
  1730. GetItemState(cell.row, cell.col) & ~GVIS_SELECTED);
  1731. // If this is to be reselected, continue on past the redraw
  1732. if (nMinRow <= cell.row && cell.row <= nMaxRow &&
  1733. nMinCol <= cell.col && cell.col <= nMaxCol)
  1734. continue;
  1735. if (VisCellRange.IsValid() && VisCellRange.InRange(cell))
  1736. {
  1737. if (bForceRepaint && pDC) // Redraw NOW
  1738. RedrawCell(cell.row, cell.col, pDC);
  1739. else
  1740. InvalidateCellRect(cell); // Redraw at leisure
  1741. }
  1742. }
  1743. else
  1744. {
  1745. m_SelectedCellMap.RemoveKey(key); // if it's not valid, get rid of it!
  1746. }
  1747. }
  1748. // if we are selecting cells, and there are previous selected cells to be retained
  1749. // (eg Ctrl is being held down) then copy them to the newly created list, and mark
  1750. // all these cells as selected
  1751. // Note that if we are list mode, single row selection, the we won't be adding
  1752. // the previous cells. Only the current row of cells will be added (see below)
  1753. if (!GetSingleRowSelection() &&
  1754. nMinRow >= 0 && nMinCol >= 0 && nMaxRow >= 0 && nMaxCol >= 0)
  1755. {
  1756. for (pos = m_PrevSelectedCellMap.GetStartPosition(); pos != NULL; /* nothing */)
  1757. {
  1758. DWORD key;
  1759. CCellID cell;
  1760. m_PrevSelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  1761. if (!IsValid(cell))
  1762. continue;
  1763. int nState = GetItemState(cell.row, cell.col);
  1764. // Set state as Selected. This will add the cell to m_SelectedCellMap
  1765. SetItemState(cell.row, cell.col, nState | GVIS_SELECTED);
  1766. if (VisCellRange.IsValid() && VisCellRange.InRange(cell))
  1767. {
  1768. // Redraw (immediately or at leisure)
  1769. if (bForceRepaint && pDC)
  1770. RedrawCell(cell.row, cell.col, pDC);
  1771. else
  1772. InvalidateCellRect(cell);
  1773. }
  1774. }
  1775. }
  1776. }
  1777. // Now select/deselect all cells in the cell range specified. If selecting, and the cell
  1778. // has already been marked as selected (above) then ignore it. If we are deselecting and
  1779. // the cell isn't selected, then ignore
  1780. if (nMinRow >= 0 && nMinCol >= 0 && nMaxRow >= 0 && nMaxCol >= 0 &&
  1781. nMaxRow < m_nRows && nMaxCol < m_nCols &&
  1782. nMinRow <= nMaxRow && nMinCol <= nMaxCol)
  1783. {
  1784. for (int row = nMinRow; row <= nMaxRow; row++)
  1785. for (int col = nMinCol; col <= nMaxCol; col++)
  1786. {
  1787. int nState = GetItemState(row, col);
  1788. // Why is there no XOR operator in C??? We have bitwise XOR ^, but what about ^^??
  1789. if ((bSelectCells && (nState & GVIS_SELECTED)) ||
  1790. (!bSelectCells && !(nState & GVIS_SELECTED)))
  1791. continue; // Already selected or deselected - ignore
  1792. // Set the selected state. This will add/remove the cell to m_SelectedCellMap
  1793. if (bSelectCells)
  1794. SetItemState(row, col, nState | GVIS_SELECTED);
  1795. else
  1796. SetItemState(row, col, GetItemState(row, col) & ~GVIS_SELECTED);
  1797. if (VisCellRange.IsValid() && VisCellRange.InRange(row, col))
  1798. {
  1799. // Redraw (immediately or at leisure)
  1800. if (bForceRepaint && pDC)
  1801. RedrawCell(row, col, pDC);
  1802. else
  1803. InvalidateCellRect(row, col);
  1804. }
  1805. }
  1806. }
  1807. // TRACE(_T("%d cells selected.\n"), m_SelectedCellMap.GetCount());
  1808. if (pDC != NULL)
  1809. ReleaseDC(pDC);
  1810. }
  1811. // selects all cells
  1812. void CGridCtrl::SelectAllCells()
  1813. {
  1814. if (!m_bEnableSelection)
  1815. return;
  1816. SetSelectedRange(m_nFixedRows, m_nFixedCols, GetRowCount() - 1, GetColumnCount() - 1);
  1817. }
  1818. // selects columns
  1819. void CGridCtrl::SelectColumns(CCellID currentCell,
  1820. BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
  1821. {
  1822. if (!m_bEnableSelection)
  1823. return;
  1824. //if (currentCell.col == m_idCurrentCell.col) return;
  1825. if (currentCell.col < m_nFixedCols)
  1826. return;
  1827. if (!IsValid(currentCell))
  1828. return;
  1829. if (GetSingleColSelection())
  1830. SetSelectedRange(GetFixedRowCount(), currentCell.col,
  1831. GetRowCount() - 1, currentCell.col,
  1832. bForceRedraw, bSelectCells);
  1833. else
  1834. SetSelectedRange(GetFixedRowCount(),
  1835. min(m_SelectionStartCell.col, currentCell.col),
  1836. GetRowCount() - 1,
  1837. max(m_SelectionStartCell.col, currentCell.col),
  1838. bForceRedraw, bSelectCells);
  1839. }
  1840. // selects rows
  1841. void CGridCtrl::SelectRows(CCellID currentCell,
  1842. BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
  1843. {
  1844. if (!m_bEnableSelection)
  1845. return;
  1846. //if (currentCell.row; == m_idCurrentCell.row) return;
  1847. if (currentCell.row < m_nFixedRows)
  1848. return;
  1849. if (!IsValid(currentCell))
  1850. return;
  1851. if (GetSingleRowSelection())
  1852. SetSelectedRange(currentCell.row, GetFixedColumnCount(),
  1853. currentCell.row, GetColumnCount() - 1,
  1854. bForceRedraw, bSelectCells);
  1855. else
  1856. SetSelectedRange(min(m_SelectionStartCell.row, currentCell.row),
  1857. GetFixedColumnCount(),
  1858. max(m_SelectionStartCell.row, currentCell.row),
  1859. GetColumnCount() - 1,
  1860. bForceRedraw, bSelectCells);
  1861. }
  1862. // selects cells
  1863. void CGridCtrl::SelectCells(CCellID currentCell,
  1864. BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
  1865. {
  1866. if (!m_bEnableSelection)
  1867. return;
  1868. int row = currentCell.row;
  1869. int col = currentCell.col;
  1870. if (row < m_nFixedRows || col < m_nFixedCols)
  1871. return;
  1872. if (!IsValid(currentCell))
  1873. return;
  1874. // Prevent unnecessary redraws
  1875. //if (currentCell == m_LeftClickDownCell) return;
  1876. //else if (currentCell == m_idCurrentCell) return;
  1877. SetSelectedRange(min(m_SelectionStartCell.row, row),
  1878. min(m_SelectionStartCell.col, col),
  1879. max(m_SelectionStartCell.row, row),
  1880. max(m_SelectionStartCell.col, col),
  1881. bForceRedraw, bSelectCells);
  1882. }
  1883. // Called when mouse/keyboard selection is a-happening.
  1884. void CGridCtrl::OnSelecting(const CCellID& currentCell)
  1885. {
  1886. if (!m_bEnableSelection)
  1887. return;
  1888. switch (m_MouseMode)
  1889. {
  1890. case MOUSE_SELECT_ALL:
  1891. SelectAllCells();
  1892. break;
  1893. case MOUSE_SELECT_COL:
  1894. SelectColumns(currentCell, FALSE);
  1895. break;
  1896. case MOUSE_SELECT_ROW:
  1897. SelectRows(currentCell, FALSE);
  1898. break;
  1899. case MOUSE_SELECT_CELLS:
  1900. SelectCells(currentCell, FALSE);
  1901. break;
  1902. }
  1903. // EFW - Bug fix [REMOVED CJM: this will cause infinite loop in list mode]
  1904. // SetFocusCell(max(currentCell.row, m_nFixedRows), max(currentCell.col, m_nFixedCols));
  1905. }
  1906. void CGridCtrl::ValidateAndModifyCellContents(int nRow, int nCol, LPCTSTR strText)
  1907. {
  1908. if (!IsCellEditable(nRow, nCol))
  1909. return;
  1910. if (SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT) >= 0)
  1911. {
  1912. CString strCurrentText = GetItemText(nRow, nCol);
  1913. if (strCurrentText != strText)
  1914. {
  1915. SetItemText(nRow, nCol, strText);
  1916. if (ValidateEdit(nRow, nCol, strText) &&
  1917. SendMessageToParent(nRow, nCol, GVN_ENDLABELEDIT) >= 0)
  1918. {
  1919. SetModified(TRUE, nRow, nCol);
  1920. RedrawCell(nRow, nCol);
  1921. }
  1922. else
  1923. {
  1924. SetItemText(nRow, nCol, strCurrentText);
  1925. }
  1926. }
  1927. }
  1928. }
  1929. void CGridCtrl::ClearCells(CCellRange Selection)
  1930. {
  1931. for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
  1932. {
  1933. for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
  1934. {
  1935. // don't clear hidden cells
  1936. if (m_arRowHeights[row] > 0 && m_arColWidths[col] > 0)
  1937. {
  1938. ValidateAndModifyCellContents(row, col, _T(""));
  1939. }
  1940. }
  1941. }
  1942. Refresh();
  1943. }
  1944. #ifndef GRIDCONTROL_NO_CLIPBOARD
  1945. ////////////////////////////////////////////////////////////////////////////////////////
  1946. // Clipboard functions
  1947. // Deletes the contents from the selected cells
  1948. void CGridCtrl::CutSelectedText()
  1949. {
  1950. if (!IsEditable())
  1951. return;
  1952. CCellRange Selection = GetSelectedCellRange();
  1953. if (!IsValid(Selection))
  1954. return;
  1955. ClearCells(Selection);
  1956. }
  1957. // Copies text from the selected cells to the clipboard
  1958. COleDataSource* CGridCtrl::CopyTextFromGrid()
  1959. {
  1960. USES_CONVERSION;
  1961. CCellRange Selection = GetSelectedCellRange();
  1962. if (!IsValid(Selection))
  1963. return NULL;
  1964. if (GetVirtualMode())
  1965. SendCacheHintToParent(Selection);
  1966. // Write to shared file (REMEBER: CF_TEXT is ANSI, not UNICODE, so we need to convert)
  1967. CSharedFile sf(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
  1968. // Get a tab delimited string to copy to cache
  1969. CString str;
  1970. CGridCellBase *pCell;
  1971. for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
  1972. {
  1973. // don't copy hidden cells
  1974. if (m_arRowHeights[row] <= 0)
  1975. continue;
  1976. str.Empty();
  1977. for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
  1978. {
  1979. // don't copy hidden cells
  1980. if (m_arColWidths[col] <= 0)
  1981. continue;
  1982. pCell = GetCell(row, col);
  1983. if (pCell && (pCell->GetState() & GVIS_SELECTED))
  1984. {
  1985. // if (!pCell->GetText())
  1986. // str += _T(" ");
  1987. // else
  1988. str += pCell->GetText();
  1989. }
  1990. if (col != Selection.GetMaxCol())
  1991. str += _T("\t");
  1992. }
  1993. if (row != Selection.GetMaxRow())
  1994. str += _T("\n");
  1995. sf.Write(T2A(str.GetBuffer(1)), str.GetLength());
  1996. str.ReleaseBuffer();
  1997. }
  1998. char c = '\0';
  1999. sf.Write(&c, 1);
  2000. if (GetVirtualMode())
  2001. SendCacheHintToParent(CCellRange(-1, -1, -1, -1));
  2002. DWORD dwLen = (DWORD)sf.GetLength();
  2003. HGLOBAL hMem = sf.Detach();
  2004. if (!hMem)
  2005. return NULL;
  2006. hMem = ::GlobalReAlloc(hMem, dwLen, GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
  2007. if (!hMem)
  2008. return NULL;
  2009. // Cache data
  2010. COleDataSource* pSource = new COleDataSource();
  2011. pSource->CacheGlobalData(CF_TEXT, hMem);
  2012. return pSource;
  2013. }
  2014. // Pastes text from the clipboard to the selected cells
  2015. BOOL CGridCtrl::PasteTextToGrid(CCellID cell, COleDataObject* pDataObject)
  2016. {
  2017. if (!IsValid(cell) || !IsCellEditable(cell) || !pDataObject->IsDataAvailable(CF_TEXT))
  2018. return FALSE;
  2019. // Get the text from the COleDataObject
  2020. // Ñ¡ÔñºÏÊʵĸñʽ;
  2021. UINT uiFormat = (sizeof(TCHAR)==sizeof(WCHAR)) ? CF_UNICODETEXT : CF_TEXT;
  2022. HGLOBAL hmem = pDataObject->GetGlobalData(uiFormat); // CF_TEXT
  2023. CMemFile sf((BYTE*) ::GlobalLock(hmem), ::GlobalSize(hmem));
  2024. // CF_TEXT is ANSI text, so we need to allocate a char* buffer
  2025. // to hold this.
  2026. LPTSTR szBuffer = new TCHAR[::GlobalSize(hmem)];
  2027. if (!szBuffer)
  2028. return FALSE;
  2029. sf.Read(szBuffer, ::GlobalSize(hmem));
  2030. ::GlobalUnlock(hmem);
  2031. // Now store in generic TCHAR form so we no longer have to deal with
  2032. // ANSI/UNICODE problems
  2033. CString strText = szBuffer;
  2034. delete szBuffer;
  2035. // Parse text data and set in cells...
  2036. strText.LockBuffer();
  2037. CString strLine = strText;
  2038. int nLine = 0;
  2039. // Find the end of the first line
  2040. int nIndex;
  2041. do
  2042. {
  2043. int nColumn = 0;
  2044. nIndex = strLine.Find(_T("\n"));
  2045. // Store the remaining chars after the newline
  2046. CString strNext = (nIndex < 0) ? _T("") : strLine.Mid(nIndex + 1);
  2047. // Remove all chars after the newline
  2048. if (nIndex >= 0)
  2049. strLine = strLine.Left(nIndex);
  2050. int nLineIndex = strLine.FindOneOf(_T("\t,"));
  2051. CString strCellText = (nLineIndex >= 0) ? strLine.Left(nLineIndex) : strLine;
  2052. // skip hidden rows
  2053. int iRowVis = cell.row + nLine;
  2054. while (iRowVis < GetRowCount())
  2055. {
  2056. if (GetRowHeight(iRowVis) > 0)
  2057. break;
  2058. nLine++;
  2059. iRowVis++;
  2060. }
  2061. while (!strLine.IsEmpty())
  2062. {
  2063. // skip hidden columns
  2064. int iColVis = cell.col + nColumn;
  2065. while (iColVis < GetColumnCount())
  2066. {
  2067. if (GetColumnWidth(iColVis) > 0)
  2068. break;
  2069. nColumn++;
  2070. iColVis++;
  2071. }
  2072. CCellID TargetCell(iRowVis, iColVis);
  2073. if (IsValid(TargetCell))
  2074. {
  2075. strCellText.TrimLeft();
  2076. strCellText.TrimRight();
  2077. ValidateAndModifyCellContents(TargetCell.row, TargetCell.col, strCellText);
  2078. // Make sure cell is not selected to avoid data loss
  2079. SetItemState(TargetCell.row, TargetCell.col,
  2080. GetItemState(TargetCell.row, TargetCell.col) & ~GVIS_SELECTED);
  2081. }
  2082. strLine = (nLineIndex >= 0) ? strLine.Mid(nLineIndex + 1) : _T("");
  2083. nLineIndex = strLine.FindOneOf(_T("\t,"));
  2084. strCellText = (nLineIndex >= 0) ? strLine.Left(nLineIndex) : strLine;
  2085. nColumn++;
  2086. }
  2087. strLine = strNext;
  2088. nLine++;
  2089. } while (nIndex >= 0);
  2090. strText.UnlockBuffer();
  2091. Refresh();
  2092. return TRUE;
  2093. }
  2094. #endif
  2095. #ifndef GRIDCONTROL_NO_DRAGDROP
  2096. // Start drag n drop
  2097. void CGridCtrl::OnBeginDrag()
  2098. {
  2099. if (!m_bAllowDragAndDrop)
  2100. return;
  2101. COleDataSource* pSource = CopyTextFromGrid();
  2102. if (pSource)
  2103. {
  2104. SendMessageToParent(GetSelectedCellRange().GetTopLeft().row,
  2105. GetSelectedCellRange().GetTopLeft().col,
  2106. GVN_BEGINDRAG);
  2107. m_MouseMode = MOUSE_DRAGGING;
  2108. m_bLMouseButtonDown = FALSE;
  2109. DROPEFFECT dropEffect = pSource->DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE);
  2110. if (dropEffect & DROPEFFECT_MOVE)
  2111. CutSelectedText();
  2112. if (pSource)
  2113. delete pSource; // Did not pass source to clipboard, so must delete
  2114. }
  2115. }
  2116. // Handle drag over grid
  2117. DROPEFFECT CGridCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState,
  2118. CPoint point)
  2119. {
  2120. // Any text data available for us?
  2121. if (!m_bAllowDragAndDrop || !IsEditable() || !pDataObject->IsDataAvailable(CF_TEXT))
  2122. return DROPEFFECT_NONE;
  2123. // Find which cell we are over and drop-highlight it
  2124. CCellID cell = GetCellFromPt(point, FALSE);
  2125. // If not valid, set the previously drop-highlighted cell as no longer drop-highlighted
  2126. if (!IsValid(cell))
  2127. {
  2128. OnDragLeave();
  2129. m_LastDragOverCell = CCellID(-1, -1);
  2130. return DROPEFFECT_NONE;
  2131. }
  2132. if (!IsCellEditable(cell))
  2133. return DROPEFFECT_NONE;
  2134. // Have we moved over a different cell than last time?
  2135. if (cell != m_LastDragOverCell)
  2136. {
  2137. // Set the previously drop-highlighted cell as no longer drop-highlighted
  2138. if (IsValid(m_LastDragOverCell))
  2139. {
  2140. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  2141. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  2142. nState & ~GVIS_DROPHILITED);
  2143. RedrawCell(m_LastDragOverCell);
  2144. }
  2145. m_LastDragOverCell = cell;
  2146. // Set the new cell as drop-highlighted
  2147. if (IsValid(m_LastDragOverCell))
  2148. {
  2149. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  2150. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  2151. nState | GVIS_DROPHILITED);
  2152. RedrawCell(m_LastDragOverCell);
  2153. }
  2154. }
  2155. // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
  2156. if (dwKeyState & MK_CONTROL)
  2157. return DROPEFFECT_COPY;
  2158. else
  2159. return DROPEFFECT_MOVE;
  2160. }
  2161. // Something has just been dragged onto the grid
  2162. DROPEFFECT CGridCtrl::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState,
  2163. CPoint point)
  2164. {
  2165. // Any text data available for us?
  2166. if (!m_bAllowDragAndDrop || !pDataObject->IsDataAvailable(CF_TEXT))
  2167. return DROPEFFECT_NONE;
  2168. // Find which cell we are over and drop-highlight it
  2169. m_LastDragOverCell = GetCellFromPt(point, FALSE);
  2170. if (!IsValid(m_LastDragOverCell))
  2171. return DROPEFFECT_NONE;
  2172. if (!IsCellEditable(m_LastDragOverCell))
  2173. return DROPEFFECT_NONE;
  2174. if (IsValid(m_LastDragOverCell))
  2175. {
  2176. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  2177. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  2178. nState | GVIS_DROPHILITED);
  2179. RedrawCell(m_LastDragOverCell);
  2180. }
  2181. // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
  2182. if (dwKeyState & MK_CONTROL)
  2183. return DROPEFFECT_COPY;
  2184. else
  2185. return DROPEFFECT_MOVE;
  2186. }
  2187. // Something has just been dragged away from the grid
  2188. void CGridCtrl::OnDragLeave()
  2189. {
  2190. // Set the previously drop-highlighted cell as no longer drop-highlighted
  2191. if (IsValid(m_LastDragOverCell))
  2192. {
  2193. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  2194. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  2195. nState & ~GVIS_DROPHILITED);
  2196. RedrawCell(m_LastDragOverCell);
  2197. }
  2198. }
  2199. // Something has just been dropped onto the grid
  2200. BOOL CGridCtrl::OnDrop(COleDataObject* pDataObject, DROPEFFECT /*dropEffect*/,
  2201. CPoint /* point */)
  2202. {
  2203. m_MouseMode = MOUSE_NOTHING;
  2204. if (!m_bAllowDragAndDrop || !IsCellEditable(m_LastDragOverCell))
  2205. return FALSE;
  2206. OnDragLeave();
  2207. return PasteTextToGrid(m_LastDragOverCell, pDataObject);
  2208. }
  2209. #endif
  2210. #ifndef GRIDCONTROL_NO_CLIPBOARD
  2211. void CGridCtrl::OnEditCut()
  2212. {
  2213. if (!IsEditable())
  2214. return;
  2215. COleDataSource* pSource = CopyTextFromGrid();
  2216. if (!pSource)
  2217. return;
  2218. pSource->SetClipboard();
  2219. CutSelectedText();
  2220. }
  2221. void CGridCtrl::OnEditCopy()
  2222. {
  2223. COleDataSource* pSource = CopyTextFromGrid();
  2224. if (!pSource)
  2225. return;
  2226. pSource->SetClipboard();
  2227. }
  2228. void CGridCtrl::OnEditPaste()
  2229. {
  2230. if (!IsEditable())
  2231. return;
  2232. // Get the Focus cell, or if none, get the topleft (non-fixed) cell
  2233. CCellID cell = GetFocusCell();
  2234. if (!IsValid(cell))
  2235. cell = GetTopleftNonFixedCell();
  2236. if (!IsValid(cell))
  2237. return;
  2238. // If a cell is being edited, then call it's edit window paste function.
  2239. if (IsItemEditing(cell.row, cell.col))
  2240. {
  2241. CGridCellBase* pCell = GetCell(cell.row, cell.col);
  2242. ASSERT(pCell);
  2243. if (!pCell) return;
  2244. CWnd* pEditWnd = pCell->GetEditWnd();
  2245. if (pEditWnd && pEditWnd->IsKindOf(RUNTIME_CLASS(CEdit)))
  2246. {
  2247. ((CEdit*)pEditWnd)->Paste();
  2248. return;
  2249. }
  2250. }
  2251. // Attach a COleDataObject to the clipboard and paste the data to the grid
  2252. COleDataObject obj;
  2253. if (obj.AttachClipboard())
  2254. PasteTextToGrid(cell, &obj);
  2255. }
  2256. #endif
  2257. void CGridCtrl::OnEditSelectAll()
  2258. {
  2259. SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
  2260. SelectAllCells();
  2261. SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
  2262. }
  2263. #ifndef GRIDCONTROL_NO_CLIPBOARD
  2264. void CGridCtrl::OnUpdateEditCopy(CCmdUI* pCmdUI)
  2265. {
  2266. CCellRange Selection = GetSelectedCellRange();
  2267. pCmdUI->Enable(Selection.Count() && IsValid(Selection));
  2268. }
  2269. void CGridCtrl::OnUpdateEditCut(CCmdUI* pCmdUI)
  2270. {
  2271. CCellRange Selection = GetSelectedCellRange();
  2272. pCmdUI->Enable(IsEditable() && Selection.Count() && IsValid(Selection));
  2273. }
  2274. void CGridCtrl::OnUpdateEditPaste(CCmdUI* pCmdUI)
  2275. {
  2276. CCellID cell = GetFocusCell();
  2277. BOOL bCanPaste = IsValid(cell) && IsCellEditable(cell) &&
  2278. ::IsClipboardFormatAvailable(CF_TEXT);
  2279. pCmdUI->Enable(bCanPaste);
  2280. }
  2281. #endif
  2282. void CGridCtrl::OnUpdateEditSelectAll(CCmdUI* pCmdUI)
  2283. {
  2284. pCmdUI->Enable(m_bEnableSelection);
  2285. }
  2286. ////////////////////////////////////////////////////////////////////////////////////////
  2287. // hittest-like functions
  2288. // TRUE if the mouse is over a row resize area
  2289. BOOL CGridCtrl::MouseOverRowResizeArea(CPoint& point)
  2290. {
  2291. if (point.x >= GetFixedColumnWidth())
  2292. return FALSE;
  2293. CCellID idCurrentCell = GetCellFromPt(point);
  2294. CPoint start;
  2295. if (!GetCellOrigin(idCurrentCell, &start))
  2296. return FALSE;
  2297. int endy = start.y + GetRowHeight(idCurrentCell.row);
  2298. if ((point.y - start.y < m_nResizeCaptureRange && idCurrentCell.row != 0) ||
  2299. endy - point.y < m_nResizeCaptureRange)
  2300. {
  2301. return TRUE;
  2302. }
  2303. else
  2304. return FALSE;
  2305. }
  2306. // TRUE if the mouse is over a column resize area. point is in Client coords
  2307. BOOL CGridCtrl::MouseOverColumnResizeArea(CPoint& point)
  2308. {
  2309. if (point.y >= GetFixedRowHeight())
  2310. return FALSE;
  2311. CCellID idCurrentCell = GetCellFromPt(point);
  2312. CPoint start;
  2313. if (!GetCellOrigin(idCurrentCell, &start))
  2314. return FALSE;
  2315. int endx = start.x + GetColumnWidth(idCurrentCell.col);
  2316. if ((point.x - start.x < m_nResizeCaptureRange && idCurrentCell.col != 0) ||
  2317. endx - point.x < m_nResizeCaptureRange)
  2318. {
  2319. return TRUE;
  2320. }
  2321. else
  2322. return FALSE;
  2323. }
  2324. // Get cell from point.
  2325. // point - client coordinates
  2326. // bAllowFixedCellCheck - if TRUE then fixed cells are checked
  2327. CCellID CGridCtrl::GetCellFromPt(CPoint point, BOOL bAllowFixedCellCheck /*=TRUE*/)
  2328. {
  2329. CCellID cellID; // return value
  2330. CCellID idTopLeft = GetTopleftNonFixedCell();
  2331. if (!bAllowFixedCellCheck && !IsValid(idTopLeft))
  2332. return cellID;
  2333. // calculate column index
  2334. int fixedColWidth = GetFixedColumnWidth();
  2335. if (point.x < 0 || (!bAllowFixedCellCheck && point.x < fixedColWidth)) // not in window
  2336. cellID.col = -1;
  2337. else if (point.x < fixedColWidth) // in fixed col
  2338. {
  2339. int xpos = 0;
  2340. int col = 0;
  2341. while (col < m_nFixedCols)
  2342. {
  2343. xpos += GetColumnWidth(col);
  2344. if (xpos > point.x)
  2345. break;
  2346. col++;
  2347. }
  2348. cellID.col = col;
  2349. }
  2350. else // in non-fixed col
  2351. {
  2352. int xpos = fixedColWidth;
  2353. int col = idTopLeft.col; //m_nFixedCols;
  2354. while (col < GetColumnCount())
  2355. {
  2356. xpos += GetColumnWidth(col);
  2357. if (xpos > point.x)
  2358. break;
  2359. col++;
  2360. }
  2361. if (col >= GetColumnCount())
  2362. cellID.col = -1;
  2363. else
  2364. cellID.col = col;
  2365. }
  2366. // calculate row index
  2367. int fixedRowHeight = GetFixedRowHeight();
  2368. if (point.y < 0 || (!bAllowFixedCellCheck && point.y < fixedRowHeight)) // not in window
  2369. cellID.row = -1;
  2370. else if (point.y < fixedRowHeight) // in fixed col
  2371. {
  2372. int ypos = 0;
  2373. int row = 0;
  2374. while (row < m_nFixedRows)
  2375. {
  2376. ypos += GetRowHeight(row);
  2377. if (ypos > point.y)
  2378. break;
  2379. row++;
  2380. }
  2381. cellID.row = row;
  2382. }
  2383. else
  2384. {
  2385. int ypos = fixedRowHeight;
  2386. int row = idTopLeft.row; //m_nFixedRows;
  2387. while (row < GetRowCount())
  2388. {
  2389. ypos += GetRowHeight(row);
  2390. if (ypos > point.y)
  2391. break;
  2392. row++;
  2393. }
  2394. if (row >= GetRowCount())
  2395. cellID.row = -1;
  2396. else
  2397. cellID.row = row;
  2398. }
  2399. return cellID;
  2400. }
  2401. ////////////////////////////////////////////////////////////////////////////////
  2402. // CGridCtrl cellrange functions
  2403. // Gets the first non-fixed cell ID
  2404. CCellID CGridCtrl::GetTopleftNonFixedCell(BOOL bForceRecalculation /*=FALSE*/)
  2405. {
  2406. // Used cached value if possible
  2407. if (m_idTopLeftCell.IsValid() && !bForceRecalculation)
  2408. return m_idTopLeftCell;
  2409. int nVertScroll = GetScrollPos(SB_VERT),
  2410. nHorzScroll = GetScrollPos(SB_HORZ);
  2411. m_idTopLeftCell.col = m_nFixedCols;
  2412. int nRight = 0;
  2413. while (nRight < nHorzScroll && m_idTopLeftCell.col < (GetColumnCount() - 1))
  2414. nRight += GetColumnWidth(m_idTopLeftCell.col++);
  2415. m_idTopLeftCell.row = m_nFixedRows;
  2416. int nTop = 0;
  2417. while (nTop < nVertScroll && m_idTopLeftCell.row < (GetRowCount() - 1))
  2418. nTop += GetRowHeight(m_idTopLeftCell.row++);
  2419. //TRACE2("TopLeft cell is row %d, col %d\n",m_idTopLeftCell.row, m_idTopLeftCell.col);
  2420. return m_idTopLeftCell;
  2421. }
  2422. // This gets even partially visible cells
  2423. CCellRange CGridCtrl::GetVisibleNonFixedCellRange(LPRECT pRect /*=NULL*/,
  2424. BOOL bForceRecalculation /*=FALSE*/)
  2425. {
  2426. CRect rect;
  2427. GetClientRect(rect);
  2428. CCellID idTopLeft = GetTopleftNonFixedCell(bForceRecalculation);
  2429. // calc bottom
  2430. int i = 0;
  2431. int bottom = GetFixedRowHeight();
  2432. for (i = idTopLeft.row; i < GetRowCount(); i++)
  2433. {
  2434. bottom += GetRowHeight(i);
  2435. if (bottom >= rect.bottom)
  2436. {
  2437. bottom = rect.bottom;
  2438. break;
  2439. }
  2440. }
  2441. int maxVisibleRow = min(i, GetRowCount() - 1);
  2442. // calc right
  2443. int right = GetFixedColumnWidth();
  2444. for (i = idTopLeft.col; i < GetColumnCount(); i++)
  2445. {
  2446. right += GetColumnWidth(i);
  2447. if (right >= rect.right)
  2448. {
  2449. right = rect.right;
  2450. break;
  2451. }
  2452. }
  2453. int maxVisibleCol = min(i, GetColumnCount() - 1);
  2454. if (pRect)
  2455. {
  2456. pRect->left = pRect->top = 0;
  2457. pRect->right = right;
  2458. pRect->bottom = bottom;
  2459. }
  2460. return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
  2461. }
  2462. // used by ResetScrollBars() - This gets only fully visible cells
  2463. CCellRange CGridCtrl::GetUnobstructedNonFixedCellRange(BOOL bForceRecalculation /*=FALSE*/)
  2464. {
  2465. CRect rect;
  2466. GetClientRect(rect);
  2467. CCellID idTopLeft = GetTopleftNonFixedCell(bForceRecalculation);
  2468. // calc bottom
  2469. int i = 0;
  2470. int bottom = GetFixedRowHeight();
  2471. for (i = idTopLeft.row; i < GetRowCount(); i++)
  2472. {
  2473. bottom += GetRowHeight(i);
  2474. if (bottom >= rect.bottom)
  2475. break;
  2476. }
  2477. int maxVisibleRow = min(i, GetRowCount() - 1);
  2478. if (maxVisibleRow > 0 && bottom > rect.bottom)
  2479. maxVisibleRow--;
  2480. // calc right
  2481. int right = GetFixedColumnWidth();
  2482. for (i = idTopLeft.col; i < GetColumnCount(); i++)
  2483. {
  2484. right += GetColumnWidth(i);
  2485. if (right >= rect.right)
  2486. break;
  2487. }
  2488. int maxVisibleCol = min(i, GetColumnCount() - 1);
  2489. if (maxVisibleCol > 0 && right > rect.right)
  2490. maxVisibleCol--;
  2491. return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
  2492. }
  2493. // Returns the minimum bounding range of the current selection
  2494. // If no selection, then the returned CCellRange will be invalid
  2495. CCellRange CGridCtrl::GetSelectedCellRange() const
  2496. {
  2497. CCellRange Selection(GetRowCount(), GetColumnCount(), -1, -1);
  2498. for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL;)
  2499. {
  2500. DWORD key;
  2501. CCellID cell;
  2502. m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  2503. Selection.SetMinRow(min(Selection.GetMinRow(), cell.row));
  2504. Selection.SetMinCol(min(Selection.GetMinCol(), cell.col));
  2505. Selection.SetMaxRow(max(Selection.GetMaxRow(), cell.row));
  2506. Selection.SetMaxCol(max(Selection.GetMaxCol(), cell.col));
  2507. }
  2508. return Selection;
  2509. }
  2510. // Returns ALL the cells in the grid
  2511. CCellRange CGridCtrl::GetCellRange() const
  2512. {
  2513. return CCellRange(0, 0, GetRowCount() - 1, GetColumnCount() - 1);
  2514. }
  2515. // Resets the selected cell range to the empty set.
  2516. void CGridCtrl::ResetSelectedRange()
  2517. {
  2518. m_PrevSelectedCellMap.RemoveAll();
  2519. SetSelectedRange(-1, -1, -1, -1);
  2520. SetFocusCell(-1, -1);
  2521. }
  2522. // Get/Set scroll position using 32 bit functions
  2523. int CGridCtrl::GetScrollPos32(int nBar, BOOL bGetTrackPos /* = FALSE */)
  2524. {
  2525. SCROLLINFO si;
  2526. si.cbSize = sizeof(SCROLLINFO);
  2527. if (bGetTrackPos)
  2528. {
  2529. if (GetScrollInfo(nBar, &si, SIF_TRACKPOS))
  2530. return si.nTrackPos;
  2531. }
  2532. else
  2533. {
  2534. if (GetScrollInfo(nBar, &si, SIF_POS))
  2535. return si.nPos;
  2536. }
  2537. return 0;
  2538. }
  2539. BOOL CGridCtrl::SetScrollPos32(int nBar, int nPos, BOOL bRedraw /* = TRUE */)
  2540. {
  2541. m_idTopLeftCell.row = -1;
  2542. SCROLLINFO si;
  2543. si.cbSize = sizeof(SCROLLINFO);
  2544. si.fMask = SIF_POS;
  2545. si.nPos = nPos;
  2546. return SetScrollInfo(nBar, &si, bRedraw);
  2547. }
  2548. void CGridCtrl::EnableScrollBars(int nBar, BOOL bEnable /*=TRUE*/)
  2549. {
  2550. if (bEnable)
  2551. {
  2552. if (!IsVisibleHScroll() && (nBar == SB_HORZ || nBar == SB_BOTH))
  2553. {
  2554. CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
  2555. m_nBarState |= GVL_HORZ;
  2556. }
  2557. if (!IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
  2558. {
  2559. CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
  2560. m_nBarState |= GVL_VERT;
  2561. }
  2562. }
  2563. else
  2564. {
  2565. if (IsVisibleHScroll() && (nBar == SB_HORZ || nBar == SB_BOTH))
  2566. {
  2567. CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
  2568. m_nBarState &= ~GVL_HORZ;
  2569. }
  2570. if (IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
  2571. {
  2572. CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
  2573. m_nBarState &= ~GVL_VERT;
  2574. }
  2575. }
  2576. }
  2577. // If resizing or cell counts/sizes change, call this - it'll fix up the scroll bars
  2578. void CGridCtrl::ResetScrollBars()
  2579. {
  2580. // Force a refresh.
  2581. m_idTopLeftCell.row = -1;
  2582. if (!m_bAllowDraw || !::IsWindow(GetSafeHwnd()))
  2583. return;
  2584. CRect rect;
  2585. // This would have caused OnSize event - Brian
  2586. //EnableScrollBars(SB_BOTH, FALSE);
  2587. GetClientRect(rect);
  2588. if (rect.left == rect.right || rect.top == rect.bottom)
  2589. return;
  2590. if (IsVisibleVScroll())
  2591. rect.right += GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetrics(SM_CXBORDER);
  2592. if (IsVisibleHScroll())
  2593. rect.bottom += GetSystemMetrics(SM_CYHSCROLL) + GetSystemMetrics(SM_CYBORDER);
  2594. rect.left += GetFixedColumnWidth();
  2595. rect.top += GetFixedRowHeight();
  2596. if (rect.left >= rect.right || rect.top >= rect.bottom)
  2597. {
  2598. EnableScrollBarCtrl(SB_BOTH, FALSE);
  2599. return;
  2600. }
  2601. CRect VisibleRect(GetFixedColumnWidth(), GetFixedRowHeight(), rect.right, rect.bottom);
  2602. CRect VirtualRect(GetFixedColumnWidth(), GetFixedRowHeight(), GetVirtualWidth(), GetVirtualHeight());
  2603. // Removed to fix single row scrollbar problem (Pontus Goffe)
  2604. // CCellRange visibleCells = GetUnobstructedNonFixedCellRange();
  2605. // if (!IsValid(visibleCells)) return;
  2606. //TRACE(_T("Visible: %d x %d, Virtual %d x %d. H %d, V %d\n"),
  2607. // VisibleRect.Width(), VisibleRect.Height(),
  2608. // VirtualRect.Width(), VirtualRect.Height(),
  2609. // IsVisibleHScroll(), IsVisibleVScroll());
  2610. // If vertical scroll bar, horizontal space is reduced
  2611. if (VisibleRect.Height() < VirtualRect.Height())
  2612. VisibleRect.right -= ::GetSystemMetrics(SM_CXVSCROLL);
  2613. // If horz scroll bar, vert space is reduced
  2614. if (VisibleRect.Width() < VirtualRect.Width())
  2615. VisibleRect.bottom -= ::GetSystemMetrics(SM_CYHSCROLL);
  2616. // Recheck vertical scroll bar
  2617. //if (VisibleRect.Height() < VirtualRect.Height())
  2618. // VisibleRect.right -= ::GetSystemMetrics(SM_CXVSCROLL);
  2619. if (VisibleRect.Height() < VirtualRect.Height())
  2620. {
  2621. EnableScrollBars(SB_VERT, TRUE);
  2622. m_nVScrollMax = VirtualRect.Height() - 1;
  2623. }
  2624. else
  2625. {
  2626. EnableScrollBars(SB_VERT, FALSE);
  2627. m_nVScrollMax = 0;
  2628. }
  2629. if (VisibleRect.Width() < VirtualRect.Width())
  2630. {
  2631. EnableScrollBars(SB_HORZ, TRUE);
  2632. m_nHScrollMax = VirtualRect.Width() - 1;
  2633. }
  2634. else
  2635. {
  2636. EnableScrollBars(SB_HORZ, FALSE);
  2637. m_nHScrollMax = 0;
  2638. }
  2639. ASSERT(m_nVScrollMax < INT_MAX && m_nHScrollMax < INT_MAX); // This should be fine
  2640. /* Old code - CJM
  2641. SCROLLINFO si;
  2642. si.cbSize = sizeof(SCROLLINFO);
  2643. si.fMask = SIF_PAGE;
  2644. si.nPage = (m_nHScrollMax>0)? VisibleRect.Width() : 0;
  2645. SetScrollInfo(SB_HORZ, &si, FALSE);
  2646. si.nPage = (m_nVScrollMax>0)? VisibleRect.Height() : 0;
  2647. SetScrollInfo(SB_VERT, &si, FALSE);
  2648. SetScrollRange(SB_VERT, 0, m_nVScrollMax, TRUE);
  2649. SetScrollRange(SB_HORZ, 0, m_nHScrollMax, TRUE);
  2650. */
  2651. // New code - Paul Runstedler
  2652. SCROLLINFO si;
  2653. si.cbSize = sizeof(SCROLLINFO);
  2654. si.fMask = SIF_PAGE | SIF_RANGE;
  2655. si.nPage = (m_nHScrollMax > 0) ? VisibleRect.Width() : 0;
  2656. si.nMin = 0;
  2657. si.nMax = m_nHScrollMax;
  2658. SetScrollInfo(SB_HORZ, &si, TRUE);
  2659. si.fMask |= SIF_DISABLENOSCROLL;
  2660. si.nPage = (m_nVScrollMax > 0) ? VisibleRect.Height() : 0;
  2661. si.nMin = 0;
  2662. si.nMax = m_nVScrollMax;
  2663. SetScrollInfo(SB_VERT, &si, TRUE);
  2664. }
  2665. ////////////////////////////////////////////////////////////////////////////////////
  2666. // Row/Column position functions
  2667. // returns the top left point of the cell. Returns FALSE if cell not visible.
  2668. BOOL CGridCtrl::GetCellOrigin(int nRow, int nCol, LPPOINT p)
  2669. {
  2670. int i;
  2671. if (!IsValid(nRow, nCol))
  2672. return FALSE;
  2673. CCellID idTopLeft;
  2674. if (nCol >= m_nFixedCols || nRow >= m_nFixedRows)
  2675. idTopLeft = GetTopleftNonFixedCell();
  2676. if ((nRow >= m_nFixedRows && nRow < idTopLeft.row) ||
  2677. (nCol >= m_nFixedCols && nCol < idTopLeft.col))
  2678. return FALSE;
  2679. p->x = 0;
  2680. if (nCol < m_nFixedCols) // is a fixed column
  2681. for (i = 0; i < nCol; i++)
  2682. p->x += GetColumnWidth(i);
  2683. else
  2684. { // is a scrollable data column
  2685. for (i = 0; i < m_nFixedCols; i++)
  2686. p->x += GetColumnWidth(i);
  2687. for (i = idTopLeft.col; i < nCol; i++)
  2688. p->x += GetColumnWidth(i);
  2689. }
  2690. p->y = 0;
  2691. if (nRow < m_nFixedRows) // is a fixed row
  2692. for (i = 0; i < nRow; i++)
  2693. p->y += GetRowHeight(i);
  2694. else
  2695. { // is a scrollable data row
  2696. for (i = 0; i < m_nFixedRows; i++)
  2697. p->y += GetRowHeight(i);
  2698. for (i = idTopLeft.row; i < nRow; i++)
  2699. p->y += GetRowHeight(i);
  2700. }
  2701. return TRUE;
  2702. }
  2703. BOOL CGridCtrl::GetCellOrigin(const CCellID& cell, LPPOINT p)
  2704. {
  2705. return GetCellOrigin(cell.row, cell.col, p);
  2706. }
  2707. // Returns the bounding box of the cell
  2708. BOOL CGridCtrl::GetCellRect(const CCellID& cell, LPRECT pRect)
  2709. {
  2710. return GetCellRect(cell.row, cell.col, pRect);
  2711. }
  2712. BOOL CGridCtrl::GetCellRect(int nRow, int nCol, LPRECT pRect)
  2713. {
  2714. CPoint CellOrigin;
  2715. if (!GetCellOrigin(nRow, nCol, &CellOrigin))
  2716. return FALSE;
  2717. pRect->left = CellOrigin.x;
  2718. pRect->top = CellOrigin.y;
  2719. pRect->right = CellOrigin.x + GetColumnWidth(nCol) - 1;
  2720. pRect->bottom = CellOrigin.y + GetRowHeight(nRow) - 1;
  2721. //TRACE("Row %d, col %d: L %d, T %d, W %d, H %d: %d,%d - %d,%d\n",
  2722. // nRow,nCol, CellOrigin.x, CellOrigin.y, GetColumnWidth(nCol), GetRowHeight(nRow),
  2723. // pRect->left, pRect->top, pRect->right, pRect->bottom);
  2724. return TRUE;
  2725. }
  2726. BOOL CGridCtrl::GetTextRect(const CCellID& cell, LPRECT pRect)
  2727. {
  2728. return GetTextRect(cell.row, cell.col, pRect);
  2729. }
  2730. BOOL CGridCtrl::GetTextRect(int nRow, int nCol, LPRECT pRect)
  2731. {
  2732. CGridCellBase* pCell = GetCell(nRow, nCol);
  2733. if (pCell == NULL)
  2734. return FALSE;
  2735. if (!GetCellRect(nRow, nCol, pRect))
  2736. return FALSE;
  2737. return pCell->GetTextRect(pRect);
  2738. }
  2739. // Returns the bounding box of a range of cells
  2740. BOOL CGridCtrl::GetCellRangeRect(const CCellRange& cellRange, LPRECT lpRect)
  2741. {
  2742. CPoint MinOrigin, MaxOrigin;
  2743. if (!GetCellOrigin(cellRange.GetMinRow(), cellRange.GetMinCol(), &MinOrigin))
  2744. return FALSE;
  2745. if (!GetCellOrigin(cellRange.GetMaxRow(), cellRange.GetMaxCol(), &MaxOrigin))
  2746. return FALSE;
  2747. lpRect->left = MinOrigin.x;
  2748. lpRect->top = MinOrigin.y;
  2749. lpRect->right = MaxOrigin.x + GetColumnWidth(cellRange.GetMaxCol()) - 1;
  2750. lpRect->bottom = MaxOrigin.y + GetRowHeight(cellRange.GetMaxRow()) - 1;
  2751. return TRUE;
  2752. }
  2753. ////////////////////////////////////////////////////////////////////////////////////
  2754. // Grid attribute functions
  2755. LRESULT CGridCtrl::OnSetFont(WPARAM hFont, LPARAM /*lParam */)
  2756. {
  2757. LRESULT result = Default();
  2758. // Get the logical font
  2759. LOGFONT lf;
  2760. if (!GetObject((HFONT)hFont, sizeof(LOGFONT), &lf))
  2761. return result;
  2762. m_cellDefault.SetFont(&lf);
  2763. m_cellFixedColDef.SetFont(&lf);
  2764. m_cellFixedRowDef.SetFont(&lf);
  2765. m_cellFixedRowColDef.SetFont(&lf);
  2766. Refresh();
  2767. return result;
  2768. }
  2769. LRESULT CGridCtrl::OnGetFont(WPARAM /*wParam*/, LPARAM /*lParam*/)
  2770. {
  2771. //LOGFONT lf;
  2772. //m_cellDefault.GetFontObject()->GetLogFont(&lf);
  2773. return (LRESULT)m_cellDefault.GetFontObject()->GetSafeHandle();
  2774. }
  2775. #ifndef _WIN32_WCE_NO_CURSOR
  2776. BOOL CGridCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  2777. {
  2778. if (nHitTest == HTCLIENT)
  2779. {
  2780. switch (m_MouseMode)
  2781. {
  2782. case MOUSE_OVER_COL_DIVIDE:
  2783. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  2784. break;
  2785. case MOUSE_OVER_ROW_DIVIDE:
  2786. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
  2787. break;
  2788. #ifndef GRIDCONTROL_NO_DRAGDROP
  2789. case MOUSE_DRAGGING:
  2790. break;
  2791. #endif
  2792. default:
  2793. if (!GetVirtualMode())
  2794. {
  2795. CPoint pt(GetMessagePos());
  2796. ScreenToClient(&pt);
  2797. CCellID cell = GetCellFromPt(pt);
  2798. if (IsValid(cell))
  2799. {
  2800. CGridCellBase* pCell = GetCell(cell.row, cell.col);
  2801. if (pCell)
  2802. return pCell->OnSetCursor();
  2803. }
  2804. }
  2805. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  2806. }
  2807. return TRUE;
  2808. }
  2809. return CWnd::OnSetCursor(pWnd, nHitTest, message);
  2810. }
  2811. #endif
  2812. ////////////////////////////////////////////////////////////////////////////////////
  2813. // Row/Column count functions
  2814. BOOL CGridCtrl::SetFixedRowCount(int nFixedRows)
  2815. {
  2816. if (m_nFixedRows == nFixedRows)
  2817. return TRUE;
  2818. ASSERT(nFixedRows >= 0);
  2819. ResetSelectedRange();
  2820. // Force recalculation
  2821. m_idTopLeftCell.col = -1;
  2822. if (nFixedRows > GetRowCount())
  2823. if (!SetRowCount(nFixedRows))
  2824. return FALSE;
  2825. if (m_idCurrentCell.row < nFixedRows)
  2826. SetFocusCell(-1, -1);
  2827. if (!GetVirtualMode())
  2828. {
  2829. if (nFixedRows > m_nFixedRows)
  2830. {
  2831. for (int i = m_nFixedRows; i < nFixedRows; i++)
  2832. for (int j = 0; j < GetColumnCount(); j++)
  2833. {
  2834. SetItemState(i, j, GetItemState(i, j) | GVIS_FIXED | GVIS_FIXEDROW);
  2835. SetItemBkColour(i, j, CLR_DEFAULT);
  2836. SetItemFgColour(i, j, CLR_DEFAULT);
  2837. }
  2838. }
  2839. else
  2840. {
  2841. for (int i = nFixedRows; i < m_nFixedRows; i++)
  2842. {
  2843. int j;
  2844. for (j = 0; j < GetFixedColumnCount(); j++)
  2845. SetItemState(i, j, GetItemState(i, j) & ~GVIS_FIXEDROW);
  2846. for (j = GetFixedColumnCount(); j < GetColumnCount(); j++)
  2847. {
  2848. SetItemState(i, j, GetItemState(i, j) & ~(GVIS_FIXED | GVIS_FIXEDROW));
  2849. SetItemBkColour(i, j, CLR_DEFAULT);
  2850. SetItemFgColour(i, j, CLR_DEFAULT);
  2851. }
  2852. }
  2853. }
  2854. }
  2855. m_nFixedRows = nFixedRows;
  2856. Refresh();
  2857. return TRUE;
  2858. }
  2859. BOOL CGridCtrl::SetFixedColumnCount(int nFixedCols)
  2860. {
  2861. if (m_nFixedCols == nFixedCols)
  2862. return TRUE;
  2863. ASSERT(nFixedCols >= 0);
  2864. if (nFixedCols > GetColumnCount())
  2865. if (!SetColumnCount(nFixedCols))
  2866. return FALSE;
  2867. if (m_idCurrentCell.col < nFixedCols)
  2868. SetFocusCell(-1, -1);
  2869. ResetSelectedRange();
  2870. // Force recalculation
  2871. m_idTopLeftCell.col = -1;
  2872. if (!GetVirtualMode())
  2873. {
  2874. if (nFixedCols > m_nFixedCols)
  2875. {
  2876. for (int i = 0; i < GetRowCount(); i++)
  2877. for (int j = m_nFixedCols; j < nFixedCols; j++)
  2878. {
  2879. SetItemState(i, j, GetItemState(i, j) | GVIS_FIXED | GVIS_FIXEDCOL);
  2880. SetItemBkColour(i, j, CLR_DEFAULT);
  2881. SetItemFgColour(i, j, CLR_DEFAULT);
  2882. }
  2883. }
  2884. else
  2885. {
  2886. int i = 0;
  2887. for (i = 0; i < GetFixedRowCount(); i++)
  2888. for (int j = nFixedCols; j < m_nFixedCols; j++)
  2889. SetItemState(i, j, GetItemState(i, j) & ~GVIS_FIXEDCOL);
  2890. for (i = GetFixedRowCount(); i < GetRowCount(); i++)
  2891. for (int j = nFixedCols; j < m_nFixedCols; j++)
  2892. {
  2893. SetItemState(i, j, GetItemState(i, j) & ~(GVIS_FIXED | GVIS_FIXEDCOL));
  2894. SetItemBkColour(i, j, CLR_DEFAULT);
  2895. SetItemFgColour(i, j, CLR_DEFAULT);
  2896. }
  2897. }
  2898. }
  2899. m_nFixedCols = nFixedCols;
  2900. Refresh();
  2901. return TRUE;
  2902. }
  2903. BOOL CGridCtrl::SetRowCount(int nRows)
  2904. {
  2905. BOOL bResult = TRUE;
  2906. ASSERT(nRows >= 0);
  2907. if (nRows == GetRowCount())
  2908. return bResult;
  2909. // Force recalculation
  2910. m_idTopLeftCell.col = -1;
  2911. if (nRows < m_nFixedRows)
  2912. m_nFixedRows = nRows;
  2913. if (m_idCurrentCell.row >= nRows)
  2914. SetFocusCell(-1, -1);
  2915. int addedRows = nRows - GetRowCount();
  2916. // If we are about to lose rows, then we need to delete the GridCell objects
  2917. // in each column within each row
  2918. if (addedRows < 0)
  2919. {
  2920. if (!GetVirtualMode())
  2921. {
  2922. for (int row = nRows; row < m_nRows; row++)
  2923. {
  2924. // Delete cells
  2925. for (int col = 0; col < m_nCols; col++)
  2926. DestroyCell(row, col);
  2927. // Delete rows
  2928. GRID_ROW* pRow = m_RowData[row];
  2929. if (pRow)
  2930. delete pRow;
  2931. }
  2932. }
  2933. m_nRows = nRows;
  2934. }
  2935. TRY
  2936. {
  2937. m_arRowHeights.SetSize(nRows);
  2938. if (GetVirtualMode())
  2939. {
  2940. m_nRows = nRows;
  2941. if (addedRows > 0)
  2942. {
  2943. int startRow = nRows - addedRows;
  2944. for (int row = startRow; row < nRows; row++)
  2945. m_arRowHeights[row] = m_cellDefault.GetHeight();
  2946. }
  2947. }
  2948. else
  2949. {
  2950. // Change the number of rows.
  2951. m_RowData.SetSize(nRows);
  2952. // If we have just added rows, we need to construct new elements for each cell
  2953. // and set the default row height
  2954. if (addedRows > 0)
  2955. {
  2956. // initialize row heights and data
  2957. int startRow = nRows - addedRows;
  2958. for (int row = startRow; row < nRows; row++)
  2959. {
  2960. m_arRowHeights[row] = m_cellDefault.GetHeight();
  2961. m_RowData[row] = new GRID_ROW;
  2962. m_RowData[row]->SetSize(m_nCols);
  2963. for (int col = 0; col < m_nCols; col++)
  2964. {
  2965. GRID_ROW* pRow = m_RowData[row];
  2966. if (pRow && !GetVirtualMode())
  2967. pRow->SetAt(col, CreateCell(row, col));
  2968. }
  2969. m_nRows++;
  2970. }
  2971. }
  2972. }
  2973. }
  2974. CATCH(CMemoryException, e)
  2975. {
  2976. e->ReportError();
  2977. bResult = FALSE;
  2978. }
  2979. END_CATCH
  2980. SetModified();
  2981. ResetScrollBars();
  2982. Refresh();
  2983. return bResult;
  2984. }
  2985. BOOL CGridCtrl::SetColumnCount(int nCols)
  2986. {
  2987. BOOL bResult = TRUE;
  2988. ASSERT(nCols >= 0);
  2989. if (nCols == GetColumnCount())
  2990. return bResult;
  2991. // Force recalculation
  2992. m_idTopLeftCell.col = -1;
  2993. if (nCols < m_nFixedCols)
  2994. m_nFixedCols = nCols;
  2995. if (m_idCurrentCell.col >= nCols)
  2996. SetFocusCell(-1, -1);
  2997. int addedCols = nCols - GetColumnCount();
  2998. // If we are about to lose columns, then we need to delete the GridCell objects
  2999. // within each column
  3000. if (addedCols < 0 && !GetVirtualMode())
  3001. {
  3002. for (int row = 0; row < m_nRows; row++)
  3003. for (int col = nCols; col < GetColumnCount(); col++)
  3004. DestroyCell(row, col);
  3005. }
  3006. TRY
  3007. {
  3008. // Change the number of columns.
  3009. m_arColWidths.SetSize(nCols);
  3010. // Change the number of columns in each row.
  3011. if (!GetVirtualMode())
  3012. for (int i = 0; i < m_nRows; i++)
  3013. if (m_RowData[i])
  3014. m_RowData[i]->SetSize(nCols);
  3015. // If we have just added columns, we need to construct new elements for each cell
  3016. // and set the default column width
  3017. if (addedCols > 0)
  3018. {
  3019. // initialized column widths
  3020. int col = 0;
  3021. int startCol = nCols - addedCols;
  3022. for (col = startCol; col < nCols; col++)
  3023. m_arColWidths[col] = m_cellFixedColDef.GetWidth();
  3024. // initialise column data
  3025. if (!GetVirtualMode())
  3026. {
  3027. for (int row = 0; row < m_nRows; row++)
  3028. for (col = startCol; col < nCols; col++)
  3029. {
  3030. GRID_ROW* pRow = m_RowData[row];
  3031. if (pRow)
  3032. pRow->SetAt(col, CreateCell(row, col));
  3033. }
  3034. }
  3035. }
  3036. // else // check for selected cell ranges
  3037. // ResetSelectedRange();
  3038. }
  3039. CATCH(CMemoryException, e)
  3040. {
  3041. e->ReportError();
  3042. bResult = FALSE;
  3043. }
  3044. END_CATCH
  3045. m_nCols = nCols;
  3046. SetModified();
  3047. ResetScrollBars();
  3048. Refresh();
  3049. return bResult;
  3050. }
  3051. // Insert a column at a given position, or add to end of columns (if nColumn = -1)
  3052. int CGridCtrl::InsertColumn(LPCTSTR strHeading,
  3053. UINT nFormat /* = DT_CENTER|DT_VCENTER|DT_SINGLELINE */,
  3054. int nColumn /* = -1 */)
  3055. {
  3056. if (nColumn >= 0 && nColumn < m_nFixedCols)
  3057. {
  3058. // TODO: Fix it so column insertion works for in the fixed column area
  3059. ASSERT(FALSE);
  3060. return -1;
  3061. }
  3062. // If the insertion is for a specific column, check it's within range.
  3063. if (nColumn >= 0 && nColumn > GetColumnCount())
  3064. return -1;
  3065. // Force recalculation
  3066. m_idTopLeftCell.col = -1;
  3067. ResetSelectedRange();
  3068. // Gotta be able to at least _see_ some of the column.
  3069. if (m_nRows < 1)
  3070. SetRowCount(1);
  3071. // Allow the user to insert after the last of the columns, but process it as a
  3072. // "-1" column, meaning it gets flaged as being the last column, and not a regular
  3073. // "insert" routine.
  3074. if (nColumn == GetColumnCount())
  3075. nColumn = -1;
  3076. TRY
  3077. {
  3078. if (nColumn < 0)
  3079. {
  3080. nColumn = m_nCols;
  3081. m_arColWidths.Add(0);
  3082. if (!GetVirtualMode())
  3083. {
  3084. for (int row = 0; row < m_nRows; row++)
  3085. {
  3086. GRID_ROW* pRow = m_RowData[row];
  3087. if (!pRow)
  3088. return -1;
  3089. pRow->Add(CreateCell(row, nColumn));
  3090. }
  3091. }
  3092. }
  3093. else
  3094. {
  3095. m_arColWidths.InsertAt(nColumn, (int)0, 1);
  3096. if (!GetVirtualMode())
  3097. {
  3098. for (int row = 0; row < m_nRows; row++)
  3099. {
  3100. GRID_ROW* pRow = m_RowData[row];
  3101. if (!pRow)
  3102. return -1;
  3103. pRow->InsertAt(nColumn, CreateCell(row, nColumn));
  3104. }
  3105. }
  3106. }
  3107. }
  3108. CATCH(CMemoryException, e)
  3109. {
  3110. e->ReportError();
  3111. return FALSE;
  3112. }
  3113. END_CATCH
  3114. m_nCols++;
  3115. // Initialise column data
  3116. SetItemText(0, nColumn, strHeading);
  3117. for (int row = 0; row < m_nRows; row++)
  3118. SetItemFormat(row, nColumn, nFormat);
  3119. // initialized column width
  3120. m_arColWidths[nColumn] = GetTextExtent(0, nColumn, strHeading).cx;
  3121. if (m_idCurrentCell.col != -1 && nColumn < m_idCurrentCell.col)
  3122. m_idCurrentCell.col++;
  3123. ResetScrollBars();
  3124. SetModified();
  3125. return nColumn;
  3126. }
  3127. // Insert a row at a given position, or add to end of rows (if nRow = -1)
  3128. int CGridCtrl::InsertRow(LPCTSTR strHeading, int nRow /* = -1 */)
  3129. {
  3130. if (nRow >= 0 && nRow < m_nFixedRows)
  3131. {
  3132. // TODO: Fix it so column insertion works for in the fixed row area
  3133. ASSERT(FALSE);
  3134. return -1;
  3135. }
  3136. // If the insertion is for a specific row, check it's within range.
  3137. if (nRow >= 0 && nRow >= GetRowCount())
  3138. return -1;
  3139. // Force recalculation
  3140. m_idTopLeftCell.col = -1;
  3141. ResetSelectedRange();
  3142. // Gotta be able to at least _see_ some of the row.
  3143. if (m_nCols < 1)
  3144. SetColumnCount(1);
  3145. TRY
  3146. {
  3147. // Adding a row to the bottom
  3148. if (nRow < 0)
  3149. {
  3150. nRow = m_nRows;
  3151. m_arRowHeights.Add(0);
  3152. if (!GetVirtualMode())
  3153. m_RowData.Add(new GRID_ROW);
  3154. }
  3155. else
  3156. {
  3157. m_arRowHeights.InsertAt(nRow, (int)0, 1);
  3158. if (!GetVirtualMode())
  3159. m_RowData.InsertAt(nRow, new GRID_ROW);
  3160. }
  3161. if (!GetVirtualMode())
  3162. m_RowData[nRow]->SetSize(m_nCols);
  3163. }
  3164. CATCH(CMemoryException, e)
  3165. {
  3166. e->ReportError();
  3167. return FALSE;
  3168. }
  3169. END_CATCH
  3170. m_nRows++;
  3171. // Initialise cell data
  3172. if (!GetVirtualMode())
  3173. {
  3174. for (int col = 0; col < m_nCols; col++)
  3175. {
  3176. GRID_ROW* pRow = m_RowData[nRow];
  3177. if (!pRow)
  3178. return -1;
  3179. pRow->SetAt(col, CreateCell(nRow, col));
  3180. }
  3181. }
  3182. // Set row title
  3183. SetItemText(nRow, 0, strHeading);
  3184. // initialized row height
  3185. if (strHeading && strHeading[0])
  3186. m_arRowHeights[nRow] = GetTextExtent(nRow, 0, strHeading).cy;
  3187. else
  3188. m_arRowHeights[nRow] = m_cellFixedRowDef.GetHeight();
  3189. if (m_idCurrentCell.row != -1 && nRow < m_idCurrentCell.row)
  3190. m_idCurrentCell.row++;
  3191. ResetScrollBars();
  3192. SetModified();
  3193. return nRow;
  3194. }
  3195. ///////////////////////////////////////////////////////////////////////////////
  3196. // Cell creation stuff
  3197. BOOL CGridCtrl::SetCellType(int nRow, int nCol, CRuntimeClass* pRuntimeClass)
  3198. {
  3199. if (GetVirtualMode())
  3200. return FALSE;
  3201. ASSERT(IsValid(nRow, nCol));
  3202. if (!IsValid(nRow, nCol))
  3203. return FALSE;
  3204. if (!pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
  3205. {
  3206. ASSERT(FALSE);
  3207. return FALSE;
  3208. }
  3209. CGridCellBase* pNewCell = (CGridCellBase*)pRuntimeClass->CreateObject();
  3210. CGridCellBase* pCurrCell = GetCell(nRow, nCol);
  3211. if (pCurrCell)
  3212. *pNewCell = *pCurrCell;
  3213. SetCell(nRow, nCol, pNewCell);
  3214. delete pCurrCell;
  3215. return TRUE;
  3216. }
  3217. BOOL CGridCtrl::SetDefaultCellType(CRuntimeClass* pRuntimeClass)
  3218. {
  3219. ASSERT(pRuntimeClass != NULL);
  3220. if (!pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
  3221. {
  3222. ASSERT(FALSE);
  3223. return FALSE;
  3224. }
  3225. m_pRtcDefault = pRuntimeClass;
  3226. return TRUE;
  3227. }
  3228. // Creates a new grid cell and performs any necessary initialisation
  3229. /*virtual*/ CGridCellBase* CGridCtrl::CreateCell(int nRow, int nCol)
  3230. {
  3231. ASSERT(!GetVirtualMode());
  3232. if (!m_pRtcDefault || !m_pRtcDefault->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
  3233. {
  3234. ASSERT(FALSE);
  3235. return NULL;
  3236. }
  3237. CGridCellBase* pCell = (CGridCellBase*)m_pRtcDefault->CreateObject();
  3238. if (!pCell)
  3239. return NULL;
  3240. pCell->SetGrid(this);
  3241. pCell->SetCoords(nRow, nCol);
  3242. if (nCol < m_nFixedCols)
  3243. pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDCOL);
  3244. if (nRow < m_nFixedRows)
  3245. pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDROW);
  3246. pCell->SetFormat(pCell->GetDefaultCell()->GetFormat());
  3247. return pCell;
  3248. }
  3249. // Performs any cell cleanup necessary to maintain grid integrity
  3250. /*virtual*/ void CGridCtrl::DestroyCell(int nRow, int nCol)
  3251. {
  3252. // Should NEVER get here in virtual mode.
  3253. ASSERT(!GetVirtualMode());
  3254. // Set the cells state to 0. If the cell is selected, this
  3255. // will remove the cell from the selected list.
  3256. SetItemState(nRow, nCol, 0);
  3257. delete GetCell(nRow, nCol);
  3258. }
  3259. BOOL CGridCtrl::DeleteColumn(int nColumn)
  3260. {
  3261. if (nColumn < 0 || nColumn >= GetColumnCount())
  3262. return FALSE;
  3263. ResetSelectedRange();
  3264. if (!GetVirtualMode())
  3265. {
  3266. for (int row = 0; row < GetRowCount(); row++)
  3267. {
  3268. GRID_ROW* pRow = m_RowData[row];
  3269. if (!pRow)
  3270. return FALSE;
  3271. DestroyCell(row, nColumn);
  3272. pRow->RemoveAt(nColumn);
  3273. }
  3274. }
  3275. m_arColWidths.RemoveAt(nColumn);
  3276. m_nCols--;
  3277. if (nColumn < m_nFixedCols)
  3278. m_nFixedCols--;
  3279. if (nColumn == m_idCurrentCell.col)
  3280. m_idCurrentCell.row = m_idCurrentCell.col = -1;
  3281. else if (nColumn < m_idCurrentCell.col)
  3282. m_idCurrentCell.col--;
  3283. ResetScrollBars();
  3284. SetModified();
  3285. return TRUE;
  3286. }
  3287. BOOL CGridCtrl::DeleteRow(int nRow)
  3288. {
  3289. if (nRow < 0 || nRow >= GetRowCount())
  3290. return FALSE;
  3291. ResetSelectedRange();
  3292. if (!GetVirtualMode())
  3293. {
  3294. GRID_ROW* pRow = m_RowData[nRow];
  3295. if (!pRow)
  3296. return FALSE;
  3297. for (int col = 0; col < GetColumnCount(); col++)
  3298. DestroyCell(nRow, col);
  3299. delete pRow;
  3300. m_RowData.RemoveAt(nRow);
  3301. }
  3302. m_arRowHeights.RemoveAt(nRow);
  3303. m_nRows--;
  3304. if (nRow < m_nFixedRows)
  3305. m_nFixedRows--;
  3306. if (nRow == m_idCurrentCell.row)
  3307. m_idCurrentCell.row = m_idCurrentCell.col = -1;
  3308. else if (nRow < m_idCurrentCell.row)
  3309. m_idCurrentCell.row--;
  3310. ResetScrollBars();
  3311. SetModified();
  3312. return TRUE;
  3313. }
  3314. // Handy function that removes all non-fixed rows
  3315. BOOL CGridCtrl::DeleteNonFixedRows()
  3316. {
  3317. ResetSelectedRange();
  3318. int nFixed = GetFixedRowCount();
  3319. int nCount = GetRowCount();
  3320. // Delete all data rows
  3321. for (int nRow = nCount; nRow >= nFixed; nRow--)
  3322. DeleteRow(nRow);
  3323. return TRUE;
  3324. }
  3325. // Removes all rows, columns and data from the grid.
  3326. BOOL CGridCtrl::DeleteAllItems()
  3327. {
  3328. ResetSelectedRange();
  3329. m_arColWidths.RemoveAll();
  3330. m_arRowHeights.RemoveAll();
  3331. // Delete all cells in the grid
  3332. if (!GetVirtualMode())
  3333. {
  3334. for (int row = 0; row < m_nRows; row++)
  3335. {
  3336. for (int col = 0; col < m_nCols; col++)
  3337. DestroyCell(row, col);
  3338. GRID_ROW* pRow = m_RowData[row];
  3339. delete pRow;
  3340. }
  3341. // Remove all rows
  3342. m_RowData.RemoveAll();
  3343. }
  3344. m_idCurrentCell.row = m_idCurrentCell.col = -1;
  3345. m_nRows = m_nFixedRows = m_nCols = m_nFixedCols = 0;
  3346. ResetScrollBars();
  3347. SetModified();
  3348. return TRUE;
  3349. }
  3350. void CGridCtrl::AutoFill()
  3351. {
  3352. if (!::IsWindow(m_hWnd))
  3353. return;
  3354. CRect rect;
  3355. GetClientRect(rect);
  3356. SetColumnCount(rect.Width() / m_cellDefault.GetWidth() + 1);
  3357. SetRowCount(rect.Height() / m_cellDefault.GetHeight() + 1);
  3358. SetFixedRowCount(1);
  3359. SetFixedColumnCount(1);
  3360. ExpandToFit();
  3361. }
  3362. /////////////////////////////////////////////////////////////////////////////
  3363. // CGridCtrl data functions
  3364. // Set CListCtrl::GetNextItem for details
  3365. CCellID CGridCtrl::GetNextItem(CCellID& cell, int nFlags) const
  3366. {
  3367. if ((nFlags & GVNI_ALL) == GVNI_ALL)
  3368. { // GVNI_ALL Search whole Grid beginning from cell
  3369. // First row (cell.row) -- ONLY Columns to the right of cell
  3370. // following rows -- ALL Columns
  3371. int row = cell.row, col = cell.col + 1;
  3372. if (row <= 0)
  3373. row = GetFixedRowCount();
  3374. for (; row < GetRowCount(); row++)
  3375. {
  3376. if (col <= 0)
  3377. col = GetFixedColumnCount();
  3378. for (; col < GetColumnCount(); col++)
  3379. {
  3380. int nState = GetItemState(row, col);
  3381. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3382. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3383. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3384. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3385. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3386. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3387. return CCellID(row, col);
  3388. }
  3389. // go to First Column
  3390. col = GetFixedColumnCount();
  3391. }
  3392. }
  3393. else if ((nFlags & GVNI_BELOW) == GVNI_BELOW &&
  3394. (nFlags & GVNI_TORIGHT) == GVNI_TORIGHT)
  3395. { // GVNI_AREA Search Grid beginning from cell to Lower-Right of Grid
  3396. // Only rows starting with cell.row and below
  3397. // All rows -- ONLY Columns to the right of cell
  3398. int row = cell.row;
  3399. if (row <= 0)
  3400. row = GetFixedRowCount();
  3401. for (; row < GetRowCount(); row++)
  3402. {
  3403. int col = cell.col + 1;
  3404. if (col <= 0)
  3405. col = GetFixedColumnCount();
  3406. for (; col < GetColumnCount(); col++)
  3407. {
  3408. int nState = GetItemState(row, col);
  3409. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3410. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3411. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3412. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3413. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3414. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3415. return CCellID(row, col);
  3416. }
  3417. }
  3418. }
  3419. else if ((nFlags & GVNI_ABOVE) == GVNI_ABOVE)
  3420. {
  3421. for (int row = cell.row - 1; row >= GetFixedRowCount(); row--)
  3422. {
  3423. int nState = GetItemState(row, cell.col);
  3424. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3425. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3426. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3427. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3428. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3429. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3430. return CCellID(row, cell.col);
  3431. }
  3432. }
  3433. else if ((nFlags & GVNI_BELOW) == GVNI_BELOW)
  3434. {
  3435. for (int row = cell.row + 1; row < GetRowCount(); row++)
  3436. {
  3437. int nState = GetItemState(row, cell.col);
  3438. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3439. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3440. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3441. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3442. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3443. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3444. return CCellID(row, cell.col);
  3445. }
  3446. }
  3447. else if ((nFlags & GVNI_TOLEFT) == GVNI_TOLEFT)
  3448. {
  3449. for (int col = cell.col - 1; col >= GetFixedColumnCount(); col--)
  3450. {
  3451. int nState = GetItemState(cell.row, col);
  3452. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3453. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3454. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3455. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3456. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3457. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3458. return CCellID(cell.row, col);
  3459. }
  3460. }
  3461. else if ((nFlags & GVNI_TORIGHT) == GVNI_TORIGHT)
  3462. {
  3463. for (int col = cell.col + 1; col < GetColumnCount(); col++)
  3464. {
  3465. int nState = GetItemState(cell.row, col);
  3466. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3467. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3468. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3469. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3470. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3471. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3472. return CCellID(cell.row, col);
  3473. }
  3474. }
  3475. return CCellID(-1, -1);
  3476. }
  3477. // Sorts on a given column using the cell text
  3478. BOOL CGridCtrl::SortTextItems(int nCol, BOOL bAscending, LPARAM data /* = 0 */)
  3479. {
  3480. SetSortColumn(nCol);
  3481. SetSortAscending(bAscending);
  3482. ResetSelectedRange();
  3483. SetFocusCell(-1, -1);
  3484. // -AfxMessageBox("SortTextItems");
  3485. return CGridCtrl::SortItems(pfnCellTextCompare, nCol, bAscending, data);
  3486. }
  3487. void CGridCtrl::SetCompareFunction(PFNLVCOMPARE pfnCompare)
  3488. {
  3489. m_pfnCompare = pfnCompare;
  3490. }
  3491. // Sorts on a given column using the cell text and using the specified comparison
  3492. // function
  3493. BOOL CGridCtrl::SortItems(int nCol, BOOL bAscending, LPARAM data /* = 0 */)
  3494. {
  3495. SetSortColumn(nCol);
  3496. SetSortAscending(bAscending);
  3497. ResetSelectedRange();
  3498. SetFocusCell(-1, -1);
  3499. if (m_pfnCompare == NULL)
  3500. return CGridCtrl::SortItems(pfnCellTextCompare, nCol, bAscending, data);
  3501. else
  3502. return CGridCtrl::SortItems(m_pfnCompare, nCol, bAscending, data);
  3503. }
  3504. // Sorts on a given column using the supplied compare function (see CListCtrl::SortItems)
  3505. BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending,
  3506. LPARAM data /* = 0 */)
  3507. {
  3508. SetSortColumn(nCol);
  3509. SetSortAscending(bAscending);
  3510. ResetSelectedRange();
  3511. SetFocusCell(-1, -1);
  3512. return SortItems(pfnCompare, nCol, bAscending, data, GetFixedRowCount(), -1);
  3513. }
  3514. int CALLBACK CGridCtrl::pfnCellTextCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  3515. {
  3516. UNUSED_ALWAYS(lParamSort);
  3517. CGridCellBase* pCell1 = (CGridCellBase*)lParam1;
  3518. CGridCellBase* pCell2 = (CGridCellBase*)lParam2;
  3519. if (!pCell1 || !pCell2) return 0;
  3520. return _tcscmp(pCell1->GetText(), pCell2->GetText());
  3521. }
  3522. int CALLBACK CGridCtrl::pfnCellNumericCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  3523. {
  3524. UNUSED_ALWAYS(lParamSort);
  3525. CGridCellBase* pCell1 = (CGridCellBase*)lParam1;
  3526. CGridCellBase* pCell2 = (CGridCellBase*)lParam2;
  3527. if (!pCell1 || !pCell2) return 0;
  3528. int nValue1 = _ttol(pCell1->GetText());
  3529. int nValue2 = _ttol(pCell2->GetText());
  3530. if (nValue1 < nValue2)
  3531. return -1;
  3532. else if (nValue1 == nValue2)
  3533. return 0;
  3534. else
  3535. return 1;
  3536. }
  3537. // private recursive sort implementation
  3538. BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data,
  3539. int low, int high)
  3540. {
  3541. ///-AfxMessageBox("SortItems3");
  3542. if (nCol >= GetColumnCount())
  3543. return FALSE;
  3544. if (high == -1)
  3545. high = GetRowCount() - 1;
  3546. int lo = low;
  3547. int hi = high;
  3548. if (hi <= lo)
  3549. return FALSE;
  3550. //LPARAM midItem = GetItemData((lo + hi)/2, nCol);
  3551. LPARAM pMidCell = (LPARAM)GetCell((lo + hi) / 2, nCol);
  3552. // loop through the list until indices cross
  3553. while (lo <= hi)
  3554. {
  3555. // Find the first element that is greater than or equal to the partition
  3556. // element starting from the left Index.
  3557. if (bAscending)
  3558. while (lo < high && pfnCompare((LPARAM)GetCell(lo, nCol), (LPARAM)pMidCell, data) < 0)
  3559. ++lo;
  3560. else
  3561. while (lo < high && pfnCompare((LPARAM)GetCell(lo, nCol), pMidCell, data) > 0)
  3562. ++lo;
  3563. // Find an element that is smaller than or equal to the partition
  3564. // element starting from the right Index.
  3565. if (bAscending)
  3566. while (hi > low && pfnCompare((LPARAM)GetCell(hi, nCol), pMidCell, data) > 0)
  3567. --hi;
  3568. else
  3569. while (hi > low && pfnCompare((LPARAM)GetCell(hi, nCol), pMidCell, data) < 0)
  3570. --hi;
  3571. // If the indexes have not crossed, swap if the items are not equal
  3572. if (lo <= hi)
  3573. {
  3574. // swap only if the items are not equal
  3575. if (pfnCompare((LPARAM)GetCell(lo, nCol), (LPARAM)GetCell(hi, nCol), data) != 0)
  3576. {
  3577. for (int col = 0; col < GetColumnCount(); col++)
  3578. {
  3579. CGridCellBase *pCell = GetCell(lo, col);
  3580. SetCell(lo, col, GetCell(hi, col));
  3581. SetCell(hi, col, pCell);
  3582. }
  3583. UINT nRowHeight = m_arRowHeights[lo];
  3584. m_arRowHeights[lo] = m_arRowHeights[hi];
  3585. m_arRowHeights[hi] = nRowHeight;
  3586. }
  3587. ++lo;
  3588. --hi;
  3589. }
  3590. }
  3591. // If the right index has not reached the left side of array
  3592. // must now sort the left partition.
  3593. if (low < hi)
  3594. SortItems(pfnCompare, nCol, bAscending, data, low, hi);
  3595. // If the left index has not reached the right side of array
  3596. // must now sort the right partition.
  3597. if (lo < high)
  3598. SortItems(pfnCompare, nCol, bAscending, data, lo, high);
  3599. return TRUE;
  3600. }
  3601. /////////////////////////////////////////////////////////////////////////////
  3602. // CGridCtrl data functions
  3603. BOOL CGridCtrl::SetItem(const GV_ITEM* pItem)
  3604. {
  3605. if (!pItem || GetVirtualMode())
  3606. return FALSE;
  3607. CGridCellBase* pCell = GetCell(pItem->row, pItem->col);
  3608. if (!pCell)
  3609. return FALSE;
  3610. SetModified(TRUE, pItem->row, pItem->col);
  3611. if (pItem->mask & GVIF_TEXT)
  3612. pCell->SetText(pItem->strText);
  3613. if (pItem->mask & GVIF_PARAM)
  3614. pCell->SetData(pItem->lParam);
  3615. if (pItem->mask & GVIF_IMAGE)
  3616. pCell->SetImage(pItem->iImage);
  3617. if (pItem->mask & GVIF_STATE)
  3618. SetItemState(pItem->row, pItem->col, pItem->nState);
  3619. if (pItem->mask & GVIF_FORMAT)
  3620. pCell->SetFormat(pItem->nFormat);
  3621. if (pItem->mask & GVIF_BKCLR)
  3622. pCell->SetBackClr(pItem->crBkClr);
  3623. if (pItem->mask & GVIF_FGCLR)
  3624. pCell->SetTextClr(pItem->crFgClr);
  3625. if (pItem->mask & GVIF_FONT)
  3626. pCell->SetFont(&(pItem->lfFont));
  3627. if (pItem->mask & GVIF_MARGIN)
  3628. pCell->SetMargin(pItem->nMargin);
  3629. return TRUE;
  3630. }
  3631. BOOL CGridCtrl::GetItem(GV_ITEM* pItem)
  3632. {
  3633. if (!pItem)
  3634. return FALSE;
  3635. CGridCellBase* pCell = GetCell(pItem->row, pItem->col);
  3636. if (!pCell)
  3637. return FALSE;
  3638. if (pItem->mask & GVIF_TEXT)
  3639. pItem->strText = GetItemText(pItem->row, pItem->col);
  3640. if (pItem->mask & GVIF_PARAM)
  3641. pItem->lParam = pCell->GetData();;
  3642. if (pItem->mask & GVIF_IMAGE)
  3643. pItem->iImage = pCell->GetImage();
  3644. if (pItem->mask & GVIF_STATE)
  3645. pItem->nState = pCell->GetState();
  3646. if (pItem->mask & GVIF_FORMAT)
  3647. pItem->nFormat = pCell->GetFormat();
  3648. if (pItem->mask & GVIF_BKCLR)
  3649. pItem->crBkClr = pCell->GetBackClr();
  3650. if (pItem->mask & GVIF_FGCLR)
  3651. pItem->crFgClr = pCell->GetTextClr();
  3652. if (pItem->mask & GVIF_FONT)
  3653. memcpy(&(pItem->lfFont), pCell->GetFont(), sizeof(LOGFONT));
  3654. if (pItem->mask & GVIF_MARGIN)
  3655. pItem->nMargin = pCell->GetMargin();
  3656. return TRUE;
  3657. }
  3658. BOOL CGridCtrl::SetItemText(int nRow, int nCol, LPCTSTR str)
  3659. {
  3660. if (GetVirtualMode())
  3661. return FALSE;
  3662. CGridCellBase* pCell = GetCell(nRow, nCol);
  3663. if (!pCell)
  3664. return FALSE;
  3665. pCell->SetText(str);
  3666. SetModified(TRUE, nRow, nCol);
  3667. return TRUE;
  3668. }
  3669. #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 210)
  3670. // EFW - 06/13/99 - Added to support printf-style formatting codes
  3671. BOOL CGridCtrl::SetItemTextFmt(int nRow, int nCol, LPCTSTR szFmt, ...)
  3672. {
  3673. if (GetVirtualMode())
  3674. return FALSE;
  3675. CString strText;
  3676. va_list argptr;
  3677. CGridCellBase* pCell = GetCell(nRow, nCol);
  3678. if (!pCell)
  3679. return FALSE;
  3680. // Format the message text
  3681. va_start(argptr, szFmt);
  3682. strText.FormatV(szFmt, argptr);
  3683. va_end(argptr);
  3684. pCell->SetText(strText);
  3685. SetModified(TRUE, nRow, nCol);
  3686. return TRUE;
  3687. }
  3688. // EFW - 06/13/99 - Added to support string resource ID. Supports
  3689. // a variable argument list too.
  3690. BOOL CGridCtrl::SetItemTextFmtID(int nRow, int nCol, UINT nID, ...)
  3691. {
  3692. if (GetVirtualMode())
  3693. return FALSE;
  3694. CString strFmt, strText;
  3695. va_list argptr;
  3696. CGridCellBase* pCell = GetCell(nRow, nCol);
  3697. if (!pCell)
  3698. return FALSE;
  3699. // Format the message text
  3700. va_start(argptr, nID);
  3701. VERIFY(strFmt.LoadString(nID));
  3702. strText.FormatV(strFmt, argptr);
  3703. va_end(argptr);
  3704. pCell->SetText(strText);
  3705. SetModified(TRUE, nRow, nCol);
  3706. return TRUE;
  3707. }
  3708. #endif
  3709. BOOL CGridCtrl::SetItemData(int nRow, int nCol, LPARAM lParam)
  3710. {
  3711. if (GetVirtualMode())
  3712. return FALSE;
  3713. CGridCellBase* pCell = GetCell(nRow, nCol);
  3714. if (!pCell)
  3715. return FALSE;
  3716. pCell->SetData(lParam);
  3717. SetModified(TRUE, nRow, nCol);
  3718. return TRUE;
  3719. }
  3720. LPARAM CGridCtrl::GetItemData(int nRow, int nCol) const
  3721. {
  3722. CGridCellBase* pCell = GetCell(nRow, nCol);
  3723. if (!pCell)
  3724. return (LPARAM)0;
  3725. return pCell->GetData();
  3726. }
  3727. BOOL CGridCtrl::SetItemImage(int nRow, int nCol, int iImage)
  3728. {
  3729. if (GetVirtualMode())
  3730. return FALSE;
  3731. CGridCellBase* pCell = GetCell(nRow, nCol);
  3732. if (!pCell)
  3733. return FALSE;
  3734. pCell->SetImage(iImage);
  3735. SetModified(TRUE, nRow, nCol);
  3736. return TRUE;
  3737. }
  3738. int CGridCtrl::GetItemImage(int nRow, int nCol) const
  3739. {
  3740. CGridCellBase* pCell = GetCell(nRow, nCol);
  3741. ASSERT(pCell);
  3742. if (!pCell)
  3743. return -1;
  3744. return pCell->GetImage();
  3745. }
  3746. BOOL CGridCtrl::SetItemState(int nRow, int nCol, UINT state)
  3747. {
  3748. BOOL bSelected = IsCellSelected(nRow, nCol);
  3749. // If the cell is being unselected, remove it from the selected list
  3750. if (bSelected && !(state & GVIS_SELECTED))
  3751. {
  3752. CCellID cell;
  3753. DWORD key = MAKELONG(nRow, nCol);
  3754. if (m_SelectedCellMap.Lookup(key, (CCellID&)cell))
  3755. {
  3756. m_SelectedCellMap.RemoveKey(key);
  3757. //chn add
  3758. for (int i = 0; i < m_nArrayListChoose.GetCount(); i++)
  3759. {
  3760. if (m_nArrayListChoose.GetAt(i) == nRow)
  3761. {
  3762. m_nArrayListChoose.RemoveAt(i);
  3763. break;
  3764. }
  3765. }
  3766. }
  3767. }
  3768. // If cell is being selected, add it to the list of selected cells
  3769. else if (!bSelected && (state & GVIS_SELECTED))
  3770. {
  3771. CCellID cell(nRow, nCol);
  3772. m_SelectedCellMap.SetAt(MAKELONG(nRow, nCol), cell);
  3773. //chn add
  3774. bool bExist = false;
  3775. for (int i = 0; i < m_nArrayListChoose.GetCount(); i++)
  3776. {
  3777. if (m_nArrayListChoose.GetAt(i) == nRow)
  3778. {
  3779. bExist = true;
  3780. break;
  3781. }
  3782. }
  3783. if (!bExist)
  3784. m_nArrayListChoose.Add(nRow);
  3785. }
  3786. if (GetVirtualMode())
  3787. return FALSE;
  3788. CGridCellBase* pCell = GetCell(nRow, nCol);
  3789. ASSERT(pCell);
  3790. if (!pCell)
  3791. return FALSE;
  3792. // Set the cell's state
  3793. pCell->SetState(state);
  3794. return TRUE;
  3795. }
  3796. UINT CGridCtrl::GetItemState(int nRow, int nCol) const
  3797. {
  3798. CGridCellBase* pCell = GetCell(nRow, nCol);
  3799. ASSERT(pCell);
  3800. if (!pCell)
  3801. return 0;
  3802. return pCell->GetState();
  3803. }
  3804. BOOL CGridCtrl::SetItemFormat(int nRow, int nCol, UINT nFormat)
  3805. {
  3806. if (GetVirtualMode())
  3807. return FALSE;
  3808. CGridCellBase* pCell = GetCell(nRow, nCol);
  3809. ASSERT(pCell);
  3810. if (!pCell)
  3811. return FALSE;
  3812. pCell->SetFormat(nFormat);
  3813. return TRUE;
  3814. }
  3815. UINT CGridCtrl::GetItemFormat(int nRow, int nCol) const
  3816. {
  3817. CGridCellBase* pCell = GetCell(nRow, nCol);
  3818. ASSERT(pCell);
  3819. if (!pCell)
  3820. return 0;
  3821. return pCell->GetFormat();
  3822. }
  3823. BOOL CGridCtrl::SetItemBkColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
  3824. {
  3825. if (GetVirtualMode())
  3826. return FALSE;
  3827. CGridCellBase* pCell = GetCell(nRow, nCol);
  3828. ASSERT(pCell);
  3829. if (!pCell)
  3830. return FALSE;
  3831. pCell->SetBackClr(cr);
  3832. return TRUE;
  3833. }
  3834. COLORREF CGridCtrl::GetItemBkColour(int nRow, int nCol) const
  3835. {
  3836. CGridCellBase* pCell = GetCell(nRow, nCol);
  3837. ASSERT(pCell);
  3838. if (!pCell)
  3839. return 0;
  3840. return pCell->GetBackClr();
  3841. }
  3842. BOOL CGridCtrl::SetItemFgColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
  3843. {
  3844. if (GetVirtualMode())
  3845. return FALSE;
  3846. CGridCellBase* pCell = GetCell(nRow, nCol);
  3847. ASSERT(pCell);
  3848. if (!pCell)
  3849. return FALSE;
  3850. pCell->SetTextClr(cr);
  3851. return TRUE;
  3852. }
  3853. COLORREF CGridCtrl::GetItemFgColour(int nRow, int nCol) const
  3854. {
  3855. CGridCellBase* pCell = GetCell(nRow, nCol);
  3856. ASSERT(pCell);
  3857. if (!pCell)
  3858. return 0;
  3859. return pCell->GetTextClr();
  3860. }
  3861. BOOL CGridCtrl::SetItemFont(int nRow, int nCol, const LOGFONT* plf)
  3862. {
  3863. if (GetVirtualMode())
  3864. return FALSE;
  3865. CGridCellBase* pCell = GetCell(nRow, nCol);
  3866. ASSERT(pCell);
  3867. if (!pCell)
  3868. return FALSE;
  3869. pCell->SetFont(plf);
  3870. return TRUE;
  3871. }
  3872. const LOGFONT* CGridCtrl::GetItemFont(int nRow, int nCol)
  3873. {
  3874. CGridCellBase* pCell = GetCell(nRow, nCol);
  3875. ASSERT(pCell);
  3876. if (!pCell)
  3877. return GetDefaultCell(nRow < GetFixedRowCount(), nCol < GetFixedColumnCount())->GetFont();
  3878. return pCell->GetFont();
  3879. }
  3880. BOOL CGridCtrl::IsItemEditing(int nRow, int nCol)
  3881. {
  3882. CGridCellBase* pCell = GetCell(nRow, nCol);
  3883. ASSERT(pCell);
  3884. if (!pCell)
  3885. return FALSE;
  3886. return pCell->IsEditing();
  3887. }
  3888. ////////////////////////////////////////////////////////////////////////////////////
  3889. // Row/Column size functions
  3890. long CGridCtrl::GetVirtualWidth() const
  3891. {
  3892. long lVirtualWidth = 0;
  3893. int iColCount = GetColumnCount();
  3894. for (int i = 0; i < iColCount; i++)
  3895. lVirtualWidth += m_arColWidths[i];
  3896. return lVirtualWidth;
  3897. }
  3898. long CGridCtrl::GetVirtualHeight() const
  3899. {
  3900. long lVirtualHeight = 0;
  3901. int iRowCount = GetRowCount();
  3902. for (int i = 0; i < iRowCount; i++)
  3903. lVirtualHeight += m_arRowHeights[i];
  3904. return lVirtualHeight;
  3905. }
  3906. int CGridCtrl::GetRowHeight(int nRow) const
  3907. {
  3908. ASSERT(nRow >= 0 && nRow < m_nRows);
  3909. if (nRow < 0 || nRow >= m_nRows)
  3910. return -1;
  3911. return m_arRowHeights[nRow];
  3912. }
  3913. int CGridCtrl::GetColumnWidth(int nCol) const
  3914. {
  3915. ASSERT(nCol >= 0 && nCol < m_nCols);
  3916. if (nCol < 0 || nCol >= m_nCols)
  3917. return -1;
  3918. return m_arColWidths[nCol];
  3919. }
  3920. BOOL CGridCtrl::SetRowHeight(int nRow, int height)
  3921. {
  3922. ASSERT(nRow >= 0 && nRow < m_nRows && height >= 0);
  3923. if (nRow < 0 || nRow >= m_nRows || height < 0)
  3924. return FALSE;
  3925. m_arRowHeights[nRow] = height;
  3926. ResetScrollBars();
  3927. return TRUE;
  3928. }
  3929. BOOL CGridCtrl::SetColumnWidth(int nCol, int width)
  3930. {
  3931. ASSERT(nCol >= 0 && nCol < m_nCols && width >= 0);
  3932. if (nCol < 0 || nCol >= m_nCols || width < 0)
  3933. return FALSE;
  3934. m_arColWidths[nCol] = width;
  3935. ResetScrollBars();
  3936. return TRUE;
  3937. }
  3938. int CGridCtrl::GetFixedRowHeight() const
  3939. {
  3940. int nHeight = 0;
  3941. for (int i = 0; i < m_nFixedRows; i++)
  3942. nHeight += GetRowHeight(i);
  3943. return nHeight;
  3944. }
  3945. int CGridCtrl::GetFixedColumnWidth() const
  3946. {
  3947. int nWidth = 0;
  3948. for (int i = 0; i < m_nFixedCols; i++)
  3949. nWidth += GetColumnWidth(i);
  3950. return nWidth;
  3951. }
  3952. BOOL CGridCtrl::AutoSizeColumn(int nCol, UINT nAutoSizeStyle /*=GVS_DEFAULT*/,
  3953. BOOL bResetScroll /*=TRUE*/)
  3954. {
  3955. ASSERT(nCol >= 0 && nCol < m_nCols);
  3956. if (nCol < 0 || nCol >= m_nCols)
  3957. return FALSE;
  3958. // Skip hidden columns when autosizing
  3959. if (GetColumnWidth(nCol) <= 0)
  3960. return FALSE;
  3961. CSize size;
  3962. CDC* pDC = GetDC();
  3963. if (!pDC)
  3964. return FALSE;
  3965. int nWidth = 0;
  3966. ASSERT(GVS_DEFAULT <= nAutoSizeStyle && nAutoSizeStyle <= GVS_BOTH);
  3967. if (nAutoSizeStyle == GVS_DEFAULT)
  3968. nAutoSizeStyle = GetAutoSizeStyle();
  3969. int nStartRow = (nAutoSizeStyle & GVS_HEADER) ? 0 : GetFixedRowCount();
  3970. int nEndRow = (nAutoSizeStyle & GVS_DATA) ? GetRowCount() - 1 : GetFixedRowCount() - 1;
  3971. if (GetVirtualMode())
  3972. SendCacheHintToParent(CCellRange(nStartRow, nCol, nEndRow, nCol));
  3973. for (int nRow = nStartRow; nRow <= nEndRow; nRow++)
  3974. {
  3975. CGridCellBase* pCell = GetCell(nRow, nCol);
  3976. if (pCell)
  3977. size = pCell->GetCellExtent(pDC);
  3978. if (size.cx > nWidth)
  3979. nWidth = size.cx;
  3980. }
  3981. if (GetVirtualMode())
  3982. SendCacheHintToParent(CCellRange(-1, -1, -1, -1));
  3983. m_arColWidths[nCol] = nWidth;
  3984. ReleaseDC(pDC);
  3985. if (bResetScroll)
  3986. ResetScrollBars();
  3987. return TRUE;
  3988. }
  3989. BOOL CGridCtrl::AutoSizeRow(int nRow, BOOL bResetScroll /*=TRUE*/)
  3990. {
  3991. ASSERT(nRow >= 0 && nRow < m_nRows);
  3992. if (nRow < 0 || nRow >= m_nRows)
  3993. return FALSE;
  3994. // Skip hidden rows when autosizing
  3995. if (GetRowHeight(nRow) <= 0)
  3996. return FALSE;
  3997. CSize size;
  3998. CDC* pDC = GetDC();
  3999. if (!pDC)
  4000. return FALSE;
  4001. int nHeight = 0;
  4002. int nNumColumns = GetColumnCount();
  4003. if (GetVirtualMode())
  4004. SendCacheHintToParent(CCellRange(nRow, 0, nRow, nNumColumns));
  4005. for (int nCol = 0; nCol < nNumColumns; nCol++)
  4006. {
  4007. CGridCellBase* pCell = GetCell(nRow, nCol);
  4008. if (pCell)
  4009. size = pCell->GetCellExtent(pDC);
  4010. if (size.cy > nHeight)
  4011. nHeight = size.cy;
  4012. }
  4013. m_arRowHeights[nRow] = nHeight;
  4014. if (GetVirtualMode())
  4015. SendCacheHintToParent(CCellRange(-1, -1, -1, -1));
  4016. ReleaseDC(pDC);
  4017. if (bResetScroll)
  4018. ResetScrollBars();
  4019. return TRUE;
  4020. }
  4021. void CGridCtrl::AutoSizeColumns(UINT nAutoSizeStyle /*=GVS_DEFAULT*/)
  4022. {
  4023. int nNumColumns = GetColumnCount();
  4024. for (int nCol = 0; nCol < nNumColumns; nCol++)
  4025. {
  4026. // Skip hidden columns when autosizing
  4027. if (GetColumnWidth(nCol) > 0)
  4028. AutoSizeColumn(nCol, nAutoSizeStyle, FALSE);
  4029. }
  4030. ResetScrollBars();
  4031. }
  4032. void CGridCtrl::AutoSizeRows()
  4033. {
  4034. int nNumRows = GetRowCount();
  4035. for (int nRow = 0; nRow < nNumRows; nRow++)
  4036. {
  4037. // Skip hidden rows when autosizing
  4038. if (GetRowHeight(nRow) > 0)
  4039. AutoSizeRow(nRow, FALSE);
  4040. }
  4041. ResetScrollBars();
  4042. }
  4043. // sizes all rows and columns
  4044. // faster than calling both AutoSizeColumns() and AutoSizeRows()
  4045. void CGridCtrl::AutoSize(UINT nAutoSizeStyle /*=GVS_DEFAULT*/)
  4046. {
  4047. CDC* pDC = GetDC();
  4048. if (!pDC)
  4049. return;
  4050. int nNumColumns = GetColumnCount();
  4051. int nCol, nRow;
  4052. ASSERT(GVS_DEFAULT <= nAutoSizeStyle && nAutoSizeStyle <= GVS_BOTH);
  4053. if (nAutoSizeStyle == GVS_DEFAULT)
  4054. nAutoSizeStyle = GetAutoSizeStyle();
  4055. int nStartRow = (nAutoSizeStyle & GVS_HEADER) ? 0 : GetFixedRowCount();
  4056. int nEndRow = (nAutoSizeStyle & GVS_DATA) ? GetRowCount() - 1 : GetFixedRowCount() - 1;
  4057. if (GetVirtualMode())
  4058. SendCacheHintToParent(CCellRange(nStartRow, 0, nEndRow, nNumColumns));
  4059. // Row initialisation - only work on rows whose height is > 0
  4060. for (nRow = nStartRow; nRow <= nEndRow; nRow++)
  4061. {
  4062. if (GetRowHeight(nRow) > 0)
  4063. m_arRowHeights[nRow] = 1;
  4064. }
  4065. CSize size;
  4066. for (nCol = 0; nCol < nNumColumns; nCol++)
  4067. {
  4068. // Don't size hidden columns or rows
  4069. if (GetColumnWidth(nCol) > 0)
  4070. {
  4071. // Skip columns that are hidden, but now initialize
  4072. m_arColWidths[nCol] = 0;
  4073. for (nRow = nStartRow; nRow <= nEndRow; nRow++)
  4074. {
  4075. if (GetRowHeight(nRow) > 0)
  4076. {
  4077. CGridCellBase* pCell = GetCell(nRow, nCol);
  4078. if (pCell)
  4079. size = pCell->GetCellExtent(pDC);
  4080. if (size.cx > (int)m_arColWidths[nCol])
  4081. m_arColWidths[nCol] = size.cx;
  4082. if (size.cy > (int)m_arRowHeights[nRow])
  4083. m_arRowHeights[nRow] = size.cy;
  4084. }
  4085. }
  4086. }
  4087. }
  4088. if (GetVirtualMode())
  4089. SendCacheHintToParent(CCellRange(-1, -1, -1, -1));
  4090. ReleaseDC(pDC);
  4091. ResetScrollBars();
  4092. Refresh();
  4093. }
  4094. // Expands the columns to fit the screen space. If bExpandFixed is FALSE then fixed
  4095. // columns will not be affected
  4096. void CGridCtrl::ExpandColumnsToFit(BOOL bExpandFixed /*=TRUE*/)
  4097. {
  4098. if (bExpandFixed)
  4099. {
  4100. if (GetColumnCount() <= 0) return;
  4101. }
  4102. else
  4103. {
  4104. if (GetColumnCount() <= GetFixedColumnCount()) return;
  4105. }
  4106. EnableScrollBars(SB_HORZ, FALSE);
  4107. CRect rect;
  4108. GetClientRect(rect);
  4109. int nFirstColumn = (bExpandFixed) ? 0 : GetFixedColumnCount();
  4110. int col = 0;
  4111. int nNumColumnsAffected = 0;
  4112. for (col = nFirstColumn; col < GetColumnCount(); col++)
  4113. {
  4114. if (m_arColWidths[col] > 0)
  4115. nNumColumnsAffected++;
  4116. }
  4117. if (nNumColumnsAffected <= 0)
  4118. return;
  4119. long virtualWidth = GetVirtualWidth();
  4120. int nDifference = rect.Width() - (int)virtualWidth;
  4121. int nColumnAdjustment = nDifference / nNumColumnsAffected;
  4122. for (col = nFirstColumn; col < GetColumnCount(); col++)
  4123. {
  4124. if (m_arColWidths[col] > 0)
  4125. m_arColWidths[col] += nColumnAdjustment;
  4126. }
  4127. if (nDifference > 0)
  4128. {
  4129. int leftOver = nDifference % nNumColumnsAffected;
  4130. for (int nCount = 0, col = nFirstColumn;
  4131. (col < GetColumnCount()) && (nCount < leftOver); col++, nCount++)
  4132. {
  4133. if (m_arColWidths[col] > 0)
  4134. m_arColWidths[col] += 1;
  4135. }
  4136. }
  4137. else
  4138. {
  4139. int leftOver = (-nDifference) % nNumColumnsAffected;
  4140. for (int nCount = 0, col = nFirstColumn;
  4141. (col < GetColumnCount()) && (nCount < leftOver); col++, nCount++)
  4142. {
  4143. if (m_arColWidths[col] > 0)
  4144. m_arColWidths[col] -= 1;
  4145. }
  4146. }
  4147. Refresh();
  4148. ResetScrollBars();
  4149. }
  4150. void CGridCtrl::ExpandLastColumn()
  4151. {
  4152. if (GetColumnCount() <= 0)
  4153. return;
  4154. // Search for last non-hidden column
  4155. int nLastColumn = GetColumnCount() - 1;
  4156. while (m_arColWidths[nLastColumn] <= 0)
  4157. nLastColumn--;
  4158. if (nLastColumn <= 0)
  4159. return;
  4160. EnableScrollBars(SB_HORZ, FALSE);
  4161. CRect rect;
  4162. GetClientRect(rect);
  4163. long virtualWidth = GetVirtualWidth();
  4164. int nDifference = rect.Width() - (int)virtualWidth;
  4165. if (nDifference > 0)
  4166. {
  4167. //if (GetVirtualHeight() > rect.Height())
  4168. // nDifference -= GetSystemMetrics(SM_CXVSCROLL);
  4169. m_arColWidths[nLastColumn] += nDifference;
  4170. Refresh();
  4171. }
  4172. ResetScrollBars();
  4173. }
  4174. // Expands the rows to fit the screen space. If bExpandFixed is FALSE then fixed
  4175. // rows will not be affected
  4176. void CGridCtrl::ExpandRowsToFit(BOOL bExpandFixed /*=TRUE*/)
  4177. {
  4178. if (bExpandFixed)
  4179. {
  4180. if (GetRowCount() <= 0) return;
  4181. }
  4182. else
  4183. {
  4184. if (GetRowCount() <= GetFixedRowCount()) return;
  4185. }
  4186. EnableScrollBars(SB_VERT, FALSE);
  4187. CRect rect;
  4188. GetClientRect(rect);
  4189. int nFirstRow = (bExpandFixed) ? 0 : GetFixedRowCount();
  4190. int row = 0;
  4191. int nNumRowsAffected = 0;
  4192. for (row = nFirstRow; row < GetRowCount(); row++)
  4193. {
  4194. if (m_arRowHeights[row] > 0)
  4195. nNumRowsAffected++;
  4196. }
  4197. if (nNumRowsAffected <= 0)
  4198. return;
  4199. long virtualHeight = GetVirtualHeight();
  4200. int nDifference = rect.Height() - (int)virtualHeight;
  4201. int nRowAdjustment = nDifference / nNumRowsAffected;
  4202. for (row = nFirstRow; row < GetRowCount(); row++)
  4203. {
  4204. if (m_arRowHeights[row] > 0)
  4205. m_arRowHeights[row] += nRowAdjustment;
  4206. }
  4207. if (nDifference > 0)
  4208. {
  4209. int leftOver = nDifference % nNumRowsAffected;
  4210. for (int nCount = 0, row = nFirstRow;
  4211. (row < GetRowCount()) && (nCount < leftOver); row++, nCount++)
  4212. {
  4213. if (m_arRowHeights[row] > 0)
  4214. m_arRowHeights[row] += 1;
  4215. }
  4216. }
  4217. else
  4218. {
  4219. int leftOver = (-nDifference) % nNumRowsAffected;
  4220. for (int nCount = 0, row = nFirstRow;
  4221. (row < GetRowCount()) && (nCount < leftOver); row++, nCount++)
  4222. {
  4223. if (m_arRowHeights[row] > 0)
  4224. m_arRowHeights[row] -= 1;
  4225. }
  4226. }
  4227. Refresh();
  4228. ResetScrollBars();
  4229. }
  4230. // Expands the cells to fit the screen space. If bExpandFixed is FALSE then fixed
  4231. // cells will not be affected
  4232. void CGridCtrl::ExpandToFit(BOOL bExpandFixed /*=TRUE*/)
  4233. {
  4234. ExpandColumnsToFit(bExpandFixed); // This will remove any existing horz scrollbar
  4235. ExpandRowsToFit(bExpandFixed); // This will remove any existing vert scrollbar
  4236. ExpandColumnsToFit(bExpandFixed); // Just in case the first adjustment was with a vert
  4237. // scrollbar in place
  4238. Refresh();
  4239. }
  4240. /////////////////////////////////////////////////////////////////////////////////////
  4241. // Attributes
  4242. void CGridCtrl::SetVirtualMode(BOOL bVirtual)
  4243. {
  4244. DeleteAllItems();
  4245. m_bVirtualMode = bVirtual;
  4246. // Force some defaults here.
  4247. if (m_bVirtualMode)
  4248. {
  4249. SetEditable(FALSE);
  4250. SetHeaderSort(FALSE);
  4251. SetAutoSizeStyle(GVS_HEADER);
  4252. SetFixedColumnSelection(FALSE);
  4253. SetFixedRowSelection(FALSE);
  4254. }
  4255. }
  4256. void CGridCtrl::SetGridLines(int nWhichLines /*=GVL_BOTH*/)
  4257. {
  4258. m_nGridLines = nWhichLines;
  4259. Refresh();
  4260. }
  4261. void CGridCtrl::SetListMode(BOOL bEnableListMode /*=TRUE*/)
  4262. {
  4263. ResetSelectedRange();
  4264. SetSortColumn(-1);
  4265. m_bListMode = bEnableListMode;
  4266. SetFixedRowSelection(FALSE);
  4267. Refresh();
  4268. }
  4269. void CGridCtrl::SetSortColumn(int nCol)
  4270. {
  4271. if (m_nSortColumn >= 0)
  4272. InvalidateCellRect(0, m_nSortColumn);
  4273. m_nSortColumn = nCol;
  4274. if (nCol >= 0)
  4275. InvalidateCellRect(0, nCol);
  4276. }
  4277. BOOL CGridCtrl::IsCellFixed(int nRow, int nCol)
  4278. {
  4279. return (nRow < GetFixedRowCount() || nCol < GetFixedColumnCount());
  4280. }
  4281. void CGridCtrl::SetModified(BOOL bModified /*=TRUE*/, int nRow /*=-1*/, int nCol /*=-1*/)
  4282. {
  4283. // Cannot guarantee sorting anymore...
  4284. if (nCol < 0 || nCol == GetSortColumn())
  4285. SetSortColumn(-1);
  4286. if (nRow >= 0 && nCol >= 0)
  4287. {
  4288. if (bModified)
  4289. {
  4290. SetItemState(nRow, nCol, GetItemState(nRow, nCol) | GVIS_MODIFIED);
  4291. m_bModified = TRUE;
  4292. }
  4293. else
  4294. SetItemState(nRow, nCol, GetItemState(nRow, nCol) & ~GVIS_MODIFIED);
  4295. }
  4296. else
  4297. m_bModified = bModified;
  4298. if (!m_bModified)
  4299. {
  4300. for (int row = 0; row < GetRowCount(); row++)
  4301. for (int col = 0; col < GetColumnCount(); col++)
  4302. SetItemState(row, col, GetItemState(row, col) & ~GVIS_MODIFIED);
  4303. }
  4304. }
  4305. BOOL CGridCtrl::GetModified(int nRow /*=-1*/, int nCol /*=-1*/)
  4306. {
  4307. if (nRow >= 0 && nCol >= 0)
  4308. return ((GetItemState(nRow, nCol) & GVIS_MODIFIED) == GVIS_MODIFIED);
  4309. else
  4310. return m_bModified;
  4311. }
  4312. /////////////////////////////////////////////////////////////////////////////////////
  4313. // GridCtrl cell visibility tests and invalidation/redraw functions
  4314. void CGridCtrl::Refresh()
  4315. {
  4316. if (GetSafeHwnd() && m_bAllowDraw)
  4317. Invalidate();
  4318. }
  4319. // EnsureVisible supplied by Roelf Werkman
  4320. void CGridCtrl::EnsureVisible(int nRow, int nCol)
  4321. {
  4322. if (!m_bAllowDraw)
  4323. return;
  4324. CRect rectWindow;
  4325. /*
  4326. // set the scroll to the approximate position of row (Nigel Page-Jones)
  4327. int nPos = (int)((float)nRow / GetRowCount() * 1000);
  4328. float fPos = (float)nPos / 1000;
  4329. SCROLLINFO scrollInfo;
  4330. GetScrollInfo(SB_VERT, &scrollInfo);
  4331. scrollInfo.nPos = (int)(scrollInfo.nMax * fPos);
  4332. SetScrollInfo(SB_VERT, &scrollInfo, FALSE);
  4333. GetClientRect(rectWindow);
  4334. // redraw cells if necessary (Nigel Page-Jones)
  4335. CCellID idTopLeft = GetTopleftNonFixedCell(FALSE);
  4336. CCellID idNewTopLeft = GetTopleftNonFixedCell(TRUE);
  4337. if (idNewTopLeft != idTopLeft)
  4338. {
  4339. rectWindow.top = GetFixedRowHeight();
  4340. InvalidateRect(rectWindow);
  4341. }
  4342. */
  4343. // We are gonna send some scroll messages, which will steal the focus
  4344. // from it's rightful owner. Squirrel it away ourselves so we can give
  4345. // it back. (Damir)
  4346. CWnd* pFocusWnd = GetFocus();
  4347. CCellRange VisibleCells = GetVisibleNonFixedCellRange();
  4348. int right = nCol - VisibleCells.GetMaxCol();
  4349. int left = VisibleCells.GetMinCol() - nCol;
  4350. int down = nRow - VisibleCells.GetMaxRow();
  4351. int up = VisibleCells.GetMinRow() - nRow;
  4352. int iColumnStart;
  4353. int iRowStart;
  4354. iColumnStart = VisibleCells.GetMaxCol() + 1;
  4355. while (right > 0)
  4356. {
  4357. if (GetColumnWidth(iColumnStart) > 0)
  4358. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  4359. right--;
  4360. iColumnStart++;
  4361. }
  4362. iColumnStart = VisibleCells.GetMinCol() - 1;
  4363. while (left > 0)
  4364. {
  4365. if (GetColumnWidth(iColumnStart) > 0)
  4366. SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  4367. left--;
  4368. iColumnStart--;
  4369. }
  4370. iRowStart = VisibleCells.GetMaxRow() + 1;
  4371. while (down > 0)
  4372. {
  4373. if (GetRowHeight(iRowStart) > 0)
  4374. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  4375. down--;
  4376. iRowStart++;
  4377. }
  4378. iRowStart = VisibleCells.GetMinRow() - 1;
  4379. while (up > 0)
  4380. {
  4381. if (GetRowHeight(iRowStart) > 0)
  4382. SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  4383. up--;
  4384. iRowStart--;
  4385. }
  4386. // Move one more if we only see a snall bit of the cell
  4387. CRect rectCell;
  4388. if (!GetCellRect(nRow, nCol, rectCell))
  4389. {
  4390. pFocusWnd->SetFocus();
  4391. return;
  4392. }
  4393. GetClientRect(rectWindow);
  4394. // The previous fix was fixed properly by Martin Richter <martin.richter@grutzeck.de>
  4395. while (rectCell.right > rectWindow.right
  4396. && rectCell.left > GetFixedColumnWidth())
  4397. {
  4398. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  4399. if (!GetCellRect(nRow, nCol, rectCell))
  4400. {
  4401. pFocusWnd->SetFocus();
  4402. return;
  4403. }
  4404. }
  4405. while (rectCell.bottom > rectWindow.bottom
  4406. && rectCell.top > GetFixedRowHeight())
  4407. {
  4408. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  4409. if (!GetCellRect(nRow, nCol, rectCell))
  4410. {
  4411. pFocusWnd->SetFocus();
  4412. return;
  4413. }
  4414. }
  4415. // restore focus to whoever owned it
  4416. pFocusWnd->SetFocus();
  4417. }
  4418. BOOL CGridCtrl::IsCellEditable(CCellID &cell) const
  4419. {
  4420. return IsCellEditable(cell.row, cell.col);
  4421. }
  4422. BOOL CGridCtrl::IsCellEditable(int nRow, int nCol) const
  4423. {
  4424. return IsEditable() && ((GetItemState(nRow, nCol) & GVIS_READONLY) != GVIS_READONLY);
  4425. }
  4426. BOOL CGridCtrl::IsCellSelected(CCellID &cell) const
  4427. {
  4428. return IsCellSelected(cell.row, cell.col);
  4429. }
  4430. BOOL CGridCtrl::IsCellSelected(int nRow, int nCol) const
  4431. {
  4432. if (GetVirtualMode())
  4433. {
  4434. if (!IsSelectable())
  4435. return FALSE;
  4436. CCellID cell;
  4437. DWORD key = MAKELONG(nRow, nCol);
  4438. return (m_SelectedCellMap.Lookup(key, (CCellID&)cell));
  4439. }
  4440. else
  4441. return IsSelectable() && ((GetItemState(nRow, nCol) & GVIS_SELECTED) == GVIS_SELECTED);
  4442. }
  4443. BOOL CGridCtrl::IsCellVisible(CCellID cell)
  4444. {
  4445. return IsCellVisible(cell.row, cell.col);
  4446. }
  4447. BOOL CGridCtrl::IsCellVisible(int nRow, int nCol)
  4448. {
  4449. if (!IsWindow(m_hWnd))
  4450. return FALSE;
  4451. int x, y;
  4452. CCellID TopLeft;
  4453. if (nCol >= GetFixedColumnCount() || nRow >= GetFixedRowCount())
  4454. {
  4455. TopLeft = GetTopleftNonFixedCell();
  4456. if (nCol >= GetFixedColumnCount() && nCol < TopLeft.col)
  4457. return FALSE;
  4458. if (nRow >= GetFixedRowCount() && nRow < TopLeft.row)
  4459. return FALSE;
  4460. }
  4461. CRect rect;
  4462. GetClientRect(rect);
  4463. if (nCol < GetFixedColumnCount())
  4464. {
  4465. x = 0;
  4466. for (int i = 0; i <= nCol; i++)
  4467. {
  4468. if (x >= rect.right)
  4469. return FALSE;
  4470. x += GetColumnWidth(i);
  4471. }
  4472. }
  4473. else
  4474. {
  4475. x = GetFixedColumnWidth();
  4476. for (int i = TopLeft.col; i <= nCol; i++)
  4477. {
  4478. if (x >= rect.right)
  4479. return FALSE;
  4480. x += GetColumnWidth(i);
  4481. }
  4482. }
  4483. if (nRow < GetFixedRowCount())
  4484. {
  4485. y = 0;
  4486. for (int i = 0; i <= nRow; i++)
  4487. {
  4488. if (y >= rect.bottom)
  4489. return FALSE;
  4490. y += GetRowHeight(i);
  4491. }
  4492. }
  4493. else
  4494. {
  4495. if (nRow < TopLeft.row)
  4496. return FALSE;
  4497. y = GetFixedRowHeight();
  4498. for (int i = TopLeft.row; i <= nRow; i++)
  4499. {
  4500. if (y >= rect.bottom)
  4501. return FALSE;
  4502. y += GetRowHeight(i);
  4503. }
  4504. }
  4505. return TRUE;
  4506. }
  4507. BOOL CGridCtrl::InvalidateCellRect(const CCellID& cell)
  4508. {
  4509. return InvalidateCellRect(cell.row, cell.col);
  4510. }
  4511. BOOL CGridCtrl::InvalidateCellRect(const int row, const int col)
  4512. {
  4513. if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw)
  4514. return FALSE;
  4515. if (!IsValid(row, col))
  4516. return FALSE;
  4517. if (!IsCellVisible(row, col))
  4518. return FALSE;
  4519. CRect rect;
  4520. if (!GetCellRect(row, col, rect))
  4521. return FALSE;
  4522. rect.right++;
  4523. rect.bottom++;
  4524. InvalidateRect(rect, TRUE);
  4525. return TRUE;
  4526. }
  4527. BOOL CGridCtrl::InvalidateCellRect(const CCellRange& cellRange)
  4528. {
  4529. ASSERT(IsValid(cellRange));
  4530. if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw)
  4531. return FALSE;
  4532. CCellRange visibleCellRange = GetVisibleNonFixedCellRange().Intersect(cellRange);
  4533. CRect rect;
  4534. if (!GetCellRangeRect(visibleCellRange, rect))
  4535. return FALSE;
  4536. rect.right++;
  4537. rect.bottom++;
  4538. InvalidateRect(rect, TRUE);
  4539. return TRUE;
  4540. }
  4541. /////////////////////////////////////////////////////////////////////////////
  4542. // CGridCtrl Mouse stuff
  4543. // Handles mouse wheel notifications
  4544. // Note - if this doesn't work for win95 then use OnRegisteredMouseWheel instead
  4545. #if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
  4546. BOOL CGridCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
  4547. {
  4548. // A m_nRowsPerWheelNotch value less than 0 indicates that the mouse
  4549. // wheel scrolls whole pages, not just lines.
  4550. if (m_nRowsPerWheelNotch == -1)
  4551. {
  4552. int nPagesScrolled = zDelta / 120;
  4553. if (nPagesScrolled > 0)
  4554. for (int i = 0; i < nPagesScrolled; i++)
  4555. PostMessage(WM_VSCROLL, SB_PAGEUP, 0);
  4556. else
  4557. for (int i = 0; i > nPagesScrolled; i--)
  4558. PostMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
  4559. }
  4560. else
  4561. {
  4562. int nRowsScrolled = m_nRowsPerWheelNotch * zDelta / 120;
  4563. if (nRowsScrolled > 0)
  4564. for (int i = 0; i < nRowsScrolled; i++)
  4565. PostMessage(WM_VSCROLL, SB_LINEUP, 0);
  4566. else
  4567. for (int i = 0; i > nRowsScrolled; i--)
  4568. PostMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  4569. }
  4570. return CWnd::OnMouseWheel(nFlags, zDelta, pt);
  4571. }
  4572. #endif // !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
  4573. void CGridCtrl::OnMouseMove(UINT /*nFlags*/, CPoint point)
  4574. {
  4575. CRect rect;
  4576. GetClientRect(rect);
  4577. #ifndef GRIDCONTROL_NO_DRAGDROP
  4578. // If outside client area, return (unless we are drag n dropping)
  4579. if (m_MouseMode != MOUSE_DRAGGING && !rect.PtInRect(point))
  4580. return;
  4581. #endif
  4582. // Sometimes a MOUSEMOVE message can come after the left buttons
  4583. // has been let go, but before the BUTTONUP message hs been processed.
  4584. // We'll keep track of mouse buttons manually to avoid this.
  4585. // All bMouseButtonDown's have been replaced with the member m_bLMouseButtonDown
  4586. // BOOL bMouseButtonDown = ((nFlags & MK_LBUTTON) == MK_LBUTTON);
  4587. // If the left mouse button is up, then test to see if row/column sizing is imminent
  4588. if (!m_bLMouseButtonDown ||
  4589. (m_bLMouseButtonDown && m_MouseMode == MOUSE_NOTHING))
  4590. {
  4591. if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
  4592. {
  4593. if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
  4594. {
  4595. #ifndef _WIN32_WCE_NO_CURSOR
  4596. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  4597. #endif
  4598. m_MouseMode = MOUSE_OVER_COL_DIVIDE;
  4599. }
  4600. }
  4601. else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
  4602. {
  4603. if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
  4604. {
  4605. #ifndef _WIN32_WCE_NO_CURSOR
  4606. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
  4607. #endif
  4608. m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
  4609. }
  4610. }
  4611. else if (m_MouseMode != MOUSE_NOTHING)
  4612. {
  4613. #ifndef _WIN32_WCE_NO_CURSOR
  4614. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  4615. #endif
  4616. m_MouseMode = MOUSE_NOTHING;
  4617. }
  4618. if (m_MouseMode == MOUSE_NOTHING)
  4619. {
  4620. CGridCellBase* pCell = NULL;
  4621. CCellID idCurrentCell;
  4622. if (!GetVirtualMode() || m_bTitleTips)
  4623. {
  4624. // Let the cell know that a big fat cursor is currently hovering
  4625. // over it.
  4626. idCurrentCell = GetCellFromPt(point);
  4627. pCell = GetCell(idCurrentCell.row, idCurrentCell.col);
  4628. if (pCell)
  4629. pCell->OnMouseOver();
  4630. }
  4631. #ifndef GRIDCONTROL_NO_TITLETIPS
  4632. // Titletips anyone? anyone?
  4633. if (m_bTitleTips)
  4634. {
  4635. CRect TextRect, CellRect;
  4636. if (pCell)
  4637. {
  4638. LPCTSTR szTipText = pCell->GetTipText();
  4639. if (!m_bRMouseButtonDown
  4640. && szTipText && szTipText[0]
  4641. && !pCell->IsEditing()
  4642. && GetCellRect(idCurrentCell.row, idCurrentCell.col, &TextRect)
  4643. && pCell->GetTipTextRect(&TextRect)
  4644. && GetCellRect(idCurrentCell.row, idCurrentCell.col, CellRect))
  4645. {
  4646. //TRACE0("Showing TitleTip\n");
  4647. m_TitleTip.Show(TextRect, pCell->GetTipText(), 0, CellRect,
  4648. pCell->GetFont(), GetTitleTipTextClr(), GetTitleTipBackClr());
  4649. }
  4650. }
  4651. }
  4652. #endif
  4653. }
  4654. m_LastMousePoint = point;
  4655. return;
  4656. }
  4657. if (!IsValid(m_LeftClickDownCell))
  4658. {
  4659. m_LastMousePoint = point;
  4660. return;
  4661. }
  4662. // If the left mouse button is down, then process appropriately
  4663. if (m_bLMouseButtonDown)
  4664. {
  4665. switch (m_MouseMode)
  4666. {
  4667. case MOUSE_SELECT_ALL:
  4668. break;
  4669. case MOUSE_SELECT_COL:
  4670. case MOUSE_SELECT_ROW:
  4671. case MOUSE_SELECT_CELLS:
  4672. {
  4673. CCellID idCurrentCell = GetCellFromPt(point);
  4674. if (!IsValid(idCurrentCell))
  4675. return;
  4676. if (idCurrentCell != GetFocusCell())
  4677. {
  4678. OnSelecting(idCurrentCell);
  4679. // EFW - BUG FIX - Keep the appropriate cell row and/or
  4680. // column focused. A fix in SetFocusCell() will place
  4681. // the cursor in a non-fixed cell as needed.
  4682. if ((idCurrentCell.row >= m_nFixedRows &&
  4683. idCurrentCell.col >= m_nFixedCols) ||
  4684. m_MouseMode == MOUSE_SELECT_COL ||
  4685. m_MouseMode == MOUSE_SELECT_ROW)
  4686. {
  4687. SetFocusCell(idCurrentCell);
  4688. }
  4689. }
  4690. break;
  4691. }
  4692. case MOUSE_SIZING_COL:
  4693. {
  4694. CDC* pDC = GetDC();
  4695. if (!pDC)
  4696. break;
  4697. CRect oldInvertedRect(m_LastMousePoint.x, rect.top,
  4698. m_LastMousePoint.x + 2, rect.bottom);
  4699. pDC->InvertRect(&oldInvertedRect);
  4700. CRect newInvertedRect(point.x, rect.top,
  4701. point.x + 2, rect.bottom);
  4702. pDC->InvertRect(&newInvertedRect);
  4703. ReleaseDC(pDC);
  4704. }
  4705. break;
  4706. case MOUSE_SIZING_ROW:
  4707. {
  4708. CDC* pDC = GetDC();
  4709. if (!pDC)
  4710. break;
  4711. CRect oldInvertedRect(rect.left, m_LastMousePoint.y,
  4712. rect.right, m_LastMousePoint.y + 2);
  4713. pDC->InvertRect(&oldInvertedRect);
  4714. CRect newInvertedRect(rect.left, point.y,
  4715. rect.right, point.y + 2);
  4716. pDC->InvertRect(&newInvertedRect);
  4717. ReleaseDC(pDC);
  4718. }
  4719. break;
  4720. #ifndef GRIDCONTROL_NO_DRAGDROP
  4721. case MOUSE_PREPARE_EDIT:
  4722. case MOUSE_PREPARE_DRAG:
  4723. m_MouseMode = MOUSE_PREPARE_DRAG;
  4724. OnBeginDrag();
  4725. break;
  4726. #endif
  4727. }
  4728. }
  4729. m_LastMousePoint = point;
  4730. }
  4731. // Returns the point inside the cell that was clicked (coords relative to cell top left)
  4732. CPoint CGridCtrl::GetPointClicked(int nRow, int nCol, const CPoint& point)
  4733. {
  4734. CPoint PointCellOrigin;
  4735. if (!GetCellOrigin(nRow, nCol, &PointCellOrigin))
  4736. return CPoint(0, 0);
  4737. CPoint PointClickedCellRelative(point);
  4738. PointClickedCellRelative -= PointCellOrigin;
  4739. return PointClickedCellRelative;
  4740. }
  4741. void CGridCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
  4742. {
  4743. //TRACE0("CGridCtrl::OnLButtonDblClk\n");
  4744. CCellID cell = GetCellFromPt(point);
  4745. if (!IsValid(cell))
  4746. {
  4747. //ASSERT(FALSE);
  4748. return;
  4749. }
  4750. #ifdef _WIN32_WCE
  4751. if (MouseOverColumnResizeArea(point))
  4752. #else
  4753. if (m_MouseMode == MOUSE_OVER_COL_DIVIDE)
  4754. #endif
  4755. {
  4756. CPoint start;
  4757. if (!GetCellOrigin(0, cell.col, &start))
  4758. return;
  4759. if (point.x - start.x < m_nResizeCaptureRange) // Clicked right of border
  4760. cell.col--;
  4761. // ignore columns that are hidden and look left towards first visible column
  4762. BOOL bFoundVisible = FALSE;
  4763. while (cell.col >= 0)
  4764. {
  4765. if (GetColumnWidth(cell.col) > 0)
  4766. {
  4767. bFoundVisible = TRUE;
  4768. break;
  4769. }
  4770. cell.col--;
  4771. }
  4772. if (!bFoundVisible)
  4773. return;
  4774. AutoSizeColumn(cell.col, GetAutoSizeStyle());
  4775. Invalidate();
  4776. }
  4777. #ifdef _WIN32_WCE
  4778. else if (MouseOverRowResizeArea(point))
  4779. #else
  4780. else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE)
  4781. #endif
  4782. {
  4783. CPoint start;
  4784. if (!GetCellOrigin(0, cell.col, &start))
  4785. return;
  4786. if (point.y - start.y < m_nResizeCaptureRange) // Clicked below border
  4787. cell.row--;
  4788. // ignore rows that are hidden and look up towards first visible row
  4789. BOOL bFoundVisible = FALSE;
  4790. while (cell.row >= 0)
  4791. {
  4792. if (GetRowHeight(cell.row) > 0)
  4793. {
  4794. bFoundVisible = TRUE;
  4795. break;
  4796. }
  4797. cell.row--;
  4798. }
  4799. if (!bFoundVisible)
  4800. return;
  4801. AutoSizeRow(cell.row);
  4802. Invalidate();
  4803. }
  4804. else if (m_MouseMode == MOUSE_NOTHING)
  4805. {
  4806. CPoint pointClickedRel;
  4807. pointClickedRel = GetPointClicked(cell.row, cell.col, point);
  4808. CGridCellBase* pCell = NULL;
  4809. if (IsValid(cell))
  4810. pCell = GetCell(cell.row, cell.col);
  4811. // Clicked in the text area? Only then will cell selection work
  4812. BOOL bInTextArea = FALSE;
  4813. if (pCell)
  4814. {
  4815. CRect rectCell;
  4816. if (GetCellRect(cell.row, cell.col, rectCell) && pCell->GetTextRect(rectCell))
  4817. bInTextArea = rectCell.PtInRect(point);
  4818. }
  4819. if (cell.row >= m_nFixedRows && IsValid(m_LeftClickDownCell) &&
  4820. cell.col >= m_nFixedCols && bInTextArea)
  4821. {
  4822. OnEditCell(cell.row, cell.col, pointClickedRel, VK_LBUTTON);
  4823. }
  4824. else if (m_bListMode)
  4825. {
  4826. if (!IsValid(cell))
  4827. return;
  4828. if (cell.row >= m_nFixedRows && cell.col >= m_nFixedCols && bInTextArea)
  4829. OnEditCell(cell.row, cell.col, pointClickedRel, VK_LBUTTON);
  4830. }
  4831. if (IsValid(cell))
  4832. {
  4833. CGridCellBase* pCell = GetCell(cell.row, cell.col);
  4834. if (pCell)
  4835. pCell->OnDblClick(pointClickedRel);
  4836. SendMessageToParent(cell.row, cell.col, NM_DBLCLK);
  4837. }
  4838. }
  4839. CWnd::OnLButtonDblClk(nFlags, point);
  4840. }
  4841. void CGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
  4842. {
  4843. #ifdef GRIDCONTROL_USE_TITLETIPS
  4844. // EFW - Bug Fix
  4845. m_TitleTip.Hide(); // hide any titletips
  4846. #endif
  4847. // TRACE0("CGridCtrl::OnLButtonDown\n");
  4848. // CWnd::OnLButtonDown(nFlags, point);
  4849. SetFocus();
  4850. m_bLMouseButtonDown = TRUE;
  4851. m_LeftClickDownPoint = point;
  4852. m_LeftClickDownCell = GetCellFromPt(point);
  4853. if (!IsValid(m_LeftClickDownCell))
  4854. return;
  4855. // If the SHIFT key is not down, then the start of the selection area should be the
  4856. // cell just clicked. Otherwise, keep the previous selection-start-cell so the user
  4857. // can add to their previous cell selections in an intuitive way. If no selection-
  4858. // start-cell has been specified, then set it's value here and now.
  4859. if ((nFlags & MK_SHIFT) != MK_SHIFT)
  4860. m_SelectionStartCell = m_LeftClickDownCell;
  4861. else
  4862. {
  4863. if (!IsValid(m_SelectionStartCell))
  4864. m_SelectionStartCell = m_idCurrentCell;
  4865. }
  4866. EndEditing();
  4867. // tell the cell about it
  4868. CGridCellBase* pCell = GetCell(m_LeftClickDownCell.row, m_LeftClickDownCell.col);
  4869. if (pCell)
  4870. pCell->OnClickDown(GetPointClicked(m_LeftClickDownCell.row, m_LeftClickDownCell.col, point));
  4871. // Clicked in the text area? Only then will cell selection work
  4872. BOOL bInTextArea = FALSE;
  4873. if (pCell)
  4874. {
  4875. CRect rectCell;
  4876. if (GetCellRect(m_LeftClickDownCell.row, m_LeftClickDownCell.col, rectCell) &&
  4877. pCell->GetTextRect(rectCell))
  4878. {
  4879. bInTextArea = rectCell.PtInRect(point);
  4880. }
  4881. }
  4882. // If the user clicks on the current cell, then prepare to edit it.
  4883. // (If the user moves the mouse, then dragging occurs)
  4884. if (m_LeftClickDownCell == m_idCurrentCell &&
  4885. !(nFlags & MK_CONTROL) && bInTextArea &&
  4886. IsCellEditable(m_LeftClickDownCell))
  4887. {
  4888. m_MouseMode = MOUSE_PREPARE_EDIT;
  4889. return;
  4890. }
  4891. // If the user clicks on a selected cell, then prepare to drag it.
  4892. // (If the user moves the mouse, then dragging occurs)
  4893. else if (IsCellSelected(m_LeftClickDownCell))
  4894. {
  4895. // If control is pressed then unselect the cell or row (depending on the list mode)
  4896. if (nFlags & MK_CONTROL)
  4897. {
  4898. SetFocusCell(m_LeftClickDownCell);
  4899. if (GetListMode())
  4900. SelectRows(m_LeftClickDownCell, TRUE, FALSE);
  4901. else
  4902. SelectCells(m_LeftClickDownCell, TRUE, FALSE);
  4903. return;
  4904. }
  4905. #ifndef GRIDCONTROL_NO_DRAGDROP
  4906. else if (m_bAllowDragAndDrop)
  4907. m_MouseMode = MOUSE_PREPARE_DRAG;
  4908. #endif
  4909. }
  4910. else if (m_MouseMode != MOUSE_OVER_COL_DIVIDE &&
  4911. m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
  4912. {
  4913. SetFocusCell(-1, -1);
  4914. if (GetRowCount() > GetFixedRowCount() &&
  4915. GetColumnCount() > GetFixedColumnCount())
  4916. SetFocusCell(max(m_LeftClickDownCell.row, m_nFixedRows),
  4917. max(m_LeftClickDownCell.col, m_nFixedCols));
  4918. }
  4919. SetCapture();
  4920. if (m_MouseMode == MOUSE_NOTHING)
  4921. {
  4922. if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
  4923. {
  4924. if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
  4925. {
  4926. #ifndef _WIN32_WCE_NO_CURSOR
  4927. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  4928. #endif
  4929. m_MouseMode = MOUSE_OVER_COL_DIVIDE;
  4930. }
  4931. }
  4932. else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
  4933. {
  4934. if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
  4935. {
  4936. #ifndef _WIN32_WCE_NO_CURSOR
  4937. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
  4938. #endif
  4939. m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
  4940. }
  4941. }
  4942. // else if (m_MouseMode != MOUSE_NOTHING)
  4943. //{
  4944. // SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  4945. // m_MouseMode = MOUSE_NOTHING;
  4946. //}
  4947. }
  4948. if (m_MouseMode == MOUSE_OVER_COL_DIVIDE) // sizing column
  4949. {
  4950. m_MouseMode = MOUSE_SIZING_COL;
  4951. // Kludge for if we are over the last column...
  4952. if (GetColumnWidth(GetColumnCount() - 1) < m_nResizeCaptureRange)
  4953. {
  4954. CRect VisRect;
  4955. GetVisibleNonFixedCellRange(VisRect);
  4956. if (abs(point.x - VisRect.right) < m_nResizeCaptureRange)
  4957. m_LeftClickDownCell.col = GetColumnCount() - 1;
  4958. }
  4959. CPoint start;
  4960. if (!GetCellOrigin(0, m_LeftClickDownCell.col, &start))
  4961. return;
  4962. if (!m_bHiddenColUnhide)
  4963. {
  4964. // ignore columns that are hidden and look left towards first visible column
  4965. BOOL bLookForVisible = TRUE;
  4966. BOOL bIsCellRightBorder = point.x - start.x >= m_nResizeCaptureRange;
  4967. if (bIsCellRightBorder
  4968. && m_LeftClickDownCell.col + 1 >= GetColumnCount())
  4969. {
  4970. // clicked on last column's right border
  4971. // if last column is visible, don't do anything
  4972. if (m_LeftClickDownCell.col >= 0)
  4973. bLookForVisible = FALSE;
  4974. }
  4975. if (bLookForVisible)
  4976. {
  4977. // clicked on column divider other than last right border
  4978. BOOL bFoundVisible = FALSE;
  4979. int iOffset = 1;
  4980. if (bIsCellRightBorder)
  4981. iOffset = 0;
  4982. while (m_LeftClickDownCell.col - iOffset >= 0)
  4983. {
  4984. if (GetColumnWidth(m_LeftClickDownCell.col - iOffset) > 0)
  4985. {
  4986. bFoundVisible = TRUE;
  4987. break;
  4988. }
  4989. m_LeftClickDownCell.col--;
  4990. }
  4991. if (!bFoundVisible)
  4992. return;
  4993. }
  4994. }
  4995. CRect rect;
  4996. GetClientRect(rect);
  4997. CRect invertedRect(point.x, rect.top, point.x + 2, rect.bottom);
  4998. CDC* pDC = GetDC();
  4999. if (pDC)
  5000. {
  5001. pDC->InvertRect(&invertedRect);
  5002. ReleaseDC(pDC);
  5003. }
  5004. // If we clicked to the right of the colimn divide, then reset the click-down cell
  5005. // as the cell to the left of the column divide - UNLESS we clicked on the last column
  5006. // and the last column is teensy (kludge fix)
  5007. if (point.x - start.x < m_nResizeCaptureRange)
  5008. {
  5009. if (m_LeftClickDownCell.col < GetColumnCount() - 1 ||
  5010. GetColumnWidth(GetColumnCount() - 1) >= m_nResizeCaptureRange)
  5011. {
  5012. if (!GetCellOrigin(0, --m_LeftClickDownCell.col, &start))
  5013. return;
  5014. }
  5015. }
  5016. // Allow a cell resize width no greater than that which can be viewed within
  5017. // the grid itself
  5018. int nMaxCellWidth = rect.Width() - GetFixedColumnWidth();
  5019. rect.left = start.x + 1;
  5020. rect.right = rect.left + nMaxCellWidth;
  5021. ClientToScreen(rect);
  5022. #ifndef _WIN32_WCE_NO_CURSOR
  5023. ClipCursor(rect);
  5024. #endif
  5025. }
  5026. else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE) // sizing row
  5027. {
  5028. m_MouseMode = MOUSE_SIZING_ROW;
  5029. // Kludge for if we are over the last column...
  5030. if (GetRowHeight(GetRowCount() - 1) < m_nResizeCaptureRange)
  5031. {
  5032. CRect VisRect;
  5033. GetVisibleNonFixedCellRange(VisRect);
  5034. if (abs(point.y - VisRect.bottom) < m_nResizeCaptureRange)
  5035. m_LeftClickDownCell.row = GetRowCount() - 1;
  5036. }
  5037. CPoint start;
  5038. if (!GetCellOrigin(m_LeftClickDownCell, &start))
  5039. return;
  5040. if (!m_bHiddenRowUnhide)
  5041. {
  5042. // ignore rows that are hidden and look up towards first visible row
  5043. BOOL bLookForVisible = TRUE;
  5044. BOOL bIsCellBottomBorder = point.y - start.y >= m_nResizeCaptureRange;
  5045. if (bIsCellBottomBorder
  5046. && m_LeftClickDownCell.row + 1 >= GetRowCount())
  5047. {
  5048. // clicked on last row's bottom border
  5049. // if last row is visible, don't do anything
  5050. if (m_LeftClickDownCell.row >= 0)
  5051. bLookForVisible = FALSE;
  5052. }
  5053. if (bLookForVisible)
  5054. {
  5055. // clicked on row divider other than last bottom border
  5056. BOOL bFoundVisible = FALSE;
  5057. int iOffset = 1;
  5058. if (bIsCellBottomBorder)
  5059. iOffset = 0;
  5060. while (m_LeftClickDownCell.row - iOffset >= 0)
  5061. {
  5062. if (GetRowHeight(m_LeftClickDownCell.row - iOffset) > 0)
  5063. {
  5064. bFoundVisible = TRUE;
  5065. break;
  5066. }
  5067. m_LeftClickDownCell.row--;
  5068. }
  5069. if (!bFoundVisible)
  5070. return;
  5071. }
  5072. }
  5073. CRect rect;
  5074. GetClientRect(rect);
  5075. CRect invertedRect(rect.left, point.y, rect.right, point.y + 2);
  5076. CDC* pDC = GetDC();
  5077. if (pDC)
  5078. {
  5079. pDC->InvertRect(&invertedRect);
  5080. ReleaseDC(pDC);
  5081. }
  5082. // If we clicked below the row divide, then reset the click-down cell
  5083. // as the cell above the row divide - UNLESS we clicked on the last row
  5084. // and the last row is teensy (kludge fix)
  5085. if (point.y - start.y < m_nResizeCaptureRange) // clicked below border
  5086. {
  5087. if (m_LeftClickDownCell.row < GetRowCount() - 1 ||
  5088. GetRowHeight(GetRowCount() - 1) >= m_nResizeCaptureRange)
  5089. {
  5090. if (!GetCellOrigin(--m_LeftClickDownCell.row, 0, &start))
  5091. return;
  5092. }
  5093. }
  5094. int nMaxCellHeight = rect.Height() - GetFixedRowHeight();
  5095. rect.top = start.y + 1;
  5096. rect.bottom = rect.top + nMaxCellHeight;
  5097. ClientToScreen(rect);
  5098. #ifndef _WIN32_WCE_NO_CURSOR
  5099. ClipCursor(rect);
  5100. #endif
  5101. }
  5102. else
  5103. #ifndef GRIDCONTROL_NO_DRAGDROP
  5104. if (m_MouseMode != MOUSE_PREPARE_DRAG) // not sizing or editing -- selecting
  5105. #endif
  5106. {
  5107. SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
  5108. // If Ctrl pressed, save the current cell selection. This will get added
  5109. // to the new cell selection at the end of the cell selection process
  5110. m_PrevSelectedCellMap.RemoveAll();
  5111. if (nFlags & MK_CONTROL)
  5112. {
  5113. for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL;)
  5114. {
  5115. DWORD key;
  5116. CCellID cell;
  5117. m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  5118. m_PrevSelectedCellMap.SetAt(key, cell);
  5119. }
  5120. }
  5121. if (m_LeftClickDownCell.row < GetFixedRowCount())
  5122. OnFixedRowClick(m_LeftClickDownCell);
  5123. else if (m_LeftClickDownCell.col < GetFixedColumnCount())
  5124. OnFixedColumnClick(m_LeftClickDownCell);
  5125. else
  5126. {
  5127. m_MouseMode = m_bListMode ? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
  5128. OnSelecting(m_LeftClickDownCell);
  5129. m_nTimerID = SetTimer(WM_LBUTTONDOWN, m_nTimerInterval, 0);
  5130. }
  5131. }
  5132. m_LastMousePoint = point;
  5133. }
  5134. void CGridCtrl::OnLButtonUp(UINT nFlags, CPoint point)
  5135. {
  5136. // TRACE0("CGridCtrl::OnLButtonUp\n");
  5137. CWnd::OnLButtonUp(nFlags, point);
  5138. m_bLMouseButtonDown = FALSE;
  5139. #ifndef _WIN32_WCE_NO_CURSOR
  5140. ClipCursor(NULL);
  5141. #endif
  5142. if (GetCapture()->GetSafeHwnd() == GetSafeHwnd())
  5143. {
  5144. ReleaseCapture();
  5145. KillTimer(m_nTimerID);
  5146. m_nTimerID = 0;
  5147. }
  5148. CPoint pointClickedRel;
  5149. pointClickedRel = GetPointClicked(m_idCurrentCell.row, m_idCurrentCell.col, point);
  5150. // m_MouseMode == MOUSE_PREPARE_EDIT only if user clicked down on current cell
  5151. // and then didn't move mouse before clicking up (releasing button)
  5152. if (m_MouseMode == MOUSE_PREPARE_EDIT)
  5153. {
  5154. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, pointClickedRel, VK_LBUTTON);
  5155. }
  5156. #ifndef GRIDCONTROL_NO_DRAGDROP
  5157. // m_MouseMode == MOUSE_PREPARE_DRAG only if user clicked down on a selected cell
  5158. // and then didn't move mouse before clicking up (releasing button)
  5159. else if (m_MouseMode == MOUSE_PREPARE_DRAG)
  5160. {
  5161. CGridCellBase* pCell = GetCell(m_idCurrentCell.row, m_idCurrentCell.col);
  5162. if (pCell)
  5163. pCell->OnClick(GetPointClicked(m_idCurrentCell.row, m_idCurrentCell.col, point));
  5164. SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, NM_CLICK);
  5165. SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
  5166. ResetSelectedRange();
  5167. SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
  5168. }
  5169. #endif
  5170. else if (m_MouseMode == MOUSE_SIZING_COL)
  5171. {
  5172. CRect rect;
  5173. GetClientRect(rect);
  5174. CRect invertedRect(m_LastMousePoint.x, rect.top, m_LastMousePoint.x + 2, rect.bottom);
  5175. CDC* pDC = GetDC();
  5176. if (pDC)
  5177. {
  5178. pDC->InvertRect(&invertedRect);
  5179. ReleaseDC(pDC);
  5180. }
  5181. if (m_LeftClickDownPoint != point && (point.x != 0 || point.y != 0)) // 0 pt fix by email1@bierling.net
  5182. {
  5183. CPoint start;
  5184. if (!GetCellOrigin(m_LeftClickDownCell, &start))
  5185. return;
  5186. int nColumnWidth = max(point.x - start.x, m_bAllowColHide ? 0 : 1);
  5187. SetColumnWidth(m_LeftClickDownCell.col, nColumnWidth);
  5188. ResetScrollBars();
  5189. Invalidate();
  5190. }
  5191. }
  5192. else if (m_MouseMode == MOUSE_SIZING_ROW)
  5193. {
  5194. CRect rect;
  5195. GetClientRect(rect);
  5196. CRect invertedRect(rect.left, m_LastMousePoint.y, rect.right, m_LastMousePoint.y + 2);
  5197. CDC* pDC = GetDC();
  5198. if (pDC)
  5199. {
  5200. pDC->InvertRect(&invertedRect);
  5201. ReleaseDC(pDC);
  5202. }
  5203. if (m_LeftClickDownPoint != point && (point.x != 0 || point.y != 0)) // 0 pt fix by email1@bierling.net
  5204. {
  5205. CPoint start;
  5206. if (!GetCellOrigin(m_LeftClickDownCell, &start))
  5207. return;
  5208. int nRowHeight = max(point.y - start.y, m_bAllowRowHide ? 0 : 1);
  5209. SetRowHeight(m_LeftClickDownCell.row, nRowHeight);
  5210. ResetScrollBars();
  5211. Invalidate();
  5212. }
  5213. }
  5214. else
  5215. {
  5216. SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
  5217. CGridCellBase* pCell = GetCell(m_idCurrentCell.row, m_idCurrentCell.col);
  5218. if (pCell)
  5219. pCell->OnClick(GetPointClicked(m_idCurrentCell.row, m_idCurrentCell.col, point));
  5220. SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, NM_CLICK);
  5221. }
  5222. m_MouseMode = MOUSE_NOTHING;
  5223. #ifndef _WIN32_WCE_NO_CURSOR
  5224. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  5225. #endif
  5226. if (!IsValid(m_LeftClickDownCell))
  5227. return;
  5228. CWnd *pOwner = GetOwner();
  5229. if (pOwner && IsWindow(pOwner->m_hWnd))
  5230. pOwner->PostMessage(WM_COMMAND, MAKELONG(GetDlgCtrlID(), BN_CLICKED),
  5231. (LPARAM)GetSafeHwnd());
  5232. }
  5233. #ifndef _WIN32_WCE
  5234. void CGridCtrl::OnRButtonDown(UINT nFlags, CPoint point)
  5235. {
  5236. CWnd::OnRButtonDown(nFlags, point);
  5237. m_bRMouseButtonDown = TRUE;
  5238. #ifdef GRIDCONTROL_USE_TITLETIPS
  5239. //TRACE0("Hiding TitleTip\n");
  5240. m_TitleTip.Hide(); // hide any titletips
  5241. #endif
  5242. }
  5243. // EFW - Added to forward right click to parent so that a context
  5244. // menu can be shown without deriving a new grid class.
  5245. void CGridCtrl::OnRButtonUp(UINT nFlags, CPoint point)
  5246. {
  5247. CWnd::OnRButtonUp(nFlags, point);
  5248. m_bRMouseButtonDown = FALSE;
  5249. CCellID FocusCell;
  5250. FocusCell = GetCellFromPt(point);
  5251. EndEditing(); // Auto-destroy any InPlaceEdit's
  5252. // If not a valid cell, pass -1 for row and column
  5253. if (!IsValid(FocusCell))
  5254. SendMessageToParent(-1, -1, NM_RCLICK);
  5255. else
  5256. {
  5257. SetFocusCell(-1, -1);
  5258. SetFocusCell(max(FocusCell.row, m_nFixedRows),
  5259. max(FocusCell.col, m_nFixedCols));
  5260. // tell the cell about it
  5261. CGridCellBase* pCell = GetCell(FocusCell.row, FocusCell.col);
  5262. if (pCell)
  5263. pCell->OnRClick(GetPointClicked(FocusCell.row, FocusCell.col, point));
  5264. SendMessageToParent(FocusCell.row, FocusCell.col, NM_RCLICK);
  5265. }
  5266. }
  5267. #endif
  5268. #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  5269. /////////////////////////////////////////////////////////////////////////////
  5270. // CGridCtrl printing
  5271. // EFW - New print margin support functions
  5272. void CGridCtrl::SetPrintMarginInfo(int nHeaderHeight, int nFooterHeight,
  5273. int nLeftMargin, int nRightMargin, int nTopMargin,
  5274. int nBottomMargin, int nGap)
  5275. {
  5276. // If any parameter is -1, keep the existing setting
  5277. if (nHeaderHeight > -1)
  5278. m_nHeaderHeight = nHeaderHeight;
  5279. if (nFooterHeight > -1)
  5280. m_nFooterHeight = nFooterHeight;
  5281. if (nLeftMargin > -1)
  5282. m_nLeftMargin = nLeftMargin;
  5283. if (nRightMargin > -1)
  5284. m_nRightMargin = nRightMargin;
  5285. if (nTopMargin > -1)
  5286. m_nTopMargin = nTopMargin;
  5287. if (nBottomMargin > -1)
  5288. m_nBottomMargin = nBottomMargin;
  5289. if (nGap > -1)
  5290. m_nGap = nGap;
  5291. }
  5292. void CGridCtrl::GetPrintMarginInfo(int &nHeaderHeight, int &nFooterHeight,
  5293. int &nLeftMargin, int &nRightMargin, int &nTopMargin,
  5294. int &nBottomMargin, int &nGap)
  5295. {
  5296. nHeaderHeight = m_nHeaderHeight;
  5297. nFooterHeight = m_nFooterHeight;
  5298. nLeftMargin = m_nLeftMargin;
  5299. nRightMargin = m_nRightMargin;
  5300. nTopMargin = m_nTopMargin;
  5301. nBottomMargin = m_nBottomMargin;
  5302. nGap = m_nGap;
  5303. }
  5304. void CGridCtrl::Print(CPrintDialog* pPrntDialog /*=NULL*/)
  5305. {
  5306. CDC dc;
  5307. if (pPrntDialog == NULL)
  5308. {
  5309. CPrintDialog printDlg(FALSE);
  5310. if (printDlg.DoModal() != IDOK) // Get printer settings from user
  5311. return;
  5312. dc.Attach(printDlg.GetPrinterDC()); // attach a printer DC
  5313. }
  5314. else
  5315. dc.Attach(pPrntDialog->GetPrinterDC()); // attach a printer DC
  5316. dc.m_bPrinting = TRUE;
  5317. CString strTitle;
  5318. strTitle.LoadString(AFX_IDS_APP_TITLE);
  5319. if (strTitle.IsEmpty())
  5320. {
  5321. CWnd *pParentWnd = GetParent();
  5322. while (pParentWnd)
  5323. {
  5324. pParentWnd->GetWindowText(strTitle);
  5325. if (strTitle.GetLength()) // can happen if it is a CView, CChildFrm has the title
  5326. break;
  5327. pParentWnd = pParentWnd->GetParent();
  5328. }
  5329. }
  5330. DOCINFO di; // Initialise print doc details
  5331. memset(&di, 0, sizeof(DOCINFO));
  5332. di.cbSize = sizeof(DOCINFO);
  5333. di.lpszDocName = strTitle;
  5334. BOOL bPrintingOK = dc.StartDoc(&di); // Begin a new print job
  5335. CPrintInfo Info;
  5336. Info.m_rectDraw.SetRect(0, 0, dc.GetDeviceCaps(HORZRES), dc.GetDeviceCaps(VERTRES));
  5337. OnBeginPrinting(&dc, &Info); // Initialise printing
  5338. for (UINT page = Info.GetMinPage(); page <= Info.GetMaxPage() && bPrintingOK; page++)
  5339. {
  5340. dc.StartPage(); // begin new page
  5341. Info.m_nCurPage = page;
  5342. OnPrint(&dc, &Info); // Print page
  5343. bPrintingOK = (dc.EndPage() > 0); // end page
  5344. }
  5345. OnEndPrinting(&dc, &Info); // Clean up after printing
  5346. if (bPrintingOK)
  5347. dc.EndDoc(); // end a print job
  5348. else
  5349. dc.AbortDoc(); // abort job.
  5350. dc.Detach(); // detach the printer DC
  5351. }
  5352. /////////////////////////////////////////////////////////////////////////////
  5353. // CGridCtrl printing overridables - for Doc/View print/print preview framework
  5354. // EFW - Various changes in the next few functions to support the
  5355. // new print margins and a few other adjustments.
  5356. void CGridCtrl::OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo)
  5357. {
  5358. // OnBeginPrinting() is called after the user has committed to
  5359. // printing by OK'ing the Print dialog, and after the framework
  5360. // has created a CDC object for the printer or the preview view.
  5361. // This is the right opportunity to set up the page range.
  5362. // Given the CDC object, we can determine how many rows will
  5363. // fit on a page, so we can in turn determine how many printed
  5364. // pages represent the entire document.
  5365. ASSERT(pDC && pInfo);
  5366. if (!pDC || !pInfo) return;
  5367. // Get a DC for the current window (will be a screen DC for print previewing)
  5368. CDC *pCurrentDC = GetDC(); // will have dimensions of the client area
  5369. if (!pCurrentDC) return;
  5370. CSize PaperPixelsPerInch(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
  5371. CSize ScreenPixelsPerInch(pCurrentDC->GetDeviceCaps(LOGPIXELSX), pCurrentDC->GetDeviceCaps(LOGPIXELSY));
  5372. // Create the printer font
  5373. int nFontSize = -10;
  5374. CString strFontName = _T("Arial");
  5375. m_PrinterFont.CreateFont(nFontSize, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET,
  5376. OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY,
  5377. DEFAULT_PITCH | FF_DONTCARE, strFontName);
  5378. CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
  5379. // Get the average character width (in GridCtrl units) and hence the margins
  5380. m_CharSize = pDC->GetTextExtent(_T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSATUVWXYZ"), 52);
  5381. m_CharSize.cx /= 52;
  5382. int nMargins = (m_nLeftMargin + m_nRightMargin)*m_CharSize.cx;
  5383. // Get the page sizes (physical and logical)
  5384. m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
  5385. if (m_bWysiwygPrinting)
  5386. {
  5387. m_LogicalPageSize.cx = ScreenPixelsPerInch.cx * m_PaperSize.cx / PaperPixelsPerInch.cx * 3 / 4;
  5388. m_LogicalPageSize.cy = ScreenPixelsPerInch.cy * m_PaperSize.cy / PaperPixelsPerInch.cy * 3 / 4;
  5389. }
  5390. else
  5391. {
  5392. m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
  5393. m_LogicalPageSize.cx = GetVirtualWidth() + nMargins;
  5394. #ifdef _WIN32_WCE
  5395. m_LogicalPageSize.cy = (m_LogicalPageSize.cx * m_PaperSize.cy) / m_PaperSize.cx;
  5396. #else
  5397. m_LogicalPageSize.cy = MulDiv(m_LogicalPageSize.cx, m_PaperSize.cy, m_PaperSize.cx);
  5398. #endif
  5399. }
  5400. m_nPageHeight = m_LogicalPageSize.cy - GetFixedRowHeight()
  5401. - (m_nHeaderHeight + m_nFooterHeight + 2 * m_nGap)*m_CharSize.cy;
  5402. // Get the number of pages. Assumes no row is bigger than the page size.
  5403. int nTotalRowHeight = 0;
  5404. m_nNumPages = 1;
  5405. for (int row = GetFixedRowCount(); row < GetRowCount(); row++)
  5406. {
  5407. nTotalRowHeight += GetRowHeight(row);
  5408. if (nTotalRowHeight > m_nPageHeight) {
  5409. m_nNumPages++;
  5410. nTotalRowHeight = GetRowHeight(row);
  5411. }
  5412. }
  5413. // now, figure out how many additional pages must print out if rows ARE bigger
  5414. // than page size
  5415. int iColumnOffset = 0;
  5416. int i1;
  5417. for (i1 = 0; i1 < GetFixedColumnCount(); i1++)
  5418. {
  5419. iColumnOffset += GetColumnWidth(i1);
  5420. }
  5421. m_nPageWidth = m_LogicalPageSize.cx - iColumnOffset
  5422. - nMargins;
  5423. m_nPageMultiplier = 1;
  5424. if (m_bWysiwygPrinting)
  5425. {
  5426. int iTotalRowWidth = 0;
  5427. for (i1 = GetFixedColumnCount(); i1 < GetColumnCount(); i1++)
  5428. {
  5429. iTotalRowWidth += GetColumnWidth(i1);
  5430. if (iTotalRowWidth > m_nPageWidth)
  5431. {
  5432. m_nPageMultiplier++;
  5433. iTotalRowWidth = GetColumnWidth(i1);
  5434. }
  5435. }
  5436. m_nNumPages *= m_nPageMultiplier;
  5437. }
  5438. // Set up the print info
  5439. pInfo->SetMaxPage(m_nNumPages);
  5440. pInfo->m_nCurPage = 1; // start printing at page# 1
  5441. ReleaseDC(pCurrentDC);
  5442. pDC->SelectObject(pOldFont);
  5443. }
  5444. void CGridCtrl::OnPrint(CDC *pDC, CPrintInfo *pInfo)
  5445. {
  5446. if (!pDC || !pInfo)
  5447. return;
  5448. //CRect rcPage(pInfo->m_rectDraw);
  5449. CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
  5450. // Set the page map mode to use GridCtrl units, and setup margin
  5451. pDC->SetMapMode(MM_ANISOTROPIC);
  5452. pDC->SetWindowExt(m_LogicalPageSize);
  5453. pDC->SetViewportExt(m_PaperSize);
  5454. pDC->SetWindowOrg(-m_nLeftMargin * m_CharSize.cx, 0);
  5455. // Header
  5456. pInfo->m_rectDraw.top = 0;
  5457. pInfo->m_rectDraw.left = 0;
  5458. pInfo->m_rectDraw.right = m_LogicalPageSize.cx - (m_nLeftMargin + m_nRightMargin) * m_CharSize.cx;
  5459. pInfo->m_rectDraw.bottom = m_nHeaderHeight * m_CharSize.cy;
  5460. PrintHeader(pDC, pInfo);
  5461. pDC->OffsetWindowOrg(0, -m_nHeaderHeight * m_CharSize.cy);
  5462. // Gap between header and column headings
  5463. pDC->OffsetWindowOrg(0, -m_nGap * m_CharSize.cy);
  5464. pDC->OffsetWindowOrg(0, -GetFixedRowHeight());
  5465. // We need to find out which row to start printing for this page.
  5466. int nTotalRowHeight = 0;
  5467. UINT nNumPages = 1;
  5468. m_nCurrPrintRow = GetFixedRowCount();
  5469. // Not only the row, but we need to figure out column, too
  5470. // Can print 4 pages, where page 1 and 2 represent the same rows but
  5471. // with different WIDE columns.
  5472. //
  5473. // .......
  5474. // .1 .2 . If representing page 3 --> iPageIfIgnoredWideCols = 2
  5475. // ....... iWideColPageOffset = 0
  5476. // .3 .4 . If representing page 2 --> iPageIfIgnoredWideCols = 1
  5477. // ....... iWideColPageOffset = 1
  5478. int iPageIfIgnoredWideCols = pInfo->m_nCurPage / m_nPageMultiplier;
  5479. int iWideColPageOffset = pInfo->m_nCurPage - (iPageIfIgnoredWideCols * m_nPageMultiplier);
  5480. if (iWideColPageOffset > 0)
  5481. iPageIfIgnoredWideCols++;
  5482. if (iWideColPageOffset == 0)
  5483. iWideColPageOffset = m_nPageMultiplier;
  5484. iWideColPageOffset--;
  5485. // calculate current print row based on iPageIfIgnoredWideCols
  5486. while (m_nCurrPrintRow < GetRowCount()
  5487. && (int)nNumPages < iPageIfIgnoredWideCols)
  5488. {
  5489. nTotalRowHeight += GetRowHeight(m_nCurrPrintRow);
  5490. if (nTotalRowHeight > m_nPageHeight) {
  5491. nNumPages++;
  5492. if ((int)nNumPages == iPageIfIgnoredWideCols) break;
  5493. nTotalRowHeight = GetRowHeight(m_nCurrPrintRow);
  5494. }
  5495. m_nCurrPrintRow++;
  5496. }
  5497. m_nPrintColumn = GetFixedColumnCount();
  5498. int iTotalRowWidth = 0;
  5499. int i1, i2;
  5500. // now, calculate which print column to start displaying
  5501. for (i1 = 0; i1 < iWideColPageOffset; i1++)
  5502. {
  5503. for (i2 = m_nPrintColumn; i2 < GetColumnCount(); i2++)
  5504. {
  5505. iTotalRowWidth += GetColumnWidth(i2);
  5506. if (iTotalRowWidth > m_nPageWidth)
  5507. {
  5508. m_nPrintColumn = i2;
  5509. iTotalRowWidth = 0;
  5510. break;
  5511. }
  5512. }
  5513. }
  5514. PrintRowButtons(pDC, pInfo); // print row buttons on each page
  5515. int iColumnOffset = 0;
  5516. for (i1 = 0; i1 < GetFixedColumnCount(); i1++)
  5517. {
  5518. iColumnOffset += GetColumnWidth(i1);
  5519. }
  5520. // Print the column headings
  5521. pInfo->m_rectDraw.bottom = GetFixedRowHeight();
  5522. if (m_nPrintColumn == GetFixedColumnCount())
  5523. {
  5524. // have the column headings fcn draw the upper left fixed cells
  5525. // for the very first columns, only
  5526. pDC->OffsetWindowOrg(0, +GetFixedRowHeight());
  5527. m_nPageWidth += iColumnOffset;
  5528. m_nPrintColumn = 0;
  5529. PrintColumnHeadings(pDC, pInfo);
  5530. m_nPageWidth -= iColumnOffset;
  5531. m_nPrintColumn = GetFixedColumnCount();
  5532. pDC->OffsetWindowOrg(-iColumnOffset, -GetFixedRowHeight());
  5533. }
  5534. else
  5535. {
  5536. // changed all of this here to match above almost exactly same
  5537. pDC->OffsetWindowOrg(0, +GetFixedRowHeight());
  5538. m_nPageWidth += iColumnOffset;
  5539. // print from column 0 ... last column that fits on the current page
  5540. PrintColumnHeadings(pDC, pInfo);
  5541. m_nPageWidth -= iColumnOffset;
  5542. pDC->OffsetWindowOrg(-iColumnOffset, -GetFixedRowHeight());
  5543. }
  5544. if (m_nCurrPrintRow >= GetRowCount()) return;
  5545. // Draw as many rows as will fit on the printed page.
  5546. // Clip the printed page so that there is no partially shown
  5547. // row at the bottom of the page (the same row which will be fully
  5548. // shown at the top of the next page).
  5549. BOOL bFirstPrintedRow = TRUE;
  5550. CRect rect;
  5551. rect.bottom = -1;
  5552. while (m_nCurrPrintRow < GetRowCount())
  5553. {
  5554. rect.top = rect.bottom + 1;
  5555. rect.bottom = rect.top + GetRowHeight(m_nCurrPrintRow) - 1;
  5556. if (rect.bottom > m_nPageHeight) break; // Gone past end of page
  5557. rect.right = -1;
  5558. // modified to allow printing of wide grids on multiple pages
  5559. for (int col = m_nPrintColumn; col < GetColumnCount(); col++)
  5560. {
  5561. rect.left = rect.right + 1;
  5562. rect.right = rect.left
  5563. + GetColumnWidth(col)
  5564. - 1;
  5565. if (rect.right > m_nPageWidth)
  5566. break;
  5567. CGridCellBase* pCell = GetCell(m_nCurrPrintRow, col);
  5568. if (pCell)
  5569. pCell->PrintCell(pDC, m_nCurrPrintRow, col, rect);
  5570. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  5571. {
  5572. int Overlap = (col == 0) ? 0 : 1;
  5573. pDC->MoveTo(rect.left - Overlap, rect.bottom);
  5574. pDC->LineTo(rect.right, rect.bottom);
  5575. if (m_nCurrPrintRow == 0) {
  5576. pDC->MoveTo(rect.left - Overlap, rect.top);
  5577. pDC->LineTo(rect.right, rect.top);
  5578. }
  5579. }
  5580. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  5581. {
  5582. int Overlap = (bFirstPrintedRow) ? 0 : 1;
  5583. pDC->MoveTo(rect.right, rect.top - Overlap);
  5584. pDC->LineTo(rect.right, rect.bottom);
  5585. if (col == 0) {
  5586. pDC->MoveTo(rect.left, rect.top - Overlap);
  5587. pDC->LineTo(rect.left, rect.bottom);
  5588. }
  5589. }
  5590. }
  5591. m_nCurrPrintRow++;
  5592. bFirstPrintedRow = FALSE;
  5593. }
  5594. // Footer
  5595. pInfo->m_rectDraw.bottom = m_nFooterHeight * m_CharSize.cy;
  5596. pDC->SetWindowOrg(-m_nLeftMargin * m_CharSize.cx,
  5597. -m_LogicalPageSize.cy + m_nFooterHeight * m_CharSize.cy);
  5598. PrintFooter(pDC, pInfo);
  5599. // SetWindowOrg back for next page
  5600. pDC->SetWindowOrg(0, 0);
  5601. pDC->SelectObject(pOldFont);
  5602. }
  5603. // added by M.Fletcher 12/17/00
  5604. void CGridCtrl::PrintFixedRowCells(int nStartColumn, int nStopColumn, int& row, CRect& rect,
  5605. CDC *pDC, BOOL& bFirst)
  5606. {
  5607. // print all cells from nStartColumn to nStopColumn on row
  5608. for (int col = nStartColumn; col < nStopColumn; col++)
  5609. {
  5610. rect.left = rect.right + 1;
  5611. rect.right = rect.left + GetColumnWidth(col) - 1;
  5612. if (rect.right > m_nPageWidth)
  5613. break;
  5614. CGridCellBase* pCell = GetCell(row, col);
  5615. if (pCell)
  5616. pCell->PrintCell(pDC, row, col, rect);
  5617. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  5618. {
  5619. int Overlap = (col == 0) ? 0 : 1;
  5620. pDC->MoveTo(rect.left - Overlap, rect.bottom);
  5621. pDC->LineTo(rect.right, rect.bottom);
  5622. if (row == 0)
  5623. {
  5624. pDC->MoveTo(rect.left - Overlap, rect.top);
  5625. pDC->LineTo(rect.right, rect.top);
  5626. }
  5627. }
  5628. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  5629. {
  5630. int Overlap = (row == 0) ? 0 : 1;
  5631. pDC->MoveTo(rect.right, rect.top - Overlap);
  5632. pDC->LineTo(rect.right, rect.bottom);
  5633. if (bFirst)
  5634. {
  5635. pDC->MoveTo(rect.left - 1, rect.top - Overlap);
  5636. pDC->LineTo(rect.left - 1, rect.bottom);
  5637. bFirst = FALSE;
  5638. }
  5639. }
  5640. } // end of column cells loop
  5641. } // end of CGridCtrl::PrintFixedRowCells
  5642. void CGridCtrl::PrintColumnHeadings(CDC *pDC, CPrintInfo* /*pInfo*/)
  5643. {
  5644. CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
  5645. CRect rect;
  5646. rect.bottom = -1;
  5647. BOOL bFirst = TRUE;
  5648. BOOL bOriginal;
  5649. // modified to allow column hdr printing of multi-page wide grids
  5650. for (int row = 0; row < GetFixedRowCount(); row++)
  5651. {
  5652. rect.top = rect.bottom + 1;
  5653. rect.bottom = rect.top + GetRowHeight(row) - 1;
  5654. rect.right = -1;
  5655. // if printColumn > fixedcolumncount we are on page 2 or more
  5656. // lets printout those fixed cell headings again the 1 or more that would be missed
  5657. // added by M.Fletcher 12/17/00
  5658. if (m_nPrintColumn >= GetFixedColumnCount())
  5659. {
  5660. bOriginal = bFirst;
  5661. // lets print the missing fixed cells on left first out to last fixed column
  5662. PrintFixedRowCells(0, GetFixedColumnCount(), row, rect, pDC, bFirst);
  5663. bFirst = bOriginal;
  5664. }
  5665. // now back to normal business print cells in heading after all fixed columns
  5666. PrintFixedRowCells(m_nPrintColumn, GetColumnCount(), row, rect, pDC, bFirst);
  5667. } // end of Row Loop
  5668. pDC->SelectObject(pOldFont);
  5669. } // end of CGridCtrl::PrintColumnHeadings
  5670. /*****************************************************************************
  5671. Prints line of row buttons on each page of the printout. Assumes that
  5672. the window origin is setup before calling
  5673. *****************************************************************************/
  5674. void CGridCtrl::PrintRowButtons(CDC *pDC, CPrintInfo* /*pInfo*/)
  5675. {
  5676. CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
  5677. CRect rect;
  5678. rect.right = -1;
  5679. BOOL bFirst = TRUE;
  5680. for (int iCol = 0; iCol < GetFixedColumnCount(); iCol++)
  5681. {
  5682. rect.left = rect.right + 1;
  5683. rect.right = rect.left
  5684. + GetColumnWidth(iCol)
  5685. - 1;
  5686. rect.bottom = -1;
  5687. for (int iRow = m_nCurrPrintRow; iRow < GetRowCount(); iRow++)
  5688. {
  5689. rect.top = rect.bottom + 1;
  5690. rect.bottom = rect.top + GetRowHeight(iRow) - 1;
  5691. if (rect.bottom > m_nPageHeight)
  5692. break;
  5693. CGridCellBase* pCell = GetCell(iRow, iCol);
  5694. if (pCell)
  5695. pCell->PrintCell(pDC, iRow, iCol, rect);
  5696. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  5697. {
  5698. int Overlap = (iCol == 0) ? 0 : 1;
  5699. pDC->MoveTo(rect.left - Overlap, rect.bottom);
  5700. pDC->LineTo(rect.right, rect.bottom);
  5701. if (bFirst) {
  5702. pDC->MoveTo(rect.left - Overlap, rect.top - 1);
  5703. pDC->LineTo(rect.right, rect.top - 1);
  5704. bFirst = FALSE;
  5705. }
  5706. }
  5707. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  5708. {
  5709. int Overlap = (iRow == 0) ? 0 : 1;
  5710. pDC->MoveTo(rect.right, rect.top - Overlap);
  5711. pDC->LineTo(rect.right, rect.bottom);
  5712. if (iCol == 0) {
  5713. pDC->MoveTo(rect.left, rect.top - Overlap);
  5714. pDC->LineTo(rect.left, rect.bottom);
  5715. }
  5716. }
  5717. }
  5718. }
  5719. pDC->SelectObject(pOldFont);
  5720. }
  5721. void CGridCtrl::PrintHeader(CDC *pDC, CPrintInfo *pInfo)
  5722. {
  5723. // print App title on top right margin
  5724. CString strRight;
  5725. strRight.LoadString(AFX_IDS_APP_TITLE);
  5726. // print parent window title in the centre (Gert Rijs)
  5727. CString strCenter;
  5728. CWnd *pParentWnd = GetParent();
  5729. while (pParentWnd)
  5730. {
  5731. pParentWnd->GetWindowText(strCenter);
  5732. if (strCenter.GetLength()) // can happen if it is a CView, CChildFrm has the title
  5733. break;
  5734. pParentWnd = pParentWnd->GetParent();
  5735. }
  5736. CFont BoldFont;
  5737. LOGFONT lf;
  5738. //create bold font for header and footer
  5739. VERIFY(m_PrinterFont.GetLogFont(&lf));
  5740. lf.lfWeight = FW_BOLD;
  5741. VERIFY(BoldFont.CreateFontIndirect(&lf));
  5742. CFont *pNormalFont = pDC->SelectObject(&BoldFont);
  5743. int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
  5744. CRect rc(pInfo->m_rectDraw);
  5745. if (!strCenter.IsEmpty())
  5746. pDC->DrawText(strCenter, &rc, DT_CENTER | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
  5747. if (!strRight.IsEmpty())
  5748. pDC->DrawText(strRight, &rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
  5749. pDC->SetBkMode(nPrevBkMode);
  5750. pDC->SelectObject(pNormalFont);
  5751. BoldFont.DeleteObject();
  5752. // draw ruled-line across top
  5753. pDC->SelectStockObject(BLACK_PEN);
  5754. pDC->MoveTo(rc.left, rc.bottom);
  5755. pDC->LineTo(rc.right, rc.bottom);
  5756. }
  5757. //print footer with a line and date, and page number
  5758. void CGridCtrl::PrintFooter(CDC *pDC, CPrintInfo *pInfo)
  5759. {
  5760. // page numbering on left
  5761. CString strLeft;
  5762. strLeft.Format(_T("Page %d of %d"), pInfo->m_nCurPage, pInfo->GetMaxPage());
  5763. // date and time on the right
  5764. CString strRight;
  5765. COleDateTime t = COleDateTime::GetCurrentTime();
  5766. strRight = t.Format(_T("%c"));
  5767. CRect rc(pInfo->m_rectDraw);
  5768. // draw ruled line on bottom
  5769. pDC->SelectStockObject(BLACK_PEN);
  5770. pDC->MoveTo(rc.left, rc.top);
  5771. pDC->LineTo(rc.right, rc.top);
  5772. CFont BoldFont;
  5773. LOGFONT lf;
  5774. //create bold font for header and footer
  5775. m_PrinterFont.GetLogFont(&lf);
  5776. lf.lfWeight = FW_BOLD;
  5777. BoldFont.CreateFontIndirect(&lf);
  5778. CFont *pNormalFont = pDC->SelectObject(&BoldFont);
  5779. int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
  5780. // EFW - Bug fix - Force text color to black. It doesn't always
  5781. // get set to a printable color when it gets here.
  5782. pDC->SetTextColor(RGB(0, 0, 0));
  5783. if (!strLeft.IsEmpty())
  5784. pDC->DrawText(strLeft, &rc, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
  5785. if (!strRight.IsEmpty())
  5786. pDC->DrawText(strRight, &rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
  5787. pDC->SetBkMode(nPrevBkMode);
  5788. pDC->SelectObject(pNormalFont);
  5789. BoldFont.DeleteObject();
  5790. }
  5791. void CGridCtrl::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
  5792. {
  5793. m_PrinterFont.DeleteObject();
  5794. }
  5795. #endif // !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  5796. #ifndef _WIN32_WCE
  5797. /////////////////////////////////////////////////////////////////////////////
  5798. // CGridCtrl persistance
  5799. BOOL CGridCtrl::Save(LPCTSTR filename, TCHAR chSeparator/*=_T(',')*/)
  5800. {
  5801. CStdioFile File;
  5802. CFileException ex;
  5803. CString strSeparator(chSeparator);
  5804. if (!File.Open(filename, CFile::modeWrite | CFile::modeCreate | CFile::typeText, &ex))
  5805. {
  5806. ex.ReportError();
  5807. return FALSE;
  5808. }
  5809. TRY
  5810. {
  5811. int nNumColumns = GetColumnCount();
  5812. for (int i = 0; i < GetRowCount(); i++)
  5813. {
  5814. for (int j = 0; j < nNumColumns; j++)
  5815. {
  5816. File.WriteString(GetItemText(i, j));
  5817. File.WriteString((j == (nNumColumns - 1)) ? _T("\n") : strSeparator);
  5818. }
  5819. }
  5820. File.Close();
  5821. }
  5822. CATCH(CFileException, e)
  5823. {
  5824. AfxMessageBox(_T("Unable to save grid list"));
  5825. return FALSE;
  5826. }
  5827. END_CATCH
  5828. return TRUE;
  5829. }
  5830. BOOL CGridCtrl::Load(LPCTSTR filename, TCHAR chSeparator/*=_T(',')*/)
  5831. {
  5832. if (GetVirtualMode())
  5833. return FALSE;
  5834. TCHAR *token, *end;
  5835. TCHAR buffer[1024];
  5836. CStdioFile File;
  5837. CFileException ex;
  5838. if (!File.Open(filename, CFile::modeRead | CFile::typeText))
  5839. {
  5840. ex.ReportError();
  5841. return FALSE;
  5842. }
  5843. DeleteAllItems();
  5844. TRY
  5845. {
  5846. // Read Header off file
  5847. File.ReadString(buffer, 1024);
  5848. // Get first token
  5849. for (token = buffer, end = buffer;
  5850. *end && (*end != chSeparator) && (*end != _T('\n'));
  5851. end++)
  5852. ;
  5853. if ((*end == _T('\0')) && (token == end))
  5854. token = NULL;
  5855. *end = _T('\0');
  5856. while (token)
  5857. {
  5858. InsertColumn(token);
  5859. // Get next token
  5860. for (token = ++end; *end && (*end != chSeparator) && (*end != _T('\n'));
  5861. end++)
  5862. ;
  5863. if ((*end == _T('\0')) && (token == end))
  5864. token = NULL;
  5865. *end = _T('\0');
  5866. }
  5867. // Read in rest of data
  5868. int nItem = 0;
  5869. while (File.ReadString(buffer, 1024))
  5870. {
  5871. // Get first token
  5872. for (token = buffer, end = buffer;
  5873. *end && (*end != chSeparator) && (*end != _T('\n')); end++)
  5874. ;
  5875. if ((*end == _T('\0')) && (token == end))
  5876. token = NULL;
  5877. *end = _T('\0');
  5878. int nSubItem = 0;
  5879. while (token)
  5880. {
  5881. if (!nSubItem)
  5882. InsertRow(token);
  5883. else
  5884. SetItemText(nItem, nSubItem, token);
  5885. // Get next token
  5886. for (token = ++end; *end && (*end != chSeparator) && (*end != _T('\n'));
  5887. end++)
  5888. ;
  5889. if ((*end == _T('\0')) && (token == end))
  5890. token = NULL;
  5891. *end = _T('\0');
  5892. nSubItem++;
  5893. }
  5894. nItem++;
  5895. }
  5896. AutoSizeColumns(GetAutoSizeStyle());
  5897. File.Close();
  5898. }
  5899. CATCH(CFileException, e)
  5900. {
  5901. AfxMessageBox(_T("Unable to load grid data"));
  5902. return FALSE;
  5903. }
  5904. END_CATCH
  5905. return TRUE;
  5906. }
  5907. #endif
  5908. /////////////////////////////////////////////////////////////////////////////
  5909. // CGridCtrl overrideables
  5910. #ifndef GRIDCONTROL_NO_DRAGDROP
  5911. // This is no longer needed since I've changed to OLE drag and drop - but it's
  5912. // still cool code. :)
  5913. CImageList* CGridCtrl::CreateDragImage(CPoint *pHotSpot)
  5914. {
  5915. CDC* pDC = GetDC();
  5916. if (!pDC)
  5917. return NULL;
  5918. CRect rect;
  5919. CCellID cell = GetFocusCell();
  5920. if (!GetCellRect(cell.row, cell.col, rect))
  5921. return NULL;
  5922. // Translate coordinate system
  5923. rect.BottomRight() = CPoint(rect.Width(), rect.Height());
  5924. rect.TopLeft() = CPoint(0, 0);
  5925. *pHotSpot = rect.BottomRight();
  5926. // Create a new imagelist (the caller of this function has responsibility
  5927. // for deleting this list)
  5928. CImageList* pList = new CImageList;
  5929. if (!pList || !pList->Create(rect.Width(), rect.Height(), ILC_MASK, 1, 1))
  5930. {
  5931. if (pList)
  5932. delete pList;
  5933. return NULL;
  5934. }
  5935. // Create mem DC and bitmap
  5936. CDC MemDC;
  5937. CBitmap bm;
  5938. MemDC.CreateCompatibleDC(pDC);
  5939. bm.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
  5940. CBitmap* pOldBitmap = MemDC.SelectObject(&bm);
  5941. MemDC.SetWindowOrg(0, 0);
  5942. // Draw cell onto bitmap in memDC
  5943. CGridCellBase* pCell = GetCell(cell.row, cell.col);
  5944. if (pCell)
  5945. pCell->Draw(&MemDC, cell.row, cell.col, rect, FALSE);
  5946. // Clean up
  5947. MemDC.SelectObject(pOldBitmap);
  5948. ReleaseDC(pDC);
  5949. // Add the bitmap we just drew to the image list.
  5950. pList->Add(&bm, GetDefaultCell(FALSE, FALSE)->GetBackClr());
  5951. bm.DeleteObject();
  5952. return pList;
  5953. }
  5954. #endif
  5955. void CGridCtrl::OnFixedRowClick(CCellID& cell)
  5956. {
  5957. if (!IsValid(cell))
  5958. return;
  5959. if (GetHeaderSort())
  5960. {
  5961. //AfxMessageBox("IF");
  5962. CWaitCursor waiter;
  5963. if (cell.col == GetSortColumn())
  5964. SortItems(cell.col, !GetSortAscending());
  5965. else
  5966. SortItems(cell.col, TRUE);
  5967. Invalidate();
  5968. }
  5969. if (GetFixedRowSelection())
  5970. {
  5971. if (cell.col < GetFixedColumnCount())
  5972. {
  5973. m_MouseMode = MOUSE_SELECT_ALL;
  5974. OnSelecting(cell);
  5975. }
  5976. else
  5977. {
  5978. m_MouseMode = MOUSE_SELECT_COL;
  5979. OnSelecting(cell);
  5980. }
  5981. }
  5982. }
  5983. void CGridCtrl::OnFixedColumnClick(CCellID& cell)
  5984. {
  5985. if (!IsValid(cell))
  5986. return;
  5987. // if (m_bListMode && (GetItemState(cell.row, m_nFixedCols) & GVNI_SELECTED))
  5988. // {
  5989. // OnEditCell(cell.row, cell.col, VK_LBUTTON);
  5990. // return;
  5991. // }
  5992. if (GetFixedColumnSelection())
  5993. {
  5994. if (cell.row < GetFixedRowCount())
  5995. {
  5996. m_MouseMode = MOUSE_SELECT_ALL;
  5997. OnSelecting(cell);
  5998. }
  5999. else
  6000. {
  6001. m_MouseMode = MOUSE_SELECT_ROW;
  6002. OnSelecting(cell);
  6003. }
  6004. }
  6005. }
  6006. // Gets the extent of the text pointed to by str (no CDC needed)
  6007. // By default this uses the selected font (which is a bigger font)
  6008. CSize CGridCtrl::GetTextExtent(int nRow, int nCol, LPCTSTR str)
  6009. {
  6010. CGridCellBase* pCell = GetCell(nRow, nCol);
  6011. if (!pCell)
  6012. return CSize(0, 0);
  6013. else
  6014. return pCell->GetTextExtent(str);
  6015. }
  6016. // virtual
  6017. void CGridCtrl::OnEditCell(int nRow, int nCol, CPoint point, UINT nChar)
  6018. {
  6019. #ifndef GRIDCONTROL_NO_TITLETIPS
  6020. m_TitleTip.Hide(); // hide any titletips
  6021. #endif
  6022. // Can we do it?
  6023. CCellID cell(nRow, nCol);
  6024. if (!IsValid(cell) || !IsCellEditable(nRow, nCol))
  6025. return;
  6026. // Can we see what we are doing?
  6027. EnsureVisible(nRow, nCol);
  6028. if (!IsCellVisible(nRow, nCol))
  6029. return;
  6030. // Where, exactly, are we gonna do it??
  6031. CRect rect;
  6032. if (!GetCellRect(cell, rect))
  6033. return;
  6034. // Check we can edit...
  6035. if (SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT) >= 0)
  6036. {
  6037. // Let's do it...
  6038. CGridCellBase* pCell = GetCell(nRow, nCol);
  6039. if (pCell)
  6040. pCell->Edit(nRow, nCol, rect, point, IDC_INPLACE_CONTROL, nChar);
  6041. }
  6042. }
  6043. // virtual
  6044. void CGridCtrl::EndEditing()
  6045. {
  6046. CCellID cell = GetFocusCell();
  6047. if (!IsValid(cell)) return;
  6048. CGridCellBase *pCell = GetCell(cell.row, cell.col);
  6049. if (pCell)
  6050. pCell->EndEdit();
  6051. }
  6052. // virtual
  6053. void CGridCtrl::OnEndEditCell(int nRow, int nCol, CString str)
  6054. {
  6055. CString strCurrentText = GetItemText(nRow, nCol);
  6056. if (strCurrentText != str)
  6057. {
  6058. SetItemText(nRow, nCol, str);
  6059. if (ValidateEdit(nRow, nCol, str) &&
  6060. SendMessageToParent(nRow, nCol, GVN_ENDLABELEDIT) >= 0)
  6061. {
  6062. SetModified(TRUE, nRow, nCol);
  6063. RedrawCell(nRow, nCol);
  6064. }
  6065. else
  6066. {
  6067. SetItemText(nRow, nCol, strCurrentText);
  6068. }
  6069. }
  6070. CGridCellBase* pCell = GetCell(nRow, nCol);
  6071. if (pCell)
  6072. pCell->OnEndEdit();
  6073. }
  6074. // If this returns FALSE then the editing isn't allowed
  6075. // virtual
  6076. BOOL CGridCtrl::ValidateEdit(int nRow, int nCol, LPCTSTR str)
  6077. {
  6078. CGridCellBase* pCell = GetCell(nRow, nCol);
  6079. ASSERT(pCell);
  6080. if (!pCell)
  6081. return TRUE;
  6082. return pCell->ValidateEdit(str);
  6083. }
  6084. // virtual
  6085. CString CGridCtrl::GetItemText(int nRow, int nCol) const
  6086. {
  6087. if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols)
  6088. return _T("");
  6089. CGridCellBase* pCell = GetCell(nRow, nCol);
  6090. ASSERT(pCell);
  6091. if (!pCell)
  6092. return _T("");
  6093. return pCell->GetText();
  6094. }
  6095. int CGridCtrl::GetSelCount()
  6096. {
  6097. return m_nArrayListChoose.GetCount();
  6098. }
  6099. int CGridCtrl::GetSelData(int iIndex)
  6100. {
  6101. return m_nArrayListChoose[iIndex];
  6102. }