Typica is a free program for professional coffee roasters. https://typica.us
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

typica.w 727KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711
  1. % Instructions for generating source code and documentation
  2. % Step 1. Convert metapost diagrams into PDF documents
  3. % $ mptopdf pipes.mp ; epstopdf pipes.ps
  4. % $ mptopdf roast.mp ; epstopdf roast.ps
  5. % $ mptopdf search.mp ; epstopdf search.ps
  6. % Step 2. Weave and typeset
  7. % $ cweave typica
  8. % $ pdftex typica
  9. % Step 3. Tangle and moc
  10. % $ ctangle typica ; mv typica.c typica.cpp
  11. % $ moc typica.cpp > moc_typica.cpp
  12. %
  13. % If you have trouble compiling, check to make sure the required headers are in
  14. % your header search path and check to make sure the required libraries are
  15. % linked. If using qmake to generate a project file, remember to add the
  16. % following lines to your .pro file:
  17. % QT += xml
  18. % QT += script
  19. % Document style instructions
  20. \input graphicx.tex
  21. \mark{\noexpand\nullsec0{A Note on Notation}}
  22. \def\pn{Typica}
  23. \def\filebase{typica}
  24. \def\version{1.9.1 \number\year-\number\month-\number\day}
  25. \def\years{2007--2018}
  26. \def\title{\pn{} (Version \version)}
  27. \newskip\dangerskipb
  28. \newskip\dangerskip
  29. \dangerskip=20pt
  30. \dangerskipb=42pt
  31. \def\hang{\hangindent\dangerskip}
  32. \def\hangb{\hangindent\dangerskipb}
  33. \font\manual=manfnt at 12pt
  34. \def\danbend{{\manual\char127}}
  35. \def\datanger{\medbreak\begingroup\clubpenalty=10000
  36. \def\par{\endgraf\endgroup\medbreak} \noindent\hang\hangafter=-2
  37. \hbox to0pt{\hskip-3.5pc\danbend\hfill}}
  38. \outer\def\danger{\datanger}%
  39. %
  40. \def\datangerb{\medbreak\begingroup\clubpenalty=10000
  41. \def\par{\endgraf\endgroup\medbreak} \noindent\hang\hangafter=-2
  42. \hbox to0pt{\hskip-3.5pc\danbend\hfill}}
  43. \outer\def\dangerb{\datangerb}
  44. \def\endanger{\medskip}
  45. \def\nullsec{\S1}
  46. \def\lheader{\mainfont\the\pageno\kern1pc(\topsecno)\eightrm
  47. \qquad\grouptitle\hfill\title}
  48. \def\rheader{\eightrm\title\hfill\grouptitle\qquad\mainfont
  49. (\topsecno)\kern1pc\the\pageno}
  50. \def\botofcontents{\vfill
  51. \noindent Copyright \copyright\ \years~Neal Evan Wilson
  52. \bigskip\noindent Permission is hereby granted, free of charge, to any
  53. person obtaining a copy of this software and associated documentation files
  54. (the ``Software''), to deal in the Software without restriction, including
  55. without limitation the rights to use, copy, modify, merge, publish,
  56. distribute, sublicense, and/or sell copies of the Software, and to permit
  57. persons to whom the Software is furnished to do so, subject to the following
  58. conditions:\medskip
  59. The above copyright notice and this permission notice shall be included in
  60. all copies or substantial portions of the Software.\medskip
  61. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  62. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  63. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  64. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  65. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  66. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  67. IN THE SOFTWARE.
  68. \bigskip\noindent Parts of \pn{} are from QextSerialPort which is used under the
  69. MIT license as follows:
  70. \bigskip\noindent Copyright \copyright\ 2000--2003 Wayne Roth
  71. \noindent Copyright \copyright\ 2004--2007 Stefan Sander
  72. \noindent Copyright \copyright\ 2007 Michal Policht
  73. \noindent Copyright \copyright\ 2008 Brandon Fosdick
  74. \noindent Copyright \copyright\ 2009--2010 Liam Staskawicz
  75. \noindent Copyright \copyright\ 2011 Debao Zhang
  76. \bigskip\noindent Web: http://code.google.com/p/qextserialport/
  77. \bigskip\noindent Permission is hereby granted, free of charge, to any person obtaining
  78. a copy of this software and associated documentation files (the
  79. ``Software''), to deal in the Software without restriction, including
  80. without limitation the rights to use, copy, modify, merge, publish,
  81. distribute, sublicense, and/or sell copies of the Software, and to
  82. permit persons to whom the Software is furnished to do so, subject to
  83. the following conditions:
  84. The above copyright notice and this permission notice shall be
  85. included in all copies or substantial portions of the Software.
  86. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
  87. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  88. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  89. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  90. LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  91. OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  92. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  93. }
  94. \let\K=\leftarrow
  95. \def\CPLUSPLUS/{{%
  96. \mc C{\hbox{\kern.5pt\raise1pt\hbox{\sevenrm+\kern-1pt+}\kern.5pt}}
  97. \spacefactor1000}}
  98. \def\PP{\uparrow}
  99. \def\MM{\downarrow}
  100. \newbox\DCBox
  101. \setbox\DCBox=\hbox{$\in$}
  102. \def\DC{\copy\DCBox}
  103. \newbox\MODbox \setbox\MODbox=\hbox{\eightrm MOD}
  104. \def\MOD{\mathbin{\copy\MODbox}}
  105. % Title page
  106. \font\authorfont=cmr12
  107. \null\vfill
  108. \centerline{\titlefont \pn}
  109. \vskip 18pt\centerline{(Version \version)}
  110. \vskip 24pt\centerline{\authorfont Neal Evan Wilson}
  111. \vfill
  112. \titletrue\eject\hbox to 0pt{}
  113. \pageno=0 \titletrue\eject
  114. \secpagedepth=1
  115. % Convenience macros
  116. \def\newline{\vskip\baselineskip}
  117. \def\cweb{\.{CWEB}}
  118. \def\web{\.{WEB}}
  119. \newcount\footnotenumber
  120. \def\nfnote{\global\advance\footnotenumber by 1
  121. \footnote{$^{\the\footnotenumber}$}}
  122. % Listing macro from The TeXBook. See page 381 for an explaination.
  123. \def\uncatcodespecials{\def\do##1{\catcode`##1=12 }\dospecials}
  124. \newcount\lineno
  125. \def\setupverbatim{\tt \lineno=0
  126. \def\par{\leavevmode\endgraf} \catcode`\`=\active
  127. \obeylines \uncatcodespecials \obeyspaces
  128. \everypar{\advance\lineno by1 \llap{\sevenrm\the\lineno\ \ }}}
  129. {\obeyspaces\global\let =\ }
  130. \def\listing#1{\par\begingroup\setupverbatim\input#1 \endgroup}
  131. % Javascript chunk handling
  132. \def\jsfile#1#2{\Y\B\4\X\secno:\.{#1}\X${}\E{}\6$\par
  133. \listing{#2}}
  134. % Type formatting
  135. @s QTime int
  136. @s QMetaType int
  137. @s DAQ int
  138. @s Channel int
  139. @s QString int
  140. @s QObject int
  141. @s QThread int
  142. @s DAQImplementation int
  143. @s QVector int
  144. @s TaskHandle int
  145. @s qint32 int
  146. @s int32 int
  147. @s QMessageBox int
  148. @s QLCDNumber int
  149. @s QWidget int
  150. @s AnnotationButton int
  151. @s AnnotationSpinBox int
  152. @s QPushButton int
  153. @s QTimer int
  154. @s QAction int
  155. @s QApplication int
  156. @s PackLayout int
  157. @s QLayout int
  158. @s QLayoutItem int
  159. @s QRect int
  160. @s QList int
  161. @s QSize int
  162. @s QGraphicsScene int
  163. @s SceneButton int
  164. @s QGraphicsSceneMouseEvent int
  165. @s QPoint int
  166. @s true const
  167. @s false const
  168. @s QGraphicsView int
  169. @s QGraphicsTextItem int
  170. @s QFrame int
  171. @s QPaintDevice int
  172. @s QColor int
  173. @s QBrush int
  174. @s QHash int
  175. @s QPointF int
  176. @s QGraphicsLineItem int
  177. @s MeasurementModel int
  178. @s QTableView int
  179. @s QVariant int
  180. @s QAbstractItemView int
  181. @s QAbstractItemModel int
  182. @s QStringList int
  183. @s QModelIndex int
  184. @s MeasurementList int
  185. @s QVariantList int
  186. @s QSplitter int
  187. @s QHBoxLayout int
  188. @s QMainWindow int
  189. @s QCoreApplication int
  190. @s QSettings int
  191. @s QMenu int
  192. @s QCloseEvent int
  193. @s LogEditWindow int
  194. @s QFile int
  195. @s QFileInfo int
  196. @s QDir int
  197. @s QXmlStreamWriter int
  198. @s QXmlStreamReader int
  199. @s QIODevice int
  200. @s QLabel int
  201. @s QTimeEdit int
  202. @s QSpinBox int
  203. @s QDoubleSpinBox int
  204. @s ThermocoupleType int
  205. @s TemperatureUnits int
  206. @s Qt int
  207. @s emit throw
  208. @s TemperatureDisplay int
  209. @s ZeroEmitter int
  210. @s MeasurementAdapter int
  211. @s GraphView int
  212. @s ZoomLog int
  213. @s TimerDisplay int
  214. @s QBoxLayout int
  215. @s WidgetDecorator int
  216. @s XMLInput int
  217. @s XMLOutput int
  218. @s CSVOutput int
  219. @s QTextStream int
  220. @s QTranslator int
  221. @s QLocale int
  222. @s Application int
  223. @s QScriptContext int
  224. @s QScriptEngine int
  225. @s QScriptEngineDebugger int
  226. @s QScriptValue int
  227. @s FakeDAQ int
  228. @s QMenuBar int
  229. @s QKeySequence int
  230. @s QFileDialog int
  231. @s Measurement int
  232. @s Date int
  233. @s QLibrary int
  234. @s daqfp int
  235. @s QResizeEvent int
  236. @s QVBoxLayout int
  237. @s QByteArray int
  238. @s QSqlDatabase int
  239. @s QComboBox int
  240. @s QXmlStreamAttribute int
  241. @s QSqlQuery int
  242. @s QLineEdit int
  243. @s QDoubleValidator int
  244. @s QIntValidator int
  245. @s QTextEdit int
  246. @s QStandardItemModel int
  247. @s QValidator int
  248. @s QMap int
  249. @s QDomElement int
  250. @s QDomNodeList int
  251. @s QDomNode int
  252. @s QStack int
  253. @s QDomDocument int
  254. @s QDomNamedNodeMap int
  255. @s QFormLayout int
  256. @s QAbstractButton int
  257. @s QAbstractScrollArea int
  258. @s SqlComboBox int
  259. @s QUuid int
  260. @s SqlComboBoxDelegate int
  261. @s QItemDelegate int
  262. @s SqlConnectionSetup int
  263. @s QDialog int
  264. @s QCheckBox int
  265. @s SaltModel int
  266. @s QStyleOptionViewItem int
  267. @s QBuffer int
  268. @s QDateEdit int
  269. @s QCalendarWidget int
  270. @s QDate int
  271. @s QFocusEvent int
  272. @s QGridLayout int
  273. @s QScrollArea int
  274. @s QSqlQueryModel int
  275. @s QSqlRecord int
  276. @s QSqlResult int
  277. @s SqlQueryConnection int
  278. @s QFont int
  279. @s SqlQueryView int
  280. @s QTextDocument int
  281. @s QTextCursor int
  282. @s QTextFrame int
  283. @s ReportTable int
  284. @s QTextTable int
  285. @s QTextTableFormat int
  286. @s QTextFrameFormat int
  287. @s QTextTableCell int
  288. @s QPrinter int
  289. @s QPrintDialog int
  290. @s QSqlError int
  291. @s FormArray int
  292. @s QRegExp int
  293. @s QRegExpValidator int
  294. @s QDomDocumentFragment int
  295. @s QStackedLayout int
  296. @s QMouseEvent int
  297. @s QGraphicsPolygonItem int
  298. @s QPolygonF int
  299. @s QGraphicsPathItem int
  300. @s QPainterPath int
  301. @s QXmlQuery int
  302. @s QGraphicsItem int
  303. @s QWebView int
  304. @s QUrl int
  305. @s QShowEvent int
  306. @s QDateTimeEdit int
  307. @s ThresholdDetector int
  308. @s EdgeDirection int
  309. @s DeviceTreeModelNode int
  310. @s QMetaObject int
  311. @s QTreeView int
  312. @s QToolButton int
  313. @s QextPortInfo int
  314. @s QextSerialEnumerator int
  315. @s QMetaEnum int
  316. @s quint16 int
  317. @s QextSerialPort int
  318. @s QGroupBox int
  319. @s QVariantMap int
  320. @s QIcon int
  321. @s QFileInfoList int
  322. @s QMetaMethod int
  323. @f error normal
  324. @f line normal
  325. @f signals public
  326. @f slots int
  327. @f qRegisterMetaType make_pair
  328. @f READ TeX
  329. @f WRITE TeX
  330. @f tr TeX
  331. @f this TeX
  332. @f foreach while
  333. @f qobject_cast make_pair
  334. @f t1 TeX
  335. @f t2 TeX
  336. @f AppInstance TeX
  337. @f getself make_pair
  338. @f TYPE TeX
  339. @f argument make_pair
  340. @f toScriptValue make_pair
  341. @f arg1 TeX
  342. @f arg2 TeX
  343. @f arg3 TeX
  344. @f arg4 TeX
  345. @f findChild make_pair
  346. @f qscriptvalue_cast make_pair
  347. \def\READ{\kern4pt{\tt READ}\kern4pt}
  348. \def\WRITE{\kern4pt{\tt WRITE}\kern4pt}
  349. \def\tr{\delta}
  350. \def\this{\forall}
  351. \def\t#1{t_{#1}}
  352. \def\AppInstance{\.{AppInstance}}
  353. \def\TYPE{\cal T\kern1pt}
  354. \def\arg#1{arg_{#1}}
  355. % Document
  356. @** A Note on Notation.
  357. \noindent As noted by Falkoff and Iverson\nfnote{A.~D.~Falkoff and
  358. K.~E.~Iverson, ``The Design of APL'' (1973)}~there is little need to limit the
  359. typography used to represent a computer program in print. The printed code of
  360. \pn{} uses a number of notations that I have found useful in making clear the
  361. intent of the code. For example, a common mistake in \CPLUSPLUS/ \kern-0.5em
  362. code is the confusion of assignment ({\tt =}) with a test for equality
  363. ({\tt ==}). The \web{} convention of using |=| for assignment and |==| to test
  364. for equality makes such errors obvious at a glance. A list of special symbols
  365. and the equivalent \CPLUSPLUS/text is provided in Table \secno. Most of these
  366. symbols should be familiar\nfnote{The {\tt NULL} symbol is a break with the
  367. conventions of most Qt applications. According the the \CPLUSPLUS/standard, |0|
  368. is both an integer constant and a null pointer constant. Most programs using Qt
  369. use |0| in place of any name for the null pointer, however conceptually these
  370. are two very different things. The notation chosen here was used by Knuth for
  371. similar purposes and seems to have worked well there.}.
  372. \medskip
  373. \settabs 9 \columns
  374. \+&&&{\tt =}&|=|&Assignment\cr
  375. \+&&&{\tt --}&|--|&Decrement\cr
  376. \+&&&{\tt ==}&|==|&Equality Test\cr
  377. \+&&&{\tt >=}&|>=|&Greater or Equal Test\cr
  378. \+&&&{\tt ++}&|++|&Increment\cr
  379. \+&&&{\tt !=}&|!=|&Inequality Test\cr
  380. \+&&&{\tt <=}&|<=|&Less or Equal Test\cr
  381. \+&&&{\tt \char'046\char'046}&$\land$&Logical AND\cr
  382. \+&&&{\tt \char'174\char'174}&$\lor$&Logical OR\cr
  383. \+&&&{\tt ::}&|::|&Member of\cr
  384. \+&&&{\tt !}&|!|&Negation\cr
  385. \+&&&{\tt NULL}&|NULL|&Null Pointer\cr
  386. \+&&&{\tt this}&|this|&Object\cr
  387. \+&&&{\tt \%}&|%|&Remainder\cr
  388. \+&&&{\tt tr()}&|tr()|&Translate\cr
  389. \smallskip
  390. \centerline{Table \secno: Special Characters In \pn}
  391. \medskip
  392. Reserved words are set in bold face. As some of these reserved words are also
  393. the names of types, type names that are not specified in \CPLUSPLUS/are also
  394. set in bold face. Type placeholders in template definitions, however, are set in
  395. caligraphic capitals to emphasize that it will be replaced with a real type at
  396. compile time. Variables and class members are set in italics, character strings
  397. are set in a typewriter style with visible spaces. Macro names are also set in
  398. typewriter style. Numeric constants and plain text comments are set in an
  399. upright roman style. Comments containing \CEE/ or mathematics are styled as
  400. such. Code that will be interpreted by the ECMA-262 host environment has no
  401. pretty printing.
  402. \danger With apologies to prof.~Knuth\nfnote{This symbol was introduced in
  403. {\underbar{Computers~\char'046~Typesetting}}@q'@> (Knuth, 1984) to point out material
  404. that is for ``wizards only.'' It seems to be as appropriate a symbol as any to
  405. point out the darker corners of this program.}, code that is known to be
  406. potentially buggy is flagged with a dangerous bend sign. Some of this code is
  407. buggy due to issues with the code \pn{} depends on, others are things that
  408. should be fixed in \pn{}. Of course, there may also be bugs that have not yet
  409. been noticed or have not been attached to a particular block of code.\endanger
  410. A basic familiarity with literate programming techniques (particularly the
  411. conventions of \cweb{}), Qt, and \CPLUSPLUS/is recommended before altering the
  412. program, but an effort has been made to keep the program understandable for
  413. those who are only interested in studying it.
  414. @** Introduction.
  415. \noindent A common tool in the craft of coffee roasting is the data logger.
  416. Perhaps the most commonly used of these fall into the category of manual data
  417. loggers which require the roaster to use paper and a writing utensil,
  418. periodically recording measurements and noting control changes and observations
  419. of interest as needed.
  420. While there are many benefits to recording roast data\nfnote{Torrey Lee, Stephan
  421. Diedrich, Carl Staub, and Jack Newall, ``How to Obtain Excellence with Drum
  422. Roasters'' (2002) {\it Specialty Coffee Association of America 14$^{th}$ Annual
  423. Conference and Exhibition}}, there are a number of limitations to the manual
  424. approach; maintaining the records in a useful order is time consuming and error
  425. prone, it is difficult to work with aggregates of such records, and the
  426. attention required to log the data by hand can distract from the roasting. Using
  427. a computer with automatic data logging software designed with coffee roasting in
  428. mind can reduce or eliminate these deficiencies. \pn{} is one such program.
  429. The file {\tt \filebase.w} contains both \CPLUSPLUS/source code and the
  430. documentation for that code. This file is intended to be processed by
  431. \cweb\nfnote{Donald E. Knuth and Silvio Levy, ``The \cweb{} System of Structured
  432. Documentation'' (1994)}~to produce source code for your compiler and plain
  433. \TeX{}\nfnote{\TeX{} (pronounced $\tau\epsilon\chi$) is a trademark of the
  434. American Mathematical Society.} documentation that can be used to generate a PDF
  435. document for gorgeous printable documentation. These generated files may have
  436. been distributed with your copy of {\tt \filebase.w} for convenience.
  437. Changes to the program can be made in three ways. \cweb{} provides a patching
  438. mechanism which can be used to experiment with the code without risk of
  439. clobbering it. Instructions for the construction of such a change file can be
  440. found in the \cweb{} documentation. Adding the name of the change file to the
  441. invocation of {\tt ctangle} and {\tt cweave} will incorporate that change
  442. seamlessly in both source and documentation files. A section is provided at the
  443. end of this program for use with this mechanism in the case that new sections
  444. must be added. Another way to create persistent modifications is to alter
  445. {\tt \filebase.w} however this may make it more difficult to use changes with
  446. future versions of the software. Changes should not be made to
  447. {\tt \filebase.cpp} if these changes are expected to persist. Finally, it is
  448. possible to make many changes to how the program looks and behaves by creating a
  449. new configuration document for the program to load. Modifications made in this
  450. way do not even require recompiling the software. Examples that can serve as a
  451. starting point for such customizations are provided with \pn{}.
  452. \pn{} is a work in progress. There are several portions of the documentation
  453. that contain suggestions for future improvement. These notes provide clues for
  454. my future development plans. Naturally, if you have needs which are not quite
  455. addressed by this program, you should feel free to modify the code to suit your
  456. needs. Hopefully this will be easy to do.
  457. In the spirit of Benjamin Franklin\nfnote{``\dots as we enjoy great advantages
  458. from the inventions of others, we should be glad of an opportunity to serve
  459. others by any invention of ours; and this we should do freely and
  460. generously.''
  461. --- Benjamin Franklin, \underbar{The Private Life of the Late
  462. Benjamin Franklin, LL.D.~Originally
  463. Written By Himself, And Now}\par\noindent
  464. \underbar{Translated From The French} (1793)}, \pn{} is shared
  465. with minimal restriction (see the license after the table of contents for legal
  466. requirements). Libraries used by \pn{} may have other restrictions. Before
  467. undertaking to distribute a binary created from this code, you may want to
  468. either determine your rights with regard to these libraries or modify the
  469. program to remove them.
  470. As CWEB generates files with the wrong extension, we leave the default
  471. generated file empty.
  472. @c
  473. /* Nothing to see here. */
  474. @ The following is an overview of the structure of \pn:
  475. @(typica.cpp@>=
  476. #define PROGRAM_NAME "Typica"
  477. @<Header files to include@>@/
  478. @<Additional type definitions@>@/
  479. @<Additional function prototypes@>@/
  480. @<Class declarations@>@/
  481. @<Additional functions@>@/
  482. @<Function prototypes for scripting@>@/
  483. @<Logging function prototype@>@/
  484. @<Class implementations@>@/
  485. @<Functions for scripting@>@/
  486. @<Logging function implementation@>@/
  487. @<The main program@>
  488. #include "moc_typica.cpp"
  489. @ \pn{} is made of a number of distinct classes.
  490. @<Class implementations@>=
  491. @<NodeInserter implementation@>@/
  492. @<Measurement implementation@>@/
  493. @<DAQ Implementation@>@/
  494. @<DataqSdkDevice implementation@>@/
  495. @<FakeDAQ Implementation@>@/
  496. @<Channel Implementation@>@/
  497. @<TemperatureDisplay Implementation@>@/
  498. @<MeasurementTimeOffset Implementation@>@/
  499. @<ZeroEmitter Implementation@>@/
  500. @<MeasurementAdapter Implementation@>@/
  501. @<GraphView Implementation@>@/
  502. @<ZoomLog Implementation@>@/
  503. @<MeasurementModel Implementation@>@/
  504. @<AnnotationButton Implementation@>@/
  505. @<AnnotationSpinBox Implementation@>@/
  506. @<TimerDisplay Implementation@>@/
  507. @<PackLayout Implementation@>@/
  508. @<SceneButton Implementation@>@/
  509. @<WidgetDecorator Implementation@>@/
  510. @<LogEditWindow Implementation@>@/
  511. @<XMLOutput Implementation@>@/
  512. @<XMLInput Implementation@>@/
  513. @<CSVOutput Implementation@>@/
  514. @<SaltModel Implementation@>@/
  515. @<SqlComboBox Implementation@>@/
  516. @<SqlComboBoxDelegate Implementation@>@/
  517. @<Application Implementation@>@/
  518. @<SqlConnectionSetup implementation@>@/
  519. @<SqlQueryView implementation@>@/
  520. @<SqlQueryConnection implementation@>@/
  521. @<ReportTable implementation@>@/
  522. @<FormArray implementation@>@/
  523. @<ScaleControl implementation@>@/
  524. @<IntensityControl implementation@>@/
  525. @<ThresholdDetector Implementation@>@/
  526. @<PortSelector implementation@>@/
  527. @<BaudSelector implementation@>@/
  528. @<ParitySelector implementation@>@/
  529. @<FlowSelector implementation@>@/
  530. @<StopSelector implementation@>@/
  531. @<ModbusConfigurator implementation@>@/
  532. @<ShortHexSpinBox implementation@>@/
  533. @<ModbusRTUDevice implementation@>@/
  534. @<DeviceTreeModelNode implementation@>@/
  535. @<DeviceTreeModel implementation@>@/
  536. @<BasicDeviceConfigurationWidget implementation@>@/
  537. @<DeviceConfigurationWindow implementation@>@/
  538. @<Ni9211TcConfWidget implementation@>@/
  539. @<NiDaqMxBase9211ConfWidget implementation@>@/
  540. @<NiDaqMxBaseDriverConfWidget implementation@>@/
  541. @<ReportAction implementation@>@/
  542. @<NumericDelegate implementation@>@/
  543. @<NiDaqMxDriverConfWidget implementation@>@/
  544. @<NiDaqMx9211ConfWidget implementation@>@/
  545. @<NiDaqMxTc01ConfWidget implementation@>@/
  546. @<ModbusRtuPortConfWidget implementation@>@/
  547. @<ModbusRtuDeviceConfWidget implementation@>@/
  548. @<ModbusRtuDeviceTPvConfWidget implementation@>@/
  549. @<ModbusRtuDeviceTSvConfWidget implementation@>@/
  550. @<RoasterConfWidget implementation@>@/
  551. @<AnnotationButtonConfWidget implementation@>@/
  552. @<NoteSpinConfWidget implementation@>@/
  553. @<LinearCalibrator Implementation@>@/
  554. @<LinearSplineInterpolator Implementation@>@/
  555. @<LinearSplineInterpolationConfWidget implementation@>@/
  556. @<TranslationConfWidget implementation@>@/
  557. @<FreeAnnotationConfWidget implementation@>@/
  558. @<RateOfChange implementation@>@/
  559. @<SettingsWindow implementation@>@/
  560. @<GraphSettingsWidget implementation@>@/
  561. @<DataqSdkDeviceConfWidget implementation@>@/
  562. @<SerialScaleConfWidget implementation@>@/
  563. @<ValueAnnotation implementation@>@/
  564. @<ValueAnnotationConfWidget implementation@>@/
  565. @<ModbusNG implementation@>@/
  566. @<ThresholdAnnotationConfWidget implementation@>@/
  567. @<Annotator implementation@>@/
  568. @ A few headers are required for various parts of \pn{}. These allow the use of
  569. various Qt modules.
  570. @<Header files to include@>=
  571. #include <QtCore>
  572. #include <QtGui>
  573. #include <QtScript>
  574. #include <QtScriptTools>
  575. #include <QtXml>
  576. #include <QtSql>
  577. #include <QtDebug>
  578. #include <QtXmlPatterns>
  579. #include <QtWebKit>
  580. #include <QtSvg>
  581. #include <QtNetwork>
  582. @ New code is being written in separate files in a long term effort to improve
  583. organization of the code. The result of this is that some additional headers
  584. are required here.
  585. @<Header files to include@>=
  586. #include "helpmenu.h"
  587. @** The Scripting Engine.
  588. \noindent The main enhancement of \pn{} version 1.1 is the introduction of a
  589. scriptable environment. This change allows people to easily customize \pn{}
  590. without having to alter the program code. Instead, the user interface and
  591. program data flow is set up with a small script that runs in an ECMA-262 host
  592. environment\nfnote{Standard ECMA-262, 3$^{\rm{rd}}$ Edition\par\hbox{\indent%
  593. \pdfURL{%
  594. http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf}%
  595. {http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf}}}
  596. which requires
  597. significantly less expertise to modify than \pn{} itself. Such a scripting
  598. environment will be familiar to anybody with experience using JavaScript on web
  599. pages or ActionScript in Flash. \pn{}'@q'@>s configuration system was later updated
  600. to support running several script fragments found in an XML configuration
  601. document.
  602. Most of the application classes are available from the scripting environment.
  603. The functions that make this possible are presented along with the classes. A
  604. selection of classes provided by Qt are also available. These are presented
  605. here.
  606. This chunk provides two |QScriptValue| objects which are used in other sections
  607. appended to this chunk.
  608. @<Set up the scripting engine@>=
  609. QScriptEngine *engine = new QScriptEngine;
  610. QScriptValue constructor;
  611. QScriptValue value;
  612. @ A common task when working with objects created from a script is finding the
  613. object a method is called on from the current script context. The code for this
  614. is simple, but lengthy. This is shortened with the use of a template function
  615. that obtains the object in question and casts it to the appropriate type. If an
  616. incorrect type is specified, a null pointer or similarly invalid value will be
  617. returned.
  618. @<Functions for scripting@>=
  619. template<class TYPE> TYPE@, getself(QScriptContext *context)
  620. {
  621. TYPE@, self = qobject_cast<TYPE>(context->thisObject().toQObject());
  622. return self;
  623. }
  624. template<> QTime getself(QScriptContext *context)
  625. {
  626. QTime self = context->thisObject().toVariant().toTime();
  627. return self;
  628. }
  629. template<> QModelIndex getself(QScriptContext *context)
  630. {
  631. QModelIndex self = context->thisObject().toVariant().value<QModelIndex>();
  632. return self;
  633. }
  634. template<> QByteArray getself(QScriptContext *context)
  635. {
  636. QByteArray self = context->thisObject().toVariant().toByteArray();
  637. return self;
  638. }
  639. template<> SqlQueryConnection* getself(QScriptContext *context)
  640. {
  641. SqlQueryConnection *self =@|
  642. (SqlQueryConnection *)qscriptvalue_cast<void *>(context->thisObject());
  643. return self;
  644. }
  645. template<> QXmlQuery* getself(QScriptContext *context)
  646. {
  647. QXmlQuery *self =
  648. (QXmlQuery *)qscriptvalue_cast<void *>(context->thisObject());
  649. return self;
  650. }
  651. template<> QXmlStreamWriter* getself(QScriptContext *context)
  652. {
  653. QXmlStreamWriter *self = @|
  654. (QXmlStreamWriter *)qscriptvalue_cast<void *>(context->thisObject());
  655. return self;
  656. }
  657. template<> QXmlStreamReader* getself(QScriptContext *context)
  658. {
  659. QXmlStreamReader *self = @|
  660. (QXmlStreamReader *)qscriptvalue_cast<void *>(context->thisObject());
  661. return self;
  662. }
  663. @ Another common task is obtaining the arguments of a method call from the
  664. script context and casting these arguments to the proper type. This is once
  665. again done with templates.
  666. @<Functions for scripting@>=
  667. template<class TYPE> TYPE@, argument(int arg, QScriptContext *context)
  668. {
  669. TYPE@, argument = qobject_cast<TYPE>(context->argument(arg).toQObject());
  670. return argument;
  671. }
  672. template<> QString argument(int arg, QScriptContext *context)
  673. {
  674. return context->argument(arg).toString();
  675. }
  676. template<> QVariant argument(int arg, QScriptContext *context)
  677. {
  678. return context->argument(arg).toVariant();
  679. }
  680. template<> int argument(int arg, QScriptContext *context)
  681. {
  682. return context->argument(arg).toInt32();
  683. }
  684. template<> SqlQueryConnection* argument(int arg, QScriptContext *context)
  685. {
  686. return (SqlQueryConnection *)
  687. qscriptvalue_cast<void *>(context->argument(arg));
  688. }
  689. template<> QModelIndex argument(int arg, QScriptContext *context)
  690. {
  691. return qscriptvalue_cast<QModelIndex>(context->argument(arg));
  692. }
  693. template<> double argument(int arg, QScriptContext *context)
  694. {
  695. return (double)(context->argument(arg).toNumber());
  696. }
  697. template<> Units::Unit argument(int arg, QScriptContext *context)
  698. {
  699. return (Units::Unit)(context->argument(arg).toInt32());
  700. }
  701. template<> QByteArray argument(int arg, QScriptContext *context)
  702. {
  703. return qscriptvalue_cast<QByteArray>(context->argument(arg));
  704. }
  705. template<> bool argument(int arg, QScriptContext *context)
  706. {
  707. return context->argument(arg).toBool();
  708. }
  709. @ The scripting engine is informed of a number of classes defined elsewhere in
  710. the program. Code related to scripting these classes is grouped with the code
  711. implementing the classes. Additionally, there are several classes from Qt which
  712. are also made scriptable. These are detailed in the following sections.
  713. @* Exposing an Object Hierarchy to the Host Environment.
  714. \noindent While QtScript does a generally acceptable job of exposing
  715. information about objects that are available through the meta-object system,
  716. some methods require special handling in order to make them fully available to
  717. the host environment. Several functions are provided which provide a
  718. |QScriptValue| with these additional properties. The functions providing these
  719. properties also call other functions providing the properties of any base
  720. classes. In this way, any additional functionality provided to the host
  721. environment for a base class is also provided for any class that inherits that
  722. base class.
  723. For example, a |QBoxLayout| created in a script will have properties from
  724. |QLayout| which in turn brings in properties from |QObject| and |QLayoutItem|.
  725. A |QMainWindow| would bring in properties from |QWidget| which would bring in
  726. properties from |QObject|.
  727. Neither all methods nor all Qt classes are available from the host environment.
  728. When adding functionality to the host environment, there is a priority on
  729. classes and methods that are useful for \pn{}'@q'@>s intended purpose.
  730. @* Base Classes.
  731. \noindent There are a few classes that are base classes of classes exposed to
  732. the scripting engine. There is no need for the host environment to allow the
  733. creation of these base classes and there may not be methods that must be added
  734. as properties in derived classes, however stub functions are provided so that
  735. in the event that a method from one of these base classes is needed later, it
  736. can be added once for all derived classes.
  737. The first of these is |QObject|.
  738. @<Function prototypes for scripting@>=
  739. void setQObjectProperties(QScriptValue value, QScriptEngine *engine);
  740. QScriptValue QObject_setProperty(QScriptContext *context, QScriptEngine *engine);
  741. @ Attaching properties to a |QScriptValue| that wraps a |QObject| does not
  742. create a dynamic property on the underlying |QObject| by default. This can
  743. cause issues with certain interactions between script and native code. Rather
  744. than change every wrapper, we can instead expose a |setProperty()| method.
  745. @<Functions for scripting@>=
  746. void setQObjectProperties(QScriptValue value, QScriptEngine *engine)
  747. {
  748. value.setProperty("setProperty", engine->newFunction(QObject_setProperty));
  749. }
  750. QScriptValue QObject_setProperty(QScriptContext *context, QScriptEngine *)
  751. {
  752. QObject *self = getself<QObject *>(context);
  753. self->setProperty(argument<QString>(0, context).toUtf8().constData(),
  754. argument<QVariant>(1, context));
  755. return QScriptValue();
  756. }
  757. @ The same can be done for |QPaintDevice| and |QLayoutItem|.
  758. @<Function prototypes for scripting@>=
  759. void setQPaintDeviceProperties(QScriptValue value, QScriptEngine *engine);
  760. void setQLayoutItemProperties(QScriptValue value, QScriptEngine *engine);
  761. @ The implementations are similarly empty.
  762. @<Functions for scripting@>=
  763. void setQPaintDeviceProperties(QScriptValue, QScriptEngine *)
  764. {
  765. /* Nothing needs to be done here. */
  766. }
  767. void setQLayoutItemProperties(QScriptValue, QScriptEngine *)
  768. {
  769. /* Nothing needs to be done here. */
  770. }
  771. @* Timers.
  772. \noindent Some features in Typica require access to functionality similar to
  773. what |QTimer| provides from the host environment. This includes allowing
  774. script devices to periodically poll connected hardware and allowing a safety
  775. delay on profile translation.
  776. <@Function prototypes for scripting@>=
  777. void setQTimerProperties(QScriptValue value, QScriptEngine *engine);
  778. QScriptValue constructQTimer(QScriptContext *context, QScriptEngine *engine);
  779. @ The host environment is informed of the constructor.
  780. @<Set up the scripting engine@>=
  781. constructor = engine->newFunction(constructQTimer);
  782. value = engine->newQMetaObject(&QTimer::staticMetaObject, constructor);
  783. engine->globalObject().setProperty("Timer", value);
  784. @ Everything that we are interested in here is a signal, slot, or property so
  785. there is little else to do.
  786. @<Functions for scripting@>=
  787. void setQTimerProperties(QScriptValue value, QScriptEngine *engine)
  788. {
  789. setQObjectProperties(value, engine);
  790. }
  791. QScriptValue constructQTimer(QScriptContext *, QScriptEngine *engine)
  792. {
  793. QScriptValue object = engine->newQObject(new QTimer);
  794. setQTimerProperties(object, engine);
  795. return object;
  796. }
  797. @* Scripting QWidget.
  798. \noindent The first interesting class in this hierarchy is |QWidget|. This is
  799. mainly used as a base class for other widgets and in such a role it is not
  800. particularly interesting. It is, however, possible to apply a layout to a
  801. |QWidget| and use that to manage the size and position of one or more child
  802. widgets. A few functions are used to accomplish this.
  803. @<Function prototypes for scripting@>=
  804. void setQWidgetProperties(QScriptValue value, QScriptEngine *engine);
  805. QScriptValue constructQWidget(QScriptContext *context, QScriptEngine *engine);
  806. QScriptValue QWidget_setLayout(QScriptContext *context, QScriptEngine *engine);
  807. QScriptValue QWidget_activateWindow(QScriptContext *context,
  808. QScriptEngine *engine);
  809. @ The script constructor must be passed to the scripting engine.
  810. @<Set up the scripting engine@>=
  811. constructor = engine->newFunction(constructQWidget);
  812. value = engine->newQMetaObject(&QWidget::staticMetaObject, constructor);
  813. engine->globalObject().setProperty("QWidget", value);
  814. @ The constructor creates a script value, but uses another function to add
  815. properties that wrap methods we want to make available to subclasses. Note that
  816. properties of the base classes are added before properties of this class. This
  817. procedure ensures that properties added from base classes can be be replaced in
  818. subclasses.
  819. @<Functions for scripting@>=
  820. QScriptValue constructQWidget(QScriptContext *, QScriptEngine *engine)
  821. {
  822. QScriptValue object = engine->newQObject(new QWidget);
  823. setQWidgetProperties(object, engine);
  824. return object;
  825. }
  826. void setQWidgetProperties(QScriptValue value, QScriptEngine *engine)
  827. {
  828. setQObjectProperties(value, engine);
  829. setQPaintDeviceProperties(value, engine);
  830. value.setProperty("setLayout", engine->newFunction(QWidget_setLayout));
  831. value.setProperty("activateWindow",
  832. engine->newFunction(QWidget_activateWindow));
  833. }
  834. @ This just leaves the property implementations. |QWidget::setLayout()| takes
  835. one argument, a |QLayout| and returns |void|. This wrapper duplicates this
  836. interface. |QWidget::activateWindow()| takes no arguments and returns nothing
  837. meaningful.
  838. @<Functions for scripting@>=
  839. QScriptValue QWidget_setLayout(QScriptContext *context, QScriptEngine *)
  840. {
  841. if(context->argumentCount() == 1)
  842. {
  843. QWidget *self = getself<QWidget *>(context);
  844. QLayout *layout = argument<QLayout *>(0, context);
  845. if(layout)
  846. {
  847. self->setLayout(layout);
  848. }
  849. else
  850. {
  851. context->throwError("Incorrect argument type passed to "@|
  852. "QWidget::setLayout(). This method requires "@|
  853. "a QLayout.");
  854. }
  855. }
  856. else
  857. {
  858. context->throwError("Incorrect number of arguments passed to "@|
  859. "QWidget::setLayout(). This method takes one "@|
  860. "QLayout as an argument.");
  861. }
  862. return QScriptValue();
  863. }
  864. QScriptValue QWidget_activateWindow(QScriptContext *context,
  865. QScriptEngine *)
  866. {
  867. QWidget *self = getself<QWidget *>(context);
  868. self->activateWindow();
  869. return QScriptValue();
  870. }
  871. @* Scripting QMessageBox.
  872. \noindent Some features require that \pn{} pauses an operation until further
  873. information can be obtained. An example of this is discretionary validation
  874. where input is checked and if it seems unlikely but not impossible to be
  875. correct a dialog should come up asking if that input is correct. If it is not,
  876. the operation should be cancelled and the person using \pn{} should be allowed
  877. to correct the information and try again.
  878. For this use case, it is not necessary to fully expose the |QMessageBox| class.
  879. Instead, it is enough to provide a function that will raise an appropriate
  880. message and return the selected action.
  881. @<Function prototypes for scripting@>=
  882. QScriptValue displayWarning(QScriptContext *context, QScriptEngine *engine);
  883. QScriptValue displayError(QScriptContext *context, QScriptEngine *engine);
  884. QScriptValue displayInfo(QScriptContext *context, QScriptEngine *engine);
  885. @ This function is exposed to the host environment.
  886. @<Set up the scripting engine@>=
  887. constructor = engine->newFunction(displayWarning);
  888. engine->globalObject().setProperty("displayWarning", constructor);
  889. constructor = engine->newFunction(displayError);
  890. engine->globalObject().setProperty("displayError", constructor);
  891. constructor = engine->newFunction(displayInfo);
  892. engine->globalObject().setProperty("displayInfo", constructor);
  893. @ The function takes some arguments.
  894. @<Functions for scripting@>=
  895. QScriptValue displayWarning(QScriptContext *context, QScriptEngine *)
  896. {
  897. QMessageBox::StandardButton selection = QMessageBox::warning(NULL,
  898. argument<QString>(0, context),
  899. argument<QString>(1, context),
  900. QMessageBox::Ok | QMessageBox::Cancel);
  901. if(selection == QMessageBox::Ok) {
  902. return QScriptValue(true);
  903. }
  904. return QScriptValue(false);
  905. }
  906. QScriptValue displayError(QScriptContext *context, QScriptEngine *)
  907. {
  908. QMessageBox::critical(NULL, argument<QString>(0, context),
  909. argument<QString>(1, context));
  910. return QScriptValue();
  911. }
  912. QScriptValue displayInfo(QScriptContext *context, QScriptEngine *)
  913. {
  914. QMessageBox::information(NULL, argument<QString>(0, context),
  915. argument<QString>(1, context));
  916. return QScriptValue();
  917. }
  918. @* Scripting QMainWindow.
  919. \noindent Rather than directly exposing |QMainWindow| to the scripting engine,
  920. we expose a class derived from |QMainWindow| with a minor change allowing the
  921. script to be notified when the window is about to be closed.
  922. This allows us to save settings for objects populating the window. Close
  923. handlers can be established by connecting to the |aboutToClose()| signal which
  924. is emitted in the |closeEvent()| handler. The close event is always accepted
  925. after the script has had a chance to respond, so this cannot be used to present
  926. an, ``Are you sure?'' message without additional modification.
  927. Slots are also provided for saving the size and position of the window to
  928. settings and restoring the window geometry from these settings.
  929. As of version 1.4 window geometry management is provided for all windows. The
  930. |restoreSizeAndPosition()| and |saveSizeAndPosition()| methods should be
  931. considered depreciated.
  932. Version 1.6 adds a new property for handling the |windowModified| property
  933. such that an appropriate prompt is provided to confirm or cancel close events.
  934. Version 1.8 adds a new |setupFinished()| slot which is called after the
  935. initial |show()| at the end of window creation. This emits a |windowReady()|
  936. signal. Scripts can connect to this signal to perform tasks that must happen
  937. after the window has fully finished opening. The initial use for this is
  938. validating that all required configuration has been performed for a given
  939. window to be useful and, if not, immediately closing that. Without this, a
  940. call to |close()| in the script is reversed when the function creating the
  941. window calls |show()|.
  942. @<Class declarations@>=
  943. class ScriptQMainWindow : public QMainWindow@/
  944. {@t\1@>@/
  945. Q_OBJECT@;@/
  946. Q_PROPERTY(QString closePrompt READ closePrompt WRITE setClosePrompt)@;@/
  947. public:@/
  948. ScriptQMainWindow();
  949. QString closePrompt();@/
  950. @t\4@>public slots@t\kern-3pt@>:@/
  951. void show();
  952. void saveSizeAndPosition(const QString &key);
  953. void restoreSizeAndPosition(const QString &key);
  954. void displayStatus(const QString &message = QString());
  955. void setClosePrompt(QString prompt);
  956. void setupFinished();@/
  957. signals:@/
  958. void aboutToClose(void);
  959. void windowReady(void);@/
  960. protected:@/
  961. void closeEvent(QCloseEvent *event);
  962. void showEvent(QShowEvent *event);@/
  963. private:@/
  964. QString cprompt;@t\2@>@/
  965. }@t\kern-3pt@>;
  966. @ The implementation of these functions is simple.
  967. @<Functions for scripting@>=
  968. ScriptQMainWindow::ScriptQMainWindow()@+: QMainWindow(NULL),
  969. cprompt(tr("Closing this window may result in loss of data. Continue?"))@/
  970. {
  971. if(!AppInstance->databaseConnected())
  972. {
  973. statusBar()->addWidget(new QLabel(tr("Not connected to database")));
  974. }
  975. else
  976. {
  977. statusBar()->addWidget(new UserLabel);
  978. }
  979. }
  980. void ScriptQMainWindow::saveSizeAndPosition(const QString &key)
  981. {
  982. QSettings settings;
  983. settings.beginGroup(key);
  984. settings.setValue("pos", pos());
  985. settings.setValue("size", size());
  986. settings.endGroup();
  987. }
  988. void ScriptQMainWindow::restoreSizeAndPosition(const QString &key)
  989. {
  990. QSettings settings;
  991. settings.beginGroup(key);
  992. if(settings.contains("size"))
  993. {
  994. resize(settings.value("size").toSize());
  995. }
  996. if(settings.contains("pos"))
  997. {
  998. move(settings.value("pos").toPoint());
  999. }
  1000. settings.endGroup();
  1001. }
  1002. void ScriptQMainWindow::displayStatus(const QString &message)
  1003. {
  1004. statusBar()->showMessage(message);
  1005. }
  1006. void ScriptQMainWindow::showEvent(QShowEvent *event)
  1007. {
  1008. if(!event->spontaneous())
  1009. {
  1010. @<Restore window geometry@>@;
  1011. event->accept();
  1012. }
  1013. else
  1014. {
  1015. event->ignore();
  1016. }
  1017. }
  1018. void ScriptQMainWindow::show()
  1019. {
  1020. QMainWindow::show();
  1021. }
  1022. void ScriptQMainWindow::setupFinished()
  1023. {
  1024. emit windowReady();
  1025. }
  1026. @ When a close event occurs, we check the |windowModified| property to
  1027. determine if closing the window could result in loss of data. If this is
  1028. true, we allow the event to be cancelled. Otherwise, a signal is emitted which
  1029. allows scripts to perform any cleanup that may be required before closing the
  1030. window and the window geometry data is saved before allowing the window to
  1031. close.
  1032. @<Functions for scripting@>=
  1033. void ScriptQMainWindow::closeEvent(QCloseEvent *event)
  1034. {
  1035. if(isWindowModified()) {
  1036. @<Allow close event to be cancelled@>@;
  1037. }
  1038. emit aboutToClose();
  1039. @<Save window geometry@>@;
  1040. event->accept();
  1041. }
  1042. @ The prompt text for our confirmation window is provided through the
  1043. |closePrompt| property.
  1044. @<Allow close event to be cancelled@>=
  1045. QMessageBox::StandardButton result;
  1046. result = QMessageBox::warning(this, "Typica", closePrompt(),
  1047. QMessageBox::Ok | QMessageBox::Cancel);
  1048. if(result == QMessageBox::Cancel)
  1049. {
  1050. event->ignore();
  1051. return;
  1052. }
  1053. @ Implementation of the |closePrompt| property is trivial.
  1054. @<Functions for scripting@>=
  1055. QString ScriptQMainWindow::closePrompt()
  1056. {
  1057. return cprompt;
  1058. }
  1059. void ScriptQMainWindow::setClosePrompt(QString prompt)
  1060. {
  1061. cprompt = prompt;
  1062. }
  1063. @ Window geometry management from version 1.4 on makes use of the window ID to
  1064. produce an appropriate QSettings key. This decision relies on the ID being set
  1065. before any show or close events are received and it relies on every distinct
  1066. type of window having a unique ID. If this is not the case then other things
  1067. are likely very broken. Note that with this approach multiple instances of the
  1068. same type of window will use the same key. This may not be ideal in all cases,
  1069. but further refinements can be produced if necessary.
  1070. @<Save window geometry@>=
  1071. QSettings settings;
  1072. settings.setValue(QString("geometries/%1").arg(objectName()), saveGeometry());
  1073. @ Restoring saved geometry is performed similarly to saving it.
  1074. @<Restore window geometry@>=
  1075. QSettings settings;
  1076. restoreGeometry(settings.value(QString("geometries/%1").arg(objectName())).
  1077. toByteArray());
  1078. @ Three functions are required to obtain the required functionality from a
  1079. script. A fourth adds properties for the object hierarchy.
  1080. @<Function prototypes for scripting@>=
  1081. QScriptValue constructQMainWindow(QScriptContext *context,
  1082. QScriptEngine *engine);
  1083. QScriptValue QMainWindow_setCentralWidget(QScriptContext *context,@|
  1084. QScriptEngine *engine);
  1085. QScriptValue QMainWindow_menuBar(QScriptContext *context,
  1086. QScriptEngine *engine);
  1087. void setQMainWindowProperties(QScriptValue value, QScriptEngine *engine);
  1088. @ Of these, the engine only needs to be informed of the constructor initially.
  1089. @<Set up the scripting engine@>=
  1090. constructor = engine->newFunction(constructQMainWindow);
  1091. value = engine->newQMetaObject(&ScriptQMainWindow::staticMetaObject,
  1092. constructor);
  1093. engine->globalObject().setProperty("QMainWindow", value);
  1094. @ The constructor calls a function to add the additional properties to the
  1095. newly created value.
  1096. @<Functions for scripting@>=
  1097. QScriptValue constructQMainWindow(QScriptContext *, QScriptEngine *engine)
  1098. {
  1099. QScriptValue object = engine->newQObject(new ScriptQMainWindow);
  1100. setQMainWindowProperties(object, engine);
  1101. return object;
  1102. }
  1103. void setQMainWindowProperties(QScriptValue value, QScriptEngine *engine)
  1104. {
  1105. setQWidgetProperties(value, engine);
  1106. value.setProperty("setCentralWidget",
  1107. engine->newFunction(QMainWindow_setCentralWidget));
  1108. value.setProperty("menuBar", engine->newFunction(QMainWindow_menuBar));
  1109. }
  1110. @ The |"setCentralWidget"| property is used for setting a widget in the main
  1111. area of the window. In \pn{} this will usually be a |QSplitter| object, but it
  1112. could also be a bare |QWidget| with a layout managing multiple widgets or a
  1113. custom widget defined in a local change. This is a simple wrapper around
  1114. |QMainWindow::setCentralWidget()|.
  1115. @<Functions for scripting@>=
  1116. QScriptValue QMainWindow_setCentralWidget(QScriptContext *context,
  1117. QScriptEngine *)
  1118. {
  1119. if(context->argumentCount() == 1)
  1120. {
  1121. QMainWindow *self = getself<QMainWindow *>(context);
  1122. QWidget *widget = argument<QWidget *>(0, context);
  1123. if(widget)
  1124. {
  1125. self->setCentralWidget(widget);
  1126. }
  1127. else
  1128. {
  1129. context->throwError("Incorrect argument type passed to "@|
  1130. "QMainWindow::setCentralWidget(). This "@|
  1131. "method requires a QWidget.");
  1132. }
  1133. }
  1134. else
  1135. {
  1136. context->throwError("Incorrect number of arguments passed to "@|
  1137. "QMainWindow::setCentralWidget(). This method "@|
  1138. "takes one QWidget as an argument.");
  1139. }
  1140. return QScriptValue();
  1141. }
  1142. @ The |"menuBar"| property requires that we expose |QMenuBar| to the scripting
  1143. environment in a limited fashion. We don'@q'@>t need to allow scripts to create a
  1144. new menu bar as it can be obtained from the window, however to add the menus to
  1145. the menu bar, we need to add a property to the |QMenuBar| object before passing
  1146. it back.
  1147. @<Functions for scripting@>=
  1148. QScriptValue QMainWindow_menuBar(QScriptContext *context, QScriptEngine *engine)
  1149. {
  1150. QScriptValue object;
  1151. if(context->argumentCount() == 0)
  1152. {
  1153. QMainWindow *self = getself<@[QMainWindow *@]>(context);
  1154. QMenuBar *bar = self->menuBar();
  1155. object = engine->newQObject(bar);
  1156. setQMenuBarProperties(object, engine);
  1157. }
  1158. else
  1159. {
  1160. context->throwError("Incorrect number of arguments passed to "@|
  1161. "QMainWindow::menuBar(). This method takes no "@|
  1162. "arguments.");
  1163. }
  1164. return object;
  1165. }
  1166. @ The previous function is the only place a new |QMenuBar| is created through
  1167. the host environment. Two functions are used in handling this object creation.
  1168. @<Function prototypes for scripting@>=
  1169. void setQMenuBarProperties(QScriptValue value, QScriptEngine *engine);
  1170. QScriptValue QMenuBar_addMenu(QScriptContext *context, QScriptEngine *engine);
  1171. @ The first of these adds the appropriate properties to the newly created
  1172. object.
  1173. @<Functions for scripting@>=
  1174. void setQMenuBarProperties(QScriptValue value, QScriptEngine *engine)
  1175. {
  1176. setQWidgetProperties(value, engine);
  1177. value.setProperty("addMenu", engine->newFunction(QMenuBar_addMenu));
  1178. }
  1179. @ This function can be used to add new menus to a menu bar. In order to do
  1180. anything with the newly created menus, two properties are added to the |QMenu|
  1181. objects which allow actions to be added as menu items and allow separators to be
  1182. placed between groups of menu items.
  1183. At the time of this writing, there are three |QMenuBar::addMenu()| methods. This
  1184. function wraps |QMenu* QMenuBar::addMenu(const QString &title)|.
  1185. @<Functions for scripting@>=
  1186. QScriptValue QMenuBar_addMenu(QScriptContext *context, QScriptEngine *engine)
  1187. {
  1188. QScriptValue object;
  1189. if(context->argumentCount() == 1)
  1190. {
  1191. QMenuBar *self = getself<@[QMenuBar *@]>(context);
  1192. QString title = argument<QString>(0, context);
  1193. object = engine->newQObject(self->addMenu(title));
  1194. setQMenuProperties(object, engine);
  1195. }
  1196. else
  1197. {
  1198. context->throwError("Incorrect number of arguments passed to "@|
  1199. "QMenuBar::addMenu(). This method takes one "@|
  1200. "string as an argument.");
  1201. }
  1202. return object;
  1203. }
  1204. @ These three functions allow adding items to the menu and adding separators
  1205. between groups of items.
  1206. @<Function prototypes for scripting@>=
  1207. void setQMenuProperties(QScriptValue value, QScriptEngine *engine);
  1208. QScriptValue QMenu_addAction(QScriptContext *context, QScriptEngine *engine);
  1209. QScriptValue QMenu_addSeparator(QScriptContext *context, QScriptEngine *engine);
  1210. @ The first of these add properties to newly created |QMenu| objects.
  1211. @<Functions for scripting@>=
  1212. void setQMenuProperties(QScriptValue value, QScriptEngine *engine)
  1213. {
  1214. setQWidgetProperties(value, engine);
  1215. value.setProperty("addAction", engine->newFunction(QMenu_addAction));
  1216. value.setProperty("addSeparator", engine->newFunction(QMenu_addSeparator));
  1217. }
  1218. @ These functions are simple wrappers around |QMenu| methods.
  1219. @<Functions for scripting@>=
  1220. QScriptValue QMenu_addAction(QScriptContext *context, QScriptEngine *)
  1221. {
  1222. if(context->argumentCount() == 1)
  1223. {
  1224. QMenu *self = getself<@[QMenu *@]>(context);
  1225. QAction *action = argument<QAction *>(0, context);
  1226. if(action)
  1227. {
  1228. self->addAction(action);
  1229. }
  1230. else
  1231. {
  1232. context->throwError("Incorrect argument type passed to "@|
  1233. "QMenu::addAction(). This method requires a "@|
  1234. "QAction.");
  1235. }
  1236. }
  1237. else
  1238. {
  1239. context->throwError("Incorrect number of arguments passed to "@|
  1240. "QMenu::addAction(). This method takes one "@|
  1241. "QAction as an argument.");
  1242. }
  1243. return QScriptValue();
  1244. }
  1245. QScriptValue QMenu_addSeparator(QScriptContext *context, QScriptEngine *)
  1246. {
  1247. if(context->argumentCount() == 0)
  1248. {
  1249. QMenu *self = getself<@[QMenu *@]>(context);
  1250. self->addSeparator();
  1251. }
  1252. else
  1253. {
  1254. context->throwError("Incorrect number of arguments passed to "@|
  1255. "QMenu::addSeparator(). This method takes no "@|
  1256. "arguments.");
  1257. }
  1258. return QScriptValue();
  1259. }
  1260. @* Scripting QFrame.
  1261. \noindent |QFrame| is another class for which little needs to be done. It exists
  1262. as a subclass of |QWidget| and a superclass for |QSplitter|, |QLCDNumber|, and
  1263. |QAbstractScrollArea| among other classes.
  1264. @<Function prototypes for scripting@>=
  1265. void setQFrameProperties(QScriptValue value, QScriptEngine *engine);
  1266. QScriptValue constructQFrame(QScriptContext *context, QScriptEngine *engine);
  1267. @ The constructor must be passed to the scripting engine.
  1268. @<Set up the scripting engine@>=
  1269. constructor = engine->newFunction(constructQFrame);
  1270. value = engine->newQMetaObject(&QFrame::staticMetaObject, constructor);
  1271. engine->globalObject().setProperty("QFrame", value);
  1272. @ The implementation of these functions should seem familiar.
  1273. @<Functions for scripting@>=
  1274. QScriptValue constructQFrame(QScriptContext *, QScriptEngine *engine)
  1275. {
  1276. QScriptValue object = engine->newQObject(new QFrame);
  1277. setQFrameProperties(object, engine);
  1278. return object;
  1279. }
  1280. void setQFrameProperties(QScriptValue value, QScriptEngine *engine)
  1281. {
  1282. setQWidgetProperties(value, engine);
  1283. }
  1284. @* Scripting QLabel.
  1285. \noindent When constructing an interface wholly or partially through dynamic
  1286. means rather than entirely through the XML configuration document it can
  1287. sometimes be desirable to construct |QLabel| instances. This is usually used
  1288. to provide a very small amount of text.
  1289. @<Function prototypes for scripting@>=
  1290. void setQLabelProperties(QScriptValue value, QScriptEngine *engine);
  1291. QScriptValue constructQLabel(QScriptContext *context, QScriptEngine *engine);
  1292. @ The constructor must be passed to the scripting engine.
  1293. @<Set up the scripting engine@>=
  1294. constructor = engine->newFunction(constructQLabel);
  1295. value = engine->newQMetaObject(&QLabel::staticMetaObject, constructor);
  1296. engine->globalObject().setProperty("QLabel", value);
  1297. @ In the constructor we allow an optional argument to specify the text of the
  1298. label.
  1299. @<Functions for scripting@>=
  1300. QScriptValue constructQLabel(QScriptContext *context, QScriptEngine *engine)
  1301. {
  1302. QString text;
  1303. if(context->argumentCount() == 1)
  1304. {
  1305. text = argument<QString>(0, context);
  1306. }
  1307. QScriptValue object = engine->newQObject(new QLabel(text));
  1308. setQLabelProperties(object, engine);
  1309. return object;
  1310. }
  1311. void setQLabelProperties(QScriptValue value, QScriptEngine *engine)
  1312. {
  1313. setQFrameProperties(value, engine);
  1314. }
  1315. @* Scripting QSvgWidget.
  1316. \noindent Sometimes it is useful to provide a space for simple drawings without
  1317. the need for all of the other capabilities of a web view. This was introduced
  1318. as a way to draw box plots to help guide the creation of roast specifications.
  1319. @<Function prototypes for scripting@>=
  1320. void setQSvgWidgetProperties(QScriptValue value, QScriptEngine *engine);
  1321. QScriptValue constructQSvgWidget(QScriptContext *context,
  1322. QScriptEngine *engine);
  1323. QScriptValue QSvgWidget_loadDevice(QScriptContext *context,
  1324. QScriptEngine *engine);
  1325. void addSvgWidgetToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  1326. QStack<QLayout *> *layoutStack);
  1327. @ The constructor must be passed to the scripting engine.
  1328. @<Set up the scripting engine@>=
  1329. constructor = engine->newFunction(constructQSvgWidget);
  1330. value = engine->newQMetaObject(&QSvgWidget::staticMetaObject, constructor);
  1331. engine->globalObject().setProperty("QSvgWidget", value);
  1332. @ The constructor is trivial.
  1333. @<Functions for scripting@>=
  1334. QScriptValue constructQSvgWidget(QScriptContext *,
  1335. QScriptEngine *engine)
  1336. {
  1337. QScriptValue object = engine->newQObject(new QSvgWidget);
  1338. setQSvgWidgetProperties(object, engine);
  1339. return object;
  1340. }
  1341. @ A property is added that allows loading data from a |QIODevice|.
  1342. @<Functions for scripting@>=
  1343. void setQSvgWidgetProperties(QScriptValue value, QScriptEngine *engine)
  1344. {
  1345. setQWidgetProperties(value, engine);
  1346. value.setProperty("loadDevice",
  1347. engine->newFunction(QSvgWidget_loadDevice));
  1348. }
  1349. QScriptValue QSvgWidget_loadDevice(QScriptContext *context, QScriptEngine *)
  1350. {
  1351. if(context->argumentCount() == 1)
  1352. {
  1353. QSvgWidget *self = getself<@[QSvgWidget *@]>(context);
  1354. QIODevice *device = argument<QIODevice *>(0, context);
  1355. device->reset();
  1356. QByteArray data = device->readAll();
  1357. self->load(data);
  1358. }
  1359. else
  1360. {
  1361. context->throwError("Incorrect number of arguments passed to "@|
  1362. "QSvgWidget::loadData(). This method takes one "@|
  1363. "QIODevice as an argument.");
  1364. }
  1365. return QScriptValue();
  1366. }
  1367. @ Additional work is needed to allow including this from the XML description of
  1368. a window.
  1369. @<Additional box layout elements@>=
  1370. else if(currentElement.tagName() == "svgwidget")
  1371. {
  1372. addSvgWidgetToLayout(currentElement, widgetStack, layoutStack);
  1373. }
  1374. @ The function used to create this follows the usual pattern.
  1375. @<Functions for scripting@>=
  1376. void addSvgWidgetToLayout(QDomElement element, QStack<QWidget *> *,
  1377. QStack<QLayout *> *layoutStack)
  1378. {
  1379. QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
  1380. QSvgWidget *widget = new QSvgWidget;
  1381. layout->addWidget(widget);
  1382. QString id = element.attribute("id");
  1383. if(!id.isEmpty())
  1384. {
  1385. widget->setObjectName(id);
  1386. }
  1387. }
  1388. @* Scripting QLineEdit.
  1389. \noindent Similarly, we may want to allow line edits in interfaces defined
  1390. through the host environment. For example, this is used for the free text
  1391. annotation control for roasters this has been configured on.
  1392. @<Function prototypes for scripting@>=
  1393. void setQLineEditProperties(QScriptValue value, QScriptEngine *engine);
  1394. QScriptValue constructQLineEdit(QScriptContext *context, QScriptEngine *engine);
  1395. @ The constructor must be passed to the host environment.
  1396. @<Set up the scripting engine@>=
  1397. constructor = engine->newFunction(constructQLineEdit);
  1398. value = engine->newQMetaObject(&QLineEdit::staticMetaObject, constructor);
  1399. engine->globalObject().setProperty("QLineEdit", value);
  1400. @ The constructor is trivial.
  1401. @<Functions for scripting@>=
  1402. QScriptValue constructQLineEdit(QScriptContext *, QScriptEngine *engine)
  1403. {
  1404. QScriptValue object = engine->newQObject(new QLineEdit());
  1405. setQLineEditProperties(object, engine);
  1406. return object;
  1407. }
  1408. @ At present all of the QLineEdit functionality exposed through this interface
  1409. is provided automatically through the meta-object system.
  1410. @<Functions for scripting@>=
  1411. void setQLineEditProperties(QScriptValue value, QScriptEngine *engine)
  1412. {
  1413. setQWidgetProperties(value, engine);
  1414. }
  1415. @* Scripting QSplitter.
  1416. \noindent The |QSplitter| class is one of the main classes used for user
  1417. interface object layout in \pn{}. To provide this class to the scripting engine,
  1418. we provide five functions: a constructor, a method for adding widgets to the
  1419. splitter, a method for saving the size of each widget in the splitter, a
  1420. method for restoring these saved sizes, and a function for adding these methods
  1421. as properties of newly created |QSplitter| objects.
  1422. @<Function prototypes for scripting@>=
  1423. QScriptValue constructQSplitter(QScriptContext *context, QScriptEngine *engine);
  1424. QScriptValue QSplitter_addWidget(QScriptContext *context,
  1425. QScriptEngine *engine);
  1426. QScriptValue QSplitter_saveState(QScriptContext *context,
  1427. QScriptEngine *engine);
  1428. QScriptValue QSplitter_restoreState(QScriptContext *context,
  1429. QScriptEngine *engine);
  1430. QScriptValue QSplitter_count(QScriptContext *context,
  1431. QScriptEngine *engine);
  1432. QScriptValue QSplitter_setCollapsible(QScriptContext *context,
  1433. QScriptEngine *engine);
  1434. void setQSplitterProperties(QScriptValue value, QScriptEngine *engine);
  1435. @ Of these, the scripting engine must be informed of the constructor.
  1436. @<Set up the scripting engine@>=
  1437. constructor = engine->newFunction(constructQSplitter);
  1438. value = engine->newQMetaObject(&QSplitter::staticMetaObject, constructor);
  1439. engine->globalObject().setProperty("QSplitter", value);
  1440. @ The constructor creates the object and adds the required properties to it.
  1441. @<Functions for scripting@>=
  1442. QScriptValue constructQSplitter(QScriptContext *, QScriptEngine *engine)
  1443. {
  1444. QScriptValue object = engine->newQObject(new QSplitter);
  1445. setQSplitterProperties(object, engine);
  1446. return object;
  1447. }
  1448. void setQSplitterProperties(QScriptValue value, QScriptEngine *engine)
  1449. {
  1450. setQFrameProperties(value, engine);
  1451. value.setProperty("addWidget", engine->newFunction(QSplitter_addWidget));
  1452. value.setProperty("saveState", engine->newFunction(QSplitter_saveState));
  1453. value.setProperty("restoreState",
  1454. engine->newFunction(QSplitter_restoreState));
  1455. value.setProperty("count", engine->newFunction(QSplitter_count));
  1456. value.setProperty("setCollapsible", engine->newFunction(QSplitter_setCollapsible));
  1457. }
  1458. @ The |"addWidget"| property is a simple wrapper around
  1459. |QSplitter::addWidget()|.
  1460. @<Functions for scripting@>=
  1461. QScriptValue QSplitter_addWidget(QScriptContext *context, QScriptEngine *)
  1462. {
  1463. if(context->argumentCount() == 1)
  1464. {
  1465. QSplitter *self = getself<QSplitter *>(context);
  1466. QWidget *widget = argument<QWidget *>(0, context);
  1467. if(widget)
  1468. {
  1469. self->addWidget(widget);
  1470. }
  1471. else
  1472. {
  1473. context->throwError("Incorrect argument type passed to "@|
  1474. "QSplitter::addWidget(). This method "@|
  1475. "requires a QWidget.");
  1476. }
  1477. }
  1478. else
  1479. {
  1480. context->throwError("Incorrect number of arguments passed to "@|
  1481. "QSplitter::addWidget(). This method takes one "@|
  1482. "QWidget as an argument.");
  1483. }
  1484. return QScriptValue();
  1485. }
  1486. @ The methods for saving and restoring the state of a splitter do not behave
  1487. well when the number of widgets contained in the splitter increase. This is a
  1488. problem in the logging view where we may want to allow zero width indicators
  1489. but reconfiguration can cause the number of indicators to increase. This would
  1490. result in the right most indicators such as the batch timer disappearing. Most
  1491. people do not notice the splitter handle or think to drag that to the left to
  1492. correct this issue so it would be better to save the number of indicators when
  1493. saving the state and if the number of indicators does not match, we should not
  1494. restore the obsolete saved state.
  1495. @<Functions for scripting@>=
  1496. QScriptValue QSplitter_count(QScriptContext *context, QScriptEngine *)
  1497. {
  1498. QSplitter *self = getself<QSplitter *>(context);
  1499. return QScriptValue(self->count());
  1500. }
  1501. @ When saving and restoring the state of a splitter, we always want to do this
  1502. through a |QSettings| object. For this, we take an extra argument specifying the
  1503. settings key to read from or write to. Unlike the equivalent functions called
  1504. from native code, neither of these functions called from a script will return
  1505. the data being saved.
  1506. @<Functions for scripting@>=
  1507. QScriptValue QSplitter_saveState(QScriptContext *context, QScriptEngine *)
  1508. {
  1509. if(context->argumentCount() == 1)
  1510. {
  1511. QSplitter *self = getself<QSplitter *>(context);
  1512. QString key = argument<QString>(0, context);
  1513. QSettings settings;
  1514. settings.setValue(key, self->saveState());
  1515. }
  1516. else
  1517. {
  1518. context->throwError("Incorrect number of arguments passed to "@|
  1519. "QSplitter::saveState(). This method takes one "@|
  1520. "string as an argument.");
  1521. }
  1522. return QScriptValue();
  1523. }
  1524. QScriptValue QSplitter_restoreState(QScriptContext *context, QScriptEngine *)
  1525. {
  1526. if(context->argumentCount() == 1)
  1527. {
  1528. QSplitter *self = getself<QSplitter *>(context);
  1529. QString key = argument<QString>(0, context);
  1530. QSettings settings;
  1531. self->restoreState(settings.value(key).toByteArray());
  1532. }
  1533. else
  1534. {
  1535. context->throwError("Incorrect number of arguments passed to "@|
  1536. "QSplitter::restoreState(). This method takes "@|
  1537. "one string as an argument.");
  1538. }
  1539. return QScriptValue();
  1540. }
  1541. @ Sometimes a |QSplitter| is used to make it easy to hide optional elements. In
  1542. this use case it can be useful to indicate that required elements cannot be
  1543. collapsed.
  1544. @<Functions for scripting@>=
  1545. QScriptValue QSplitter_setCollapsible(QScriptContext *context, QScriptEngine *)
  1546. {
  1547. if(context->argumentCount() == 2)
  1548. {
  1549. QSplitter *self = getself<QSplitter *>(context);
  1550. self->setCollapsible(argument<int>(0, context), argument<bool>(1, context));
  1551. }
  1552. else
  1553. {
  1554. context->throwError("Incorrect number of arguments");
  1555. }
  1556. return QScriptValue();
  1557. }
  1558. @* Scripting Layout classes.
  1559. \noindent Layout classes simplify managing the size and position of widgets in a
  1560. user interface. Qt provides several such classes, including |QBoxLayout| which
  1561. can be used to construct a variety of different interfaces. As widgets
  1562. containing a layout should not really need to care which layout is being used,
  1563. the |QLayout| class acts as an abstract base for all layout classes. A bare
  1564. |QLayout| will never be constructed, however subclasses can make use of the
  1565. |addWidget()| property.
  1566. @<Function prototypes for scripting@>=
  1567. void setQLayoutProperties(QScriptValue value, QScriptEngine *engine);
  1568. QScriptValue QLayout_addWidget(QScriptContext *context, QScriptEngine *engine);
  1569. @ The implementation is trivial.
  1570. @<Functions for scripting@>=
  1571. void setQLayoutProperties(QScriptValue value, QScriptEngine *engine)
  1572. {
  1573. setQLayoutItemProperties(value, engine);
  1574. value.setProperty("addWidget", engine->newFunction(QLayout_addWidget));
  1575. }
  1576. QScriptValue QLayout_addWidget(QScriptContext *context, QScriptEngine *)
  1577. {
  1578. if(context->argumentCount() == 1)
  1579. {
  1580. QLayout *self = getself<QLayout *>(context);
  1581. QWidget *widget = argument<QWidget *>(0, context);
  1582. if(widget)
  1583. {
  1584. self->addWidget(widget);
  1585. }
  1586. else
  1587. {
  1588. context->throwError("Incorrect argument type passed to "@|
  1589. "QLayout::addWidget(). This method requires "@|
  1590. "a QWidget.");
  1591. }
  1592. }
  1593. else
  1594. {
  1595. context->throwError("Incorrect number of arguments passed to "@|
  1596. "QLayout::addWidget(). This method takes one "@|
  1597. "QWidget as an argument.");
  1598. }
  1599. return QScriptValue();
  1600. }
  1601. @ |QBoxLayout| is a more interesting layout class. This allows widgets to be
  1602. arranged in a single row or column and can be used, for example, to arrange a
  1603. row of buttons as in figure \secno.
  1604. \medskip
  1605. \resizebox*{6.3in}{!}{\includegraphics{boxlayoutexample}}
  1606. \smallskip
  1607. \centerline{Figure \secno: Buttons in a |QBoxLayout|.}
  1608. \medskip
  1609. This class makes use of the |addWidget()| method from |QLayout|.
  1610. @<Function prototypes for scripting@>=
  1611. QScriptValue constructQBoxLayout(QScriptContext *context,
  1612. QScriptEngine *engine);
  1613. void setQBoxLayoutProperties(QScriptValue value, QScriptEngine *engine);
  1614. QScriptValue QBoxLayout_addLayout(QScriptContext *context, QScriptEngine *engine);
  1615. QScriptValue QBoxLayout_addWidget(QScriptContext *context, QScriptEngine *engine);
  1616. @ The script constructor must be passed to the scripting engine.
  1617. @<Set up the scripting engine@>=
  1618. constructor = engine->newFunction(constructQBoxLayout);
  1619. value = engine->newQMetaObject(&QBoxLayout::staticMetaObject, constructor);
  1620. engine->globalObject().setProperty("QBoxLayout", value);
  1621. @ The implementation of these functions should seem familiar by now. Note that
  1622. while a horizontal layout is provided by default, this can be changed from the
  1623. script once the layout is created.
  1624. @<Functions for scripting@>=
  1625. QScriptValue constructQBoxLayout(QScriptContext *, QScriptEngine *engine)
  1626. {
  1627. QScriptValue object =
  1628. engine->newQObject(new QBoxLayout(QBoxLayout::LeftToRight));
  1629. setQBoxLayoutProperties(object, engine);
  1630. return object;
  1631. }
  1632. void setQBoxLayoutProperties(QScriptValue value, QScriptEngine *engine)
  1633. {
  1634. setQLayoutProperties(value, engine);
  1635. value.setProperty("addLayout", engine->newFunction(QBoxLayout_addLayout));
  1636. value.setProperty("addWidget", engine->newFunction(QBoxLayout_addWidget));
  1637. }
  1638. QScriptValue QBoxLayout_addLayout(QScriptContext *context, QScriptEngine *)
  1639. {
  1640. if(context->argumentCount() > 0 && context->argumentCount() < 3)
  1641. {
  1642. QBoxLayout *self = getself<QBoxLayout *>(context);
  1643. QLayout *layout = argument<QLayout *>(0, context);
  1644. int stretch = 0;
  1645. if(context->argumentCount() == 2)
  1646. {
  1647. stretch = argument<int>(1, context);
  1648. }
  1649. if(layout)
  1650. {
  1651. self->addLayout(layout, stretch);
  1652. }
  1653. else
  1654. {
  1655. context->throwError("Incorrect argument type passed to "@|
  1656. "QLayout::addLayout(). This method requires "@|
  1657. "a QLayout.");
  1658. }
  1659. }
  1660. else
  1661. {
  1662. context->throwError("Incorrect number of arguments passed to "@|
  1663. "QLayout::addLayout(). This method takes one "@|
  1664. "QLayout as an argument and optionally one integer.");
  1665. }
  1666. return QScriptValue();
  1667. }
  1668. @ We override the base class wrapper for |addWidget| to add two optional
  1669. arguments: one specifies the stretch factor of the widget and the other
  1670. specifies the alignment of the widget within the layout.
  1671. @<Functions for scripting@>=
  1672. QScriptValue QBoxLayout_addWidget(QScriptContext *context, QScriptEngine *)
  1673. {
  1674. if(context->argumentCount() > 0 && context->argumentCount() < 4)
  1675. {
  1676. QBoxLayout *self = getself<QBoxLayout *>(context);
  1677. QWidget *widget = argument<QWidget *>(0, context);
  1678. int stretch = 0;
  1679. Qt::Alignment alignment = 0;
  1680. if(context->argumentCount() > 1)
  1681. {
  1682. stretch = argument<int>(1, context);
  1683. }
  1684. if(context->argumentCount() > 2)
  1685. {
  1686. alignment = (Qt::Alignment)(argument<int>(2, context));
  1687. }
  1688. if(widget)
  1689. {
  1690. self->addWidget(widget, stretch, alignment);
  1691. }
  1692. else
  1693. {
  1694. context->throwError("Incorrect argument type passed to "@|
  1695. "QBoxLayout::addWidget(). This method requires "@|
  1696. "a QWidget.");
  1697. }
  1698. }
  1699. else
  1700. {
  1701. context->throwError("Incorrect number of arguments passed to "@|
  1702. "QBoxLayout::addWidget(). This method takes one "@|
  1703. "QWidget and optionally up to two integers as "@|
  1704. "arguments.");
  1705. }
  1706. return QScriptValue();
  1707. }
  1708. @* Scripting QAction.
  1709. \noindent The |QAction| class is used in \pn{} to create menu items and respond
  1710. to the selection of these items. Three functions are required for our scripting
  1711. needs with regard to this class.
  1712. @<Function prototypes for scripting@>=
  1713. QScriptValue constructQAction(QScriptContext *context, QScriptEngine *engine);
  1714. QScriptValue QAction_setShortcut(QScriptContext *context,
  1715. QScriptEngine *engine);
  1716. void setQActionProperties(QScriptValue value, QScriptEngine *engine);
  1717. @ The scripting engine must be informed of the constructor.
  1718. @<Set up the scripting engine@>=
  1719. constructor = engine->newFunction(constructQAction);
  1720. value = engine->newQMetaObject(&QAction::staticMetaObject, constructor);
  1721. engine->globalObject().setProperty("QAction", value);
  1722. @ The constructor is simple, however some might sensibly question why the
  1723. |"setShortcut"| property is needed at all. Why not have scripts simply set the
  1724. |shortcut| property of the |QAction| directly? The answer to this is that the
  1725. property expects data of the |QKeySequence| type. While this can be created from
  1726. a |QString|, passing a string to the property through the scripting engine did
  1727. not work at the time this was written.
  1728. @<Functions for scripting@>=
  1729. QScriptValue constructQAction(QScriptContext *, QScriptEngine *engine)
  1730. {
  1731. QScriptValue object = engine->newQObject(new QAction(NULL));
  1732. setQActionProperties(object, engine);
  1733. return object;
  1734. }
  1735. void setQActionProperties(QScriptValue value, QScriptEngine *engine)
  1736. {
  1737. setQObjectProperties(value, engine);
  1738. value.setProperty("setShortcut", engine->newFunction(QAction_setShortcut));
  1739. }
  1740. QScriptValue QAction_setShortcut(QScriptContext *context, QScriptEngine *)
  1741. {
  1742. if(context->argumentCount() == 1)
  1743. {
  1744. QAction *self = getself<@[QAction *@]>(context);
  1745. self->setShortcut(argument<QString>(0, context));
  1746. }
  1747. else
  1748. {
  1749. context->throwError("Incorrect number of arguments passed to "@|
  1750. "QAction::setShortcut(). This method takes one "@|
  1751. "string as an argument.");
  1752. }
  1753. return QScriptValue();
  1754. }
  1755. @* Scripting QFileDialog.
  1756. \noindent |QFileDialog| provides two static member functions which is all that
  1757. we need. The objects returned from these methods are built on the |QDialog|
  1758. abstract base class.
  1759. @<Function prototypes for scripting@>=
  1760. QScriptValue QFileDialog_getOpenFileName(QScriptContext *context,
  1761. QScriptEngine *engine);
  1762. QScriptValue QFileDialog_getSaveFileName(QScriptContext *context,
  1763. QScriptEngine *engine);
  1764. void setQFileDialogProperties(QScriptValue value, QScriptEngine *engine);
  1765. void setQDialogProperties(QScriptValue value, QScriptEngine *engine);
  1766. @ The scripting engine must be informed of the wrapper functions for the static
  1767. methods.
  1768. @<Set up the scripting engine@>=
  1769. value = engine->newQMetaObject(&QFileDialog::staticMetaObject);
  1770. value.setProperty("getOpenFileName",
  1771. engine->newFunction(QFileDialog_getOpenFileName));
  1772. value.setProperty("getSaveFileName",
  1773. engine->newFunction(QFileDialog_getSaveFileName));
  1774. engine->globalObject().setProperty("QFileDialog", value);
  1775. @ This function is just a simple wrapper around the |QFileDialog| method, but
  1776. the object returned has any properties added to the base class available.
  1777. @<Functions for scripting@>=
  1778. QScriptValue QFileDialog_getOpenFileName(QScriptContext *context,
  1779. QScriptEngine *engine)
  1780. {
  1781. QScriptValue retval;
  1782. if(context->argumentCount() == 3)
  1783. {
  1784. QWidget *widget = argument<QWidget *>(0, context);
  1785. if(widget)
  1786. {
  1787. QString caption = argument<QString>(1, context);
  1788. QString dir = argument<QString>(2, context);
  1789. retval = QScriptValue(engine,
  1790. QFileDialog::getOpenFileName(widget, caption,
  1791. dir, "", 0, 0));
  1792. setQFileDialogProperties(retval, engine);
  1793. }
  1794. else
  1795. {
  1796. context->throwError("Incorrect argument type passed to "@|
  1797. "QFileDialog::getOpenFileName(). The first "@|
  1798. "argument to this method must be a QWidget.");
  1799. }
  1800. }
  1801. else
  1802. {
  1803. context->throwError("Incorrect number of arguments passed to "@|
  1804. "QFileDialog::getOpenFileName(). This method "@|
  1805. "takes one QWidget followed by two strings for a "@|
  1806. "total of three arguments.");
  1807. }
  1808. return retval;
  1809. }
  1810. @ Similarly, this just wraps |QFileDialog::getSaveFileName()|.
  1811. @<Functions for scripting@>=
  1812. QScriptValue QFileDialog_getSaveFileName(QScriptContext *context,
  1813. QScriptEngine *engine)
  1814. {
  1815. QScriptValue retval;
  1816. if(context->argumentCount() == 3)
  1817. {
  1818. QWidget *widget = argument<QWidget *>(0, context);
  1819. if(widget)
  1820. {
  1821. QString caption = argument<QString>(1, context);
  1822. QString dir = argument<QString>(2, context);
  1823. retval = QScriptValue(engine,
  1824. QFileDialog::getSaveFileName(widget, caption,
  1825. dir, "", 0, 0));
  1826. setQFileDialogProperties(retval, engine);
  1827. }
  1828. else
  1829. {
  1830. context->throwError("Incorrect argument type passed to "@|
  1831. "QFileDialog::getSaveFileName(). The first "@|
  1832. "argument to this method must be a QWidget.");
  1833. }
  1834. }
  1835. else
  1836. {
  1837. context->throwError("Incorrect number of arguments passed to "@|
  1838. "QFileDialog::getSaveFileName(). This method "@|
  1839. "takes one QWidget followed by two strings for a "@|
  1840. "total of three arguments.");
  1841. }
  1842. return retval;
  1843. }
  1844. @ Adding object hierarchy properties to the objects created above is simple.
  1845. @<Functions for scripting@>=
  1846. void setQFileDialogProperties(QScriptValue value, QScriptEngine *engine)
  1847. {
  1848. setQDialogProperties(value, engine);
  1849. }
  1850. void setQDialogProperties(QScriptValue value, QScriptEngine *engine)
  1851. {
  1852. setQWidgetProperties(value, engine);
  1853. }
  1854. @* Scripting QFile.
  1855. \noindent When using a |QFile| in a script, we only need the constructor and two
  1856. functions for hooking it in with the rest of the object hierarchy.
  1857. @<Function prototypes for scripting@>=
  1858. QScriptValue constructQFile(QScriptContext *context, QScriptEngine *engine);
  1859. void setQFileProperties(QScriptValue value, QScriptEngine *engine);
  1860. QScriptValue QFile_remove(QScriptContext *context, QScriptEngine *engine);
  1861. void setQIODeviceProperties(QScriptValue value, QScriptEngine *engine);
  1862. QScriptValue QIODevice_open(QScriptContext *context, QScriptEngine *engine);
  1863. QScriptValue QIODevice_close(QScriptContext *context, QScriptEngine *engine);
  1864. QScriptValue QIODevice_readToString(QScriptContext *context,
  1865. QScriptEngine *engine);
  1866. QScriptValue QIODevice_putChar(QScriptContext *context, QScriptEngine *engine);
  1867. QScriptValue QIODevice_writeString(QScriptContext *context, QScriptEngine *engine);
  1868. QScriptValue QIODevice_writeBytes(QScriptContext *context, QScriptEngine *engine);
  1869. QScriptValue QIODevice_readBytes(QScriptContext *context, QScriptEngine *engine);
  1870. QScriptValue QIODevice_peek(QScriptContext *context, QScriptEngine *engine);
  1871. QScriptValue QIODevice_read(QScriptContext *context, QScriptEngine *engine);
  1872. @ This function is passed to the scripting engine.
  1873. @<Set up the scripting engine@>=
  1874. constructor = engine->newFunction(constructQFile);
  1875. value = engine->newQMetaObject(&QFile::staticMetaObject, constructor);
  1876. engine->globalObject().setProperty("QFile", value);
  1877. @ The implementation is trivial.
  1878. @<Functions for scripting@>=
  1879. QScriptValue constructQFile(QScriptContext *context, QScriptEngine *engine)
  1880. {
  1881. QScriptValue object =
  1882. engine->newQObject(new QFile(argument<QString>(0, context)));@/
  1883. setQFileProperties(object, engine);
  1884. return object;
  1885. }
  1886. @ |QFile| gets a wrapper around |remove()| to support deleting temporary files.
  1887. @<Functions for scripting@>=
  1888. void setQFileProperties(QScriptValue value, QScriptEngine *engine)
  1889. {
  1890. setQIODeviceProperties(value, engine);
  1891. value.setProperty("remove", engine->newFunction(QFile_remove));
  1892. }
  1893. QScriptValue QFile_remove(QScriptContext *context, QScriptEngine *engine)
  1894. {
  1895. QFile *self = getself<QFile *>(context);
  1896. bool retval = self->remove();
  1897. return QScriptValue(engine, retval);
  1898. }
  1899. @ Although we aren'@q'@>t going to create any instances of |QIODevice| directly,
  1900. subclasses such as |QFile| and |QBuffer| get two additional properties for
  1901. opening and closing the device.
  1902. In order to solve some class interoperability issues, a convenience method is
  1903. also added which is equivalent to creating a |QString| from the |QByteArray|
  1904. returned from the |readAll()| method.
  1905. @<Functions for scripting@>=
  1906. void setQIODeviceProperties(QScriptValue value, QScriptEngine *engine)
  1907. {
  1908. setQObjectProperties(value, engine);
  1909. value.setProperty("open", engine->newFunction(QIODevice_open));
  1910. value.setProperty("close", engine->newFunction(QIODevice_close));
  1911. value.setProperty("readToString",
  1912. engine->newFunction(QIODevice_readToString));
  1913. value.setProperty("putChar", engine->newFunction(QIODevice_putChar));
  1914. value.setProperty("writeString", engine->newFunction(QIODevice_writeString));
  1915. value.setProperty("writeBytes", engine->newFunction(QIODevice_writeBytes));
  1916. value.setProperty("readBytes", engine->newFunction(QIODevice_readBytes));
  1917. value.setProperty("peek", engine->newFunction(QIODevice_peek));
  1918. value.setProperty("read", engine->newFunction(QIODevice_read));
  1919. }
  1920. @ These are simple wrappers. In the case of the |open()| property, one argument
  1921. may be passed specifying the mode used for opening. The supported values for
  1922. this are 1 (Read Only), 2 (Write Only), and 3 (Read Write). If this argument is
  1923. not passed, it is assumed that the user wants read and write access.
  1924. @<Functions for scripting@>=
  1925. QScriptValue QIODevice_open(QScriptContext *context, QScriptEngine *)
  1926. {
  1927. QIODevice *self = getself<QIODevice *>(context);
  1928. bool retval = false;
  1929. if(context->argumentCount() == 1)
  1930. {
  1931. switch(argument<int>(0, context))
  1932. {
  1933. case 1:
  1934. retval = self->open(QIODevice::ReadOnly);
  1935. break;
  1936. case 2:
  1937. retval = self->open(QIODevice::WriteOnly);
  1938. break;
  1939. case 3:
  1940. retval = self->open(QIODevice::ReadWrite);
  1941. break;
  1942. default:
  1943. break;
  1944. }
  1945. }
  1946. else
  1947. {
  1948. retval = self->open(QIODevice::ReadWrite);
  1949. }
  1950. return QScriptValue(retval);
  1951. }
  1952. QScriptValue QIODevice_close(QScriptContext *context, QScriptEngine *)
  1953. {
  1954. QIODevice *self = getself<QIODevice *>(context);
  1955. self->close();
  1956. return QScriptValue();
  1957. }
  1958. @ The |readToString()| method is a simple extension of |QIODevice::readAll()| to
  1959. interface with classes that expect document data in the form of a string. Most
  1960. notably, this includes |QWebView|.
  1961. @<Functions for scripting@>=
  1962. QScriptValue QIODevice_readToString(QScriptContext *context, QScriptEngine *)
  1963. {
  1964. QIODevice *self = getself<QIODevice *>(context);
  1965. self->reset();
  1966. return QScriptValue(QString(self->readAll()));
  1967. }
  1968. @ In support of serial port communications, wrappers around two methods for
  1969. writing data have been added. As these are valid for other classes derived from
  1970. |QIODevice|, they are added here so the functionality is available more
  1971. broadly.
  1972. As we are unable to pass a type that guarantees only a single character, we
  1973. instead accept a string and only pass along the first character.
  1974. @<Functions for scripting@>=
  1975. QScriptValue QIODevice_putChar(QScriptContext *context, QScriptEngine *)
  1976. {
  1977. QIODevice *self = getself<QIODevice *>(context);
  1978. if(context->argumentCount() == 1)
  1979. {
  1980. return QScriptValue(self->putChar(argument<QString>(0, context).toUtf8().at(0)));
  1981. }
  1982. context->throwError("Incorrect number of arguments passed to "@|
  1983. "QIODevice::putChar()");
  1984. return QScriptValue();
  1985. }
  1986. @ Two wrappers are provided around |QIODevice::write()| for outputting
  1987. multi-byte data. If we are writing strings that are valid UTF-8, we can use the
  1988. |writeString| wrapper, but if we require full control over exactly which bytes
  1989. are output, the |writeBytes| wrapper is more appropriate.
  1990. @<Functions for scripting@>=
  1991. QScriptValue QIODevice_writeString(QScriptContext *context, QScriptEngine *)
  1992. {
  1993. QIODevice *self = getself<QIODevice *>(context);
  1994. if(context->argumentCount() == 1)
  1995. {
  1996. self->write(argument<QString>(0, context).toUtf8());
  1997. }
  1998. else
  1999. {
  2000. context->throwError("Incorrect number of arguments passed to "@|
  2001. "QIODevice::writeString()");
  2002. }
  2003. return QScriptValue();
  2004. }
  2005. QScriptValue QIODevice_writeBytes(QScriptContext *context, QScriptEngine *)
  2006. {
  2007. QIODevice *self = getself<QIODevice *>(context);
  2008. if(context->argumentCount() == 1)
  2009. {
  2010. self->write(argument<QByteArray>(0, context));
  2011. }
  2012. else
  2013. {
  2014. context->throwError("Incorrect number of arguments passed to "@|
  2015. "QIODevice::writeBytes()");
  2016. }
  2017. return QScriptValue();
  2018. }
  2019. @ The readBytes method is an alternate wrapper around |QByteArray::readAll()|
  2020. which returns the |QByteArray| instead of converting this to a |QString|.
  2021. @<Functions for scripting@>=
  2022. QScriptValue QIODevice_readBytes(QScriptContext *context, QScriptEngine *engine)
  2023. {
  2024. QIODevice *self = getself<QIODevice *>(context);
  2025. QScriptValue value = engine->toScriptValue<QByteArray>(self->readAll());
  2026. setQByteArrayProperties(value, engine);
  2027. return value;
  2028. }
  2029. @ Wrappers around |peek()| and |read()| are also provided.
  2030. @<Functions for scripting@>=
  2031. QScriptValue QIODevice_peek(QScriptContext *context, QScriptEngine *engine)
  2032. {
  2033. QIODevice *self = getself<QIODevice *>(context);
  2034. QScriptValue value = engine->toScriptValue<QByteArray>(
  2035. self->peek(argument<int>(0, context)));
  2036. setQByteArrayProperties(value, engine);
  2037. return value;
  2038. }
  2039. QScriptValue QIODevice_read(QScriptContext *context, QScriptEngine *engine)
  2040. {
  2041. QIODevice *self = getself<QIODevice *>(context);
  2042. QScriptValue value = engine->toScriptValue<QByteArray>(
  2043. self->read(argument<int>(0, context)));
  2044. setQByteArrayProperties(value, engine);
  2045. return value;
  2046. }
  2047. @* Scripting QProcess.
  2048. \noindent Sometimes it is useful to have \pn work with an external program.
  2049. The initial use case was document generation by typesetting instructions to a
  2050. file and then running \TeX to generate a shelf sign or a sheet of labels.
  2051. Other likely use cases include interfacing with external programs that output
  2052. measurement streams. There are several methods which we may want to expose,
  2053. however this is being done only as needed.
  2054. @<Function prototypes for scripting@>=
  2055. QScriptValue constructQProcess(QScriptContext *context, QScriptEngine *engine);
  2056. void setQProcessProperties(QScriptValue value, QScriptEngine *engine);
  2057. QScriptValue QProcess_execute(QScriptContext *context, QScriptEngine *engine);
  2058. QScriptValue QProcess_startDetached(QScriptContext *context, QScriptEngine *engine);
  2059. QScriptValue QProcess_setWorkingDirectory(QScriptContext *context, QScriptEngine *engine);
  2060. QScriptValue QProcess_start(QScriptContext *context, QScriptEngine *engine);
  2061. @ We follow the same pattern with this as with many other types.
  2062. @<Set up the scripting engine@>=
  2063. constructor = engine->newFunction(constructQProcess);
  2064. value = engine->newQMetaObject(&QProcess::staticMetaObject, constructor);
  2065. engine->globalObject().setProperty("QProcess", value);
  2066. @ The constructor is trivial.
  2067. @<Functions for scripting@>=
  2068. QScriptValue constructQProcess(QScriptContext *, QScriptEngine *engine)
  2069. {
  2070. QScriptValue object = engine->newQObject(new QProcess);
  2071. setQProcessProperties(object, engine);
  2072. return object;
  2073. }
  2074. @ As |QProcess| is a |QIODevice| we inherit some properties from that. We also
  2075. expose some details that are specific to |QProcess|.
  2076. @<Functions for scripting@>=
  2077. void setQProcessProperties(QScriptValue value, QScriptEngine *engine)
  2078. {
  2079. setQIODeviceProperties(value, engine);
  2080. value.setProperty("execute", engine->newFunction(QProcess_execute));
  2081. value.setProperty("startDetached", engine->newFunction(QProcess_startDetached));
  2082. value.setProperty("setWorkingDirectory", engine->newFunction(QProcess_setWorkingDirectory));
  2083. value.setProperty("start", engine->newFunction(QProcess_start));
  2084. }
  2085. @ The |execute()| method comes in two flavors: one with arguments and one without.
  2086. We always call the one with arguments and simply pass in an empty list if no
  2087. arguments are specified.
  2088. @<Functions for scripting@>=
  2089. QScriptValue QProcess_execute(QScriptContext *context, QScriptEngine *)
  2090. {
  2091. QProcess *self = getself<QProcess *>(context);
  2092. QString program = argument<QString>(0, context);
  2093. QStringList arguments = QStringList();
  2094. if(context->argumentCount() > 1) {
  2095. arguments = argument<QVariant>(1, context).toStringList();
  2096. }
  2097. int retval = self->execute(program, arguments);
  2098. return QScriptValue(retval);
  2099. }
  2100. @ Similarly |startDetached()| can be called in a few different ways.
  2101. @<Functions for scripting@>=
  2102. QScriptValue QProcess_startDetached(QScriptContext *context, QScriptEngine *)
  2103. {
  2104. QProcess *self = getself<QProcess *>(context);
  2105. QString program = argument<QString>(0, context);
  2106. QStringList arguments = QStringList();
  2107. if(context->argumentCount() > 1) {
  2108. arguments = argument<QVariant>(1, context).toStringList();
  2109. }
  2110. QString workingDirectory = "";
  2111. if(context->argumentCount() > 2) {
  2112. workingDirectory = argument<QString>(2, context);
  2113. }
  2114. bool retval;
  2115. switch(context->argumentCount())
  2116. {
  2117. case 1:
  2118. retval = self->startDetached(program);
  2119. break;
  2120. case 2:
  2121. retval = self->startDetached(program, arguments);
  2122. break;
  2123. case 3:
  2124. retval = self->startDetached(program, arguments, workingDirectory);
  2125. break;
  2126. default:
  2127. retval = false;
  2128. }
  2129. return QScriptValue(retval);
  2130. }
  2131. @ Sometimes we care about the working directory for our program.
  2132. @<Functions for scripting@>=
  2133. QScriptValue QProcess_setWorkingDirectory(QScriptContext *context, QScriptEngine *)
  2134. {
  2135. QProcess *self = getself<QProcess *>(context);
  2136. QString directory = argument<QString>(0, context);
  2137. self->setWorkingDirectory(directory);
  2138. return QScriptValue();
  2139. }
  2140. @ When using the |start()| method we always assume that we want read and write
  2141. access.
  2142. @<Functions for scripting@>=
  2143. QScriptValue QProcess_start(QScriptContext *context, QScriptEngine *)
  2144. {
  2145. QProcess *self = getself<QProcess *>(context);
  2146. QString program = argument<QString>(0, context);
  2147. QStringList arguments = QStringList();
  2148. if(context->argumentCount() > 1) {
  2149. arguments = argument<QVariant>(1, context).toStringList();
  2150. }
  2151. self->start(program, arguments);
  2152. return QScriptValue();
  2153. }
  2154. @ In order to work with |QByteArray| this should also be exposed to the host
  2155. environment.
  2156. @<Function prototypes for scripting@>=
  2157. QScriptValue QByteArray_toScriptValue(QScriptEngine *engine, const QByteArray &bytes);
  2158. void QByteArray_fromScriptValue(const QScriptValue &value, QByteArray &bytes);
  2159. QScriptValue constructQByteArray(QScriptContext *context, QScriptEngine *engine);
  2160. void setQByteArrayProperties(QScriptValue value, QScriptEngine *engine);
  2161. QScriptValue QByteArray_fromHex(QScriptContext *context, QScriptEngine *engine);
  2162. QScriptValue QByteArray_getAt(QScriptContext *context, QScriptEngine *engine);
  2163. QScriptValue QByteArray_setAt(QScriptContext *context, QScriptEngine *engine);
  2164. QScriptValue QByteArray_appendBytes(QScriptContext *context, QScriptEngine *engine);
  2165. QScriptValue QByteArray_appendString(QScriptContext *context, QScriptEngine *engine);
  2166. QScriptValue QByteArray_size(QScriptContext *context, QScriptEngine *engine);
  2167. QScriptValue QByteArray_left(QScriptContext *context, QScriptEngine *engine);
  2168. QScriptValue QByteArray_right(QScriptContext *context, QScriptEngine *engine);
  2169. QScriptValue QByteArray_mid(QScriptContext *context, QScriptEngine *engine);
  2170. QScriptValue QByteArray_chop(QScriptContext *context, QScriptEngine *engine);
  2171. QScriptValue QByteArray_remove(QScriptContext *context, QScriptEngine *engine);
  2172. QScriptValue QByteArray_toInt8(QScriptContext *context, QScriptEngine *engine);
  2173. QScriptValue QByteArray_toInt16(QScriptContext *context, QScriptEngine *engine);
  2174. QScriptValue QByteArray_toInt32(QScriptContext *context, QScriptEngine *engine);
  2175. QScriptValue QByteArray_toFloat(QScriptContext *context, QScriptEngine *engine);
  2176. QScriptValue QByteArray_toDouble(QScriptContext *context, QScriptEngine *engine);
  2177. @ First, we provide some functionns for moving array data across the
  2178. language barrier.
  2179. @<Functions for scripting@>=
  2180. QScriptValue QByteArray_toScriptValue(QScriptEngine *engine, const QByteArray &bytes)
  2181. {
  2182. QScriptValue object = engine->newVariant(QVariant(bytes));
  2183. setQByteArrayProperties(object, engine);
  2184. return object;
  2185. }
  2186. void QByteArray_fromScriptValue(const QScriptValue &value, QByteArray &bytes)
  2187. {
  2188. bytes = value.toVariant().toByteArray();
  2189. }
  2190. @ We register this our conversion functions and allow creation of new arrays
  2191. next.
  2192. @<Set up the scripting engine@>=
  2193. qScriptRegisterMetaType(engine, QByteArray_toScriptValue, QByteArray_fromScriptValue);
  2194. constructor = engine->newFunction(constructQByteArray);
  2195. engine->globalObject().setProperty("QByteArray", constructor);
  2196. @ The constructor is straightforward.
  2197. @<Functions for scripting@>=
  2198. QScriptValue constructQByteArray(QScriptContext *, QScriptEngine *engine)
  2199. {
  2200. QScriptValue object = engine->toScriptValue<QByteArray>(QByteArray());
  2201. setQByteArrayProperties(object, engine);
  2202. return object;
  2203. }
  2204. @ There are many methods which are not automatically available which we may
  2205. want to have wrappers around. These should be added as required.
  2206. @<Functions for scripting@>=
  2207. void setQByteArrayProperties(QScriptValue value, QScriptEngine *engine)
  2208. {
  2209. value.setProperty("fromHex", engine->newFunction(QByteArray_fromHex));
  2210. value.setProperty("getAt", engine->newFunction(QByteArray_getAt));
  2211. value.setProperty("setAt", engine->newFunction(QByteArray_setAt));
  2212. value.setProperty("appendBytes", engine->newFunction(QByteArray_appendBytes));
  2213. value.setProperty("appendString", engine->newFunction(QByteArray_appendString));
  2214. value.setProperty("size", engine->newFunction(QByteArray_size));
  2215. value.setProperty("left", engine->newFunction(QByteArray_left));
  2216. value.setProperty("right", engine->newFunction(QByteArray_right));
  2217. value.setProperty("mid", engine->newFunction(QByteArray_mid));
  2218. value.setProperty("chop", engine->newFunction(QByteArray_chop));
  2219. value.setProperty("remove", engine->newFunction(QByteArray_remove));
  2220. value.setProperty("toInt8", engine->newFunction(QByteArray_toInt8));
  2221. value.setProperty("toInt16", engine->newFunction(QByteArray_toInt16));
  2222. value.setProperty("toInt32", engine->newFunction(QByteArray_toInt32));
  2223. value.setProperty("toFloat", engine->newFunction(QByteArray_toFloat));
  2224. value.setProperty("toDouble", engine->newFunction(QByteArray_toDouble));
  2225. }
  2226. @ Perhaps the easiest way to deal with fixed byte strings for serial
  2227. communications across script boundaries is to use a hex encoded string.
  2228. @<Functions for scripting@>=
  2229. QScriptValue QByteArray_fromHex(QScriptContext *context, QScriptEngine *engine)
  2230. {
  2231. QByteArray self = getself<QByteArray>(context);
  2232. QByteArray retval;
  2233. retval = self.fromHex(argument<QString>(0, context).toUtf8());
  2234. QScriptValue value = engine->toScriptValue<QByteArray>(retval);
  2235. setQByteArrayProperties(value, engine);
  2236. return value;
  2237. }
  2238. @ A pair of methods is provided for getting and setting values at a particular
  2239. byte.
  2240. @<Functions for scripting@>=
  2241. QScriptValue QByteArray_getAt(QScriptContext *context, QScriptEngine *)
  2242. {
  2243. QByteArray self = getself<QByteArray>(context);
  2244. return QScriptValue((int)(self.at(argument<int>(0, context))));
  2245. }
  2246. QScriptValue QByteArray_setAt(QScriptContext *context, QScriptEngine *)
  2247. {
  2248. QByteArray self = getself<QByteArray>(context);
  2249. self[argument<int>(0, context)] = (char)(argument<int>(1, context));
  2250. return QScriptValue();
  2251. }
  2252. @ Methods are provided for appending either another |QByteArray| or a string
  2253. to a |QByteArray|. The only difference between these functions is the expected
  2254. argument type.
  2255. @<Functions for scripting@>=
  2256. QScriptValue QByteArray_appendBytes(QScriptContext *context, QScriptEngine *engine)
  2257. {
  2258. QByteArray self = getself<QByteArray>(context);
  2259. QScriptValue value =
  2260. engine->toScriptValue<QByteArray>(
  2261. self.append(argument<QByteArray>(0, context)));
  2262. setQByteArrayProperties(value, engine);
  2263. return value;
  2264. }
  2265. QScriptValue QByteArray_appendString(QScriptContext *context, QScriptEngine *engine)
  2266. {
  2267. QByteArray self = getself<QByteArray>(context);
  2268. QScriptValue value = engine->toScriptValue<QByteArray>(
  2269. self.append(argument<QString>(0, context)));
  2270. setQByteArrayProperties(value, engine);
  2271. return value;
  2272. }
  2273. @ Checking the size of our byte array frequently a requirement.
  2274. @<Functions for scripting@>=
  2275. QScriptValue QByteArray_size(QScriptContext *context, QScriptEngine *)
  2276. {
  2277. QByteArray self = getself<QByteArray>(context);
  2278. return QScriptValue(self.size());
  2279. }
  2280. @ It is also frequently useful to be able to work with specific parts of a byte
  2281. array, so a few methods are provided for carving these up.
  2282. @<Functions for scripting@>=
  2283. QScriptValue QByteArray_left(QScriptContext *context, QScriptEngine *engine)
  2284. {
  2285. QByteArray self = getself<QByteArray>(context);
  2286. QScriptValue value = engine->toScriptValue<QByteArray>(
  2287. self.left(argument<int>(0, context)));
  2288. setQByteArrayProperties(value, engine);
  2289. return value;
  2290. }
  2291. QScriptValue QByteArray_right(QScriptContext *context, QScriptEngine *engine)
  2292. {
  2293. QByteArray self = getself<QByteArray>(context);
  2294. QScriptValue value = engine->toScriptValue<QByteArray>(
  2295. self.right(argument<int>(0, context)));
  2296. setQByteArrayProperties(value, engine);
  2297. return value;
  2298. }
  2299. QScriptValue QByteArray_mid(QScriptContext *context, QScriptEngine *engine)
  2300. {
  2301. QByteArray self = getself<QByteArray>(context);
  2302. int length = -1;
  2303. if(context->argumentCount() > 1)
  2304. {
  2305. length = argument<int>(1, context);
  2306. }
  2307. QScriptValue value = engine->toScriptValue<QByteArray>(
  2308. self.mid(argument<int>(0, context), length));
  2309. setQByteArrayProperties(value, engine);
  2310. return value;
  2311. }
  2312. @ We may also want to remove bytes from an array.
  2313. @<Functions for scripting@>=
  2314. QScriptValue QByteArray_chop(QScriptContext *context, QScriptEngine *)
  2315. {
  2316. QByteArray self = getself<QByteArray>(context);
  2317. self.chop(argument<int>(0, context));
  2318. return QScriptValue();
  2319. }
  2320. QScriptValue QByteArray_remove(QScriptContext *context, QScriptEngine *engine)
  2321. {
  2322. QByteArray self = getself<QByteArray>(context);
  2323. QScriptValue value = engine->toScriptValue<QByteArray>(
  2324. self.remove(argument<int>(0, context), argument<int>(1, context)));
  2325. setQByteArrayProperties(value, engine);
  2326. return value;
  2327. }
  2328. @ When receiving data in a byte array, bytes are sometimes intended to
  2329. represent 8, 16, or 32 bit integers. In such cases we often want to perform
  2330. some computation on these values so having the ability to split off that
  2331. portion of the array (for example, with |mid()|) and convert to a Number is
  2332. useful.
  2333. @<Functions for scripting@>=
  2334. QScriptValue QByteArray_toInt8(QScriptContext *context, QScriptEngine *)
  2335. {
  2336. QByteArray self = getself<QByteArray>(context);
  2337. int value = 0;
  2338. char *bytes = (char *)&value;
  2339. bytes[0] = self[0];
  2340. return QScriptValue(value);
  2341. }
  2342. QScriptValue QByteArray_toInt16(QScriptContext *context, QScriptEngine *)
  2343. {
  2344. QByteArray self = getself<QByteArray>(context);
  2345. int value = 0;
  2346. char *bytes = (char *)&value;
  2347. bytes[0] = self[0];
  2348. bytes[1] = self[1];
  2349. return QScriptValue(value);
  2350. }
  2351. QScriptValue QByteArray_toInt32(QScriptContext *context, QScriptEngine *)
  2352. {
  2353. QByteArray self = getself<QByteArray>(context);
  2354. int value = 0;
  2355. char *bytes = (char *)&value;
  2356. bytes[0] = self[0];
  2357. bytes[1] = self[1];
  2358. bytes[2] = self[2];
  2359. bytes[3] = self[3];
  2360. return QScriptValue(value);
  2361. }
  2362. @ Similar methods are provided for converting bytes to a |float| or |double|.
  2363. Note that the return value from |toFloat| will, in the host environment, be
  2364. represented as a |double|.
  2365. @<Functions for scripting@>=
  2366. QScriptValue QByteArray_toFloat(QScriptContext *context, QScriptEngine *)
  2367. {
  2368. QByteArray self = getself<QByteArray>(context);
  2369. float value = 0.0;
  2370. char *bytes = (char *)&value;
  2371. bytes[0] = self[0];
  2372. bytes[1] = self[1];
  2373. bytes[2] = self[2];
  2374. bytes[3] = self[3];
  2375. return QScriptValue(value);
  2376. }
  2377. QScriptValue QByteArray_toDouble(QScriptContext *context, QScriptEngine *)
  2378. {
  2379. QByteArray self = getself<QByteArray>(context);
  2380. double value = 0.0;
  2381. char *bytes = (char *)&value;
  2382. bytes[0] = self[0];
  2383. bytes[1] = self[1];
  2384. bytes[2] = self[2];
  2385. bytes[3] = self[3];
  2386. bytes[4] = self[4];
  2387. bytes[5] = self[5];
  2388. bytes[6] = self[6];
  2389. bytes[7] = self[7];
  2390. return QScriptValue(value);
  2391. }
  2392. @ Some protocols require manipulating larger than 8 bit numbers as a sequence
  2393. of bytes. To facilitate this, methods are provided to construct a |QByteArray|
  2394. from different sized numbers. 8 bit numbers are provided for uniformity.
  2395. @<Function prototypes for scripting@>=
  2396. QScriptValue bytesFromInt8(QScriptContext *context, QScriptEngine *engine);
  2397. QScriptValue bytesFromInt16(QScriptContext *context, QScriptEngine *engine);
  2398. QScriptValue bytesFromInt32(QScriptContext *context, QScriptEngine *engine);
  2399. QScriptValue bytesFromFloat(QScriptContext *context, QScriptEngine *engine);
  2400. QScriptValue bytesFromDouble(QScriptContext *context, QScriptEngine *engine);
  2401. @ These are globally available.
  2402. @<Set up the scripting engine@>=
  2403. engine->globalObject().setProperty("bytesFromInt8", engine->newFunction(bytesFromInt8));
  2404. engine->globalObject().setProperty("bytesFromInt16", engine->newFunction(bytesFromInt16));
  2405. engine->globalObject().setProperty("bytesFromInt32", engine->newFunction(bytesFromInt32));
  2406. engine->globalObject().setProperty("bytesFromFloat", engine->newFunction(bytesFromFloat));
  2407. engine->globalObject().setProperty("bytesFromDouble", engine->newFunction(bytesFromDouble));
  2408. @ The methods all work by casting the appropriate numeric type to a |char *|
  2409. and copying the bytes to a new |QByteArray|. Note that the ECMA-262 standard
  2410. only has one type of number and this is an IEEE 754 binary64 double precision
  2411. floating point number. Functions other than |bytesFromDouble| will be cast
  2412. from |double|.
  2413. @<Functions for scripting@>=
  2414. QScriptValue bytesFromInt8(QScriptContext *context, QScriptEngine *engine)
  2415. {
  2416. qint8 value = (qint8)(argument<int>(0, context));
  2417. char *bytes = (char *)&value;
  2418. QByteArray retval;
  2419. retval.resize(1);
  2420. retval[0] = bytes[0];
  2421. QScriptValue v = engine->toScriptValue<QByteArray>(retval);
  2422. setQByteArrayProperties(v, engine);
  2423. return v;
  2424. }
  2425. QScriptValue bytesFromInt16(QScriptContext *context, QScriptEngine *engine)
  2426. {
  2427. qint16 value = (qint16)(argument<int>(0, context));
  2428. char *bytes = (char *)&value;
  2429. QByteArray retval;
  2430. retval.resize(2);
  2431. retval[0] = bytes[0];
  2432. retval[1] = bytes[1];
  2433. QScriptValue v = engine->toScriptValue<QByteArray>(retval);
  2434. setQByteArrayProperties(v, engine);
  2435. return v;
  2436. }
  2437. QScriptValue bytesFromInt32(QScriptContext *context, QScriptEngine *engine)
  2438. {
  2439. qint32 value = (qint32)(argument<int>(0, context));
  2440. char *bytes = (char *)&value;
  2441. QByteArray retval;
  2442. retval.resize(4);
  2443. retval[0] = bytes[0];
  2444. retval[1] = bytes[1];
  2445. retval[2] = bytes[2];
  2446. retval[3] = bytes[3];
  2447. QScriptValue v = engine->toScriptValue<QByteArray>(retval);
  2448. setQByteArrayProperties(v, engine);
  2449. return v;
  2450. }
  2451. QScriptValue bytesFromFloat(QScriptContext *context, QScriptEngine *engine)
  2452. {
  2453. float value = (float)(argument<double>(0, context));
  2454. char *bytes = (char *)&value;
  2455. QByteArray retval;
  2456. retval.resize(4);
  2457. retval[0] = bytes[0];
  2458. retval[1] = bytes[1];
  2459. retval[2] = bytes[2];
  2460. retval[3] = bytes[3];
  2461. QScriptValue v = engine->toScriptValue<QByteArray>(retval);
  2462. setQByteArrayProperties(v, engine);
  2463. return v;
  2464. }
  2465. QScriptValue bytesFromDouble(QScriptContext *context, QScriptEngine *engine)
  2466. {
  2467. double value = (double)(argument<double>(0, context));
  2468. char *bytes = (char *)&value;
  2469. QByteArray retval;
  2470. retval.resize(8);
  2471. retval[0] = bytes[0];
  2472. retval[1] = bytes[1];
  2473. retval[2] = bytes[2];
  2474. retval[3] = bytes[3];
  2475. retval[4] = bytes[4];
  2476. retval[5] = bytes[5];
  2477. retval[6] = bytes[6];
  2478. retval[7] = bytes[7];
  2479. QScriptValue v = engine->toScriptValue<QByteArray>(retval);
  2480. setQByteArrayProperties(v, engine);
  2481. return v;
  2482. }
  2483. @* Scripting QBuffer.
  2484. \noindent Sometimes it is desirable to load a roast profile from a file. At
  2485. other times, it is more useful to load that profile from a byte array stored in
  2486. a database. The |XMLInput| class takes data from a |QIODevice| object, which
  2487. means that we can choose from a |QFile| when we want the former or a |QBuffer|
  2488. when we want the latter.
  2489. @<Function prototypes for scripting@>=
  2490. QScriptValue constructQBuffer(QScriptContext *context, QScriptEngine *engine);
  2491. void setQBufferProperties(QScriptValue value, QScriptEngine *engine);
  2492. QScriptValue QBuffer_setData(QScriptContext *context, QScriptEngine *engine);
  2493. QScriptValue QBuffer_data(QScriptContext *context, QScriptEngine *engine);
  2494. @ The host environment needs to be aware of the constructor.
  2495. @<Set up the scripting engine@>=
  2496. constructor = engine->newFunction(constructQBuffer);
  2497. value = engine->newQMetaObject(&QBuffer::staticMetaObject, constructor);
  2498. engine->globalObject().setProperty("QBuffer", value);
  2499. @ The implementation is trivial.
  2500. @<Functions for scripting@>=
  2501. QScriptValue constructQBuffer(QScriptContext *context, QScriptEngine *engine)
  2502. {
  2503. QByteArray *array = new QByteArray(argument<QString>(0, context).toAscii());
  2504. QScriptValue object = engine->newQObject(new QBuffer(array));
  2505. setQBufferProperties(object, engine);
  2506. return object;
  2507. }
  2508. void setQBufferProperties(QScriptValue value, QScriptEngine *engine)
  2509. {
  2510. setQIODeviceProperties(value, engine);
  2511. value.setProperty("setData", engine->newFunction(QBuffer_setData));
  2512. value.setProperty("data", engine->newFunction(QBuffer_data));
  2513. }
  2514. QScriptValue QBuffer_setData(QScriptContext *context, QScriptEngine *)
  2515. {
  2516. QBuffer *self = getself<QBuffer *>(context);
  2517. self->setData(argument<QString>(0, context).toAscii());
  2518. return QScriptValue();
  2519. }
  2520. QScriptValue QBuffer_data(QScriptContext *context, QScriptEngine *)
  2521. {
  2522. QBuffer *self = getself<QBuffer *>(context);
  2523. return QScriptValue(QString(self->data()));
  2524. }
  2525. @* Scripting QXmlQuery.
  2526. \noindent Sometimes we have some XML data in a file or a buffer and we would
  2527. like to extract certain information from that data in the host environment.
  2528. Rather than write complicated string manipulation routines in an attempt to deal
  2529. with this sensibly, we can use the XQuery language to extract the information we
  2530. want. One common use case for this is extracting all measurements from a roast
  2531. profile that are associated with an annotation.
  2532. @<Function prototypes for scripting@>=
  2533. QScriptValue constructXQuery(QScriptContext *context, QScriptEngine *engine);
  2534. QScriptValue XQuery_bind(QScriptContext *context, QScriptEngine *engine);
  2535. QScriptValue XQuery_exec(QScriptContext *context, QScriptEngine *engine);
  2536. QScriptValue XQuery_setQuery(QScriptContext *context, QScriptEngine *engine);
  2537. QScriptValue XQuery_invalidate(QScriptContext *context, QScriptEngine *engine);
  2538. void setXQueryProperties(QScriptValue value, QScriptEngine *engine);
  2539. @ The constructor must be registered with the host environment. This is done a
  2540. bit differently from most classes as |QXmlQuery| is not a |QObject|.
  2541. @<Set up the scripting engine@>=
  2542. constructor = engine->newFunction(constructXQuery);
  2543. engine->globalObject().setProperty("XQuery", constructor);
  2544. @ The constructor just needs to make sure the functions we want to make
  2545. available are applied. A method is also provided to free the |QXmlQuery|.
  2546. @<Functions for scripting@>=
  2547. QScriptValue constructXQuery(QScriptContext *, QScriptEngine *engine)
  2548. {
  2549. QScriptValue object = engine->toScriptValue<void *>(new QXmlQuery);
  2550. setXQueryProperties(object, engine);
  2551. return object;
  2552. }
  2553. QScriptValue XQuery_invalidate(QScriptContext *context, QScriptEngine *)
  2554. {
  2555. QXmlQuery *self = getself<QXmlQuery *>(context);
  2556. delete self;
  2557. return QScriptValue();
  2558. }
  2559. void setXQueryProperties(QScriptValue value, QScriptEngine *engine)
  2560. {
  2561. value.setProperty("bind", engine->newFunction(XQuery_bind));
  2562. value.setProperty("exec", engine->newFunction(XQuery_exec));
  2563. value.setProperty("setQuery", engine->newFunction(XQuery_setQuery));
  2564. value.setProperty("invalidate", engine->newFunction(XQuery_invalidate));
  2565. }
  2566. @ The |bind()| property can be used to specify a |QIODevice| to be referenced by
  2567. a variable within a query.
  2568. @<Functions for scripting@>=
  2569. QScriptValue XQuery_bind(QScriptContext *context, QScriptEngine *)
  2570. {
  2571. QXmlQuery *self = getself<QXmlQuery *>(context);
  2572. QIODevice *buffer = argument<QIODevice *>(1, context);
  2573. self->bindVariable(argument<QString>(0, context), buffer);
  2574. return QScriptValue();
  2575. }
  2576. @ A method is also required for setting the query we wish to conduct.
  2577. @<Functions for scripting@>=
  2578. QScriptValue XQuery_setQuery(QScriptContext *context, QScriptEngine *)
  2579. {
  2580. QXmlQuery *self = getself<QXmlQuery *>(context);
  2581. self->setQuery(argument<QString>(0, context));
  2582. return QScriptValue();
  2583. }
  2584. @ This method runs the previously specified query.
  2585. @<Functions for scripting@>=
  2586. QScriptValue XQuery_exec(QScriptContext *context, QScriptEngine *)
  2587. {
  2588. QXmlQuery *self = getself<QXmlQuery *>(context);
  2589. QString result;
  2590. self->evaluateTo(&result);
  2591. return QScriptValue(result);
  2592. }
  2593. @* Scripting QXmlStreamWriter.
  2594. \noindent There are some cases where it may be desirable to produce XML from the
  2595. host environment. While there are several ways to accomplish this, the
  2596. |QXmlStreamWriter| class greatly simplifies generating complex XML documents.
  2597. This class is not related to |QObject|, so several functions are needed to
  2598. expose the functionality of this class to the host environment.
  2599. @<Function prototypes for scripting@>=
  2600. QScriptValue constructXmlWriter(QScriptContext *context, QScriptEngine *engine);
  2601. QScriptValue XmlWriter_setDevice(QScriptContext *context,
  2602. QScriptEngine *engine);
  2603. QScriptValue XmlWriter_writeAttribute(QScriptContext *context,
  2604. QScriptEngine *engine);
  2605. QScriptValue XmlWriter_writeCDATA(QScriptContext *context,
  2606. QScriptEngine *engine);
  2607. QScriptValue XmlWriter_writeCharacters(QScriptContext *context,
  2608. QScriptEngine *engine);
  2609. QScriptValue XmlWriter_writeDTD(QScriptContext *context, QScriptEngine *engine);
  2610. QScriptValue XmlWriter_writeEmptyElement(QScriptContext *context,
  2611. QScriptEngine *engine);
  2612. QScriptValue XmlWriter_writeEndDocument(QScriptContext *context,
  2613. QScriptEngine *engine);
  2614. QScriptValue XmlWriter_writeEndElement(QScriptContext *context,
  2615. QScriptEngine *engine);
  2616. QScriptValue XmlWriter_writeEntityReference(QScriptContext *context,
  2617. QScriptEngine *engine);
  2618. QScriptValue XmlWriter_writeProcessingInstruction(QScriptContext *context,
  2619. QScriptEngine *engine);
  2620. QScriptValue XmlWriter_writeStartDocument(QScriptContext *context,
  2621. QScriptEngine *engine);
  2622. QScriptValue XmlWriter_writeStartElement(QScriptContext *context,
  2623. QScriptEngine *engine);
  2624. QScriptValue XmlWriter_writeTextElement(QScriptContext *context,
  2625. QScriptEngine *engine);
  2626. void setXmlWriterProperties(QScriptValue value, QScriptEngine *engine);
  2627. @ The constructor must be registered with the host environment.
  2628. @<Set up the scripting engine@>=
  2629. constructor = engine->newFunction(constructXmlWriter);
  2630. engine->globalObject().setProperty("XmlWriter", constructor);
  2631. @ The constructor takes an optional argument allowing the output device to be
  2632. specified.
  2633. @<Functions for scripting@>=
  2634. QScriptValue constructXmlWriter(QScriptContext *context, QScriptEngine *engine)
  2635. {
  2636. QXmlStreamWriter *retval;
  2637. if(context->argumentCount() == 1)
  2638. {
  2639. retval = new QXmlStreamWriter(argument<QIODevice *>(0, context));
  2640. }
  2641. else
  2642. {
  2643. retval = new QXmlStreamWriter;
  2644. }
  2645. QScriptValue object = engine->toScriptValue<void *>(retval);
  2646. setXmlWriterProperties(object, engine);
  2647. return object;
  2648. }
  2649. void setXmlWriterProperties(QScriptValue value, QScriptEngine *engine)
  2650. {
  2651. value.setProperty("setDevice", engine->newFunction(XmlWriter_setDevice));
  2652. value.setProperty("writeAttribute",
  2653. engine->newFunction(XmlWriter_writeAttribute));
  2654. value.setProperty("writeCDATA", engine->newFunction(XmlWriter_writeCDATA));
  2655. value.setProperty("writeCharacters",
  2656. engine->newFunction(XmlWriter_writeCharacters));
  2657. value.setProperty("writeDTD", engine->newFunction(XmlWriter_writeDTD));
  2658. value.setProperty("writeEmptyElement",
  2659. engine->newFunction(XmlWriter_writeEmptyElement));
  2660. value.setProperty("writeEndDocument",
  2661. engine->newFunction(XmlWriter_writeEndDocument));
  2662. value.setProperty("writeEndElement",
  2663. engine->newFunction(XmlWriter_writeEndElement));
  2664. value.setProperty("writeEntityReference",
  2665. engine->newFunction(XmlWriter_writeEntityReference));
  2666. value.setProperty("writeProcessingInstruction",
  2667. engine->newFunction(XmlWriter_writeProcessingInstruction));
  2668. value.setProperty("writeStartDocument",
  2669. engine->newFunction(XmlWriter_writeStartDocument));
  2670. value.setProperty("writeStartElement",
  2671. engine->newFunction(XmlWriter_writeStartElement));
  2672. value.setProperty("writeTextElement",
  2673. engine->newFunction(XmlWriter_writeTextElement));
  2674. }
  2675. @ If the output device needs to be changed or if one is not passed to the
  2676. constructor, the |setDevice()| method can be used.
  2677. @<Functions for scripting@>=
  2678. QScriptValue XmlWriter_setDevice(QScriptContext *context, QScriptEngine *)
  2679. {
  2680. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2681. QIODevice *device = argument<QIODevice *>(0, context);
  2682. self->setDevice(device);
  2683. return QScriptValue();
  2684. }
  2685. @ The remaining functions are simple wrappers used for writing various types of
  2686. data. After creating a writer and setting the output device, the start of the
  2687. document should be written. One argument is required containing the XML version
  2688. number. Another function handles writing the end of the document.
  2689. @<Functions for scripting@>=
  2690. QScriptValue XmlWriter_writeStartDocument(QScriptContext *context,
  2691. QScriptEngine *)
  2692. {
  2693. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2694. self->writeStartDocument(argument<QString>(0, context));
  2695. return QScriptValue();
  2696. }
  2697. QScriptValue XmlWriter_writeEndDocument(QScriptContext *context,
  2698. QScriptEngine *)
  2699. {
  2700. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2701. self->writeEndDocument();
  2702. return QScriptValue();
  2703. }
  2704. @ After the start of the document, a DTD is commonly needed.
  2705. @<Functions for scripting@>=
  2706. QScriptValue XmlWriter_writeDTD(QScriptContext *context, QScriptEngine *)
  2707. {
  2708. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2709. self->writeDTD(argument<QString>(0, context));
  2710. return QScriptValue();
  2711. }
  2712. @ After this, elements need to be written. For this, we write the start
  2713. element, any attributes needed, character data, and the end element.
  2714. @<Functions for scripting@>=
  2715. QScriptValue XmlWriter_writeStartElement(QScriptContext *context,
  2716. QScriptEngine *)
  2717. {
  2718. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2719. self->writeStartElement(argument<QString>(0, context));
  2720. return QScriptValue();
  2721. }
  2722. QScriptValue XmlWriter_writeAttribute(QScriptContext *context, QScriptEngine *)
  2723. {
  2724. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2725. self->writeAttribute(argument<QString>(0, context),
  2726. argument<QString>(1, context));
  2727. return QScriptValue();
  2728. }
  2729. QScriptValue XmlWriter_writeCharacters(QScriptContext *context, QScriptEngine *)
  2730. {
  2731. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2732. self->writeCharacters(argument<QString>(0, context));
  2733. return QScriptValue();
  2734. }
  2735. QScriptValue XmlWriter_writeEndElement(QScriptContext *context, QScriptEngine *)
  2736. {
  2737. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2738. self->writeEndElement();
  2739. return QScriptValue();
  2740. }
  2741. @ For convenience, two other methods are provided for writing elements. Elements
  2742. which do not require anything between the start and end elements can be created
  2743. with |writeEmptyElement()|. Elements which do not require attributes, but do
  2744. contain text can be created with |writeTextElement()|.
  2745. @<Functions for scripting@>=
  2746. QScriptValue XmlWriter_writeEmptyElement(QScriptContext *context,
  2747. QScriptEngine *)
  2748. {
  2749. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2750. self->writeEmptyElement(argument<QString>(0, context));
  2751. return QScriptValue();
  2752. }
  2753. QScriptValue XmlWriter_writeTextElement(QScriptContext *context,
  2754. QScriptEngine *)
  2755. {
  2756. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2757. self->writeTextElement(argument<QString>(0, context),
  2758. argument<QString>(1, context));
  2759. return QScriptValue();
  2760. }
  2761. @ Less commonly needed are functions for writing CDATA sections, entity
  2762. references, and processing instructions.
  2763. @<Functions for scripting@>=
  2764. QScriptValue XmlWriter_writeCDATA(QScriptContext *context, QScriptEngine *)
  2765. {
  2766. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2767. self->writeCDATA(argument<QString>(0, context));
  2768. return QScriptValue();
  2769. }
  2770. QScriptValue XmlWriter_writeEntityReference(QScriptContext *context,
  2771. QScriptEngine *)
  2772. {
  2773. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2774. self->writeEntityReference(argument<QString>(0, context));
  2775. return QScriptValue();
  2776. }
  2777. QScriptValue XmlWriter_writeProcessingInstruction(QScriptContext *context,
  2778. QScriptEngine *)
  2779. {
  2780. QXmlStreamWriter *self = getself<QXmlStreamWriter *>(context);
  2781. self->writeProcessingInstruction(argument<QString>(0, context),
  2782. argument<QString>(1, context));
  2783. return QScriptValue();
  2784. }
  2785. @* Scripting QXmlStreamReader.
  2786. \noindent When a serializer is written using |QXmlStreamWriter|, a corresponding
  2787. deserializer should also be written. While there are several possible ways to do
  2788. this, using |QXmlStreamReader| is often the best choice. \pn{} provides a subset
  2789. of the functionality from this class which should be adequate for most purposes.
  2790. @<Function prototypes for scripting@>=
  2791. QScriptValue constructXmlReader(QScriptContext *context, QScriptEngine *engine);
  2792. QScriptValue XmlReader_atEnd(QScriptContext *context, QScriptEngine *engine);
  2793. QScriptValue XmlReader_attribute(QScriptContext *context,
  2794. QScriptEngine *engine);
  2795. QScriptValue XmlReader_hasAttribute(QScriptContext *context,
  2796. QScriptEngine *engine);
  2797. QScriptValue XmlReader_isDTD(QScriptContext *context, QScriptEngine *engine);
  2798. QScriptValue XmlReader_isStartElement(QScriptContext *context,
  2799. QScriptEngine *engine);
  2800. QScriptValue XmlReader_name(QScriptContext *context, QScriptEngine *engine);
  2801. QScriptValue XmlReader_readElementText(QScriptContext *context,
  2802. QScriptEngine *engine);
  2803. QScriptValue XmlReader_readNext(QScriptContext *context, QScriptEngine *engine);
  2804. QScriptValue XmlReader_text(QScriptContext *context, QScriptEngine *engine);
  2805. void setXmlReaderProperties(QScriptValue value, QScriptEngine *engine);
  2806. @ The constructor must be registered with the host environment.
  2807. @<Set up the scripting engine@>=
  2808. constructor = engine->newFunction(constructXmlReader);
  2809. engine->globalObject().setProperty("XmlReader", constructor);
  2810. @ The constructor requires an argument specifying the output device. This can be
  2811. any |QIODevice|. The |open()| method must be called on the device before passing
  2812. it as an argument to this function.
  2813. @<Functions for scripting@>=
  2814. QScriptValue constructXmlReader(QScriptContext *context, QScriptEngine *engine)
  2815. {
  2816. QXmlStreamReader *retval =
  2817. new QXmlStreamReader(argument<QIODevice *>(0, context));
  2818. QScriptValue object = engine->toScriptValue<void *>(retval);
  2819. setXmlReaderProperties(object, engine);
  2820. return object;
  2821. }
  2822. void setXmlReaderProperties(QScriptValue value, QScriptEngine *engine)
  2823. {
  2824. value.setProperty("atEnd", engine->newFunction(XmlReader_atEnd));
  2825. value.setProperty("attribute", engine->newFunction(XmlReader_attribute));
  2826. value.setProperty("hasAttribute",
  2827. engine->newFunction(XmlReader_hasAttribute));
  2828. value.setProperty("isDTD", engine->newFunction(XmlReader_isDTD));
  2829. value.setProperty("isStartElement",
  2830. engine->newFunction(XmlReader_isStartElement));
  2831. value.setProperty("name", engine->newFunction(XmlReader_name));
  2832. value.setProperty("readElementText",
  2833. engine->newFunction(XmlReader_readElementText));
  2834. value.setProperty("readNext",
  2835. engine->newFunction(XmlReader_readNext));
  2836. value.setProperty("text", engine->newFunction(XmlReader_text));
  2837. }
  2838. @ Most of the functions are simple member function wrappers. Two of these
  2839. properties are not. These are the |attribute()| and |hasAttribute()| properties.
  2840. @<Functions for scripting@>=
  2841. QScriptValue XmlReader_attribute(QScriptContext *context, QScriptEngine *)
  2842. {
  2843. QXmlStreamReader *self = getself<QXmlStreamReader *>(context);
  2844. QString retval =
  2845. self->attributes().value(argument<QString>(0, context)).toString();
  2846. return QScriptValue(retval);
  2847. }
  2848. QScriptValue XmlReader_hasAttribute(QScriptContext *context, QScriptEngine *)
  2849. {
  2850. QXmlStreamReader *self = getself<QXmlStreamReader *>(context);
  2851. bool retval =
  2852. self->attributes().hasAttribute(argument<QString>(0, context));
  2853. return QScriptValue(retval);
  2854. }
  2855. @ Other properties can be used for determining how to proceed with the
  2856. processing.
  2857. @<Functions for scripting@>=
  2858. QScriptValue XmlReader_atEnd(QScriptContext *context, QScriptEngine *)
  2859. {
  2860. QXmlStreamReader *self = getself<QXmlStreamReader *>(context);
  2861. return QScriptValue(self->atEnd());
  2862. }
  2863. QScriptValue XmlReader_isDTD(QScriptContext *context, QScriptEngine *)
  2864. {
  2865. QXmlStreamReader *self = getself<QXmlStreamReader *>(context);
  2866. return QScriptValue(self->isDTD());
  2867. }
  2868. QScriptValue XmlReader_isStartElement(QScriptContext *context, QScriptEngine *)
  2869. {
  2870. QXmlStreamReader *self = getself<QXmlStreamReader *>(context);
  2871. return QScriptValue(self->isStartElement());
  2872. }
  2873. @ We move from one element to the next with the |readNext()| property.
  2874. @<Functions for scripting@>=
  2875. QScriptValue XmlReader_readNext(QScriptContext *context, QScriptEngine *)
  2876. {
  2877. QXmlStreamReader *self = getself<QXmlStreamReader *>(context);
  2878. self->readNext();
  2879. return QScriptValue();
  2880. }
  2881. @ The remaining properties return the element name and text.
  2882. @<Functions for scripting@>=
  2883. QScriptValue XmlReader_name(QScriptContext *context, QScriptEngine *)
  2884. {
  2885. QXmlStreamReader *self = getself<QXmlStreamReader *>(context);
  2886. return QScriptValue(self->name().toString());
  2887. }
  2888. QScriptValue XmlReader_readElementText(QScriptContext *context, QScriptEngine *)
  2889. {
  2890. QXmlStreamReader *self = getself<QXmlStreamReader *>(context);
  2891. return QScriptValue(self->readElementText());
  2892. }
  2893. QScriptValue XmlReader_text(QScriptContext *context, QScriptEngine *)
  2894. {
  2895. QXmlStreamReader *self = getself<QXmlStreamReader *>(context);
  2896. return QScriptValue(self->text().toString());
  2897. }
  2898. @* Scripting QSettings.
  2899. \noindent Rather than have a script create a |QSettings| object when it needs to
  2900. save or load settings, the object is provided along with properties for getting
  2901. and setting values. Two functions are needed for this along with a third which
  2902. ensures any properties added to |QObject| are also available to |QSettings| from
  2903. the host environment.
  2904. @<Function prototypes for scripting@>=
  2905. QScriptValue QSettings_value(QScriptContext *context, QScriptEngine *engine);
  2906. QScriptValue QSettings_setValue(QScriptContext *context, QScriptEngine *engine);
  2907. void setQSettingsProperties(QScriptValue value, QScriptEngine *engine);
  2908. @ The object with properties for these functions is passed to the scripting
  2909. engine.
  2910. @<Set up the scripting engine@>=
  2911. value = engine->newQObject(&settings);
  2912. setQSettingsProperties(value, engine);
  2913. engine->globalObject().setProperty("QSettings", value);
  2914. @ Adding properties to the |QSettings| object should seem familiar.
  2915. @<Functions for scripting@>=
  2916. void setQSettingsProperties(QScriptValue value, QScriptEngine *engine)
  2917. {
  2918. setQObjectProperties(value, engine);
  2919. value.setProperty("value", engine->newFunction(QSettings_value));
  2920. value.setProperty("setValue", engine->newFunction(QSettings_setValue));
  2921. }
  2922. @ When getting a value from saved settings, there is the possibility that there
  2923. will not be a value saved for the requested key. An optional second argument can
  2924. be used to supply a default value.
  2925. @<Functions for scripting@>=
  2926. QScriptValue QSettings_value(QScriptContext *context, QScriptEngine *engine)
  2927. {
  2928. QScriptValue object;
  2929. if(context->argumentCount() == 1 || context->argumentCount() == 2)
  2930. {
  2931. QSettings settings;
  2932. QString key = argument<QString>(0, context);
  2933. QVariant value;
  2934. QVariant retval;
  2935. if(context->argumentCount() > 1)
  2936. {
  2937. value = argument<QVariant>(1, context);
  2938. retval = settings.value(key, value);
  2939. }
  2940. else
  2941. {
  2942. retval = settings.value(key);
  2943. }
  2944. object = engine->newVariant(retval);
  2945. }
  2946. else
  2947. {
  2948. context->throwError("Incorrect number of arguments passed to "@|
  2949. "QSettings::value(). This method takes one "@|
  2950. "string and one optional variant type.");
  2951. }
  2952. return object;
  2953. }
  2954. QScriptValue QSettings_setValue(QScriptContext *context, QScriptEngine *)
  2955. {
  2956. if(context->argumentCount() == 2)
  2957. {
  2958. QSettings settings;
  2959. QString key = argument<QString>(0, context);
  2960. QVariant value = argument<QVariant>(1, context);
  2961. settings.setValue(key, value);
  2962. }
  2963. else
  2964. {
  2965. context->throwError("Incorrect number of arguments passed to "@|
  2966. "QSettings::setValue(). This method takes one "@|
  2967. "string and one variant type for a total of two "@|
  2968. "arguments.");
  2969. }
  2970. return QScriptValue();
  2971. }
  2972. @* Scripting QLCDNumber.
  2973. \noindent |QLCDNumber| is used as a base class for \pn{}'@q'@>s |TemperatureDisplay|
  2974. and |TimerDisplay| classes, but it can also be used on its own for the display
  2975. of mainly numeric information.
  2976. @<Function prototypes for scripting@>=
  2977. QScriptValue constructQLCDNumber(QScriptContext *context,
  2978. QScriptEngine *engine);
  2979. void setQLCDNumberProperties(QScriptValue value, QScriptEngine *engine);
  2980. @ The constructor must be passed to the scripting engine.
  2981. @<Set up the scripting engine@>=
  2982. constructor = engine->newFunction(constructQLCDNumber);
  2983. value = engine->newQMetaObject(&QLCDNumber::staticMetaObject, constructor);
  2984. engine->globalObject().setProperty("QLCDNumber", value);
  2985. @ There is nothing special about the implementation.
  2986. @<Functions for scripting@>=
  2987. QScriptValue constructQLCDNumber(QScriptContext *, QScriptEngine *engine)
  2988. {
  2989. QScriptValue object = engine->newQObject(new QLCDNumber());
  2990. setQLCDNumberProperties(object, engine);
  2991. return object;
  2992. }
  2993. void setQLCDNumberProperties(QScriptValue value, QScriptEngine *engine)
  2994. {
  2995. setQFrameProperties(value, engine);
  2996. }
  2997. @* Scripting QTime.
  2998. \noindent |QTime| is a little different from the classes examined so far. This
  2999. class can be used for synchonizing time among various objects by creating a
  3000. common base reference time. This should not be needed as ECMA-262 already
  3001. specifies a |Date| class, however this has historically been troublesome to use.
  3002. One thing that makes this class different is that it is not related to
  3003. |QObject|. This makes usefully exposing it to the scripting engine a little more
  3004. difficult.
  3005. @<Function prototypes for scripting@>=
  3006. QScriptValue constructQTime(QScriptContext *context, QScriptEngine *engine);
  3007. QScriptValue QTime_addMSecs(QScriptContext *context, QScriptEngine *engine);
  3008. QScriptValue QTime_addSecs(QScriptContext *context, QScriptEngine *engine);
  3009. QScriptValue QTime_elapsed(QScriptContext *context, QScriptEngine *engine);
  3010. QScriptValue QTime_hour(QScriptContext *context, QScriptEngine *engine);
  3011. QScriptValue QTime_isNull(QScriptContext *context, QScriptEngine *engine);
  3012. QScriptValue QTime_isValid(QScriptContext *context, QScriptEngine *engine);
  3013. QScriptValue QTime_minute(QScriptContext *context, QScriptEngine *engine);
  3014. QScriptValue QTime_msec(QScriptContext *context, QScriptEngine *engine);
  3015. QScriptValue QTime_msecsTo(QScriptContext *context, QScriptEngine *engine);
  3016. QScriptValue QTime_restart(QScriptContext *context, QScriptEngine *engine);
  3017. QScriptValue QTime_second(QScriptContext *context, QScriptEngine *engine);
  3018. QScriptValue QTime_secsTo(QScriptContext *context, QScriptEngine *engine);
  3019. QScriptValue QTime_setHMS(QScriptContext *context, QScriptEngine *engine);
  3020. QScriptValue QTime_start(QScriptContext *context, QScriptEngine *engine);
  3021. QScriptValue QTime_toString(QScriptContext *context, QScriptEngine *engine);
  3022. QScriptValue QTime_currentTime(QScriptContext *context, QScriptEngine *engine);
  3023. QScriptValue QTime_fromString(QScriptContext *context, QScriptEngine *engine);
  3024. QScriptValue QTime_valueOf(QScriptContext *context, QScriptEngine *engine);
  3025. void setQTimeProperties(QScriptValue value, QScriptEngine *engine);
  3026. @ We must tell the script engine about the constructor. This is not done in
  3027. quite the same way as is done for |QObject| derived types.
  3028. @<Set up the scripting engine@>=
  3029. constructor = engine->newFunction(constructQTime);
  3030. engine->globalObject().setProperty("QTime", constructor);
  3031. @ The constructor has a couple interesting twists. The first is the ability to
  3032. accept a variable number of integer arguments. The other is that |QTime| is not
  3033. derived from |QObject|. The lack of |break| statements in the |switch| is
  3034. intended.
  3035. @<Functions for scripting@>=
  3036. QScriptValue constructQTime(QScriptContext *context,
  3037. QScriptEngine *engine)
  3038. {
  3039. QScriptValue object;
  3040. if(context->argumentCount() == 0 ||
  3041. (context->argumentCount() >= 2 && context->argumentCount() <= 4))@/
  3042. {
  3043. int arg1 = 0;
  3044. int arg2 = 0;
  3045. int arg3 = 0;
  3046. int arg4 = 0;
  3047. switch(context->argumentCount())
  3048. {@t\1@>@/
  3049. case 4:@/
  3050. arg4 = argument<int>(3, context);
  3051. case 3:@/
  3052. arg3 = argument<int>(2, context);
  3053. case 2:@/
  3054. arg2 = argument<int>(1, context);
  3055. arg1 = argument<int>(0, context);
  3056. default:@/
  3057. break;@t\2@>@/
  3058. }
  3059. if(context->argumentCount())
  3060. {
  3061. object = engine->toScriptValue<QTime>(QTime(arg1, arg2, arg3,
  3062. arg4));
  3063. }
  3064. else
  3065. {
  3066. object = engine->toScriptValue<QTime>(QTime());
  3067. }
  3068. setQTimeProperties(object, engine);
  3069. }
  3070. else
  3071. {
  3072. context->throwError("Incorrect number of arguments passed to "@|
  3073. "QTime::QTime(). This method takes zero, two, "@|
  3074. "three, or four integer arguments.");
  3075. }
  3076. return object;
  3077. }
  3078. @ In order to use the various |QTime| methods, we must add wrapper functions as
  3079. properties of newly created script objects. The last two of these should really
  3080. be callable without starting from an existing |QTime|.
  3081. @<Functions for scripting@>=
  3082. void setQTimeProperties(QScriptValue value, QScriptEngine *engine)
  3083. {
  3084. value.setProperty("addMSecs", engine->newFunction(QTime_addMSecs));
  3085. value.setProperty("addSecs", engine->newFunction(QTime_addSecs));
  3086. value.setProperty("elapsed", engine->newFunction(QTime_elapsed));
  3087. value.setProperty("hour", engine->newFunction(QTime_hour));
  3088. value.setProperty("isNull", engine->newFunction(QTime_isNull));
  3089. value.setProperty("isValid", engine->newFunction(QTime_isValid));
  3090. value.setProperty("minute", engine->newFunction(QTime_minute));
  3091. value.setProperty("msec", engine->newFunction(QTime_msec));
  3092. value.setProperty("msecsTo", engine->newFunction(QTime_msecsTo));
  3093. value.setProperty("restart", engine->newFunction(QTime_restart));
  3094. value.setProperty("second", engine->newFunction(QTime_second));
  3095. value.setProperty("secsTo", engine->newFunction(QTime_secsTo));
  3096. value.setProperty("setHMS", engine->newFunction(QTime_setHMS));
  3097. value.setProperty("start", engine->newFunction(QTime_start));
  3098. value.setProperty("toString", engine->newFunction(QTime_toString));
  3099. value.setProperty("currentTime", engine->newFunction(QTime_currentTime));
  3100. value.setProperty("fromString", engine->newFunction(QTime_fromString));
  3101. value.setProperty("valueOf", engine->newFunction(QTime_valueOf));
  3102. }
  3103. @ The |valueOf()| method exposes a numeric representation of the time
  3104. suitable for use in comparing two time values. With this it is possible to
  3105. take two |QTime| values in script code {\tt t1} and {\tt t2} and get the
  3106. expected results from {\tt t1 == t2}, {\tt t1 < t2}, {\tt t1 > t2} and
  3107. similar comparative operations.
  3108. @<Functions for scripting@>=
  3109. QScriptValue QTime_valueOf(QScriptContext *context, QScriptEngine *)
  3110. {
  3111. QTime self = getself<QTime>(context);
  3112. int retval = (self.hour() * 60 * 60 * 1000) + (self.minute() * 60 * 1000) +
  3113. (self.second() * 1000) + self.msec();
  3114. return QScriptValue(retval);
  3115. }
  3116. @ These functions are effectively wrapper functions around existing |QTime|
  3117. functionality with some error checking for the scripting engine.
  3118. The |addMSecs()| and |addSecs()| methods return a new |QTime| object.
  3119. @<Functions for scripting@>=
  3120. QScriptValue QTime_addMSecs(QScriptContext *context, QScriptEngine *engine)
  3121. {
  3122. QTime time;
  3123. QScriptValue retval;
  3124. if(context->argumentCount() == 1)
  3125. {
  3126. QTime self = getself<QTime>(context);
  3127. time = self.addMSecs(argument<int>(0, context));
  3128. retval = engine->toScriptValue<QTime>(time);
  3129. setQTimeProperties(retval, engine);
  3130. }
  3131. else
  3132. {
  3133. context->throwError("Incorrect number of arguments passed to "@|
  3134. "QTime::addMSecs(). This method takes one "@|
  3135. "integer as an argument.");
  3136. }
  3137. return retval;
  3138. }
  3139. QScriptValue QTime_addSecs(QScriptContext *context, QScriptEngine *engine)
  3140. {
  3141. QTime time;
  3142. QScriptValue retval;
  3143. if(context->argumentCount() == 1)
  3144. {
  3145. QTime self = getself<QTime>(context);
  3146. time = self.addSecs(argument<int>(0, context));
  3147. retval = engine->toScriptValue<QTime>(time);
  3148. setQTimeProperties(retval, engine);
  3149. }
  3150. else
  3151. {
  3152. context->throwError("Incorrect number of arguments passed to "@|
  3153. "QTime::addSecs(). This method takes one "@|
  3154. "integer as an argument.");
  3155. }
  3156. return retval;
  3157. }
  3158. @ The |elapsed()| method returns an integer value.
  3159. @<Functions for scripting@>=
  3160. QScriptValue QTime_elapsed(QScriptContext *context, QScriptEngine *engine)
  3161. {
  3162. QScriptValue retval;
  3163. if(context->argumentCount() == 0)
  3164. {
  3165. QTime self = getself<QTime>(context);
  3166. retval = QScriptValue(engine, self.elapsed());
  3167. }
  3168. else
  3169. {
  3170. context->throwError("Incorrect number of arguments passed to "@|
  3171. "QTime::elapsed(). This method takes no "@|
  3172. "arguments.");
  3173. }
  3174. return retval;
  3175. }
  3176. @ The |hour()|, |minute()|, |second()| and |msec()| methods return an integer
  3177. with various parts of the time. The |hour()| method is typical of these methods.
  3178. @<Functions for scripting@>=
  3179. QScriptValue QTime_hour(QScriptContext *context, QScriptEngine *engine)
  3180. {
  3181. QScriptValue retval;
  3182. if(context->argumentCount() == 0)
  3183. {
  3184. QTime self = getself<QTime>(context);
  3185. retval = QScriptValue(engine, self.hour());
  3186. }
  3187. else
  3188. {
  3189. context->throwError("Incorrect number of arguments passed to "@|
  3190. "QTime::hour(). This method takes no "@|
  3191. "arguments.");
  3192. }
  3193. return retval;
  3194. }
  3195. @ The |minute()|, |second()|, and |msec()| methods are implemented similarly.
  3196. @<Functions for scripting@>=
  3197. QScriptValue QTime_minute(QScriptContext *context, QScriptEngine *engine)
  3198. {
  3199. QScriptValue retval;
  3200. if(context->argumentCount() == 0)
  3201. {
  3202. QTime self = getself<QTime>(context);
  3203. retval = QScriptValue(engine, self.minute());
  3204. }
  3205. else
  3206. {
  3207. context->throwError("Incorrect number of arguments passed to "@|
  3208. "QTime::minute(). This method takes no "@|
  3209. "arguments.");
  3210. }
  3211. return retval;
  3212. }
  3213. QScriptValue QTime_second(QScriptContext *context, QScriptEngine *engine)
  3214. {
  3215. QScriptValue retval;
  3216. if(context->argumentCount() == 0)
  3217. {
  3218. QTime self = getself<QTime>(context);
  3219. retval = QScriptValue(engine, self.second());
  3220. }
  3221. else
  3222. {
  3223. context->throwError("Incorrect number of arguments passed to "@|
  3224. "QTime::second(). This method takes no "@|
  3225. "arguments.");
  3226. }
  3227. return retval;
  3228. }
  3229. QScriptValue QTime_msec(QScriptContext *context, QScriptEngine *engine)
  3230. {
  3231. QScriptValue retval;
  3232. if(context->argumentCount() == 0)
  3233. {
  3234. QTime self = getself<QTime>(context);
  3235. retval = QScriptValue(engine, self.msec());
  3236. }
  3237. else
  3238. {
  3239. context->throwError("Incorrect number of arguments passed to "@|
  3240. "QTime::msec(). This method takes no "@|
  3241. "arguments.");
  3242. }
  3243. return retval;
  3244. }
  3245. @ The |isNull()| and |isValid()| methods return a boolean value. A |QTime| is
  3246. considered null if it was created with a constructor with no arguments. It is
  3247. considered invalid if it is null or if part of the time is out of range.
  3248. @<Functions for scripting@>=
  3249. QScriptValue QTime_isNull(QScriptContext *context, QScriptEngine *engine)
  3250. {
  3251. QScriptValue retval;
  3252. if(context->argumentCount() == 0)
  3253. {
  3254. QTime self = getself<QTime>(context);
  3255. retval = QScriptValue(engine, self.isNull());
  3256. }
  3257. else
  3258. {
  3259. context->throwError("Incorrect number of arguments passed to "@|
  3260. "QTime::isNull(). This method takes no "@|
  3261. "arguments.");
  3262. }
  3263. return retval;
  3264. }
  3265. QScriptValue QTime_isValid(QScriptContext *context, QScriptEngine *engine)
  3266. {
  3267. QScriptValue retval;
  3268. if(context->argumentCount() == 0)
  3269. {
  3270. QTime self = getself<QTime>(context);
  3271. retval = QScriptValue(engine, self.isValid());
  3272. }
  3273. else
  3274. {
  3275. context->throwError("Incorrect number of arguments passed to "@|
  3276. "QTime::isValid(). This method takes no "@|
  3277. "arguments.");
  3278. }
  3279. return retval;
  3280. }
  3281. @ The |secsTo()| and |msecsTo()| methods return an integer value indicating the
  3282. number of seconds or milliseconds until a |QTime| argument.
  3283. @<Functions for scripting@>=
  3284. QScriptValue QTime_msecsTo(QScriptContext *context, QScriptEngine *engine)
  3285. {
  3286. QScriptValue retval;
  3287. if(context->argumentCount() == 1)
  3288. {
  3289. QTime self = getself<QTime>(context);
  3290. QTime arg = argument<QVariant>(0, context).toTime();
  3291. retval = QScriptValue(engine, self.msecsTo(arg));
  3292. }
  3293. else
  3294. {
  3295. context->throwError("Incorrect number of arguments passed to "@|
  3296. "QTime::msecsTo(). This method takes one QTime.");
  3297. }
  3298. return retval;
  3299. }
  3300. QScriptValue QTime_secsTo(QScriptContext *context, QScriptEngine *engine)
  3301. {
  3302. QScriptValue retval;
  3303. if(context->argumentCount() == 1)
  3304. {
  3305. QTime self = getself<QTime>(context);
  3306. QTime arg = argument<QVariant>(0, context).toTime();
  3307. retval = QScriptValue(engine, self.secsTo(arg));
  3308. }
  3309. else
  3310. {
  3311. context->throwError("Incorrect number of arguments passed to "@|
  3312. "QTime::secsTo(). This method takes one QTime.");
  3313. }
  3314. return retval;
  3315. }
  3316. @ The |start()| and |restart()| methods each set the value of the |QTime()| to
  3317. the current time. The |restart()| method additionally returns the same value as
  3318. the |elapsed()| method.
  3319. @<Functions for scripting@>=
  3320. QScriptValue QTime_restart(QScriptContext *context, QScriptEngine *engine)
  3321. {
  3322. QScriptValue retval;
  3323. if(context->argumentCount() == 0)
  3324. {
  3325. QTime self = getself<QTime>(context);
  3326. retval = QScriptValue(engine, self.restart());
  3327. }
  3328. else
  3329. {
  3330. context->throwError("Incorrect number of arguments passed to "@|
  3331. "QTime::restart(). This method takes no "@|
  3332. "arguments.");
  3333. }
  3334. return retval;
  3335. }
  3336. QScriptValue QTime_start(QScriptContext *context, QScriptEngine *)
  3337. {
  3338. if(context->argumentCount() == 0)
  3339. {
  3340. QTime self = getself<QTime>(context);
  3341. self.start();
  3342. }
  3343. else
  3344. {
  3345. context->throwError("Incorrect number of arguments passed to "@|
  3346. "QTime::start(). This method takes no arguments.");
  3347. }
  3348. return QScriptValue();
  3349. }
  3350. @ The slightly inappropriately named |setHMS()| method changes the current value
  3351. of the time and returns a boolean to indicate if the new time value is valid.
  3352. @<Functions for scripting@>=
  3353. QScriptValue QTime_setHMS(QScriptContext *context, QScriptEngine *engine)
  3354. {
  3355. QScriptValue retval;
  3356. if(context->argumentCount() == 3 || context->argumentCount() == 4)
  3357. {
  3358. QTime self = getself<QTime>(context);
  3359. int arg1 = 0;
  3360. int arg2 = 0;
  3361. int arg3 = 0;
  3362. int arg4 = 0;
  3363. switch(context->argumentCount())@/
  3364. {@t\1@>@/
  3365. case 4:@/
  3366. arg4 = argument<int>(3, context);
  3367. case 3:@/
  3368. arg3 = argument<int>(2, context);
  3369. arg2 = argument<int>(1, context);
  3370. arg1 = argument<int>(0, context);
  3371. default:@/
  3372. break;@t\2@>@/
  3373. }
  3374. retval = QScriptValue(engine, self.setHMS(arg1, arg2, arg3, arg4));
  3375. }
  3376. else
  3377. {
  3378. context->throwError("Incorrect number of arguments passed to "@|
  3379. "QTime::setHMS(). This method takes three or "@|
  3380. "four integer arguments.");
  3381. }
  3382. return retval;
  3383. }
  3384. @ The |toString()| method returns a string representation of the time. See the
  3385. Qt documentation for instructions on creating a valid format string.
  3386. @<Functions for scripting@>=
  3387. QScriptValue QTime_toString(QScriptContext *context, QScriptEngine *engine)
  3388. {
  3389. QScriptValue retval;
  3390. if(context->argumentCount() == 1)
  3391. {
  3392. QTime self = getself<QTime>(context);
  3393. retval = QScriptValue(engine, self.toString(argument<QString>(0, context)));
  3394. }
  3395. else
  3396. {
  3397. context->throwError("Incorrect number of arguments passed to "@|
  3398. "QTime::toString(). This method takes one QString "@|
  3399. "as an argument.");
  3400. }
  3401. return retval;
  3402. }
  3403. @ The |currentTime()| and |fromString()| methods return a new |QTime| object.
  3404. These methods make no reference to the any other existing |QTime|.
  3405. @<Functions for scripting@>=
  3406. QScriptValue QTime_currentTime(QScriptContext *, QScriptEngine *engine)
  3407. {
  3408. QScriptValue object;
  3409. object = engine->toScriptValue<QTime>(QTime::currentTime());
  3410. setQTimeProperties(object, engine);
  3411. return object;
  3412. }
  3413. QScriptValue QTime_fromString(QScriptContext *context, QScriptEngine *engine)
  3414. {
  3415. QScriptValue object;
  3416. if(context->argumentCount() == 2)
  3417. {
  3418. QString time = argument<QString>(0, context);
  3419. QString format = argument<QString>(1, context);
  3420. object = engine->toScriptValue<QTime>(QTime::fromString(time, format));
  3421. setQTimeProperties(object, engine);
  3422. }
  3423. else
  3424. {
  3425. context->throwError("Incorrect number of arguments passed to "@|
  3426. "QTime::fromString(). This method takes two "@|
  3427. "string arguments.");
  3428. }
  3429. return object;
  3430. }
  3431. @ In order to pass |QTime| objects back from a script, we also need to overload
  3432. |argument()| for this type.
  3433. @<Functions for scripting@>=
  3434. template<> QTime argument(int arg, QScriptContext *context)
  3435. {
  3436. return qscriptvalue_cast<QTime>(context->argument(arg));
  3437. }
  3438. @* Scripting QColor.
  3439. \noindent |QColor| support is limited to creating colors from strings to pass
  3440. to objects expecting a color.
  3441. @<Function prototypes for scripting@>=
  3442. QScriptValue constructQColor(QScriptContext *context, QScriptEngine *engine);
  3443. @ We must tell the script engine about the constructor. This is not done in
  3444. quite the same way as is done for |QObject| derived types.
  3445. @<Set up the scripting engine@>=
  3446. constructor = engine->newFunction(constructQColor);
  3447. engine->globalObject().setProperty("QColor", constructor);
  3448. @ The constructor is trivial.
  3449. @<Functions for scripting@>=
  3450. QScriptValue constructQColor(QScriptContext *context, QScriptEngine *engine)
  3451. {
  3452. QScriptValue object = engine->toScriptValue<QColor>(QColor(argument<QString>(0, context)));
  3453. return object;
  3454. }
  3455. @* Scripting QBrush.
  3456. \noindent |QBrush| support is limited to creating brushes from color strings to
  3457. pass to objects expecting a brush.
  3458. @<Function prototypes for scripting@>=
  3459. QScriptValue constructQBrush(QScriptContext *context, QScriptEngine *engine);
  3460. @ The script is informed of the constructor.
  3461. @<Set up the scripting engine@>=
  3462. constructor = engine->newFunction(constructQBrush);
  3463. engine->globalObject().setProperty("QBrush", constructor);
  3464. @ The constructor is trivial.
  3465. @<Functions for scripting@>=
  3466. QScriptValue constructQBrush(QScriptContext *context, QScriptEngine *engine)
  3467. {
  3468. QBrush theBrush = QBrush(QColor(argument<QString>(0, context)));
  3469. QScriptValue object = engine->toScriptValue(theBrush);
  3470. return object;
  3471. }
  3472. @* Scripting Item View Classes.
  3473. \noindent |QAbstractScrollArea| is a |QFrame| that serves as the base class for
  3474. classes such as |QGraphicsView| and |QAbstractItemView|. Objects from this class
  3475. are not created directly.
  3476. @<Function prototypes for scripting@>=
  3477. void setQAbstractScrollAreaProperties(QScriptValue value,
  3478. QScriptEngine *engine);
  3479. @ The implementation of this is simple.
  3480. @<Functions for scripting@>=
  3481. void setQAbstractScrollAreaProperties(QScriptValue value, QScriptEngine *engine)
  3482. {
  3483. setQFrameProperties(value, engine);
  3484. }
  3485. @ This class is used by the |QAbstractItemView| class. This is another class
  3486. that we do not need a script constructor for.
  3487. @<Function prototypes for scripting@>=
  3488. void setQAbstractItemViewProperties(QScriptValue value, QScriptEngine *engine);
  3489. @ This function has another simple implementation.
  3490. @<Functions for scripting@>=
  3491. void setQAbstractItemViewProperties(QScriptValue value, QScriptEngine *engine)
  3492. {
  3493. setQAbstractScrollAreaProperties(value, engine);
  3494. }
  3495. @ The |QGraphicsView| and |QTableView| classes form the base of \pn{} classes.
  3496. @<Function prototypes for scripting@>=
  3497. void setQGraphicsViewProperties(QScriptValue value, QScriptEngine *engine);
  3498. void setQTableViewProperties(QScriptValue value, QScriptEngine *engine);
  3499. @ Again, the implementations are boring.
  3500. @<Functions for scripting@>=
  3501. void setQGraphicsViewProperties(QScriptValue value, QScriptEngine *engine)
  3502. {
  3503. setQAbstractScrollAreaProperties(value, engine);
  3504. }
  3505. void setQTableViewProperties(QScriptValue value, QScriptEngine *engine)
  3506. {
  3507. setQAbstractItemViewProperties(value, engine);
  3508. }
  3509. @* Scripting Button Classes.
  3510. \noindent \pn{} provides an |AnnotationButton| class which is a special kind of
  3511. |QPushButton| which in turn comes from |QAbstractButton|. While
  3512. |AnnotationButton| can be used in exactly the same way as a |QPushButton|, if
  3513. an annotation is not needed, there is little reason not to use the base class.
  3514. @<Function prototypes for scripting@>=
  3515. void setQAbstractButtonProperties(QScriptValue value, QScriptEngine *engine);
  3516. void setQPushButtonProperties(QScriptValue value, QScriptEngine *engine);
  3517. QScriptValue constructQPushButton(QScriptContext *context,
  3518. QScriptEngine *engine);
  3519. @ The constructor for |QPushButton| should be passed to the scripting engine.
  3520. @<Set up the scripting engine@>=
  3521. constructor = engine->newFunction(constructQPushButton);
  3522. value = engine->newQMetaObject(&QPushButton::staticMetaObject, constructor);
  3523. engine->globalObject().setProperty("QPushButton", value);
  3524. @ The implementation should seem familiar.
  3525. @<Functions for scripting@>=
  3526. QScriptValue constructQPushButton(QScriptContext *, QScriptEngine *engine)
  3527. {
  3528. QScriptValue object = engine->newQObject(new QPushButton());
  3529. setQPushButtonProperties(object, engine);
  3530. return object;
  3531. }
  3532. void setQPushButtonProperties(QScriptValue value, QScriptEngine *engine)
  3533. {
  3534. setQAbstractButtonProperties(value, engine);
  3535. }
  3536. void setQAbstractButtonProperties(QScriptValue value, QScriptEngine *engine)
  3537. {
  3538. setQWidgetProperties(value, engine);
  3539. }
  3540. @* Scripting QSqlQuery.
  3541. \noindent With this class exposed to the host environment, it becomes possible
  3542. for script code to execute SQL queries and evaluate the result.
  3543. Rather than use |QSqlQuery| directly, however, we use a proxy \nfnote{Erich
  3544. Gamma, Richard Helm, Raph Johnson, and John
  3545. Vlissides,\par\indent\underbar{Design Patterns: elements of reusable
  3546. object-oriented software} (1995) pp. 207--217} class. This class obtains its own
  3547. database connection and handles properly closing and removing these connections
  3548. when the query object is destroyed.
  3549. @<Class declarations@>=
  3550. class SqlQueryConnection : public QSqlQuery@/
  3551. {
  3552. public:@/
  3553. SqlQueryConnection(const QString &query = QString());
  3554. ~SqlQueryConnection();
  3555. QSqlQuery* operator->() const;
  3556. private:@/
  3557. QString connection;
  3558. QSqlQuery *q;
  3559. };
  3560. @ The constructor can be somewhat simplified from the four forms of |QSqlQuery|.
  3561. We are not interested in creating an object from a |QSqlResult| or from another
  3562. |QSqlQuery|. The database connection is managed by the class itself so the
  3563. constructor only needs an optional string containing a query. This is used to
  3564. initialize a real |QSqlQuery| object.
  3565. @<SqlQueryConnection implementation@>=
  3566. SqlQueryConnection::SqlQueryConnection(const QString &query)
  3567. {
  3568. QSqlDatabase database = AppInstance->database();
  3569. database.open();
  3570. q = new QSqlQuery(query, database);
  3571. connection = database.connectionName();
  3572. }
  3573. @ The destructor handles removing the |QSqlQuery| and the database connection
  3574. associated with it. The extra brackets introduce a new scope for the
  3575. |QSqlDatabase| so that it is out of scope when the connection is removed.
  3576. @<SqlQueryConnection implementation@>=
  3577. SqlQueryConnection::~SqlQueryConnection()
  3578. {
  3579. delete q;
  3580. {
  3581. QSqlDatabase database = QSqlDatabase::database(connection);
  3582. database.close();
  3583. }
  3584. QSqlDatabase::removeDatabase(connection);
  3585. }
  3586. @ For all other functionality, we simply forward the request to our |QSqlQuery|
  3587. object.
  3588. @<SqlQueryConnection implementation@>=
  3589. QSqlQuery* SqlQueryConnection::operator->() const
  3590. {
  3591. return q;
  3592. }
  3593. @ In order to use this new class in the host environment, a number of functions
  3594. are needed.
  3595. @<Function prototypes for scripting@>=
  3596. void setQSqlQueryProperties(QScriptValue value, QScriptEngine *engine);
  3597. QScriptValue constructQSqlQuery(QScriptContext *context, QScriptEngine *engine);
  3598. QScriptValue QSqlQuery_bind(QScriptContext *context, QScriptEngine *engine);
  3599. QScriptValue QSqlQuery_bindDeviceData(QScriptContext *context,
  3600. QScriptEngine *engine);
  3601. QScriptValue QSqlQuery_bindFileData(QScriptContext *context,
  3602. QScriptEngine *engine);
  3603. QScriptValue QSqlQuery_exec(QScriptContext *context,
  3604. QScriptEngine *engine);
  3605. QScriptValue QSqlQuery_executedQuery(QScriptContext *context,
  3606. QScriptEngine *engine);
  3607. QScriptValue QSqlQuery_invalidate(QScriptContext *context, QScriptEngine *engine);
  3608. QScriptValue QSqlQuery_next(QScriptContext *context, QScriptEngine *engine);
  3609. QScriptValue QSqlQuery_prepare(QScriptContext *context, QScriptEngine *engine);
  3610. QScriptValue QSqlQuery_value(QScriptContext *context, QScriptEngine *engine);
  3611. @ For conceptual convenience we simply pretend that we are working with a real
  3612. |QSqlQuery| object.
  3613. @<Set up the scripting engine@>=
  3614. constructor = engine->newFunction(constructQSqlQuery);
  3615. engine->globalObject().setProperty("QSqlQuery", constructor);
  3616. @ With connection creation no longer needed in the constructor, all that is
  3617. needed is object creation and applying the appropriate properties to the script
  3618. value.
  3619. @<Functions for scripting@>=
  3620. QScriptValue constructQSqlQuery(QScriptContext *, QScriptEngine *engine)
  3621. {
  3622. SqlQueryConnection *obj = new SqlQueryConnection();
  3623. QScriptValue object =
  3624. engine->toScriptValue<void *>(obj);
  3625. setQSqlQueryProperties(object, engine);
  3626. return object;
  3627. }
  3628. @ As this class does not derive from |QObject|, we must wrap all of the methods
  3629. we might want to use.
  3630. @<Functions for scripting@>=
  3631. void setQSqlQueryProperties(QScriptValue value, QScriptEngine *engine)
  3632. {
  3633. value.setProperty("bind", engine->newFunction(QSqlQuery_bind));
  3634. value.setProperty("bindFileData",
  3635. engine->newFunction(QSqlQuery_bindFileData));
  3636. value.setProperty("bindDeviceData",
  3637. engine->newFunction(QSqlQuery_bindDeviceData));
  3638. value.setProperty("exec", engine->newFunction(QSqlQuery_exec));
  3639. value.setProperty("executedQuery", engine->newFunction(QSqlQuery_executedQuery));
  3640. value.setProperty("invalidate", engine->newFunction(QSqlQuery_invalidate));
  3641. value.setProperty("next", engine->newFunction(QSqlQuery_next));
  3642. value.setProperty("prepare", engine->newFunction(QSqlQuery_prepare));
  3643. value.setProperty("value", engine->newFunction(QSqlQuery_value));
  3644. }
  3645. @ Most of these properties are wrappers around existing |QSqlQuery| functions.
  3646. @<Functions for scripting@>=
  3647. QScriptValue QSqlQuery_exec(QScriptContext *context, QScriptEngine *engine)
  3648. {
  3649. QSqlQuery *q = getself<SqlQueryConnection *>(context)->operator->();
  3650. QScriptValue retval;
  3651. if(context->argumentCount() == 1)
  3652. {
  3653. retval = QScriptValue(engine,
  3654. q->exec(argument<QString>(0, context)));
  3655. }
  3656. else
  3657. {
  3658. retval = QScriptValue(engine, q->exec());
  3659. }
  3660. if(q->lastError().isValid())
  3661. {
  3662. qDebug() << q->lastQuery();
  3663. qDebug() << q->lastError().text();
  3664. }
  3665. return retval;
  3666. }
  3667. QScriptValue QSqlQuery_executedQuery(QScriptContext *context, QScriptEngine *)
  3668. {
  3669. QSqlQuery *query = getself<SqlQueryConnection *>(context)->operator->();
  3670. return QScriptValue(query->lastQuery());
  3671. }
  3672. QScriptValue QSqlQuery_next(QScriptContext *context, QScriptEngine *engine)
  3673. {
  3674. QSqlQuery *query = getself<SqlQueryConnection *>(context)->operator->();
  3675. return QScriptValue(engine, query->next());
  3676. }
  3677. QScriptValue QSqlQuery_value(QScriptContext *context, QScriptEngine *engine)
  3678. {
  3679. QSqlQuery *query = getself<SqlQueryConnection *>(context)->operator->();
  3680. return QScriptValue(engine,
  3681. query->value(argument<int>(0, context)).toString());
  3682. }
  3683. @ For prepared queries, we support binding variables available to the script,
  3684. data available in a named file, or data from any open |QIODevice|.
  3685. @<Functions for scripting@>=
  3686. QScriptValue QSqlQuery_prepare(QScriptContext *context, QScriptEngine *engine)
  3687. {
  3688. QSqlQuery *query = getself<SqlQueryConnection *>(context)->operator->();
  3689. return QScriptValue(engine, query->prepare(argument<QString>(0, context)));
  3690. }
  3691. QScriptValue QSqlQuery_bind(QScriptContext *context, QScriptEngine *)
  3692. {
  3693. QSqlQuery *query = getself<SqlQueryConnection *>(context)->operator->();
  3694. query->bindValue(argument<QString>(0, context),
  3695. argument<QVariant>(1, context));
  3696. return QScriptValue();
  3697. }
  3698. QScriptValue QSqlQuery_bindFileData(QScriptContext *context,
  3699. QScriptEngine *)
  3700. {
  3701. QSqlQuery *query = getself<SqlQueryConnection *>(context)->operator->();
  3702. QString placeholder = argument<QString>(0, context);
  3703. QString filename = argument<QString>(1, context);
  3704. QFile file(filename);
  3705. QByteArray data;
  3706. if(file.open(QIODevice::ReadOnly))
  3707. {
  3708. data = file.readAll();
  3709. file.close();
  3710. }
  3711. query->bindValue(placeholder, data);
  3712. return QScriptValue();
  3713. }
  3714. QScriptValue QSqlQuery_bindDeviceData(QScriptContext *context,
  3715. QScriptEngine *)
  3716. {
  3717. QSqlQuery *query = getself<SqlQueryConnection *>(context)->operator->();
  3718. QString placeholder = argument<QString>(0, context);
  3719. QIODevice *device = argument<QIODevice *>(1, context);
  3720. device->reset();
  3721. QByteArray data;
  3722. data = device->readAll();
  3723. query->bindValue(placeholder, data);
  3724. return QScriptValue();
  3725. }
  3726. @ To avoid leaking database connections, we add the |invalidate()| property
  3727. which destroys our object. The object on which this method is called must not be
  3728. used after calling this method. In script code this will typically be used as in
  3729. the following example:
  3730. {\tt query = query.invalidate();}
  3731. @<Functions for scripting@>=
  3732. QScriptValue QSqlQuery_invalidate(QScriptContext *context, QScriptEngine *)
  3733. {
  3734. SqlQueryConnection *query = getself<SqlQueryConnection *>(context);
  3735. delete query;
  3736. return QScriptValue::UndefinedValue;
  3737. }
  3738. @* Other scripting functions.
  3739. \noindent There are a few functions that are exposed to the scripting engine
  3740. that are not associated with any class. Two functions are used for extracting
  3741. information from file names. Another is used to construct array values from SQL
  3742. array values. There is also a function for setting the default font for the
  3743. application or some part of the application.
  3744. @<Function prototypes for scripting@>=
  3745. QScriptValue baseName(QScriptContext *context, QScriptEngine *engine);
  3746. QScriptValue dir(QScriptContext *context, QScriptEngine *engine);
  3747. QScriptValue sqlToArray(QScriptContext *context, QScriptEngine *engine);
  3748. QScriptValue setFont(QScriptContext *context, QScriptEngine *engine);
  3749. QScriptValue annotationFromRecord(QScriptContext *context,
  3750. QScriptEngine *engine);
  3751. QScriptValue setTabOrder(QScriptContext *context, QScriptEngine *engine);
  3752. QScriptValue saveFileFromDatabase(QScriptContext *context, QScriptEngine *engine);
  3753. QScriptValue scriptTr(QScriptContext *context, QScriptEngine *engine);
  3754. @ These functions are passed to the scripting engine.
  3755. @<Set up the scripting engine@>=
  3756. engine->globalObject().setProperty("baseName", engine->newFunction(baseName));
  3757. engine->globalObject().setProperty("dir", engine->newFunction(dir));
  3758. engine->globalObject().setProperty("sqlToArray",
  3759. engine->newFunction(sqlToArray));
  3760. engine->globalObject().setProperty("setFont", engine->newFunction(setFont));
  3761. engine->globalObject().setProperty("annotationFromRecord",
  3762. engine->newFunction(annotationFromRecord));
  3763. engine->globalObject().setProperty("setTabOrder",
  3764. engine->newFunction(setTabOrder));
  3765. engine->globalObject().setProperty("saveFileFromDatabase",
  3766. engine->newFunction(saveFileFromDatabase));
  3767. engine->globalObject().setProperty("TTR", engine->newFunction(scriptTr));
  3768. @ These functions are not part of an object. They expect a string specifying
  3769. the path to a file and return a string with either the name of the file without
  3770. the path and extension or the path of the directory containing the file.
  3771. @<Functions for scripting@>=
  3772. QScriptValue baseName(QScriptContext *context, QScriptEngine *engine)
  3773. {
  3774. QFileInfo info(argument<QString>(0, context));
  3775. QScriptValue retval(engine, info.baseName());
  3776. return retval;
  3777. }
  3778. QScriptValue dir(QScriptContext *context, QScriptEngine *engine)
  3779. {
  3780. QFileInfo info(argument<QString>(0, context));
  3781. QDir dir = info.dir();
  3782. QScriptValue retval(engine, dir.path());
  3783. return retval;
  3784. }
  3785. @ This function takes a file ID and a file name and copies file data stored in
  3786. the database out to the file system.
  3787. @<Functions for scripting@>=
  3788. QScriptValue saveFileFromDatabase(QScriptContext *context, QScriptEngine *)
  3789. {
  3790. SqlQueryConnection h;
  3791. QSqlQuery *query = h.operator->();
  3792. QString q = "SELECT file FROM files WHERE id = :file";
  3793. query->prepare(q);
  3794. query->bindValue(":file", argument<int>(0, context));
  3795. query->exec();
  3796. query->next();
  3797. QByteArray array = query->value(0).toByteArray();
  3798. QFile file(argument<QString>(1, context));
  3799. file.open(QIODevice::WriteOnly);
  3800. file.write(array);
  3801. file.close();
  3802. return QScriptValue();
  3803. }
  3804. @ This function takes a string representing a SQL array and returns an array
  3805. value.
  3806. @<Functions for scripting@>=
  3807. QScriptValue sqlToArray(QScriptContext *context, QScriptEngine *engine)
  3808. {
  3809. QString source = argument<QString>(0, context);
  3810. source.remove(0, 1);
  3811. source.chop(1);
  3812. QStringList elements = source.split(",");
  3813. QString element;
  3814. QScriptValue dest = engine->newArray(elements.size());
  3815. int i = 0;
  3816. foreach(element, elements)
  3817. {
  3818. if(element.startsWith("\"") && element.endsWith("\""))
  3819. {
  3820. element.chop(1);
  3821. element = element.remove(0, 1);
  3822. }
  3823. dest.setProperty(i, QScriptValue(engine, element));
  3824. i++;
  3825. }
  3826. return dest;
  3827. }
  3828. @ This function can be used to set the default font for the application or on
  3829. a per-class hierarchy basis.
  3830. @<Functions for scripting@>=
  3831. QScriptValue setFont(QScriptContext *context, QScriptEngine *)
  3832. {
  3833. QString font = argument<QString>(0, context);
  3834. QString classname;
  3835. if(context->argumentCount() > 1)
  3836. {
  3837. classname = argument<QString>(1, context);
  3838. QApplication::setFont(QFont(font), classname.toLatin1().constData());
  3839. }
  3840. else
  3841. {
  3842. QApplication::setFont(QFont(font));
  3843. }
  3844. return QScriptValue();
  3845. }
  3846. @ This function was briefly used prior to adding support for |QXmlQuery| in the
  3847. host environment. The function is now depreciated and should not be used.
  3848. @<Functions for scripting@>=
  3849. QScriptValue annotationFromRecord(QScriptContext *context, QScriptEngine *)
  3850. {
  3851. SqlQueryConnection h;
  3852. QSqlQuery *query = h.operator->();
  3853. QString q = "SELECT file FROM files WHERE id = :file";
  3854. query->prepare(q);
  3855. query->bindValue(":file", argument<int>(0, context));
  3856. query->exec();
  3857. query->next();
  3858. QByteArray array = query->value(0).toByteArray();
  3859. QBuffer buffer(&array);
  3860. buffer.open(QIODevice::ReadOnly);
  3861. QXmlQuery xquery;
  3862. xquery.bindVariable("profile", &buffer);
  3863. QString xq;
  3864. xq = "for $b in doc($profile) //tuple where exists($b/annotation) return $b";
  3865. xquery.setQuery(xq);
  3866. QString result;
  3867. xquery.evaluateTo(&result);
  3868. return QScriptValue(result);
  3869. }
  3870. @ This function can be used to change the tab order for controls in Typica.
  3871. Changes to the example configuration in \pn{} 1.4 made the default handling
  3872. of tab controls in the logging window unacceptable.
  3873. @<Functions for scripting@>=
  3874. QScriptValue setTabOrder(QScriptContext *context, QScriptEngine *)
  3875. {
  3876. QWidget::setTabOrder(argument<QWidget*>(0, context),
  3877. argument<QWidget*>(1, context));
  3878. return QScriptValue();
  3879. }
  3880. @ This function is used to allow text that must be placed in scripts to be
  3881. translated into other languages.
  3882. @<Functions for scripting@>=
  3883. QScriptValue scriptTr(QScriptContext *context, QScriptEngine *)
  3884. {
  3885. return QScriptValue(QCoreApplication::translate(
  3886. "configuration",
  3887. argument<QString>(1, context).toUtf8().data()));
  3888. }
  3889. @** Application Configuration.
  3890. \noindent While \pn{} is intended as a data logging application, the diversity
  3891. of equipment and supporting technology precludes the option of providing a
  3892. single interface for common tasks. It is important that the application can be
  3893. configured to work with different roasting equipment, databases, and the like.
  3894. To accomplish this, \pn{} utilizes an XML description of the desired application
  3895. configuration and provides an ECMA-262 host environment which allows application
  3896. dataflow to be configured.
  3897. The scripting environment provides access to elements of the XML file and also
  3898. allows access to most of the application classes. A selection of classes
  3899. provided by Qt is also available. See the section on The Scripting Engine for
  3900. more details.
  3901. \danger While the code is the ultimate documentation of what is possible with
  3902. this interface, additional documentation should be provided to document the
  3903. meaning of supported elements and the objects available through the scripting
  3904. engine.\endanger
  3905. The application configuration is loaded when the program is started.
  3906. Starting with version 1.4, we check for a command line option with the path to
  3907. the configuration file and load that instead of prompting for the information
  3908. if possible.
  3909. Starting with version 1.8, if there is not a -c argument, Typica will first
  3910. search a small number of locations relative to the executable.
  3911. @<Load the application configuration@>=
  3912. QStringList arguments = QCoreApplication::arguments();
  3913. int position = arguments.indexOf("-c");
  3914. QString filename = QString();
  3915. if(position != -1)
  3916. {
  3917. if(arguments.size() >= position + 1)
  3918. {
  3919. filename = arguments.at(position + 1);
  3920. }
  3921. } else {
  3922. QDir checkPath(QCoreApplication::applicationDirPath() + "/../config/");
  3923. if(checkPath.exists("config.xml")) {
  3924. filename = checkPath.filePath("config.xml");
  3925. } else {
  3926. checkPath = QDir(QCoreApplication::applicationDirPath() + "/config/");
  3927. if(checkPath.exists("config.xml")) {
  3928. filename = checkPath.filePath("config.xml");
  3929. }
  3930. }
  3931. }
  3932. if(filename.isEmpty())
  3933. {
  3934. filename = QFileDialog::getOpenFileName(NULL, "Open Configuration File",
  3935. settings.value("config", "").toString());
  3936. }
  3937. QDir directory;
  3938. if(!filename.isEmpty())
  3939. {
  3940. QFile file(filename);
  3941. QFileInfo info(filename);
  3942. directory = info.dir();
  3943. QTextCodec::setCodecForTr(QTextCodec::codecForName("utf-8"));
  3944. QTranslator *configtr = new QTranslator;
  3945. if(configtr->load(QString("config.%1").arg(QLocale::system().name()),
  3946. QString("%1/Translations").arg(directory.canonicalPath())))
  3947. {
  3948. QCoreApplication::installTranslator(configtr);
  3949. }
  3950. settings.setValue("config", directory.path());
  3951. if(file.open(QIODevice::ReadOnly))
  3952. {
  3953. app.configuration()->setContent(&file, true);
  3954. }
  3955. } else {
  3956. return 1;
  3957. }
  3958. @<Substitute included fragments@>@;
  3959. @ The {\tt <application>} element can contain an arbitrary number of
  3960. {\tt <include>} elements. These elements should not appear in the DOM. Instead,
  3961. the element should be replaced by the content of the specified document.
  3962. @<Substitute included fragments@>=
  3963. QDomElement root = app.configuration()->documentElement();
  3964. QDomNodeList children = root.childNodes();
  3965. QString replacementDoc;
  3966. QDomDocument includedDoc;
  3967. QDomDocumentFragment fragment;
  3968. for(int i = 0; i < children.size(); i++)
  3969. {
  3970. QDomNode currentNode = children.at(i);
  3971. QDomElement currentElement;
  3972. if(currentNode.nodeName() == "include")
  3973. {
  3974. currentElement = currentNode.toElement();
  3975. if(currentElement.hasAttribute("src"))
  3976. {
  3977. replacementDoc = directory.path();
  3978. replacementDoc.append('/');
  3979. replacementDoc.append(currentElement.attribute("src"));
  3980. QFile doc(replacementDoc);
  3981. if(doc.open(QIODevice::ReadOnly))
  3982. {
  3983. includedDoc.setContent(&doc, true);
  3984. fragment = includedDoc.createDocumentFragment();
  3985. fragment.appendChild(includedDoc.documentElement());
  3986. root.replaceChild(fragment, currentNode);
  3987. doc.close();
  3988. }
  3989. }
  3990. }
  3991. }
  3992. @ Simply loading the configuration document does not display a user interface or
  3993. set up any objects that allow the program to do anything. To do this, a script
  3994. obtained from the configuration document is run. The root element of the
  3995. document should be {\tt <application>}. This element should have a number of
  3996. child elements including {\tt <window>} elements which describe the various
  3997. windows that can be opened in the application and {\tt <program>} elements
  3998. containing script code. These {\tt <program>} elements can occur in a number of
  3999. different contexts including within {\tt <window>} elements which would indicate
  4000. that such scripts should be evaluated when the window being described is
  4001. created. After the configuration document is loaded, all {\tt <program>}
  4002. elements that are direct children of the {\tt <application>} element are
  4003. concatenated and the script is run.
  4004. Before the script is run and user interface elements are drawn, we also check
  4005. for {\tt <style>} elements which can be used to set up a stylesheet for the
  4006. application.
  4007. @<Find and evaluate starting script@>=
  4008. QString styleText;
  4009. QString programText;
  4010. QDomElement currentElement;
  4011. for(int i = 0; i < children.size(); i++)
  4012. {
  4013. QDomNode currentNode = children.at(i);
  4014. if(currentNode.nodeName() == "style")
  4015. {
  4016. currentElement = currentNode.toElement();
  4017. styleText.append(currentElement.text());
  4018. }
  4019. else if(currentNode.nodeName() == "program")
  4020. {
  4021. currentElement = currentNode.toElement();
  4022. programText.append(currentElement.text());
  4023. }
  4024. }
  4025. app.setStyleSheet(styleText);
  4026. QScriptValue result = engine->evaluate(programText);
  4027. @<Report scripting errors@>
  4028. @ When a script is evaluated, there is a chance that there will be some error in
  4029. the execution of that script. If this occurs, we want to report that.
  4030. @<Report scripting errors@>=
  4031. if(engine->hasUncaughtException())
  4032. {
  4033. int line = engine->uncaughtExceptionLineNumber();
  4034. qDebug() << "Uncaught excpetion at line " << line << " : " <<
  4035. result.toString();
  4036. QString trace;
  4037. foreach(trace, engine->uncaughtExceptionBacktrace())
  4038. {
  4039. qDebug() << trace;
  4040. }
  4041. }
  4042. @* Creating a window.
  4043. \noindent When a configuration document is loaded, none of the {\tt <window>}
  4044. elements are interpreted or used to create a graphical user interface. Instead,
  4045. any {\tt <program>} elements that are immediate children of the
  4046. {\tt <application>} element are interpreted. In order to convert a
  4047. {\tt <window>} element into a window displayed on screen, the script in the
  4048. {\tt <program>} elements must call a function to display a specified window.
  4049. Report windows can be produced by scripts in a similar, but slightly different
  4050. manner.
  4051. \danger This design works, but it'@q'@>s not particularly good design. It was written
  4052. under severe time constraints and should be redesigned or at least cleaned up
  4053. and reorganized.\endanger
  4054. @<Function prototypes for scripting@>=
  4055. QScriptValue createWindow(QScriptContext *context, QScriptEngine *engine);
  4056. QScriptValue createReport(QScriptContext *context, QScriptEngine *engine);
  4057. void addLayoutToWidget(QDomElement element, QStack<QWidget*> *widgetStack,
  4058. QStack<QLayout*> *layoutStack);
  4059. void addLayoutToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4060. QStack<QLayout *> *layoutStack);
  4061. void addSplitterToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4062. QStack<QLayout *> *layoutStack);
  4063. void addSplitterToSplitter(QDomElement element, QStack<QWidget *> *widgetStack,
  4064. QStack<QLayout *> *layoutStack);
  4065. void populateGridLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4066. QStack<QLayout *> *layoutStack);
  4067. void populateBoxLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4068. QStack<QLayout *> *layoutStack);
  4069. void populateSplitter(QDomElement element, QStack<QWidget *> *widgetStack,@|
  4070. QStack<QLayout *> *layoutStack);
  4071. void populateWidget(QDomElement element, QStack<QWidget *> *widgetStack,@|
  4072. QStack<QLayout *> *layoutStack);
  4073. void populateStackedLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4074. QStack<QLayout *> *layoutStack);
  4075. void populateFormLayout(QDomElement element, QStack<QWidget *> *widgetStack,@|
  4076. QStack<QLayout *> *layoutStack);
  4077. void addTemperatureDisplayToSplitter(QDomElement element,@|
  4078. QStack<QWidget *> *widgetStack,
  4079. QStack<QLayout *> *layoutStack);
  4080. void addTemperatureDisplayToLayout(QDomElement element,@|
  4081. QStack<QWidget *> *widgetStack,
  4082. QStack<QLayout *> *layoutStack);
  4083. void addTimerDisplayToSplitter(QDomElement element,@|
  4084. QStack<QWidget *> *widgetStack,
  4085. QStack<QLayout *> *layoutStack);
  4086. void addTimerDisplayToLayout(QDomElement element,@|
  4087. QStack<QWidget *> *widgetStack,
  4088. QStack<QLayout *> *layoutStack);
  4089. void addDecorationToSplitter(QDomElement element,@|
  4090. QStack<QWidget *> *widgetStack,
  4091. QStack<QLayout *> *layoutStack);
  4092. void addDecorationToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4093. QStack<QLayout *> *layoutStack);
  4094. void addWidgetToSplitter(QDomElement element, QStack<QWidget *> *widgetStack,
  4095. QStack<QLayout *> *layoutStack);
  4096. void addButtonToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4097. QStack<QLayout *> *layoutStack);
  4098. void addZoomLogToSplitter(QDomElement element, QStack<QWidget *> *widgetStack,
  4099. QStack<QLayout *> *layoutStack);
  4100. void addGraphToSplitter(QDomElement element, QStack<QWidget *> *widgetStack,
  4101. QStack<QLayout *> *layoutStack);
  4102. void addSqlDropToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4103. QStack<QLayout *> *layoutStack);
  4104. void addSaltToLayout(QDomElement element, QStack<QWidget *> *widgetStack,@|
  4105. QStack<QLayout *> *layoutStack);
  4106. void addLineToLayout(QDomElement element, QStack<QWidget *> *widgetStack,@|
  4107. QStack<QLayout *> *layoutStack);
  4108. void addTextToLayout(QDomElement element, QStack<QWidget *> *widgetStack,@|
  4109. QStack<QLayout *> *layoutStack);
  4110. void addSqlQueryViewToLayout(QDomElement element,
  4111. QStack<QWidget *> *widgetStack,
  4112. QStack<QLayout *> *layoutStack);
  4113. void addCalendarToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4114. QStack<QLayout *> *layoutStack);
  4115. void addSpinBoxToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4116. QStack<QLayout *> *layoutStack);
  4117. void addTimeEditToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4118. QStack<QLayout *> *layoutStack);
  4119. @ The functions for creating windows must be made available to the scripting
  4120. engine.
  4121. @<Set up the scripting engine@>=
  4122. engine->globalObject().setProperty("createWindow",
  4123. engine->newFunction(createWindow));
  4124. engine->globalObject().setProperty("createReport",
  4125. engine->newFunction(createReport));
  4126. @ This function must examine the configuration document in search of the
  4127. appropriate window element, parse the contents of that element, and create a
  4128. multitude of objects, all of which must be passed to the scripting engine.
  4129. @<Functions for scripting@>=
  4130. QScriptValue createWindow(QScriptContext *context, QScriptEngine *engine)@/
  4131. {
  4132. QString targetID = argument<QString>(0, context);
  4133. QDomNode element;
  4134. QScriptValue object;
  4135. @<Find the window element@>@;
  4136. if(!element.isNull())
  4137. {
  4138. @<Display the window@>@;
  4139. }
  4140. return object;
  4141. }
  4142. @ Report files are not part of the configuration document and must be created
  4143. differently. While there is a special menu type that handles all of this
  4144. without involving the host environment, scripted generation and manipulation of
  4145. report windows requires another function. This function will only work after a
  4146. window with a reports menu has been created.
  4147. @<Functions for scripting@>=
  4148. QScriptValue createReport(QScriptContext *context, QScriptEngine *engine)
  4149. {
  4150. QString targetID = argument<QString>(0, context);
  4151. QFile file(QString("reports:%1").arg(targetID));
  4152. QScriptValue object;
  4153. if(file.open(QIODevice::ReadOnly))
  4154. {
  4155. QDomDocument document;
  4156. document.setContent(&file, true);
  4157. QDomElement element = document.documentElement();
  4158. if(!element.isNull())
  4159. {
  4160. @<Display the window@>@;
  4161. }
  4162. file.close();
  4163. }
  4164. return object;
  4165. }
  4166. @ First we must locate the {\tt <window>} element. The most sensible way to do
  4167. this would require that each {\tt <window>} element has an ID attribute and
  4168. search the DOM tree for that ID. Unfortunately, as of this writing,
  4169. |QDomDocument::elementByID()| always returns a null element, so that won'@q'@>t work.
  4170. Instead, we search the tree for all {\tt <window>} elements and then examine
  4171. the resulting list to find the element with the appropriate ID.
  4172. @<Find the window element@>=
  4173. QDomNodeList windows =
  4174. AppInstance->configuration()->documentElement().elementsByTagName("window");
  4175. QDomNode nullNode;
  4176. int i = 0;
  4177. element = nullNode;
  4178. while(i < windows.count())
  4179. {
  4180. element = windows.at(i);
  4181. QDomNamedNodeMap attributes = element.attributes();
  4182. if(attributes.contains("id"))
  4183. {
  4184. if(attributes.namedItem("id").toAttr().value() == targetID)
  4185. {
  4186. break;
  4187. }
  4188. }
  4189. element = nullNode;
  4190. i++;
  4191. }
  4192. @ In order to display a window, we start by creating a new |ScriptQMainWindow|
  4193. and set the central widget of that window to a new |QWidget|. After this, we see
  4194. if the window element has any children and proceed to populate the window.
  4195. When creating child elements, care must be taken that all objects are descended
  4196. from the window. If an object is descended from the window and has an object
  4197. name, it will be possible for script code to recover the created object.
  4198. As of version 1.4, the window itself is given the value of its {\tt id}
  4199. attribute as an object name to facilitate automatic window geometry management.
  4200. @<Display the window@>=
  4201. ScriptQMainWindow *window = new ScriptQMainWindow;
  4202. window->setObjectName(targetID);
  4203. object = engine->newQObject(window);
  4204. setQMainWindowProperties(object, engine);
  4205. QWidget *central = new(QWidget);
  4206. central->setParent(window);
  4207. central->setObjectName("centralWidget");
  4208. window->setCentralWidget(central);
  4209. if(element.hasChildNodes())
  4210. {
  4211. @<Process window children@>@;
  4212. }
  4213. @<Insert help menu@>@;
  4214. window->show();
  4215. window->setupFinished();
  4216. @ Three element types make sense as top level children of a {\tt <window>}
  4217. element. An element representing a layout element can be used to apply that
  4218. layout to the central widget. An element representing a menu can be used to add
  4219. a menu to the window. A {\tt <program>} element can be used to specify a script
  4220. to be run after the window has been assembled.
  4221. \danger As the window comes with a blank central widget, elements representing
  4222. a widget to be used as the central widget of the window cannot be used directly
  4223. here. If only one widget is needed in the window, there is a need to create a
  4224. layout element and place that widget in the layout. Also note that there is not
  4225. enough error checking in the following code. Provide invalid input at your
  4226. peril.\endanger
  4227. Program fragments pulled from the window description are executed with the
  4228. newly created window available as {\tt this}. When such a fragment is run, the
  4229. entire description of the window will have already been evaluated and any
  4230. necessary objects created. Obtaining a child object of the window can be done
  4231. by calling |findChildObject()|.
  4232. @<Process window children@>=
  4233. QStack<QWidget*> widgetStack;
  4234. QStack<QLayout*> layoutStack;
  4235. QString windowScript;
  4236. widgetStack.push(central);
  4237. QDomNodeList windowChildren = element.childNodes();
  4238. int i = 0;
  4239. while(i < windowChildren.count())
  4240. {
  4241. QDomNode current;
  4242. QDomElement element;
  4243. current = windowChildren.at(i);
  4244. if(current.isElement())
  4245. {
  4246. element = current.toElement();
  4247. if(element.tagName() == "program")
  4248. {
  4249. windowScript.append(element.text());
  4250. }
  4251. else if(element.tagName() == "layout")
  4252. {
  4253. element.setAttribute("trcontext", "configuration");
  4254. addLayoutToWidget(element, &widgetStack, &layoutStack);
  4255. }
  4256. else if(element.tagName() == "menu")
  4257. {
  4258. @<Process menus@>@;
  4259. }
  4260. }
  4261. i++;
  4262. }
  4263. QScriptValue oldThis = context->thisObject();
  4264. context->setThisObject(object);
  4265. QScriptValue result = engine->evaluate(windowScript);
  4266. @<Report scripting errors@>@;
  4267. context->setThisObject(oldThis);
  4268. @ Elements representing menus may provide a number of child elements
  4269. representing the items in that menu. The XML portion of the configuration will
  4270. not provide any information on what these menu items do. The contents of the
  4271. {\tt <program>} element for the window will need to request the |QAction|
  4272. objects and connect a signal from that object to the desired functionality.
  4273. One special consideration is the Reports menu. This menu will populate itself
  4274. according to its own logic and will have a {\tt type} property of
  4275. {\tt "reports"} and a {\tt src} property indicating the directory where reports
  4276. can be found.
  4277. @<Process menus@>=
  4278. QMenuBar *bar = window->menuBar();
  4279. bar->setParent(window);
  4280. bar->setObjectName("menuBar");
  4281. if(element.hasAttribute("name"))
  4282. {
  4283. QMenu *menu = bar->addMenu(QCoreApplication::translate("configuration",
  4284. element.attribute("name").toUtf8().data()));
  4285. menu->setParent(bar);
  4286. if(element.hasAttribute("type"))
  4287. {
  4288. if(element.attribute("type") == "reports")
  4289. {
  4290. if(element.hasAttribute("src"))
  4291. {
  4292. @<Populate reports menu@>@;
  4293. }
  4294. }
  4295. }
  4296. if(element.hasChildNodes())
  4297. {
  4298. @<Process menu items@>@;
  4299. }
  4300. }
  4301. @ To add items to a menu, we check for {\tt <item>} elements under the
  4302. {\tt <menu>} element and create a |QAction| for each item.
  4303. @<Process menu items@>=
  4304. QDomNodeList menuItems = element.childNodes();
  4305. int j = 0;
  4306. while(j < menuItems.count())
  4307. {
  4308. QDomNode item = menuItems.at(j);
  4309. if(item.isElement())
  4310. {
  4311. QDomElement itemElement = item.toElement();
  4312. if(itemElement.tagName() == "item")
  4313. {
  4314. QAction *itemAction = new QAction(QCoreApplication::translate("configuration",
  4315. itemElement.text().toUtf8().data()), menu);
  4316. if(itemElement.hasAttribute("id"))
  4317. {
  4318. itemAction->setObjectName(itemElement.attribute("id"));
  4319. }
  4320. if(itemElement.hasAttribute("shortcut"))
  4321. {
  4322. itemAction->setShortcut(itemElement.attribute("shortcut"));
  4323. }
  4324. menu->addAction(itemAction);
  4325. }
  4326. else if(itemElement.tagName() == "separator")
  4327. {
  4328. menu->addSeparator();
  4329. }
  4330. else if(itemElement.tagName() == "plugins")
  4331. {
  4332. @<Process plugin item@>@;
  4333. }
  4334. }
  4335. j++;
  4336. }
  4337. @i helpmenu.w
  4338. @i licensewindow.w
  4339. @ A layout can contain a number of different elements including a variety of
  4340. widget types and other layouts. This function is responsible for applying any
  4341. layout class to the widget currently being populated and processing children of
  4342. the {\tt <layout>} element to populate that layout. External stacks are used to
  4343. keep track of which widgets and layouts are currently being populated. The
  4344. {\tt type} attribute is used to determine what sort of layout should be created.
  4345. Currently, {\tt horizontal}, {\tt vertical}, {\tt grid}, and {\tt stack} types
  4346. are supported. The first two resolve to |QBoxLayout| layouts, {\tt grid}
  4347. resolves to a |QGridLayout|, and {\tt stack} resolves to a |QStackedLayout|.
  4348. @<Functions for scripting@>=
  4349. void addLayoutToWidget(QDomElement element, QStack<QWidget*> *widgetStack,
  4350. QStack<QLayout*> *layoutStack)
  4351. {
  4352. if(element.hasAttribute("type"))
  4353. {
  4354. @<Create and populate layout@>@;
  4355. QWidget *widget = widgetStack->top();
  4356. if(layout)
  4357. {
  4358. widget->setLayout(layout);
  4359. }
  4360. layoutStack->pop();
  4361. }
  4362. }
  4363. @ As there are multiple places where a {\tt <layout>} element is parsed with
  4364. slightly different semantics, the code for creating and populating the layout is
  4365. broken out so that code written to support additional layout types only needs to
  4366. be written once.
  4367. @<Create and populate layout@>=
  4368. QLayout *layout;
  4369. QString layoutType = element.attribute("type");
  4370. if(layoutType == "horizontal")
  4371. {
  4372. layout = new QHBoxLayout;
  4373. layoutStack->push(layout);
  4374. populateBoxLayout(element, widgetStack, layoutStack);
  4375. }
  4376. else if(layoutType == "vertical")
  4377. {
  4378. layout = new QVBoxLayout;
  4379. layoutStack->push(layout);
  4380. populateBoxLayout(element, widgetStack, layoutStack);
  4381. }
  4382. else if(layoutType == "grid")
  4383. {
  4384. layout = new QGridLayout;
  4385. layoutStack->push(layout);
  4386. populateGridLayout(element, widgetStack, layoutStack);
  4387. }
  4388. else if(layoutType == "stack")
  4389. {
  4390. layout = new QStackedLayout;
  4391. layoutStack->push(layout);
  4392. populateStackedLayout(element, widgetStack, layoutStack);
  4393. }
  4394. else if(layoutType == "form")
  4395. {
  4396. layout = new QFormLayout;
  4397. layoutStack->push(layout);
  4398. populateFormLayout(element, widgetStack, layoutStack);
  4399. }
  4400. if(element.hasAttribute("id"))
  4401. {
  4402. layout->setObjectName(element.attribute("id"));
  4403. }
  4404. if(element.hasAttribute("spacing"))
  4405. {
  4406. layout->setSpacing(element.attribute("spacing").toInt());
  4407. }
  4408. if(element.hasAttribute("margin"))
  4409. {
  4410. int m = element.attribute("margin").toInt();
  4411. layout->setContentsMargins(m, m, m, m);
  4412. }
  4413. @ Any direct child of a form layout must be a {\tt <row>} element to specify
  4414. the label for the given row. The field for the given row will always be a
  4415. |QVBoxLayout| containing whatever is specified by children of the {\tt <row>}.
  4416. @<Functions for scripting@>=
  4417. void populateFormLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4418. QStack<QLayout *> *layoutStack)
  4419. {
  4420. QDomNodeList children = element.childNodes();
  4421. QFormLayout *layout = qobject_cast<QFormLayout *>(layoutStack->top());
  4422. for(int i = 0; i < children.count(); i++)
  4423. {
  4424. QDomNode current;
  4425. QDomElement currentElement;
  4426. current = children.at(i);
  4427. if(current.isElement())
  4428. {
  4429. currentElement = current.toElement();
  4430. if(currentElement.tagName() == "row")
  4431. {
  4432. QString label = QString();
  4433. if(currentElement.hasAttribute("label"))
  4434. {
  4435. label = currentElement.attribute("label");
  4436. }
  4437. QVBoxLayout *childLayout = new QVBoxLayout;
  4438. layoutStack->push(childLayout);
  4439. populateBoxLayout(currentElement, widgetStack, layoutStack);
  4440. if(label.isEmpty())
  4441. {
  4442. layout->addRow(childLayout);
  4443. }
  4444. else
  4445. {
  4446. layout->addRow(label, childLayout);
  4447. }
  4448. }
  4449. }
  4450. }
  4451. }
  4452. @ Stacked layouts are a bit different from the other types. A stacked layout has
  4453. an arbitrary number of {\tt <page>} children which are just a |QWidget| which
  4454. can have the same child elements as {\tt <widget>} elements elsewhere. Only the
  4455. first page will be visible initially, however it is possible to use script code
  4456. to set the currently visible page provided that an ID is set for the layout.
  4457. @<Functions for scripting@>=
  4458. void populateStackedLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4459. QStack<QLayout *> *layoutStack)
  4460. {
  4461. QDomNodeList children = element.childNodes();
  4462. QStackedLayout *layout = qobject_cast<QStackedLayout *>(layoutStack->top());
  4463. for(int i = 0; i < children.count(); i++)
  4464. {
  4465. QDomNode current;
  4466. QDomElement currentElement;
  4467. current = children.at(i);
  4468. if(current.isElement())
  4469. {
  4470. currentElement = current.toElement();
  4471. if(currentElement.tagName() == "page")
  4472. {
  4473. QWidget *widget = new QWidget;
  4474. layout->addWidget(widget);
  4475. widgetStack->push(widget);
  4476. currentElement.setAttribute("trcontext", "configuration");
  4477. populateWidget(currentElement, widgetStack, layoutStack);
  4478. widgetStack->pop();
  4479. }
  4480. }
  4481. }
  4482. }
  4483. @ A common use of stacked layouts is in the creation of tabbed interfaces, but
  4484. there are also many uses in \pn{} where the tabs are not required. Therefore,
  4485. tab bar creation requires a separate XML element.
  4486. @<Additional box layout elements@>=
  4487. else if(currentElement.tagName() == "tabbar")
  4488. {
  4489. addTabBarToLayout(currentElement, widgetStack, layoutStack);
  4490. }
  4491. @ The function used to create this follows the usual pattern.
  4492. @<Functions for scripting@>=
  4493. void addTabBarToLayout(QDomElement element, QStack<QWidget*> *, QStack<QLayout*> *layoutStack)
  4494. {
  4495. QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
  4496. QTabBar *widget = new QTabBar;
  4497. layout->addWidget(widget);
  4498. if(!element.attribute("id").isEmpty())
  4499. {
  4500. widget->setObjectName(element.attribute("id"));
  4501. }
  4502. }
  4503. @ Rather than define the tab set in XML, this is left to the host environment.
  4504. This means that some additional scripting support is required.
  4505. @<Set up the scripting engine@>=
  4506. constructor = engine->newFunction(constructQTabBar);
  4507. value = engine->newQMetaObject(&QTabBar::staticMetaObject, constructor);
  4508. engine->globalObject().setProperty("QTabBar", value);
  4509. @ The constructor is trivial.
  4510. @<Functions for scripting@>=
  4511. QScriptValue constructQTabBar(QScriptContext *, QScriptEngine *engine)
  4512. {
  4513. QScriptValue object = engine->newQObject(new QTabBar);
  4514. setQTabBarProperties(object, engine);
  4515. return object;
  4516. }
  4517. @ There are many functions that I might want to some day add support for, but
  4518. the immediate need is just creating the tabs in the first place.
  4519. @<Functions for scripting@>=
  4520. void setQTabBarProperties(QScriptValue value, QScriptEngine *engine)
  4521. {
  4522. setQWidgetProperties(value, engine);
  4523. value.setProperty("addTab", engine->newFunction(QTabBar_addTab));
  4524. }
  4525. QScriptValue QTabBar_addTab(QScriptContext *context, QScriptEngine *)
  4526. {
  4527. QTabBar *self = getself<QTabBar *>(context);
  4528. if(context->argumentCount() > 0)
  4529. {
  4530. self->addTab(argument<QString>(0, context));
  4531. }
  4532. else
  4533. {
  4534. context->throwError("Incorrect number of arguments passed to "@|
  4535. "QTabBar::addTab().");
  4536. }
  4537. return QScriptValue();
  4538. }
  4539. @ Function prototypes are needed.
  4540. @<Function prototypes for scripting@>=
  4541. QScriptValue constructQTabBar(QScriptContext *context, QScriptEngine *engine);
  4542. void setQTabBarProperties(QScriptValue value, QScriptEngine *engine);
  4543. QScriptValue QTabBar_addTab(QScriptContext *context, QScriptEngine *engine);
  4544. @ Using a grid layout is a bit different from using a box layout. Child elements
  4545. with various attributes are required to take full advantage of this layout type.
  4546. All direct children of a grid layout element should be {\tt <row>} elements
  4547. which may have optional {\tt height} and {\tt stretch} attributes which apply to
  4548. that row.
  4549. @<Functions for scripting@>=
  4550. void populateGridLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4551. QStack<QLayout *> *layoutStack)
  4552. {
  4553. QDomNodeList children = element.childNodes();
  4554. int row = -1;
  4555. QGridLayout *layout = qobject_cast<QGridLayout *>(layoutStack->top());
  4556. for(int i = 0; i < children.count(); i++)
  4557. {
  4558. QDomNode current;
  4559. QDomElement currentElement;
  4560. current = children.at(i);
  4561. if(current.isElement())
  4562. {
  4563. currentElement = current.toElement();
  4564. if(currentElement.tagName() == "row")
  4565. {
  4566. row++;
  4567. if(currentElement.hasAttribute("height"))
  4568. {
  4569. layout->setRowMinimumHeight(row,
  4570. currentElement.attribute("height").toInt());
  4571. }
  4572. if(currentElement.hasAttribute("stretch"))
  4573. {
  4574. layout->setRowStretch(row,
  4575. currentElement.attribute("stretch").toInt());
  4576. }
  4577. @<Populate grid layout row@>@;
  4578. }
  4579. }
  4580. }
  4581. }
  4582. @ Each {\tt <row>} may have arbitrarily many {\tt <column>} children. A row with
  4583. nothing in it or that is entirely populated by spanning cells from previous rows
  4584. might have no children.
  4585. The {\tt <column>} element supports several optional attributes. The
  4586. {\tt column} attribute can be used to specify which column the element refers
  4587. to. Sibling {\tt <column>} elements will refer to columns farther right unless
  4588. a lower column number is specified. This does mean that it is possible to
  4589. specify the same column more than once, however actually doing so is not
  4590. recommended. The {\tt width} attribute specifies the minimum width of the
  4591. column. If multiple cells in a column specify this attribute, the last one takes
  4592. priority. Similarly, the {\tt stretch} attribute specifies the column stretch.
  4593. The {\tt rowspan} and {\tt colspan} attributes can be used for cells that span
  4594. more than one row or column. A value of |-1| can be used to have the cell span
  4595. to the last row or column in the layout.
  4596. Once the attributes of the cell are known, a |QHBoxLayout| is added to the
  4597. layout at the appropriate location in the grid and it is this layout which is
  4598. further populated by child elements. Anything that can be placed under a
  4599. {\tt <layout>} element with {\tt "horizontal"} or {\tt "vertical"} {\tt type}
  4600. attribute can be a child of a {\tt <column>} element in this context.
  4601. @<Populate grid layout row@>=
  4602. int column = -1;
  4603. QDomNodeList rowChildren = currentElement.childNodes();
  4604. for(int j = 0; j < rowChildren.count(); j++)
  4605. {
  4606. QDomNode columnNode;
  4607. QDomElement columnElement;
  4608. columnNode = rowChildren.at(j);
  4609. if(columnNode.isElement())
  4610. {
  4611. columnElement = columnNode.toElement();
  4612. if(columnElement.tagName() == "column")
  4613. {
  4614. column++;
  4615. if(columnElement.hasAttribute("column"))
  4616. {
  4617. column = columnElement.attribute("column").toInt();
  4618. }
  4619. if(columnElement.hasAttribute("width"))
  4620. {
  4621. layout->setColumnMinimumWidth(column,
  4622. columnElement.attribute("width").toInt());
  4623. }
  4624. if(columnElement.hasAttribute("stretch"))
  4625. {
  4626. layout->setColumnStretch(column,
  4627. columnElement.attribute("stretch").toInt());
  4628. }
  4629. int hspan = 1;
  4630. int vspan = 1;
  4631. if(columnElement.hasAttribute("rowspan"))
  4632. {
  4633. vspan = columnElement.attribute("rowspan").toInt();
  4634. }
  4635. if(columnElement.hasAttribute("colspan"))
  4636. {
  4637. hspan = columnElement.attribute("colspan").toInt();
  4638. }
  4639. QHBoxLayout *cell = new QHBoxLayout;
  4640. layout->addLayout(cell, row, column, vspan, hspan);
  4641. layoutStack->push(cell);
  4642. columnElement.setAttribute("trcontext", "configuration");
  4643. populateBoxLayout(columnElement, widgetStack, layoutStack);
  4644. layoutStack->pop();
  4645. }
  4646. }
  4647. }
  4648. @ Box layouts are populated by checking for child elements representing
  4649. supported widget types and layouts and adding these to the current layout.
  4650. @<Functions for scripting@>=
  4651. void populateBoxLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4652. QStack<QLayout *> *layoutStack)
  4653. {
  4654. QDomNodeList children = element.childNodes();
  4655. for(int i = 0; i < children.count(); i++)
  4656. {
  4657. QDomNode current;
  4658. QDomElement currentElement;
  4659. current = children.at(i);
  4660. if(current.isElement())
  4661. {
  4662. currentElement = current.toElement();
  4663. currentElement.setAttribute("trcontext", "configuration");
  4664. if(currentElement.tagName() == "button")
  4665. {
  4666. addButtonToLayout(currentElement, widgetStack, layoutStack);
  4667. }
  4668. else if(currentElement.tagName() == "calendar")
  4669. {
  4670. addCalendarToLayout(currentElement, widgetStack, layoutStack);
  4671. }
  4672. else if(currentElement.tagName() == "timeedit")
  4673. {
  4674. addTimeEditToLayout(currentElement, widgetStack, layoutStack);
  4675. }
  4676. else if(currentElement.tagName() == "decoration")
  4677. {
  4678. addDecorationToLayout(currentElement, widgetStack,
  4679. layoutStack);
  4680. }
  4681. else if(currentElement.tagName() == "layout")
  4682. {
  4683. addLayoutToLayout(currentElement, widgetStack, layoutStack);
  4684. }
  4685. else if(currentElement.tagName() == "splitter")
  4686. {
  4687. addSplitterToLayout(currentElement, widgetStack, layoutStack);
  4688. }
  4689. else if(currentElement.tagName() == "label")
  4690. {
  4691. QBoxLayout *layout =
  4692. qobject_cast<QBoxLayout *>(layoutStack->top());
  4693. QLabel *label = new QLabel(QCoreApplication::translate(
  4694. "configuration",
  4695. currentElement.text().toUtf8().data()));
  4696. if(currentElement.hasAttribute("id"))
  4697. {
  4698. label->setObjectName(currentElement.attribute("id"));
  4699. }
  4700. layout->addWidget(label);
  4701. }
  4702. else if(currentElement.tagName() == "lcdtemperature")
  4703. {
  4704. addTemperatureDisplayToLayout(currentElement, widgetStack,
  4705. layoutStack);
  4706. }
  4707. else if(currentElement.tagName() == "lcdtimer")
  4708. {
  4709. addTimerDisplayToLayout(currentElement, widgetStack,
  4710. layoutStack);
  4711. }
  4712. else if(currentElement.tagName() == "line")
  4713. {
  4714. addLineToLayout(currentElement, widgetStack, layoutStack);
  4715. }
  4716. else if(currentElement.tagName() == "report")
  4717. {
  4718. addReportToLayout(currentElement, widgetStack, layoutStack);
  4719. }
  4720. else if(currentElement.tagName() == "sqldrop")
  4721. {
  4722. addSqlDropToLayout(currentElement, widgetStack, layoutStack);
  4723. }
  4724. else if(currentElement.tagName() == "sqltablearray")
  4725. {
  4726. addSaltToLayout(currentElement, widgetStack, layoutStack);
  4727. }
  4728. else if(currentElement.tagName() == "sqlview")
  4729. {
  4730. addSqlQueryViewToLayout(currentElement, widgetStack,
  4731. layoutStack);
  4732. }
  4733. else if(currentElement.tagName() == "textarea")
  4734. {
  4735. addTextToLayout(currentElement, widgetStack, layoutStack);
  4736. }
  4737. else if(currentElement.tagName() == "spinbox")
  4738. {
  4739. addSpinBoxToLayout(currentElement, widgetStack, layoutStack);
  4740. }
  4741. else if(currentElement.tagName() == "formarray")
  4742. {
  4743. addFormArrayToLayout(currentElement, widgetStack, layoutStack);
  4744. }
  4745. else if(currentElement.tagName() =="hscale")
  4746. {
  4747. addScaleControlToLayout(currentElement, widgetStack,
  4748. layoutStack);
  4749. }
  4750. else if(currentElement.tagName() == "vscale")
  4751. {
  4752. addIntensityControlToLayout(currentElement, widgetStack,
  4753. layoutStack);
  4754. }
  4755. else if(currentElement.tagName() == "webview")
  4756. {
  4757. addWebViewToLayout(currentElement, widgetStack, layoutStack);
  4758. }
  4759. else if(currentElement.tagName() == "stretch")
  4760. {
  4761. QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
  4762. layout->addStretch();
  4763. }
  4764. @<Additional box layout elements@>@;
  4765. }
  4766. }
  4767. }
  4768. @ Box layouts support adding additional layouts to the layout. The form of the
  4769. function is very similar to |addLayoutToWidget()|.
  4770. @<Functions for scripting@>=
  4771. void addLayoutToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4772. QStack<QLayout *> *layoutStack)
  4773. {
  4774. QLayout *targetLayout = layoutStack->pop();
  4775. QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(targetLayout);
  4776. if(element.hasAttribute("type"))
  4777. {
  4778. @<Create and populate layout@>@;
  4779. boxLayout->addLayout(layout);
  4780. layoutStack->pop();
  4781. }
  4782. layoutStack->push(targetLayout);
  4783. }
  4784. @ A splitter is similar to a layout in that it manages the size and position of
  4785. one or more widgets, however it is not a layout and therefore needs to be
  4786. handled separately.
  4787. @<Functions for scripting@>=
  4788. void addSplitterToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
  4789. QStack<QLayout *> *layoutStack)
  4790. {
  4791. QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
  4792. QSplitter *splitter = new(QSplitter);
  4793. layout->addWidget(splitter);
  4794. @<Set up splitter@>@;
  4795. }
  4796. @ As there are multiple places where a splitter element must be examined, the
  4797. common code is set aside.
  4798. @<Set up splitter@>=
  4799. QString orientation = element.attribute("type");
  4800. if(orientation == "horizontal")
  4801. {
  4802. splitter->setOrientation(Qt::Horizontal);
  4803. }
  4804. else if(orientation == "vertical")
  4805. {
  4806. splitter->setOrientation(Qt::Vertical);
  4807. }
  4808. QString id = element.attribute("id");
  4809. if(!id.isEmpty())
  4810. {
  4811. splitter->setObjectName(id);
  4812. }
  4813. if(element.hasChildNodes())
  4814. {
  4815. widgetStack->push(splitter);
  4816. populateSplitter(element, widgetStack, layoutStack);
  4817. widgetStack->pop();
  4818. }
  4819. @ When populating a splitter, it is important to note that only widgets can be
  4820. added. If a layout is needed, this can be handled by adding a |QWidget| and
  4821. applying the layout to that widget.
  4822. @<Functions for scripting@>=
  4823. void populateSplitter(QDomElement element, QStack<QWidget *> *widgetStack,@|
  4824. QStack<QLayout *> *layoutStack)
  4825. {
  4826. QDomNodeList children = element.childNodes();
  4827. for(int i = 0; i < children.count(); i++)
  4828. {
  4829. QDomNode current;
  4830. QDomElement currentElement;
  4831. current = children.at(i);
  4832. if(current.isElement())
  4833. {
  4834. currentElement = current.toElement();
  4835. currentElement.setAttribute("trcontext", "configuration");
  4836. if(currentElement.tagName() == "decoration")
  4837. {
  4838. addDecorationToSplitter(currentElement, widgetStack,
  4839. layoutStack);
  4840. }
  4841. else if(currentElement.tagName() == "graph")
  4842. {
  4843. addGraphToSplitter(currentElement, widgetStack, layoutStack);
  4844. }
  4845. else if(currentElement.tagName() == "splitter")
  4846. {
  4847. addSplitterToSplitter(currentElement, widgetStack, layoutStack);
  4848. }
  4849. else if(currentElement.tagName() == "lcdtemperature")
  4850. {
  4851. addTemperatureDisplayToSplitter(currentElement, widgetStack,
  4852. layoutStack);
  4853. }
  4854. else if(currentElement.tagName() == "lcdtimer")
  4855. {
  4856. addTimerDisplayToSplitter(currentElement, widgetStack,
  4857. layoutStack);
  4858. }
  4859. else if(currentElement.tagName() == "measurementtable")
  4860. {
  4861. addZoomLogToSplitter(currentElement, widgetStack, layoutStack);
  4862. }
  4863. else if(currentElement.tagName() == "widget")
  4864. {
  4865. addWidgetToSplitter(currentElement, widgetStack, layoutStack);
  4866. }
  4867. }
  4868. }
  4869. }
  4870. @ Adding a splitter to a splitter is similar to adding it to a layout.
  4871. @<Functions for scripting@>=
  4872. void addSplitterToSplitter(QDomElement element, QStack<QWidget *> *widgetStack,
  4873. QStack<QLayout *> *layoutStack)
  4874. {
  4875. QSplitter *parent = qobject_cast<QSplitter *>(widgetStack->top());
  4876. QSplitter *splitter = new(QSplitter);
  4877. splitter->setParent(parent);
  4878. parent->addWidget(splitter);
  4879. @<Set up splitter@>@;
  4880. }
  4881. @ Temperature displays are useful to have in an application such as this. At
  4882. present, this code only supports the {\tt id} attribute. It may be useful in the
  4883. future to allow other attributes for changing default attributes of the
  4884. indicator rather than needing to pull the object from script code and set
  4885. changes there.
  4886. @<Functions for scripting@>=
  4887. void addTemperatureDisplayToSplitter(QDomElement element,@|
  4888. QStack<QWidget *> *widgetStack,
  4889. QStack<QLayout *> *)
  4890. {
  4891. TemperatureDisplay *display = new(TemperatureDisplay);
  4892. if(element.hasAttribute("id"))
  4893. {
  4894. display->setObjectName(element.attribute("id"));
  4895. }
  4896. QSplitter *splitter = qobject_cast<QSplitter *>(widgetStack->top());
  4897. splitter->addWidget(display);
  4898. }
  4899. void addTemperatureDisplayToLayout(QDomElement element,@|
  4900. QStack<QWidget *> *,
  4901. QStack<QLayout *> *layoutStack)
  4902. {
  4903. TemperatureDisplay *display = new(TemperatureDisplay);
  4904. if(element.hasAttribute("id"))
  4905. {
  4906. display->setObjectName(element.attribute("id"));
  4907. }
  4908. QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
  4909. layout->addWidget(display);
  4910. }
  4911. @ Timer displays are similarly useful to have. The default format for a timer
  4912. display is {\tt hh:mm:ss}, but this can be changed through the {\tt format}
  4913. attribute of an {\tt <lcdtimer>} element.
  4914. @<Functions for scripting@>=
  4915. void addTimerDisplayToSplitter(QDomElement element,@|
  4916. QStack<QWidget *> *widgetStack,
  4917. QStack<QLayout *> *)
  4918. {
  4919. TimerDisplay *display = new(TimerDisplay);
  4920. if(element.hasAttribute("id"))
  4921. {
  4922. display->setObjectName(element.attribute("id"));
  4923. }
  4924. if(element.hasAttribute("format"))
  4925. {
  4926. display->setDisplayFormat(element.attribute("format"));
  4927. }
  4928. QSplitter *splitter = qobject_cast<QSplitter *>(widgetStack->top());
  4929. splitter->addWidget(display);
  4930. }
  4931. void addTimerDisplayToLayout(QDomElement element,@|
  4932. QStack<QWidget *> *,
  4933. QStack<QLayout *> *layoutStack)
  4934. {
  4935. TimerDisplay *display = new(TimerDisplay);
  4936. if(element.hasAttribute("id"))
  4937. {
  4938. display->setObjectName(element.attribute("id"));
  4939. }
  4940. if(element.hasAttribute("format"))
  4941. {
  4942. display->setDisplayFormat(element.attribute("format"));
  4943. }
  4944. QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
  4945. layout->addWidget(display);
  4946. }
  4947. @ When multiple timer or temperature displays are required, it can be useful to
  4948. provide a label to indicate just what is being measured.
  4949. @<Functions for scripting@>=
  4950. void addDecorationToLayout(QDomElement element, QStack<QWidget *> *,@|
  4951. QStack<QLayout *> *layoutStack)
  4952. {
  4953. @<Set up decoration@>@;
  4954. QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
  4955. layout->addWidget(decoration);
  4956. }
  4957. void addDecorationToSplitter(QDomElement element,
  4958. QStack<QWidget *> *widgetStack,
  4959. QStack<QLayout *> *)
  4960. {
  4961. @<Set up decoration@>@;
  4962. QSplitter *splitter = qobject_cast<QSplitter *>(widgetStack->top());
  4963. splitter->addWidget(decoration);
  4964. }
  4965. @ The decoration needs a label text, an orientation, and the widget to be
  4966. labeled.
  4967. @<Set up decoration@>=
  4968. QString labelText =
  4969. QCoreApplication::translate("configuration",
  4970. element.attribute("name").toUtf8().data());
  4971. Qt::Orientations@, orientation = Qt::Horizontal;
  4972. if(element.hasAttribute("type"))
  4973. {
  4974. if(element.attribute("type") == "horizontal")
  4975. {
  4976. orientation = Qt::Horizontal;
  4977. }
  4978. else if(element.attribute("type") == "vertical")
  4979. {
  4980. orientation = Qt::Vertical;
  4981. }
  4982. }
  4983. @<Find widget to decorate@>@;
  4984. WidgetDecorator *decoration = new WidgetDecorator(theWidget, labelText,
  4985. orientation);
  4986. if(element.hasAttribute("id"))
  4987. {
  4988. decoration->setObjectName(element.attribute("id"));
  4989. }
  4990. @ The widget to decorate should be found as a child of the {\tt <decoration>}
  4991. element.
  4992. @<Find widget to decorate@>=
  4993. QWidget *theWidget = NULL;
  4994. QDomNodeList children = element.childNodes();
  4995. for(int i = 0; i < children.count(); i++)
  4996. {
  4997. QDomNode item = children.at(i);
  4998. if(item.isElement())
  4999. {
  5000. QDomElement itemElement = item.toElement();
  5001. if(itemElement.tagName() == "lcdtemperature")
  5002. {
  5003. TemperatureDisplay *display = new TemperatureDisplay;
  5004. if(itemElement.hasAttribute("id"))
  5005. {
  5006. display->setObjectName(itemElement.attribute("id"));
  5007. }
  5008. theWidget = display;
  5009. }
  5010. else if(itemElement.tagName() == "lcdtimer")
  5011. {
  5012. TimerDisplay *display = new TimerDisplay;
  5013. if(itemElement.hasAttribute("id"))
  5014. {
  5015. display->setObjectName(itemElement.attribute("id"));
  5016. }
  5017. if(itemElement.hasAttribute("format"))
  5018. {
  5019. display->setDisplayFormat(itemElement.attribute("format"));
  5020. }
  5021. theWidget = display;
  5022. }
  5023. }
  5024. }
  5025. @ As splitters cannot contain layouts directly, there is a need to allow
  5026. otherwise empty widgets to be included in a splitter for cases where a splitter
  5027. should manage several widgets together as a group. A row of annotation buttons
  5028. is an example of such a layout.
  5029. When splitters are used as a way to hide optional features it sometimes has the
  5030. effect of forcing a window to stay larger than should be required. To fix this,
  5031. it is possible to set the \tt{ignoreSizePolicy} attribute to true. While this
  5032. does solve the window size issue, this technique is inconsistent with generally
  5033. expected behavior and its use should generally be discouraged.
  5034. @<Functions for scripting@>=
  5035. void addWidgetToSplitter(QDomElement element, QStack<QWidget *> *widgetStack,
  5036. QStack<QLayout *> *layoutStack)
  5037. {
  5038. QSplitter *splitter = qobject_cast<QSplitter *>(widgetStack->top());
  5039. QWidget *widget = new QWidget;
  5040. if(element.hasAttribute("id"))
  5041. {
  5042. widget->setObjectName(element.attribute("id"));
  5043. }
  5044. if(element.hasAttribute("ignoreSizePolicy"))
  5045. {
  5046. if(element.attribute("ignoreSizePolicy") == "true")
  5047. {
  5048. widget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
  5049. }
  5050. }
  5051. splitter->addWidget(widget);
  5052. if(element.hasChildNodes())
  5053. {
  5054. widgetStack->push(widget);
  5055. populateWidget(element, widgetStack, layoutStack);
  5056. widgetStack->pop();
  5057. }
  5058. }
  5059. void populateWidget(QDomElement element, QStack<QWidget *> *widgetStack,@|
  5060. QStack<QLayout *> *layoutStack)
  5061. {
  5062. QDomNodeList children = element.childNodes();
  5063. for(int i = 0; i < children.count(); i++)
  5064. {
  5065. QDomNode current;
  5066. QDomElement currentElement;
  5067. current = children.at(i);
  5068. if(current.isElement())
  5069. {
  5070. currentElement = current.toElement();
  5071. if(currentElement.tagName() == "layout")
  5072. {
  5073. currentElement.setAttribute("trcontext", "configuration");
  5074. addLayoutToWidget(currentElement, widgetStack, layoutStack);
  5075. }
  5076. }
  5077. }
  5078. }
  5079. @ There are two types of buttons that can be added to a layout. There are normal
  5080. push buttons and there are annotation buttons. Other button types may be added
  5081. in the future.
  5082. @<Functions for scripting@>=
  5083. void addButtonToLayout(QDomElement element, QStack<QWidget *> *,@|
  5084. QStack<QLayout *> *layoutStack)
  5085. {
  5086. QAbstractButton *button = NULL;
  5087. QString text =
  5088. QCoreApplication::translate("configuration",
  5089. element.attribute("name").toUtf8().data());
  5090. if(element.hasAttribute("type"))
  5091. {
  5092. QString type = element.attribute("type");
  5093. if(type == "annotation")
  5094. {
  5095. AnnotationButton *abutton = new AnnotationButton(text);
  5096. if(element.hasAttribute("annotation"))
  5097. {
  5098. abutton->setAnnotation(element.attribute("annotation"));
  5099. }
  5100. if(element.hasAttribute("series"))
  5101. {
  5102. abutton->setTemperatureColumn(element.attribute("series").
  5103. toInt());
  5104. }
  5105. if(element.hasAttribute("column"))
  5106. {
  5107. abutton->setAnnotationColumn(element.attribute("column").
  5108. toInt());
  5109. }
  5110. button = abutton;
  5111. }
  5112. else if(type == "check")
  5113. {
  5114. button = new QCheckBox(text);
  5115. }
  5116. else if(type == "push")
  5117. {
  5118. button = new QPushButton(text);
  5119. }
  5120. }
  5121. if(element.hasAttribute("id"))
  5122. {
  5123. button->setObjectName(element.attribute("id"));
  5124. }
  5125. QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
  5126. layout->addWidget(button);
  5127. }
  5128. @ While annotation buttons are useful for many batch notes, a spin box is
  5129. sometimes a better input choice. There are several attributes that can be set on
  5130. a spin box. These include text to be included in the annotation before and after
  5131. the value of the spin box, the temperature and annotation columns, the range of
  5132. values available in the spin box, the precision of allowed values, and the
  5133. amount by which increment and decrement operations change the value.
  5134. @<Functions for scripting@>=
  5135. void addSpinBoxToLayout(QDomElement element, QStack<QWidget *> *,@|
  5136. QStack<QLayout *> *layoutStack)
  5137. {
  5138. AnnotationSpinBox *box = new AnnotationSpinBox("", "", NULL);
  5139. if(element.hasAttribute("pretext"))
  5140. {
  5141. box->setPretext(QCoreApplication::translate(
  5142. "configuration",
  5143. element.attribute("pretext").toUtf8().data()));
  5144. }
  5145. if(element.hasAttribute("posttext"))
  5146. {
  5147. box->setPosttext(QCoreApplication::translate(
  5148. "configuration",
  5149. element.attribute("posttext").toUtf8().data()));
  5150. }
  5151. if(element.hasAttribute("series"))
  5152. {
  5153. box->setTemperatureColumn(element.attribute("series").toInt());
  5154. }
  5155. if(element.hasAttribute("column"))
  5156. {
  5157. box->setAnnotationColumn(element.attribute("column").toInt());
  5158. }
  5159. if(element.hasAttribute("min"))
  5160. {
  5161. box->setMinimum(element.attribute("min").toDouble());
  5162. }
  5163. if(element.hasAttribute("max"))
  5164. {
  5165. box->setMaximum(element.attribute("max").toDouble());
  5166. }
  5167. if(element.hasAttribute("decimals"))
  5168. {
  5169. box->setDecimals(element.attribute("decimals").toInt());
  5170. }
  5171. if(element.hasAttribute("step"))
  5172. {
  5173. box->setSingleStep(element.attribute("step").toDouble());
  5174. }
  5175. if(element.hasAttribute("id"))
  5176. {
  5177. box->setObjectName(element.attribute("id"));
  5178. }
  5179. QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
  5180. layout->addWidget(box);
  5181. }
  5182. @ Previously, in order to change a |ZoomLog| from the default set of columns,
  5183. script code would need to alter the column set. While this works fine on a Mac,
  5184. this did not work very well under Windows. For the current version, I would like
  5185. to remove the need to deal with table columns from the host environment. The
  5186. first step for this is allowing column descriptions in XML. After this, I'@q'@>d like
  5187. to remove the default column set from the widget code and provide some better
  5188. functionality for dealing with additional data sets.
  5189. When creating the |ZoomLog| here, we check for {\tt <column>} child elements
  5190. which specify the names of the columns.
  5191. @<Functions for scripting@>=
  5192. void addZoomLogToSplitter(QDomElement element, QStack<QWidget *> *widgetStack,
  5193. QStack<QLayout *> *)
  5194. {
  5195. ZoomLog *widget = new ZoomLog;
  5196. if(element.hasAttribute("id"))
  5197. {
  5198. widget->setObjectName(element.attribute("id"));
  5199. }
  5200. if(element.hasChildNodes())
  5201. {
  5202. QDomNodeList children = element.childNodes();
  5203. int column = 0;
  5204. for(int i = 0; i < children.count(); i++)
  5205. {
  5206. QDomNode current;
  5207. QDomElement currentElement;
  5208. current = children.at(i);
  5209. if(current.isElement())
  5210. {
  5211. currentElement = current.toElement();
  5212. if(currentElement.tagName() == "column")
  5213. {
  5214. QString text =
  5215. QCoreApplication::translate(
  5216. "configuration",
  5217. currentElement.text().toUtf8().data());
  5218. widget->setHeaderData(column, text);
  5219. column++;
  5220. }
  5221. }
  5222. }
  5223. }
  5224. QSplitter *splitter = qobject_cast<QSplitter *>(widgetStack->top());
  5225. if(splitter)
  5226. {
  5227. splitter->addWidget(widget);
  5228. }
  5229. else
  5230. {
  5231. qDebug() <