Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

phpvirtualbox.js 145KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063
  1. /**
  2. * @fileOverview Common classes and objects used
  3. * @author Ian Moore (imoore76 at yahoo dot com)
  4. * @copyright Copyright (C) 2010-2015 Ian Moore (imoore76 at yahoo dot com)
  5. */
  6. /**
  7. * Host details sections used on details tab
  8. *
  9. * @namespace vboxHostDetailsSections
  10. */
  11. var vboxHostDetailsSections = {
  12. /*
  13. * General
  14. */
  15. hostgeneral: {
  16. icon: 'machine_16px.png',
  17. title: 'General',
  18. settingsLink: 'General',
  19. rows: [
  20. {
  21. title: 'Name',
  22. callback: function() { return $('#vboxPane').data('vboxConfig').name; },
  23. condition: function() { return $('#vboxPane').data('vboxConfig').servers.length; }
  24. },{
  25. title: 'OS Type',
  26. callback: function(d) {
  27. return d['operatingSystem'] + ' (' + d['OSVersion'] +')';
  28. }
  29. },{
  30. title: 'VirtualBox',
  31. callback: function() {
  32. return $('#vboxPane').data('vboxConfig').version.string+' ('+$('#vboxPane').data('vboxConfig').version.revision+')';
  33. }
  34. },{
  35. title: 'Base Memory',
  36. callback: function(d) {
  37. return trans('<nobr>%1 MB</nobr>').replace('%1',d['memorySize']);
  38. }
  39. },{
  40. title: '',
  41. data: '<span id="vboxHostMemUsed"><div style="background-color:#a33" id="vboxHostMemUsedPct"><div style="background-color:#a93;float:right;" id="vboxHostMemResPct"></div></div><div style="width:100%;position:relative;top:-14px;left:0px;text-align:center;"><span id="vboxHostMemUsedLblPct" style="float:left" /><span id="vboxHostMemFreeLbl" style="float:right" /></div></span>'
  42. },{
  43. title: "Processor(s)",
  44. callback: function(d) {
  45. return d['cpus'][0] + ' (' + d['cpus'].length +')';
  46. }
  47. },{
  48. title: '',
  49. callback: function(d) {
  50. // Processor features?
  51. var cpuFeatures = new Array();
  52. for(var f in d.cpuFeatures) {
  53. if(!d.cpuFeatures[f]) continue;
  54. cpuFeatures[cpuFeatures.length] = trans(f);
  55. }
  56. return cpuFeatures.join(', ');
  57. },
  58. condition: function(d) {
  59. if(!d.cpuFeatures) return false;
  60. for(var f in d.cpuFeatures) {
  61. if(!d.cpuFeatures[f]) continue;
  62. return true;
  63. }
  64. return false;
  65. }
  66. }],
  67. onRender: function(d) {
  68. // See if timer is already set
  69. var eTimer = $('#vboxVMDetails').data('vboxHostMemInfoTimer');
  70. if(eTimer != null) {
  71. $('#vboxVMDetails').data('vboxHostMemInfoTimer',null);
  72. window.clearInterval(eTimer);
  73. }
  74. var showFree = $('#vboxPane').data('vboxConfig').hostMemInfoShowFreePct;
  75. var memRes = $('#vboxPane').data('vboxConfig').vmMemoryOffset;
  76. if(!memRes || parseInt(memRes) < 1) memRes = 0;
  77. // Memory used function
  78. var vboxHostShowMemInfo = function(avail) {
  79. // If target div no longer exists, stop updating
  80. if($('#vboxHostMemFreeLbl')[0] == null) {
  81. var eTimer = $('#vboxVMDetails').data('vboxHostMemInfoTimer');
  82. $('#vboxVMDetails').data('vboxHostMemInfoTimer',null);
  83. window.clearInterval(eTimer);
  84. return;
  85. }
  86. // Subtract reserved memory?
  87. avail -= memRes;
  88. avail = Math.max(0,avail);
  89. var mUsed = d['memorySize'] - (avail + memRes);
  90. var mUsedPct = Math.round(parseInt((mUsed / d['memorySize']) * 100));
  91. var memResPct = 0;
  92. if(memRes > 0) {
  93. memResPct = Math.round(parseInt((memRes / d['memorySize']) * 100));
  94. }
  95. // Add tooltip with info
  96. var tip = trans('<nobr>%1 MB</nobr>').replace('%1',mUsed);
  97. if(memResPct) tip += ' | ' + trans('<nobr>%1 MB</nobr>').replace('%1',memRes);
  98. tip += ' | ' + trans('<nobr>%1 MB</nobr>').replace('%1',avail);
  99. $('#vboxHostMemUsed').tipped({'source':tip,'position':'mouse'});
  100. // Update tooltip content in case tooltip is already showing
  101. var cid = $($('#tipped').data('original')).attr('id');
  102. if(cid && cid == 'vboxHostMemUsed') $('#tipped-content').html(tip);
  103. // Width(s)
  104. $('#vboxHostMemUsedPct').css({'width':((mUsedPct+memResPct)*2)+'px'});
  105. if(memRes > 0) {
  106. $('#vboxHostMemResPct').css({'width':''+(memResPct*2)+'px'});
  107. } else {
  108. $('#vboxHostMemResPct').hide();
  109. }
  110. // Labels
  111. if(!showFree) {
  112. $('#vboxHostMemUsedLblPct').html(trans('<nobr>%1 MB</nobr>').replace('%1',(mUsed)) + ' ('+trans('<nobr>%1%</nobr>').replace('%1',mUsedPct)+')');
  113. $('#vboxHostMemFreeLbl').html(trans('<nobr>%1 MB</nobr>').replace('%1',avail));
  114. } else {
  115. $('#vboxHostMemUsedLblPct').html(trans('<nobr>%1 MB</nobr>').replace('%1',mUsed));
  116. $('#vboxHostMemFreeLbl').html('('+trans('<nobr>%1%</nobr>').replace('%1',Math.round(parseInt((avail / d['memorySize']) * 100)))+') ' + trans('<nobr>%1 MB</nobr>').replace('%1',avail));
  117. }
  118. };
  119. // Refresh at configured intervals
  120. var interval = 5;
  121. try {
  122. interval = Math.max(3,parseInt($('#vboxPane').data('vboxConfig').hostMemInfoRefreshInterval));
  123. } catch (e) {
  124. interval = 5;
  125. }
  126. var vboxHostUpdateMeminfo = function() {
  127. $.when(vboxAjaxRequest('hostGetMeminfo')).done(function(d){
  128. vboxHostShowMemInfo(d.responseData);
  129. });
  130. };
  131. vboxHostUpdateMeminfo();
  132. // Failsafe
  133. if(isNaN(interval) || interval < 3) interval = 5;
  134. $('#vboxVMDetails').data('vboxHostMemInfoTimer',window.setInterval(vboxHostUpdateMeminfo,interval*1000));
  135. }
  136. },
  137. hostnetwork: {
  138. title: 'Network',
  139. icon: 'nw_16px.png',
  140. rows: function(d) {
  141. var netRows = [];
  142. d['networkInterfaces'].sort(function(a,b){
  143. return strnatcasecmp(a.name, b.name);
  144. });
  145. for(var i = 0; i < d['networkInterfaces'].length; i++) {
  146. /* Interface Name */
  147. netRows[netRows.length] = {
  148. title: d['networkInterfaces'][i].name + ' (' + trans(d['networkInterfaces'][i].status) + ')',
  149. data: ''
  150. };
  151. /* IPv4 Addr */
  152. if(d['networkInterfaces'][i].IPAddress){
  153. netRows[netRows.length] = {
  154. title: trans('IPv4 Address','UIGlobalSettingsNetwork'),
  155. data: d['networkInterfaces'][i].IPAddress + ' / ' + d['networkInterfaces'][i].networkMask,
  156. indented: true
  157. };
  158. }
  159. /* IPv6 Address */
  160. if(d['networkInterfaces'][i].IPV6Supported && d['networkInterfaces'][i].IPV6Address) {
  161. netRows[netRows.length] = {
  162. title: trans('IPv6 Address','UIGlobalSettingsNetwork'),
  163. data: d['networkInterfaces'][i].IPV6Address + ' / ' + d['networkInterfaces'][i].IPV6NetworkMaskPrefixLength,
  164. indented: true
  165. };
  166. }
  167. /* Physical info */
  168. netRows[netRows.length] = {
  169. title: '',
  170. data: trans(d['networkInterfaces'][i].mediumType) + (d['networkInterfaces'][i].hardwareAddress ? ' (' + d['networkInterfaces'][i].hardwareAddress + ')': ''),
  171. indented: true
  172. };
  173. }
  174. return netRows;
  175. }
  176. },
  177. hostdvddrives: {
  178. title: 'DVD',
  179. icon: 'cd_16px.png',
  180. language_context: 'UIApplianceEditorWidget',
  181. condition: function(d) {
  182. return d['DVDDrives'].length;
  183. },
  184. rows: function(d) {
  185. var dvdRows = [];
  186. for(var i = 0; i < d['DVDDrives'].length; i++) {
  187. dvdRows[dvdRows.length] = {
  188. title: vboxMedia.getName(vboxMedia.getMediumById(d['DVDDrives'][i].id)),
  189. data: ''
  190. };
  191. }
  192. return dvdRows;
  193. }
  194. },
  195. hostfloppydrives: {
  196. title: 'Floppy',
  197. language_context: 'UIApplianceEditorWidget',
  198. icon: "fd_16px.png",
  199. condition: function(d) { return d['floppyDrives'].length; },
  200. rows: function(d) {
  201. var fRows = [];
  202. for(var i = 0; i < d['floppyDrives'].length; i++) {
  203. fRows[fRows.length] = {
  204. title: vboxMedia.getName(vboxMedia.getMediumById(d['floppyDrives'][i].id)),
  205. data: ''
  206. };
  207. }
  208. return fRows;
  209. }
  210. }
  211. };
  212. /**
  213. * VM details sections used on details tab and snapshot pages
  214. *
  215. * @namespace vboxVMDetailsInfo
  216. */
  217. var vboxVMDetailsSections = {
  218. /*
  219. * General
  220. */
  221. general: {
  222. title: 'General',
  223. icon: 'machine_16px.png',
  224. settingsLink: 'General',
  225. multiSelectDetailsTable: true,
  226. rows: [
  227. {
  228. title: 'Name', attrib: 'name'
  229. },{
  230. title: 'OS Type', attrib: 'OSTypeDesc'
  231. },{
  232. title: 'Guest Additions Version', attrib: 'guestAdditionsVersion'
  233. },{
  234. title: 'Groups',
  235. language_context: 'UIGDetails',
  236. condition: function(d){
  237. return (d.groups.length > 1 || (d.groups.length == 1 && d.groups[0] != '/'));
  238. },
  239. callback: function(d) {
  240. if(d.groups && d.groups.length > 0)
  241. return jQuery.map(d.groups,function(elm) {
  242. if(elm.length > 1) return elm.substring(1);
  243. return elm;
  244. }).join(', ');
  245. }
  246. }
  247. ]
  248. },
  249. /*
  250. * System
  251. */
  252. system: {
  253. title: 'System',
  254. icon: 'chipset_16px.png',
  255. settingsLink: 'System',
  256. redrawMachineEvents: ['OnCPUExecutionCapChanged'],
  257. multiSelectDetailsTable: true,
  258. rows: [
  259. {
  260. title: 'Base Memory',
  261. callback: function(d) {
  262. return trans('<nobr>%1 MB</nobr>').replace('%1',d['memorySize']);
  263. }
  264. },{
  265. title: "Processor(s)",
  266. attrib: 'CPUCount',
  267. condition: function(d) { return d.CPUCount > 1; }
  268. },{
  269. title: "Execution Cap",
  270. callback: function(d) {
  271. return trans('<nobr>%1%</nobr>').replace('%1',parseInt(d['CPUExecutionCap']));
  272. },
  273. condition: function(d) { return d.CPUExecutionCap < 100; }
  274. },{
  275. title: "Boot Order",
  276. callback: function(d) {
  277. var bo = new Array();
  278. for(var i = 0; i < d['bootOrder'].length; i++) {
  279. bo[i] = trans(vboxDevice(d['bootOrder'][i]));
  280. }
  281. return bo.join(', ');
  282. }
  283. },{
  284. title: "Acceleration",
  285. language_context: 'UIGDetails',
  286. callback: function(d) {
  287. var acList = [];
  288. if(d['HWVirtExProperties'].Enabled) acList[acList.length] = trans('VT-x/AMD-V');
  289. if(d['HWVirtExProperties'].NestedPaging) acList[acList.length] = trans('Nested Paging');
  290. if(d['CpuProperties']['PAE']) acList[acList.length] = trans('PAE/NX');
  291. if(d['EffectiveParavirtProvider'] != 'None')
  292. acList[acList.length] = trans(d['EffectiveParavirtProvider'] + ' Paravirtualization');
  293. if($('#vboxPane').data('vboxConfig').enableAdvancedConfig) {
  294. if(d['HWVirtExProperties'].LargePages) acList[acList.length] = trans('Large Pages');
  295. if(d['HWVirtExProperties'].UnrestrictedExecution) acList[acList.length] = trans('VT-x unrestricted execution');
  296. if(d['HWVirtExProperties'].VPID) acList[acList.length] = trans('VT-x VPID');
  297. }
  298. return acList.join(', ');
  299. },
  300. condition: function(d) { return (d['HWVirtExProperties'].Enabled || d['CpuProperties']['PAE']); }
  301. }
  302. ]
  303. },
  304. /*
  305. * Preview box
  306. */
  307. preview: {
  308. title: 'Preview',
  309. icon: 'fullscreen_16px.png',
  310. _resolutionCache: {},
  311. settingsLink: 'Display',
  312. multiSelectDetailsTable: true,
  313. noSnapshot: true,
  314. noFooter: true,
  315. _updateInterval: undefined,
  316. _screenPadding: 17, // padding around actual screenshot in px
  317. condition: function() {
  318. // Update our default updateInterval here
  319. if(vboxVMDetailsSections.preview._updateInterval === undefined) {
  320. // Try local data first
  321. var updateInterval = vboxGetLocalDataItem('previewUpdateInterval');
  322. if(updateInterval === null || updateInterval === undefined) {
  323. updateInterval = $('#vboxPane').data('vboxConfig').previewUpdateInterval;
  324. if(updateInterval === null || updateInterval === undefined) {
  325. updateInterval = 3;
  326. }
  327. vboxSetLocalDataItem('previewUpdateInterval', parseInt(updateInterval));
  328. }
  329. vboxVMDetailsSections.preview._updateInterval = parseInt(updateInterval);
  330. }
  331. return !($('#vboxPane').data('vboxConfig').noPreview);
  332. },
  333. /**
  334. * Function triggered on VM state change
  335. *
  336. */
  337. vboxEventOnMachineStateChanged: function(eventData) {
  338. var timer = $('#vboxPane').data('vboxPreviewTimer-'+eventData.machineId);
  339. if(timer) {
  340. $('#vboxPane').data('vboxPreviewTimer-'+eventData.machineId, null);
  341. window.clearInterval(timer);
  342. }
  343. vboxVMDetailsSections.preview._drawPreview(eventData.machineId);
  344. // Kick off timer if VM is running
  345. if(vboxVMStates.isRunning(eventData)) {
  346. window.setTimeout(function(){
  347. $('#vboxPane').data('vboxPreviewTimer-'+eventData.machineId, window.setInterval('vboxVMDetailsSections.preview._drawPreview("'+eventData.machineId+'")',vboxVMDetailsSections.preview._updateInterval*1000));
  348. },vboxVMDetailsSections.preview._updateInterval*1000);
  349. }
  350. },
  351. /*
  352. *
  353. * Preivew Update Menu
  354. *
  355. */
  356. contextMenu: function() {
  357. var menu = $('#vboxDetailsPreviewMenu');
  358. if(menu[0]) return menu;
  359. /* Menu List */
  360. var ul = $('<ul />')
  361. .attr({'class':'contextMenu contextMenuNoBG','style':'display: none','id':'vboxDetailsPreviewMenu'})
  362. .click(function(){$(this).hide();})
  363. .on('contextmenu', function() { return false; })
  364. // Menu setup for "open in new window"
  365. .on('beforeshow', function(e, vmid) {
  366. var d = vboxVMDataMediator.getVMData(vmid);
  367. if(vboxVMStates.isRunning(d) || vboxVMStates.isSaved(d)) {
  368. $('#vboxDetailsViewSavedSS')
  369. .css('display','')
  370. .data({'vmid':d.id});
  371. } else {
  372. $('#vboxDetailsViewSavedSS').css('display', 'none');
  373. }
  374. });
  375. // Menu item to disable update
  376. $('<li />')
  377. .hoverClass('vboxHover')
  378. .append(
  379. $('<label />').append(
  380. $('<input />')
  381. .attr({'class':'vboxRadio','type':'radio','name':'vboxPreviewRadio','value':0})
  382. .click(function(){
  383. vboxSetLocalDataItem('previewUpdateInterval','0');
  384. vboxVMDetailsSections.preview._updateInterval = 0;
  385. })
  386. .prop('checked', parseInt(vboxVMDetailsSections.preview._updateInterval) == 0)
  387. ).append(
  388. $('<span />')
  389. .html(trans('Update disabled','UIGMachinePreview'))
  390. )
  391. ).appendTo(ul);
  392. // Update intervals
  393. var ints = [3,5,10,20,30,60];
  394. // check for update interval
  395. if(vboxVMDetailsSections.preview._updateInterval > 0 && jQuery.inArray(vboxVMDetailsSections.preview._updateInterval, ints) < 0) {
  396. ints[ints.length] = vboxVMDetailsSections.preview._updateInterval;
  397. }
  398. ints.sort(function(a,b){
  399. if(a == b) return 0;
  400. return (a > b ? 1: -1);
  401. });
  402. // Add each interval to menu
  403. for(var i = 0; i < ints.length; i++) {
  404. var li = $('<li />');
  405. if(i==0) $(li).attr('class','separator');
  406. var radio = $('<input />').attr({'class':'vboxRadio','type':'radio','name':'vboxPreviewRadio','value':ints[i]}).click(function(){
  407. var lastIntervalNone = (parseInt(vboxVMDetailsSections.preview._updateInterval) == 0);
  408. vboxSetLocalDataItem('previewUpdateInterval',$(this).val());
  409. vboxVMDetailsSections.preview._updateInterval = $(this).val();
  410. // Kick off preview updates if the last interval was 0
  411. if(lastIntervalNone) {
  412. var selVMData = vboxChooser.getSelectedVMsData();
  413. for(var i = 0; i < selVMData.length; i++) {
  414. if(vboxVMStates.isRunning(selVMData[i]) || vboxVMStates.isSaved(selVMData[i]))
  415. vboxVMDetailsSections.preview._drawPreview(selVMData[i].id);
  416. }
  417. }
  418. }).prop('checked', parseInt(vboxVMDetailsSections.preview._updateInterval) == ints[i]);
  419. $('<label />')
  420. .append(radio)
  421. .append(
  422. $('<span />')
  423. .html(trans('Every %1 seconds','UIGMachinePreview').replace('%1',ints[i]))
  424. )
  425. .appendTo(li);
  426. $(ul).append(li);
  427. }
  428. /* Append "Open in new window" */
  429. $('<li />')
  430. .attr({'id':'vboxDetailsViewSavedSS','class':'separator','style':'display:none;text-align: center;'})
  431. .click(function(){
  432. window.open(vboxEndpointConfig.screen+'?vm='+$(this).data('vmid')+'&full=1','vboxSC','toolbar=1,menubar=0,location=0,directories=0,status=true,resize=true');
  433. }).append(
  434. $('<span />')
  435. .html(trans('Open in new window','UIVMPreviewWindow'))
  436. ).appendTo(ul);
  437. /* Hover */
  438. $(ul).children().hoverClass('vboxHover');
  439. $(document).click(function(e){if(e.button!=2)$(ul).hide();});
  440. $('#vboxTabVMDetails').append(ul);
  441. return $('#vboxDetailsPreviewMenu');
  442. },
  443. /**
  444. * This is run when the preview screen is drawn
  445. */
  446. onRender: function(d) {
  447. // Not needed in canvas logic
  448. if(isCanvasSupported()) return;
  449. if(!vboxVMDetailsSections.preview._updateInterval || (!vboxVMStates.isRunning(d) && !vboxVMStates.isSaved(d))) {
  450. var timer = $('#vboxPane').data('vboxPreviewTimer-'+d.id);
  451. if(timer) {
  452. $('#vboxPane').data('vboxPreviewTimer-'+d.id, null);
  453. window.clearInterval(timer);
  454. }
  455. vboxVMDetailsSections.preview._drawPreview(d.id);
  456. return;
  457. }
  458. vboxVMDetailsSections.preview._drawPreview(d.id);
  459. if(vboxVMStates.isRunning(d)) {
  460. var timer = $('#vboxPane').data('vboxPreviewTimer-'+d.id);
  461. if(timer) window.clearInterval(timer);
  462. $('#vboxPane').data('vboxPreviewTimer-'+d.id,
  463. window.setInterval('vboxVMDetailsSections.preview._drawPreview("'+d.id+'")',
  464. vboxVMDetailsSections.preview._updateInterval * 1000));
  465. }
  466. },
  467. /**
  468. * Draw the preview window from VM screenshot
  469. *
  470. */
  471. _drawPreview: function(vmid) {
  472. // Does the target still exist?
  473. if(!$('#vboxDetailsGeneralTable-'+vmid)[0]) {
  474. var timer = $('#vboxPane').data('vboxPreviewTimer-'+vmid);
  475. if(timer) window.clearInterval(timer);
  476. $('#vboxPane').data('vboxPreviewTimer-'+vmid, null);
  477. return;
  478. }
  479. var width = $('#vboxPane').data('vboxConfig')['previewWidth'];
  480. // Get fresh VM data
  481. var vm = vboxVMDataMediator.getVMData(vmid);
  482. var __vboxDrawPreviewImg = new Image();
  483. __vboxDrawPreviewImg.onload = function() {
  484. // Does the target still exist?
  485. if(!$('#vboxDetailsGeneralTable-'+vmid)[0]) {
  486. var timer = $('#vboxPane').data('vboxPreviewTimer-'+vmid);
  487. if(timer) window.clearInterval(timer);
  488. $('#vboxPane').data('vboxPreviewTimer-'+vmid, null);
  489. return;
  490. }
  491. // Set and cache dimensions
  492. if(this.height > 0) {
  493. // If width != requested width, it is scaled
  494. if(this.width != $('#vboxPane').data('vboxConfig')['previewWidth']) {
  495. height = this.height * (width / this.width);
  496. // Not scaled
  497. } else {
  498. height = this.height;
  499. }
  500. vboxVMDetailsSections.preview._resolutionCache[vmid] = {
  501. 'height': height
  502. };
  503. // Height of image is 0
  504. } else {
  505. // Check for cached resolution
  506. if(vboxVMDetailsSections.preview._resolutionCache[vmid]) {
  507. height = vboxVMDetailsSections.preview._resolutionCache[vmid].height;
  508. } else {
  509. height = parseInt(width / $('#vboxPane').data('vboxConfig')['previewAspectRatio']);
  510. }
  511. // Clear interval if set
  512. var timer = $('#vboxPane').data('vboxPreviewTimer-'+vmid);
  513. if(timer) window.clearInterval(timer);
  514. }
  515. // Get fresh VM data
  516. var vm = vboxVMDataMediator.getVMData(vmid);
  517. // Return if this is stale
  518. if(!vm) {
  519. var timer = $('#vboxPane').data('vboxPreviewTimer-'+vmid);
  520. if(timer) window.clearInterval(timer);
  521. $('#vboxPane').data('vboxPreviewTimer-'+vmid, null);
  522. return;
  523. }
  524. // Canvas redraw
  525. if(isCanvasSupported()) {
  526. // Reset height and width
  527. $('#vboxPreviewCanvas-'+vmid).attr({'width':(width+(vboxVMDetailsSections.preview._screenPadding*2)),'height':(height+(vboxVMDetailsSections.preview._screenPadding*2))});
  528. // Redraw preview
  529. vboxDrawPreviewCanvas($('#vboxPreviewCanvas-'+vmid)[0], (this.height <= 1 ? null: this), vm.name, width, height);
  530. // HTML update
  531. } else {
  532. var baseStr = 'vboxDetailsGeneralTable-'+vmid;
  533. if(this.height <= 1) {
  534. // IE uses filter
  535. if($.browser.msie) {
  536. $('#'+baseStr+' img.vboxDetailsPreviewImg').css({'display':'none',"filter":""})
  537. .attr({'src':'images/vbox/blank.gif'}).parent().css({'background':'#000'});
  538. } else {
  539. $('#'+baseStr+' img.vboxDetailsPreviewImg').css({'display':'none'}).attr('src','images/vbox/blank.gif');
  540. }
  541. $('#'+baseStr+' div.vboxDetailsPreviewVMName').css('display','');
  542. // Resize name?
  543. $('#vboxDetailsGeneralTable-'+vmid+ ' div.vboxDetailsPreviewVMName span.textFill').textFill({maxFontPixels:20,'height':(height),'width':(width)});
  544. } else {
  545. $('#'+baseStr+' div.vboxDetailsPreviewVMName').css('display','none');
  546. $('#'+baseStr+' img.vboxDetailsPreviewImg').css({'display':'','height':height+'px','width':width+'px'});
  547. // IE uses filter
  548. if($.browser.msie) {
  549. if(vboxVMStates.isRunning(vm)) {
  550. // Setting background URL keeps image from being
  551. // requested again, but does not allow us to set
  552. // the size of the image. This is fine, since the
  553. // image is returned in the size requested.
  554. $('#'+baseStr+' img.vboxDetailsPreviewImg').css({"filter":""}).parent().css({'background':'url('+this.src+')'});
  555. } else {
  556. // This causes the image to be requested again, but
  557. // is the only way to size the background image.
  558. // Saved preview images are not returned in the size
  559. // requested and must be resized at runtime by
  560. // the browser.
  561. $('#'+baseStr+' img.vboxDetailsPreviewImg').css({"filter":"progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', src='"+this.src+"', sizingMethod='scale')"}).parent().css({'background':'#000'});
  562. }
  563. } else {
  564. $('#'+baseStr+' img.vboxDetailsPreviewImg').css({'background-image':'url('+this.src+')','background-size':(width+1) +'px ' + (height+1)+'px'});
  565. }
  566. }
  567. $('#'+baseStr+' div.vboxDetailsPreviewWrap').css({'height':height+'px','width':width+'px'});
  568. $('#'+baseStr+' img.vboxPreviewMonitor').css('width',width+'px');
  569. $('#'+baseStr+' img.vboxPreviewMonitorSide').css('height',height+'px');
  570. }
  571. };
  572. // Update disabled? State not Running or Saved
  573. if(!vboxVMDetailsSections.preview._updateInterval || (!vboxVMStates.isRunning(vm) && !vboxVMStates.isSaved(vm))) {
  574. __vboxDrawPreviewImg.height = 0;
  575. __vboxDrawPreviewImg.onload();
  576. } else {
  577. // Running VMs get random numbers.
  578. // Saved are based on last state change to try to let the browser cache Saved screen shots
  579. var randid = vm.lastStateChange;
  580. if(vboxVMStates.isRunning(vm)) {
  581. var currentTime = new Date();
  582. randid = Math.floor(currentTime.getTime() / 1000);
  583. }
  584. __vboxDrawPreviewImg.src = vboxEndpointConfig.screen+'?width='+(width)+'&vm='+vmid+'&randid='+randid;
  585. }
  586. },
  587. /**
  588. * Rows wrapper
  589. */
  590. rows: function(d) {
  591. var timer = $('#vboxPane').data('vboxPreviewTimer-'+d.id);
  592. if(timer) window.clearInterval(timer);
  593. $('#vboxPane').data('vboxPreviewTimer-'+d.id, null);
  594. return (isCanvasSupported() ? vboxVMDetailsSections.preview._rows_canvas(d): vboxVMDetailsSections.preview._rows_html(d));
  595. },
  596. /**
  597. * Draws preview window in HTML
  598. */
  599. _rows_html: function(d) {
  600. var width = $('#vboxPane').data('vboxConfig')['previewWidth'];
  601. if(!width) width = $('#vboxPane').data('vboxConfig')['previewWidth'] = 180;
  602. width = parseInt(width);
  603. var height = parseInt(width / $('#vboxPane').data('vboxConfig')['previewAspectRatio']);
  604. // Check for cached resolution
  605. if(vboxVMDetailsSections.preview._resolutionCache[d.id]) {
  606. width = vboxVMDetailsSections.preview._resolutionCache[d.id].width;
  607. height = vboxVMDetailsSections.preview._resolutionCache[d.id].height;
  608. }
  609. var divOut1 = "<div class='vboxDetailsPreviewVMName' style='position:absolute;overflow:hidden;padding:0px;height:"+height+"px;width:"+width+"px;"+
  610. "display:"+((vboxVMStates.isRunning(d) || vboxVMStates.isSaved(d)) ? 'none': '')+"' >" +
  611. "<div style='position:relative;display:table-cell;padding:0px;vertical-align:middle;color:#fff;font-weight:bold;overflow:hidden;text-align:center;height:"+height+"px;width:"+width+"px;" +
  612. ($.browser.msie ? "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=\"true\", src=\"images/monitor_glossy.png\", sizingMethod=\"scale\")": "" +
  613. "background:url(images/monitor_glossy.png) top left no-repeat;-moz-background-size:100% 100%;background-size:"+(width+1) +"px " + (height+1)+"px;-webkit-background-size:100% 100%") +
  614. "'><span class='textFill' style='font-size: 12px;position:relative;display:inline-block;'>"+$('<div />').html(d.name).text()+"</span></div>"+
  615. "</div>";
  616. return [
  617. {
  618. data: "<tr style='vertical-align: middle'>"+
  619. "<td style='text-align: center' colspan='2'>"+
  620. "<table class='vboxInvisible vboxPreviewTable' style='margin-left:auto;margin-right:auto;'>"+
  621. "<tr style='vertical-align:bottom; padding:0px; margin:0px;height:17px'>"+
  622. "<td class='vboxInvisible' style='text-align:right;width:15px;height:17px'><img src='images/monitor_tl.png' style='width:15px;height:17px;'/></td>"+
  623. "<td class='vboxInvisible'><img src='images/monitor_top.png' class='vboxPreviewMonitor' style='height:17px;width:"+width+"px'/></td>"+
  624. "<td class='vboxInvisible' style='text-align:left;width:15px;height:17px'><img src='images/monitor_tr.png' style='width:15px;height:17px;'/></td>"+
  625. "</tr>"+
  626. "<tr style='vertical-align:top;'>"+
  627. "<td class='vboxInvisible' style='text-align:right;'><img src='images/monitor_left.png' style='width:15px;height:"+height+"px' class='vboxPreviewMonitorSide' /></td>"+
  628. "<td class='vboxInvisible' style='position:relative;'><div class='vboxDetailsPreviewWrap "+ (vboxVMStates.isSaved(d) ? 'vboxPreviewSaved': '') +"' style='width: "+width+"px; height:"+height+"px; position:relative;overflow:hidden;text-align:center;background-color:#000;border:0px;display:table;#position:relative;background-repeat:no-repeat;padding:0px;margin:0px;'>"+
  629. "<img class='vboxDetailsPreviewImg' src='images/monitor_glossy.png' vspace='0px' hspace='0px' "+
  630. "style='display:"+((vboxVMStates.isRunning(d) || vboxVMStates.isSaved(d)) ? '': 'none')+";top:0px;margin:0px;border:0px;padding;0px;"+
  631. "background-position:top left;background-repeat:no-repeat;"+
  632. "-moz-background-size:100% 100%;background-size:100% 100%;-webkit-background-size:100% 100%;background-spacing:0px 0px;"+
  633. "height:"+height+"px;width:"+width+"px;' />"+
  634. divOut1+
  635. "</div></td>"+
  636. "<td class='vboxInvisible' style='text-align:left;' ><img src='images/monitor_right.png' style='width:14px;height:"+height+"px' class='vboxPreviewMonitorSide' /></td>"+
  637. "</tr>"+
  638. "<tr style='vertical-align:top;height:17px'>"+
  639. "<td class='vboxInvisible' style='text-align:right;width:15px;height:17px'><img src='images/monitor_bl.png' style='width:15px;height:17px;float:right;'/></td>"+
  640. "<td class='vboxInvisible' style='vertical-align:top'><img src='images/monitor_bottom.png' class='vboxPreviewMonitor' style='height:17px;width:"+width+"px'/></td>"+
  641. "<td class='vboxInvisible' style='text-align:left;width:15px;height:17px'><img src='images/monitor_br.png' style='width:15px;height:17px;'/></td>"+
  642. "</tr>"+
  643. "</table>"+
  644. "</td>"+
  645. "</tr>",
  646. rawRow: true
  647. }
  648. ];
  649. },
  650. /**
  651. * Draws preview on canvas object
  652. */
  653. _rows_canvas: function(d) {
  654. var width = $('#vboxPane').data('vboxConfig')['previewWidth'];
  655. if(!width) width = $('#vboxPane').data('vboxConfig')['previewWidth'] = 180;
  656. width = parseInt(width);
  657. var height = parseInt(width / $('#vboxPane').data('vboxConfig')['previewAspectRatio']);
  658. // Check for cached resolution
  659. if(vboxVMDetailsSections.preview._resolutionCache[d.id]) {
  660. height = vboxVMDetailsSections.preview._resolutionCache[d.id].height;
  661. }
  662. // Create canvas and initially draw VM name
  663. var previewCanvas = $('<canvas />').attr({'id':'vboxPreviewCanvas-'+d.id,'width':(width+(vboxVMDetailsSections.preview._screenPadding*2)),'height':(height+(vboxVMDetailsSections.preview._screenPadding*2))});
  664. vboxDrawPreviewCanvas(previewCanvas[0], null, d.name, width, height);
  665. // Draw screenshot if it's running or saved
  666. if(vboxVMDetailsSections.preview._updateInterval > 0 && (vboxVMStates.isRunning(d) || vboxVMStates.isSaved(d))) {
  667. // Preview image kicks off timer when it is loaded
  668. var preview = new Image();
  669. preview.onload = function(){
  670. // Set and cache dimensions
  671. if(this.height > 0) {
  672. // If width != requested width, it is scaled
  673. if(this.width != $('#vboxPane').data('vboxConfig')['previewWidth']) {
  674. height = this.height * (width/this.width);
  675. // Not scaled
  676. } else {
  677. height = this.height;
  678. }
  679. $('#vboxPreviewCanvas-'+d.id).attr({'width':(width+(vboxVMDetailsSections.preview._screenPadding*2)),'height':(height+(vboxVMDetailsSections.preview._screenPadding*2))});
  680. // Check for cached resolution
  681. } else if(vboxVMDetailsSections.preview._resolutionCache[d.id]) {
  682. height = vboxVMDetailsSections.preview._resolutionCache[d.id].height;
  683. } else {
  684. height = parseInt(width / $('#vboxPane').data('vboxConfig')['previewAspectRatio']);
  685. }
  686. vboxVMDetailsSections.preview._resolutionCache[d.id] = {'width':width,'height':height};
  687. // Draw this screen shot
  688. vboxDrawPreviewCanvas($('#vboxPreviewCanvas-'+d.id)[0], preview, d.name, width, height);
  689. // Kick off timer if VM is running
  690. if(vboxVMStates.isRunning(d)) {
  691. window.setTimeout(function(){
  692. $('#vboxPane').data('vboxPreviewTimer-'+d.id, window.setInterval('vboxVMDetailsSections.preview._drawPreview("'+d.id+'")',vboxVMDetailsSections.preview._updateInterval*1000));
  693. },vboxVMDetailsSections.preview._updateInterval*1000);
  694. }
  695. };
  696. var randid = d.lastStateChange;
  697. if(vboxVMStates.isRunning(d)) {
  698. var currentTime = new Date();
  699. randid = Math.floor(currentTime.getTime() / 1000);
  700. }
  701. preview.src = vboxEndpointConfig.screen+'?width='+(width)+'&vm='+d.id+'&randid='+randid;
  702. }
  703. /* Return row */
  704. return [ {
  705. data: $('<div />')
  706. .attr({'class':'vboxInvisble'})
  707. .append(previewCanvas),
  708. rawRow: true
  709. }];
  710. }
  711. },
  712. /*
  713. * Display
  714. */
  715. display: {
  716. title: 'Display',
  717. icon: 'vrdp_16px.png',
  718. settingsLink: 'Display',
  719. redrawMachineEvents: ['OnVRDEServerInfoChanged','OnVRDEServerChanged','OnMachineStateChanged'],
  720. rows: [
  721. {
  722. title: "Video Memory",
  723. callback: function(d) {
  724. return trans('<nobr>%1 MB</nobr>').replace('%1',d['VRAMSize']);
  725. }
  726. },{
  727. title: 'Remote Desktop Server Port',
  728. callback: function(d) {
  729. var chost = vboxGetVRDEHost(d);
  730. // Get ports
  731. var rowStr = d['VRDEServer']['ports'];
  732. // Just this for snapshots
  733. if(d._isSnapshot) return rowStr;
  734. // Display links?
  735. if((d['state'] == 'Running' || d['state'] == 'Paused') && d['VRDEServerInfo']) {
  736. if(d['VRDEServerInfo']['port'] <= 0) {
  737. rowStr = '<span style="text-decoration: line-through; color: #f00;">' + rowStr + '</span>';
  738. // RDP
  739. } else if(d['VRDEServer']['VRDEExtPack'].indexOf("VNC") == -1) {
  740. rowStr = " <a href='" + vboxEndpointConfig.rdpGen + "?host=" + chost + '&port=' + d['VRDEServerInfo']['port'] + "&id=" + d['id'] + "&vm=" + encodeURIComponent(d['name']) + "'>" + d['VRDEServerInfo']['port'] + "</a>";
  741. rowStr += ' <img src="images/vbox/blank.gif" style="vspace:0px;hspace:0px;height2px;width:10px;" /> (' + chost + ':' + d['VRDEServerInfo']['port'] + ')';
  742. // VNC
  743. } else {
  744. rowStr = " <a href='vnc://" + chost + ':' + d['VRDEServerInfo']['port'] + "'>" + d['VRDEServerInfo']['port'] + "</a>";
  745. rowStr += ' <img src="images/vbox/blank.gif" style="vspace:0px;hspace:0px;height2px;width:10px;" /> (' + chost + ':' + d['VRDEServerInfo']['port'] + ')';
  746. }
  747. } else {
  748. rowStr += ' ('+chost+')';
  749. }
  750. return rowStr;
  751. },
  752. html: true,
  753. condition: function(d) {
  754. // Running and paused states have real-time console info
  755. if(!d._isSnapshot && (d['state'] == 'Running' || d['state'] == 'Paused')) {
  756. return d.VRDEServer && (d.VRDEServer.enabled);
  757. }
  758. return (d['VRDEServer'] && (d._isSnapshot || d['VRDEServer']['VRDEExtPack']) && d['VRDEServer']['enabled'] && d['VRDEServer']['ports']);
  759. }
  760. },{
  761. title: "Remote Desktop Server",
  762. callback: function(d) {
  763. return trans('Disabled','VBoxGlobal',null,'details report (VRDE Server)');
  764. },
  765. condition: function(d) {
  766. return !(vboxVMDetailsSections.display.rows[1].condition(d));
  767. }
  768. }
  769. ]
  770. },
  771. /*
  772. * Storage controllers
  773. */
  774. storage: {
  775. title: 'Storage',
  776. icon: 'hd_16px.png',
  777. settingsLink: 'Storage',
  778. redrawMachineEvents: ['OnMediumChanged', 'OnMachineStateChanged'],
  779. _refreshVMMedia: function(vmid, mid) {
  780. // See if medium is there
  781. var mRefresh = true;
  782. if(!vboxMedia.getMediumById(mid)) {
  783. mRefresh = vboxAjaxRequest('vboxGetMedia');
  784. }
  785. var l = new vboxLoader();
  786. l.showLoading();
  787. $.when(mRefresh, vboxVMDataMediator.refreshVMData(vmid)).done(function(d){
  788. if(d && d.responseData) $('#vboxPane').data('vboxMedia',d.responseData);
  789. }).always(function(){
  790. l.removeLoading();
  791. });
  792. },
  793. rows: function(d) {
  794. var rows = new Array();
  795. for(var a = 0; a < d['storageControllers'].length; a++) {
  796. var con = d['storageControllers'][a];
  797. // Controller name
  798. rows[rows.length] = {
  799. title: trans('Controller: %1','UIMachineSettingsStorage').replace('%1',$('<div />').text(con.name).html()),
  800. callback: function(){return'';}
  801. };
  802. // Each attachment.
  803. for(var b = 0; b < d['storageControllers'][a]['mediumAttachments'].length; b++) {
  804. var portName = vboxStorage[d['storageControllers'][a].bus].slotName(d['storageControllers'][a]['mediumAttachments'][b].port, d['storageControllers'][a]['mediumAttachments'][b].device);
  805. // Medium / host device info
  806. var medium = (d['storageControllers'][a]['mediumAttachments'][b].medium && d['storageControllers'][a]['mediumAttachments'][b].medium.id ? vboxMedia.getMediumById(d['storageControllers'][a]['mediumAttachments'][b].medium.id): null);
  807. // Do we need to reload media?
  808. if(d['storageControllers'][a]['mediumAttachments'][b].medium && d['storageControllers'][a]['mediumAttachments'][b].medium.id && medium === null) {
  809. if(!d._isSnapshot) {
  810. portDesc = '<a href="javascript:vboxVMDetailsSections.storage._refreshVMMedia(\''+
  811. d.id+"','"+d['storageControllers'][a]['mediumAttachments'][b].medium.id+"');\">"+trans('Refresh','UIVMLogViewer')+"</a>";
  812. } else {
  813. portDesc = trans('Refresh','UIVMLogViewer');
  814. }
  815. } else {
  816. // Get base medium (snapshot -> virtual disk file)
  817. var it = false;
  818. if(medium && medium.base && (medium.base != medium.id)) {
  819. it = true;
  820. medium = vboxMedia.getMediumById(medium.base);
  821. }
  822. portDesc = vboxMedia.mediumPrint(medium,false,it);
  823. }
  824. rows[rows.length] = {
  825. title: portName,
  826. indented: true,
  827. data: (d['storageControllers'][a]['mediumAttachments'][b].type == 'DVD' ? trans('[Optical Drive]','UIGDetails') + ' ': '') + portDesc,
  828. html: true
  829. };
  830. }
  831. }
  832. return rows;
  833. }
  834. },
  835. /*
  836. * Audio
  837. */
  838. audio: {
  839. title: 'Audio',
  840. icon: 'sound_16px.png',
  841. settingsLink: 'Audio',
  842. rows: [
  843. {
  844. title: "Disabled",
  845. language_context: ['VBoxGlobal', null, 'details report (audio)'],
  846. cssClass: 'vboxDetailsNone',
  847. condition: function(d) { return !d['audioAdapter']['enabled']; },
  848. data: ''
  849. },{
  850. title: "Host Driver",
  851. language_context: 'VBoxGlobal',
  852. callback: function(d) {
  853. return trans(vboxAudioDriver(d['audioAdapter']['audioDriver']),'VBoxGlobal');
  854. },
  855. condition: function(d) { return d['audioAdapter']['enabled']; }
  856. },{
  857. title: "Controller",
  858. language_context: 'VBoxGlobal',
  859. callback: function (d) {
  860. return trans(vboxAudioController(d['audioAdapter']['audioController']),'VBoxGlobal');
  861. },
  862. condition: function(d) { return d['audioAdapter']['enabled']; }
  863. }
  864. ]
  865. },
  866. /*
  867. * Network adapters
  868. */
  869. network: {
  870. icon: 'nw_16px.png',
  871. title: 'Network',
  872. redrawMachineEvents: ['OnNetworkAdapterChanged','OnMachineStateChanged'],
  873. settingsLink: 'Network',
  874. rows: function(d) {
  875. var vboxDetailsTableNics = 0;
  876. var rows = [];
  877. for(var i = 0; i < d['networkAdapters'].length; i++) {
  878. nic = d['networkAdapters'][i];
  879. // compose extra info
  880. var adp = '';
  881. if(nic.enabled) {
  882. vboxDetailsTableNics++;
  883. switch(nic.attachmentType) {
  884. case 'Null':
  885. adp = trans('Not attached','VBoxGlobal');
  886. break;
  887. case 'Bridged':
  888. adp = trans('Bridged adapter, %1').replace('%1', nic.bridgedInterface);
  889. break;
  890. case 'HostOnly':
  891. adp = trans('Host-only adapter, \'%1\'').replace('%1', nic.hostOnlyInterface);
  892. break;
  893. case 'NAT':
  894. // 'NATNetwork' ?
  895. adp = trans('NAT','VBoxGlobal');
  896. break;
  897. case 'Internal':
  898. adp = trans('Internal network, \'%1\'').replace('%1', $('<div />').text(nic.internalNetwork).html());
  899. break;
  900. case 'Generic':
  901. // Check for properties
  902. if(nic.properties) {
  903. adp = trans('Generic Driver, \'%1\' { %2 }','UIGDetails').replace('%1', $('<div />').text(nic.genericDriver).html());
  904. var np = nic.properties.split("\n");
  905. adp = adp.replace('%2', np.join(" ,"));
  906. break;
  907. }
  908. adp = trans('Generic Driver, \'%1\'','UIGDetails').replace('%1', $('<div />').text(nic.genericDriver).html());
  909. break;
  910. case 'VDE':
  911. adp = trans('VDE network, \'%1\'').replace('%1', $('<div />').text(nic.VDENetwork).html());
  912. break;
  913. case 'NATNetwork':
  914. adp = trans('NAT Network, \'%1\'','UIGDetails').replace('%1', $('<div />').text(nic.NATNetwork).html());
  915. break;
  916. }
  917. rows[rows.length] = {
  918. title: trans("Adapter %1").replace('%1',(i + 1)),
  919. data: trans(vboxNetworkAdapterType(nic.adapterType)).replace(/\(.*\)/,'') + ' (' + adp + ')'
  920. };
  921. }
  922. }
  923. // No enabled nics
  924. if(vboxDetailsTableNics == 0) {
  925. rows[rows.length] = {
  926. title: trans('Disabled','VBoxGlobal',null,'details report (network)'),
  927. cssClass: 'vboxDetailsNone'
  928. };
  929. // Link nic to guest networking info?
  930. } else if(d['state'] == 'Running') {
  931. rows[rows.length] = {
  932. title: '',
  933. data: '<a href="javascript:vboxGuestNetworkAdaptersDialogInit(\''+d['id']+'\');">('+trans('Guest Network Adapters')+')</a>',
  934. html: true
  935. };
  936. }
  937. return rows;
  938. }
  939. },
  940. /*
  941. * Serial Ports
  942. */
  943. serialports: {
  944. title: 'Serial Ports',
  945. icon: 'serial_port_16px.png',
  946. settingsLink: 'SerialPorts',
  947. rows: function(d) {
  948. var rows = [];
  949. var vboxDetailsTableSPorts = 0;
  950. for(var i = 0; i < d['serialPorts'].length; i++) {
  951. p = d['serialPorts'][i];
  952. if(!p.enabled) continue;
  953. // compose extra info
  954. var xtra = vboxSerialPorts.getPortName(p.IRQ,p.IOBase);
  955. var mode = p.hostMode;
  956. xtra += ', ' + trans(vboxSerialMode(mode),'VBoxGlobal');
  957. if(mode != 'Disconnected') {
  958. xtra += ' (' + $('<div />').text(p.path).html() + ')';
  959. }
  960. rows[rows.length] = {
  961. title: trans("Port %1",'VBoxGlobal',null,'details report (serial ports)').replace('%1',(i + 1)),
  962. data: xtra,
  963. html: true
  964. };
  965. vboxDetailsTableSPorts++;
  966. }
  967. if(vboxDetailsTableSPorts == 0) {
  968. rows[rows.length] = {
  969. title: trans('Disabled','VBoxGlobal',null,'details report (serial ports)'),
  970. cssClass: 'vboxDetailsNone'
  971. };
  972. }
  973. return rows;
  974. }
  975. },
  976. /*
  977. * Parallel ports
  978. */
  979. parallelports: {
  980. title: 'Parallel Ports',
  981. language_context: 'UISettingsDialogMachine',
  982. icon: 'parallel_port_16px.png',
  983. settingsLink: 'ParallelPorts',
  984. condition: function() { return $('#vboxPane').data('vboxConfig').enableLPTConfig; },
  985. rows: function(d) {
  986. var rows = [];
  987. var vboxDetailsTableSPorts = 0;
  988. for(var i = 0; i < d['parallelPorts'].length; i++) {
  989. p = d['parallelPorts'][i];
  990. if(!p.enabled) continue;
  991. // compose extra info
  992. var xtra = trans(vboxParallelPorts.getPortName(p.IRQ,p.IOBase));
  993. xtra += ' (' + $('<div />').text(p.path).html() + ')';
  994. rows[rows.length] = {
  995. title: trans("Port %1",'VBoxGlobal',null,'details report (parallel ports)').replace('%1',(i + 1)),
  996. data: xtra
  997. };
  998. vboxDetailsTableSPorts++;
  999. }
  1000. if(vboxDetailsTableSPorts == 0) {
  1001. rows[0] = {
  1002. title: trans('Disabled','VBoxGlobal',null,'details report (parallel ports)'),
  1003. cssClass: 'vboxDetailsNone'
  1004. };
  1005. }
  1006. return rows;
  1007. }
  1008. },
  1009. /*
  1010. * USB
  1011. */
  1012. usb: {
  1013. icon: 'usb_16px.png',
  1014. title: 'USB',
  1015. language_context: 'UIGDetails',
  1016. settingsLink: 'USB',
  1017. rows: function(d) {
  1018. var rows = [];
  1019. var usbEnabled = false;
  1020. var usbType = 'OHCI';
  1021. for(var i = 0; i < d.USBControllers.length; i++) {
  1022. var listUSBType = d.USBControllers[i].type;
  1023. if(listUSBType == 'OHCI') {
  1024. usbEnabled = true;
  1025. }
  1026. switch(listUSBType) {
  1027. case 'OHCI':
  1028. if(usbType == 'EHCI')
  1029. break;
  1030. case 'EHCI':
  1031. if(usbType == 'XHCI')
  1032. break;
  1033. default:
  1034. usbType = listUSBType;
  1035. }
  1036. }
  1037. if(usbEnabled) {
  1038. rows.push({
  1039. title: trans("USB Controller", 'UIGDetails', null, 'details (usb)'),
  1040. data: usbType
  1041. });
  1042. var tot = 0;
  1043. var act = 0;
  1044. for(var i = 0; i < d.USBDeviceFilters.length; i++) {
  1045. tot++;
  1046. if(d.USBDeviceFilters[i].active) act++;
  1047. }
  1048. rows.push({
  1049. title: trans("Device Filters", 'UIGDetails', null, 'details (usb)'),
  1050. data: trans('%1 (%2 active)', 'UIGDetails', null, 'details (usb)').replace('%1',tot).replace('%2',act)
  1051. });
  1052. } else {
  1053. rows.push({
  1054. title: trans("Disabled", 'UIGDetails', null, 'details report (USB)'),
  1055. cssClass: 'vboxDetailsNone'
  1056. });
  1057. }
  1058. return rows;
  1059. }
  1060. },
  1061. /*
  1062. * Shared folders list
  1063. */
  1064. sharedfolders: {
  1065. title: 'Shared Folders',
  1066. language_context: 'UIGDetails',
  1067. icon: 'sf_16px.png',
  1068. settingsLink: 'SharedFolders',
  1069. rows: function(d) {
  1070. if(!d['sharedFolders'] || d['sharedFolders'].length < 1) {
  1071. return [{
  1072. title: trans('None',null,null,'details report (shared folders)'),
  1073. cssClass: 'vboxDetailsNone'
  1074. }];
  1075. }
  1076. return [{
  1077. title: trans('Shared Folders', 'UIGDetails'),
  1078. data: d['sharedFolders'].length
  1079. }];
  1080. }
  1081. },
  1082. /*
  1083. * VM Description
  1084. */
  1085. description: {
  1086. icon: 'description_16px.png',
  1087. title: 'Description',
  1088. language_context: 'UIGDetails',
  1089. settingsLink: 'General:2',
  1090. rows: function(d) {
  1091. return [{
  1092. title: '',
  1093. data: $('<tr />').attr({'class':'vboxDetailRow'}).append(
  1094. $('<td />').attr({'class':'vboxDetailDescriptionCell','colspan':'2'})
  1095. .html(d.description.length ? $('<div />').text(d.description).html(): '<span class="vboxDetailsNone">'+trans("None",null,null,'details report (description)')+'</span>')
  1096. ),
  1097. rawRow: true
  1098. }];
  1099. }
  1100. }
  1101. };
  1102. /**
  1103. * Common VM Group Actions - most of these are passed off
  1104. * to the vboxChooser object
  1105. *
  1106. * @namespace vboxVMGroupActions
  1107. */
  1108. var vboxVMGroupActions = {
  1109. 'newmachine': {
  1110. label: 'New Machine...',
  1111. icon: 'vm_new',
  1112. name: 'new',
  1113. click: function(){
  1114. vboxVMActions['new'].click(true);
  1115. },
  1116. enabled: function() {
  1117. return $('#vboxPane').data('vboxSession').admin;
  1118. }
  1119. },
  1120. addmachine: {
  1121. label: 'Add Machine...',
  1122. icon: 'vm_add',
  1123. name: 'add',
  1124. click: function() {
  1125. vboxVMActions['add'].click(true);
  1126. },
  1127. enabled: function() {
  1128. return $('#vboxPane').data('vboxSession').admin;
  1129. }
  1130. },
  1131. rename: {
  1132. label: 'Rename Group...',
  1133. icon: 'vm_group_name',
  1134. name: 'rename_group',
  1135. enabled: function() {
  1136. if(!$('#vboxPane').data('vboxSession').admin) return false;
  1137. if(!vboxChooser._editable) return false;
  1138. var gElm = vboxChooser.getSelectedGroupElements()[0];
  1139. if(!gElm) return false;
  1140. if($('#vboxPane').data('vboxConfig')['phpVboxGroups']) return true;
  1141. if($(gElm).find('td.vboxVMSessionOpen')[0]) return false;
  1142. return true;
  1143. },
  1144. click: function() {
  1145. vboxChooser.renameSelectedGroup();
  1146. }
  1147. },
  1148. ungroup: {
  1149. label: 'Ungroup',
  1150. icon: 'vm_group_remove',
  1151. name: 'remove_group',
  1152. enabled: function() {
  1153. if(!vboxChooser._editable) return false;
  1154. if(!$('#vboxPane').data('vboxSession').admin) return false;
  1155. var gElm = vboxChooser.getSelectedGroupElements()[0];
  1156. if(!gElm) return false;
  1157. if($('#vboxPane').data('vboxConfig')['phpVboxGroups']) return true;
  1158. if($(gElm).find('td.vboxVMSessionOpen')[0]) return false;
  1159. return true;
  1160. },
  1161. click: function() {
  1162. vboxChooser.unGroupSelectedGroup();
  1163. }
  1164. },
  1165. 'sort': {
  1166. label: 'Sort',
  1167. icon:'sort',
  1168. name: 'sort_group',
  1169. click: function() {
  1170. vboxChooser.sortSelectedGroup();
  1171. },
  1172. enabled: function() {
  1173. if(!vboxChooser._editable) return false;
  1174. return $('#vboxPane').data('vboxSession').admin;
  1175. }
  1176. }
  1177. };
  1178. /**
  1179. * Common VM Actions - These assume that they will be run on the selected VM as
  1180. * stored in vboxChooser.getSingleSelected()
  1181. *
  1182. * @namespace vboxVMActions
  1183. */
  1184. var vboxVMActions = {
  1185. /** Invoke the new virtual machine wizard */
  1186. 'new':{
  1187. label: 'New...',
  1188. icon: 'vm_new',
  1189. name: 'new',
  1190. click: function(fromGroup){
  1191. new vboxWizardNewVMDialog((fromGroup ? $(vboxChooser.getSelectedGroupElements()[0]).data('vmGroupPath'): '')).run();
  1192. }
  1193. },
  1194. /** Add a virtual machine via its settings file */
  1195. add: {
  1196. label: 'Add...',
  1197. icon: 'vm_add',
  1198. name: 'add',
  1199. click: function(){
  1200. vboxFileBrowser($('#vboxPane').data('vboxSystemProperties').defaultMachineFolder,function(f){
  1201. if(!f) return;
  1202. var l = new vboxLoader();
  1203. l.add('machineAdd',function(){return;},{'file':f});
  1204. l.onLoad = function(){
  1205. var lm = new vboxLoader();
  1206. lm.add('vboxGetMedia',function(d){$('#vboxPane').data('vboxMedia',d.responseData);});
  1207. lm.run();
  1208. };
  1209. l.run();
  1210. },false,trans('Add existing virtual machine','UIActionPool'),'images/vbox/machine_16px.png',true);
  1211. }
  1212. },
  1213. /** Start VM */
  1214. start: {
  1215. label: 'Start',
  1216. name: 'start',
  1217. icon: 'vm_start',
  1218. _startedVMs: {},
  1219. /*
  1220. * Subscribe to machine state changes to remove from _startedVMs
  1221. *
  1222. */
  1223. _subscribedStateChanges: false,
  1224. _subscribeStateChanges: function() {
  1225. if(vboxVMActions.start._subscribedStateChanges)
  1226. return;
  1227. vboxVMActions.start._subscribedStateChanges = true;
  1228. $('#vboxPane').on('vboxOnMachineStateChanged', function(e, eventData) {
  1229. // We did not start this VM
  1230. if(!vboxVMActions.start._startedVMs[eventData.machineId])
  1231. return;
  1232. var vmState = {'state': eventData.state};
  1233. if(vboxVMStates.isPaused(vmState) || vboxVMStates.isStuck(vmState) || vboxVMStates.isPoweredOff(vmState)) {
  1234. delete vboxVMActions.start._startedVMs[eventData.machineId];
  1235. }
  1236. });
  1237. },
  1238. /*
  1239. * Subscribe to machine runtime errors to ask for medium
  1240. * encryption password(s)
  1241. */
  1242. _subscribedRuntimeErrors: false,
  1243. _subscribeRuntimeErrors: function() {
  1244. if(vboxVMActions.start._subscribedRuntimeErrors)
  1245. return;
  1246. vboxVMActions.start._subscribedRuntimeErrors = true;
  1247. // Trigger VM media encryption password dialog
  1248. $('#vboxPane').on('vboxOnRuntimeError',function(e, eventData) {
  1249. // We did not start this VM
  1250. if(!vboxVMActions.start._startedVMs[eventData.machineId])
  1251. return;
  1252. // Disk encryption missing
  1253. if(eventData.id == "DrvVD_DEKMISSING") {
  1254. // Encryption passwords are needed to start VM
  1255. var vmData = vboxVMDataMediator.getVMDetails(eventData.machineId);
  1256. vboxVMActions.start._getEncryptionPasswordsStartVM(vmData);
  1257. return;
  1258. }
  1259. // Display runtime error
  1260. var message = vboxVMDataMediator.getVMData(eventData.machineId).title + ' - ' +
  1261. eventData.message;
  1262. vboxAlert(message);
  1263. });
  1264. },
  1265. /* Get passwords and start VM Logic */
  1266. _getEncryptionPasswordsStartVM: function(vm, validIds) {
  1267. // Encrypted media
  1268. var encIds = vboxMedia.getEncryptedMediaIds(
  1269. vboxStorage.getAttachedBaseMedia(vm)
  1270. );
  1271. // Get encryption password(s)
  1272. var pwPromise = vboxMediumEncryptionPasswordsDialog(vm.name, encIds, validIds);
  1273. $.when(pwPromise).done(function(pwdata) {
  1274. // vboxVMActions.start._getEncryptionPasswordsStartVM(vm);
  1275. $.when(vboxAjaxRequest('consoleAddDiskEncryptionPasswords',
  1276. {'vm':vm.id,'passwords':pwdata}))
  1277. .done(function(retData) {
  1278. if(!retData)
  1279. return;
  1280. var failed = retData.responseData.failed.length;
  1281. var valid = retData.responseData.accepted;
  1282. if(failed) {
  1283. var acknowledged = vboxAlert(trans('Unable to enter password!')+
  1284. '<p>'+retData.responseData.errors.join('<br />')+'</p>');
  1285. $.when(acknowledged).done(function(){
  1286. vboxVMActions.start._getEncryptionPasswordsStartVM(vm, valid);
  1287. })
  1288. }
  1289. // VMs will be started automatically if the password(s) supplied were correct
  1290. })
  1291. }).fail(function(){
  1292. // Clicked cancel
  1293. // TODO: "Close VM" dialog
  1294. });
  1295. },
  1296. /* Start a single VM */
  1297. _startVM: function(vm) {
  1298. var reqPromise = $.Deferred();
  1299. $.when(vm,vboxAjaxRequest('machineSetState',{'vm':vm.id,'state':'powerUp'}))
  1300. // VM started and / or progress op returned
  1301. .done(function(evm,d){
  1302. // check for progress operation
  1303. if(d && d.responseData && d.responseData.progress) {
  1304. if(vboxVMStates.isSaved(evm)) icon = 'progress_state_restore_90px.png';
  1305. else icon = 'progress_start_90px.png';
  1306. reqPromise.resolve();
  1307. vboxProgress({'progress':d.responseData.progress,'persist':d.persist}, function(){return;},
  1308. icon, trans('Start selected virtual machines','UIActionPool'), evm.name);
  1309. } else {
  1310. reqPromise.reject();
  1311. }
  1312. });
  1313. return reqPromise;
  1314. },
  1315. click: function (btn) {
  1316. // Setup
  1317. vboxVMActions.start._subscribeRuntimeErrors();
  1318. vboxVMActions.start._subscribeStateChanges();
  1319. // Should the "First Run" wizard be started
  1320. ////////////////////////////////////////////
  1321. var firstRun = function(vm) {
  1322. var frDef = $.Deferred();
  1323. $.when(vboxVMDataMediator.getVMDetails(vm.id)).done(function(d) {
  1324. // Not first run?
  1325. if(d.GUI.FirstRun != 'yes') {
  1326. // Just resolve, nothing to do
  1327. frDef.resolve(d);
  1328. return;
  1329. }
  1330. // Check for CD/DVD drive attachment that has no CD/DVD
  1331. var cdFound = false;
  1332. for(var i = 0; i < d.storageControllers.length; i++) {
  1333. for(var a = 0; a < d.storageControllers[i].mediumAttachments.length; a++) {
  1334. if(d.storageControllers[i].mediumAttachments[a].type == "DVD" &&
  1335. d.storageControllers[i].mediumAttachments[a].medium == null) {
  1336. cdFound = true;
  1337. break;
  1338. }
  1339. }
  1340. }
  1341. // No CD/DVD attachment
  1342. if(!cdFound) {
  1343. // Just resolve, nothing to do
  1344. frDef.resolve(d);
  1345. return;
  1346. }
  1347. // First time run
  1348. $.when(d, new vboxWizardFirstRunDialog(d).run()).done(function(vm2start){
  1349. frDef.resolve(vm2start);
  1350. });
  1351. });
  1352. return frDef.promise();
  1353. };
  1354. // Start each eligable selected vm
  1355. //////////////////////////////////////
  1356. var startVMs = function() {
  1357. var vms = vboxChooser.getSelectedVMsData();
  1358. var vmsToStart = [];
  1359. for(var i = 0; i < vms.length; i++) {
  1360. if(vboxVMStates.isPaused(vms[i]) || vboxVMStates.isPoweredOff(vms[i]) || vboxVMStates.isSaved(vms[i])) {
  1361. vmsToStart[vmsToStart.length] = vms[i];
  1362. }
  1363. }
  1364. (function runVMsToStart(vms){
  1365. (vms.length && $.when(firstRun(vms.shift())).done(function(vm){
  1366. // Save the fact that we started this VM
  1367. vboxVMActions.start._startedVMs[vm.id] = true;
  1368. $.when(vboxVMActions.start._startVM(vm)).done(function() {
  1369. // Loop
  1370. runVMsToStart(vms);
  1371. });
  1372. }));
  1373. })(vmsToStart);
  1374. };
  1375. // Check for memory limit
  1376. // Paused VMs are already using all their memory
  1377. if($('#vboxPane').data('vboxConfig').vmMemoryStartLimitWarn) {
  1378. var freeMem = 0;
  1379. var baseMem = 0;
  1380. // Host memory needs to be checked
  1381. var loadData = [vboxAjaxRequest('hostGetMeminfo')];
  1382. // Load details of each machine to get memory info
  1383. var vms = vboxChooser.getSelectedVMsData();
  1384. for(var i = 0; i < vms.length; i++) {
  1385. if(vboxVMStates.isPoweredOff(vms[i]) || vboxVMStates.isSaved(vms[i]))
  1386. loadData[loadData.length] = vboxVMDataMediator.getVMDataCombined(vms[i].id);
  1387. }
  1388. // Show loading screen while this is occuring
  1389. var l = new vboxLoader('vboxHostMemCheck');
  1390. l.showLoading();
  1391. // Load all needed data
  1392. $.when.apply($, loadData).done(function() {
  1393. // Remove loading screen
  1394. l.removeLoading();
  1395. // First result is host memory info
  1396. freeMem = arguments[0].responseData;
  1397. // Add memory of each VM
  1398. for(var i = 1; i < arguments.length; i++) {
  1399. // Paused VMs are already using their memory
  1400. if(vboxVMStates.isPaused(arguments[i])) continue;
  1401. // memory + a little bit of overhead
  1402. baseMem += (arguments[i].memorySize + 50);
  1403. }
  1404. // subtract offset
  1405. if($('#vboxPane').data('vboxConfig').vmMemoryOffset)
  1406. freeMem -= $('#vboxPane').data('vboxConfig').vmMemoryOffset;
  1407. // Memory breaches warning threshold
  1408. if(baseMem >= freeMem) {
  1409. var buttons = {};
  1410. buttons[trans('Yes','QIMessageBox')] = function(){
  1411. $(this).remove();
  1412. startVMs();
  1413. };
  1414. freeMem = Math.max(0,freeMem);
  1415. vboxConfirm('<p>The selected virtual machine(s) require(s) <b><i>approximately</b></i> ' + baseMem +
  1416. 'MB of memory, but your VirtualBox host only has ' + freeMem + 'MB '+
  1417. ($('#vboxPane').data('vboxConfig').vmMemoryOffset ? ' (-'+$('#vboxPane').data('vboxConfig').vmMemoryOffset+'MB)': '') +
  1418. ' free.</p><p>Are you sure you want to start the virtual machine(s)?</p>',buttons,trans('No','QIMessageBox'));
  1419. // Memory is fine. Start vms.
  1420. } else {
  1421. startVMs();
  1422. }
  1423. });
  1424. // No memory limit warning configured
  1425. } else {
  1426. startVMs();
  1427. }
  1428. },
  1429. enabled: function () {
  1430. return (vboxChooser.isSelectedInState('Paused') || vboxChooser.isSelectedInState('PoweredOff') || vboxChooser.isSelectedInState('Saved'));
  1431. }
  1432. },
  1433. /** Invoke VM settings dialog */
  1434. settings: {
  1435. label: 'Settings...',
  1436. icon: 'vm_settings',
  1437. name: 'settings',
  1438. click: function(){
  1439. vboxVMsettingsDialog(vboxChooser.getSingleSelectedId());
  1440. },
  1441. enabled: function () {
  1442. return vboxChooser && vboxChooser.selectionMode == vboxSelectionModeSingleVM &&
  1443. (vboxChooser.isSelectedInState('Running') || vboxChooser.isSelectedInState('Paused') || vboxChooser.isSelectedInState('Editable'));
  1444. }
  1445. },
  1446. /** Clone a VM */
  1447. clone: {
  1448. label: 'Clone...',
  1449. icon: 'vm_clone',
  1450. name: 'clone',
  1451. click: function(){
  1452. new vboxWizardCloneVMDialog({vm:vboxChooser.getSingleSelected()}).run();
  1453. },
  1454. enabled: function () {
  1455. return (vboxChooser.selectionMode == vboxSelectionModeSingleVM && vboxChooser.isSelectedInState('PoweredOff'));
  1456. }
  1457. },
  1458. /** Refresh a VM's details */
  1459. refresh: {
  1460. label: 'Refresh',
  1461. language_context: 'UIVMLogViewer',
  1462. icon:'refresh',
  1463. name: 'refresh',
  1464. click:function(){
  1465. var vmid = vboxChooser.getSingleSelectedId();
  1466. var l = new vboxLoader();
  1467. l.showLoading();
  1468. $.when(vboxVMDataMediator.refreshVMData(vmid)).done(function(){
  1469. l.removeLoading();
  1470. });
  1471. },
  1472. enabled: function () {return(vboxChooser.selectedVMs.length ==1);}
  1473. },
  1474. /** Delete / Remove a VM */
  1475. remove: {
  1476. label: 'Remove...',
  1477. icon: 'vm_delete',
  1478. name: 'remove_vm',
  1479. click:function(){
  1480. ///////////////////
  1481. // Remove VMs
  1482. //////////////////
  1483. var removeCopies = function() {
  1484. var vmList = [];
  1485. var vmNames = [];
  1486. var vms = vboxChooser.getSelectedVMsData();
  1487. for(var i = 0; i < vms.length; i++) {
  1488. if(vboxVMStates.isPoweredOff(vms[i]) && vboxChooser.vmHasUnselectedCopy(vms[i].id)) {
  1489. vmList[vmList.length] = vms[i].id;
  1490. vmNames[vmNames.length] = vms[i].name;
  1491. }
  1492. }
  1493. if(vmList.length) {
  1494. var rcDef = $.Deferred();
  1495. var buttons = {};
  1496. buttons[trans('Remove', 'UIMessageCenter')] = function() {
  1497. $(this).empty().remove();
  1498. vboxChooser.removeVMs(vmList);
  1499. rcDef.resolve();
  1500. }
  1501. vmNames = '<b>'+vmNames.join('</b>, <b>')+'</b>';
  1502. var q = trans('<p>You are about to remove following virtual machine items from the machine list:</p><p><b>%1</b></p><p>Do you wish to proceed?</p>','UIMessageCenter').replace('%1',vmNames);
  1503. vboxConfirm(q,buttons,undefined,function(){
  1504. rcDef.resolve();
  1505. });
  1506. return rcDef.promise();
  1507. }
  1508. return true;
  1509. }
  1510. //////////////////
  1511. // Unregister VMs
  1512. ///////////////////
  1513. $.when(removeCopies()).done(function() {
  1514. var unregisterVMs = function(keepFiles, vms) {
  1515. var vms = vboxChooser.getSelectedVMsData();
  1516. for(var i = 0; i < vms.length; i++) {
  1517. if(vboxVMStates.isPoweredOff(vms[i]) || vboxVMStates.isInaccessible(vms[i])) {
  1518. // Remove each selected vm
  1519. $.when(vms[i].name, vboxAjaxRequest('machineRemove',
  1520. {'vm':vms[i].id,'delete':(keepFiles ? '0': '1')}))
  1521. .done(function(vmname, d){
  1522. // check for progress operation
  1523. if(d && d.responseData && d.responseData.progress) {
  1524. vboxProgress({'progress':d.responseData.progress,'persist':d.persist},function(){return;},'progress_delete_90px.png',
  1525. trans('Remove selected virtual machines', 'UIActionPool'), vmname);
  1526. }
  1527. });
  1528. }
  1529. }
  1530. };
  1531. var buttons = {};
  1532. buttons[trans('Delete all files','UIMessageCenter')] = function(){
  1533. $(this).empty().remove();
  1534. unregisterVMs(false);
  1535. };
  1536. buttons[trans('Remove only','UIMessageCenter')] = function(){
  1537. $(this).empty().remove();
  1538. unregisterVMs(true);
  1539. };
  1540. var vmNames = [];
  1541. var vms = vboxChooser.getSelectedVMsData();
  1542. for(var i = 0; i < vms.length; i++) {
  1543. if((vboxVMStates.isPoweredOff(vms[i]) || vboxVMStates.isInaccessible(vms[i])) && !vboxChooser.vmHasUnselectedCopy(vms[i].id)) {
  1544. vmNames[vmNames.length] = vms[i].name;
  1545. }
  1546. }
  1547. if(vmNames.length) {
  1548. vmNames = '<b>'+vmNames.join('</b>, <b>')+'</b>';
  1549. var q = trans('<p>You are about to remove following virtual machines from the machine list:</p><p>%1</p><p>Would you like to delete the files containing the virtual machine from your hard disk as well? Doing this will also remove the files containing the machine\'s virtual hard disks if they are not in use by another machine.</p>','UIMessageCenter').replace('%1',vmNames);
  1550. vboxConfirm(q,buttons);
  1551. }
  1552. });
  1553. },
  1554. enabled: function () {
  1555. if(!vboxChooser._editable) return false;
  1556. return (vboxChooser.isSelectedInState('PoweredOff') || vboxChooser.isSelectedInState('Inaccessible'));
  1557. }
  1558. },
  1559. /** Create a group from VM * */
  1560. group: {
  1561. label: 'Group',
  1562. icon: 'vm_group_create',
  1563. name: 'create_group',
  1564. click: function() {
  1565. vboxChooser.groupSelectedItems();
  1566. },
  1567. enabled: function() {
  1568. if(!$('#vboxPane').data('vboxSession').admin)
  1569. return false;
  1570. if (!vboxChooser || (vboxChooser.getSingleSelectedId() == 'host'))
  1571. return false;
  1572. if(!vboxChooser._editable) return false;
  1573. return vboxChooser.isSelectedInState('Editable');
  1574. }
  1575. },
  1576. /** Discard VM State */
  1577. discard: {
  1578. label: 'Discard Saved State...',
  1579. icon: 'vm_discard',
  1580. name: 'discard',
  1581. click: function(){
  1582. var buttons = {};
  1583. buttons[trans('Discard','UIMessageCenter')] = function(){
  1584. $(this).empty().remove();
  1585. var vms = vboxChooser.getSelectedVMsData();
  1586. for(var i = 0; i < vms.length; i++) {
  1587. if(vboxVMStates.isSaved(vms[i])) {
  1588. vboxAjaxRequest('machineSetState',{'vm':vms[i].id,'state':'discardSavedState'});
  1589. }
  1590. }
  1591. };
  1592. var vmNames = [];
  1593. var vms = vboxChooser.getSelectedVMsData();
  1594. for(var i = 0; i < vms.length; i++) {
  1595. if(vboxVMStates.isSaved(vms[i])) {
  1596. vmNames[vmNames.length] = vms[i].name;
  1597. }
  1598. }
  1599. if(vmNames.length) {
  1600. vmNames = '<b>'+vmNames.join('</b>, <b>')+'</b>';
  1601. vboxConfirm(trans('<p>Are you sure you want to discard the saved state of the following virtual machines?</p><p><b>%1</b></p><p>This operation is equivalent to resetting or powering off the machine without doing a proper shutdown of the guest OS.</p>','UIMessageCenter').replace('%1',vmNames),buttons);
  1602. }
  1603. },
  1604. enabled:function(){
  1605. return vboxChooser.isSelectedInState('Saved');
  1606. }
  1607. },
  1608. /** Install Guest Additions **/
  1609. guestAdditionsInstall: {
  1610. label: 'Install Guest Additions...',
  1611. icon: 'guesttools',
  1612. name: 'guesttools',
  1613. click: function(vmid, mount_only) {
  1614. if(!vmid)
  1615. vmid = vboxChooser.getSingleSelected().id;
  1616. $.when(vboxAjaxRequest('consoleGuestAdditionsInstall',{'vm':vmid,'mount_only':mount_only})).done(function(d){
  1617. // Progress operation returned. Guest Additions are being updated.
  1618. if(d && d.responseData && d.responseData.progress) {
  1619. vboxProgress({'progress':d.responseData.progress,'persist':d.persist,'catcherrs':1},function(d){
  1620. // Error updating guest additions
  1621. if(!d.responseData.result && d.responseData.error && d.responseData.error.err) {
  1622. if(d.responseData.error.err != 'VBOX_E_NOT_SUPPORTED') {
  1623. vboxAlert({'error':trans('Failed to update Guest Additions. The Guest Additions installation image will be mounted to provide a manual installation.','UIMessageCenter'),'details':d.responseData.error.err+"\n"+d.responseData.error.message});
  1624. }
  1625. vboxVMActions['guestAdditionsInstall'].click(vmid, true);
  1626. return;
  1627. }
  1628. },'progress_install_guest_additions_90px.png',trans('Install Guest Additions...','UIActionPool').replace(/\./g,''));
  1629. // Media was mounted
  1630. } else if(d.responseData && d.responseData.result && d.responseData.result == 'mounted') {
  1631. // Media must be refreshed
  1632. var ml = new vboxLoader();
  1633. ml.add('vboxGetMedia',function(dat){$('#vboxPane').data('vboxMedia',dat.responseData);});
  1634. ml.run();
  1635. if(d.responseData.errored)
  1636. vboxAlert(trans('Failed to update Guest Additions. The Guest Additions installation image will be mounted to provide a manual installation.','UIMessageCenter'));
  1637. // There's no CDROM drive
  1638. } else if(d.responseData && d.responseData.result && d.responseData.result == 'nocdrom') {
  1639. var vm = vboxVMDataMediator.getVMData(vmid);
  1640. vboxAlert(trans("<p>Could not insert the VirtualBox Guest Additions " +
  1641. "installer CD image into the virtual machine <b>%1</b>, as the machine " +
  1642. "has no CD/DVD-ROM drives. Please add a drive using the " +
  1643. "storage page of the virtual machine settings dialog.</p>",'UIMessageCenter').replace('%1',vm.name));
  1644. // Can't find guest additions
  1645. } else if (d.responseData && d.responseData.result && d.responseData.result == 'noadditions') {
  1646. var s1 = '('+trans('None','VBoxGlobal')+')';
  1647. var s2 = s1;
  1648. if(d.responseData.sources && d.responseData.sources.length) {
  1649. if(d.responseData.sources[0]) s1 = d.responseData.sources[0];
  1650. if(d.responseData.sources[1]) s2 = d.responseData.sources[1];
  1651. }
  1652. var q = trans('<p>Could not find the VirtualBox Guest Additions CD image file <nobr><b>%1</b></nobr> or <nobr><b>%2</b>.</nobr></p><p>Do you wish to download this CD image from the Internet?</p>','UIMessageCenter').replace('%1',s1).replace('%2',s2);
  1653. var b = {};
  1654. b[trans('Yes','QIMessageBox')] = function() {
  1655. var url = 'http://download.virtualbox.org/virtualbox/%1/VBoxGuestAdditions_%2.iso';
  1656. url = url.replace('%1',$('#vboxPane').data('vboxConfig').version.string.replace('_OSE',''));
  1657. url = url.replace('%2',$('#vboxPane').data('vboxConfig').version.string.replace('_OSE',''));
  1658. $(this).remove();
  1659. window.open(url);
  1660. };
  1661. vboxConfirm(q,b,trans('No','QIMessageBox'));
  1662. }
  1663. });
  1664. }
  1665. },
  1666. /** Show VM Logs */
  1667. logs: {
  1668. label: 'Show Log...',
  1669. icon: 'vm_show_logs',
  1670. name: 'show_logs',
  1671. click: function(){
  1672. vboxShowLogsDialogInit(vboxChooser.getSingleSelected());
  1673. },
  1674. enabled:function(){
  1675. return (vboxChooser.getSingleSelectedId() && vboxChooser.getSingleSelectedId() != 'host');
  1676. }
  1677. },
  1678. /** Save the current VM State */
  1679. savestate: {
  1680. label: 'Save State',
  1681. icon: 'vm_save_state',
  1682. name: 'save_state',
  1683. stop_action: true,
  1684. enabled: function(){
  1685. return (vboxChooser.isSelectedInState('Running') || vboxChooser.isSelectedInState('Paused'));
  1686. },
  1687. click: function() {
  1688. var vms = vboxChooser.getSelectedVMsData();
  1689. for(var i = 0; i < vms.length; i++) {
  1690. if(vboxVMStates.isRunning(vms[i]) || vboxVMStates.isPaused(vms[i]))
  1691. vboxVMActions.powerAction('savestate','Save the state of the virtual machine', vms[i]);
  1692. }
  1693. }
  1694. },
  1695. /** Send ACPI Power Button to VM */
  1696. powerbutton: {
  1697. label: 'ACPI Shutdown',
  1698. icon: 'vm_shutdown',
  1699. name: 'vm_shutdown',
  1700. stop_action: true,
  1701. enabled: function(){
  1702. return vboxChooser.isSelectedInState('Running');
  1703. },
  1704. click: function() {
  1705. var buttons = {};
  1706. buttons[trans('ACPI Shutdown','UIMessageCenter')] = function() {
  1707. $(this).empty().remove();
  1708. var vms = vboxChooser.getSelectedVMsData();
  1709. for(var i = 0; i < vms.length; i++) {
  1710. if(vboxVMStates.isRunning(vms[i]))
  1711. vboxVMActions.powerAction('powerbutton','Send the ACPI Shutdown signal to the virtual machine', vms[i]);
  1712. }
  1713. };
  1714. var vmNames = [];
  1715. var vms = vboxChooser.getSelectedVMsData();
  1716. for(var i = 0; i < vms.length; i++) {
  1717. if(vboxVMStates.isRunning(vms[i])) {
  1718. vmNames[vmNames.length] = vms[i].name;
  1719. }
  1720. }
  1721. if(vmNames.length) {
  1722. vmNames = '<b>'+vmNames.join('</b>, <b>')+'</b>';
  1723. vboxConfirm(trans("<p>Do you really want to send an ACPI shutdown signal " +
  1724. "to the following virtual machines?</p><p><b>%1</b></p>",'UIMessageCenter').replace('%1', vmNames),buttons);
  1725. }
  1726. }
  1727. },
  1728. /** Pause a running VM */
  1729. pause: {
  1730. label: 'Pause',
  1731. icon: 'vm_pause',
  1732. name: 'vm_pause',
  1733. enabled: function(){
  1734. return vboxChooser.isSelectedInState('Running');
  1735. },
  1736. click: function() {
  1737. var vms = vboxChooser.getSelectedVMsData();
  1738. for(var i = 0; i < vms.length; i++) {
  1739. if(vboxVMStates.isRunning(vms[i]))
  1740. vboxVMActions.powerAction('pause','Suspend execution of selected virtual machines', vms[i]);
  1741. }
  1742. }
  1743. },
  1744. /** Power off a VM */
  1745. powerdown: {
  1746. label: 'Power Off',
  1747. icon: 'vm_poweroff',
  1748. name: 'poweroff',
  1749. stop_action: true,
  1750. enabled: function() {
  1751. return (vboxChooser.isSelectedInState('Running') || vboxChooser.isSelectedInState('Paused') || vboxChooser.isSelectedInState('Stuck'));
  1752. },
  1753. click: function() {
  1754. var buttons = {};
  1755. buttons[trans('Power Off','UIActionPool')] = function() {
  1756. $(this).empty().remove();
  1757. var vms = vboxChooser.getSelectedVMsData();
  1758. for(var i = 0; i < vms.length; i++) {
  1759. if(vboxVMStates.isRunning(vms[i]) || vboxVMStates.isPaused(vms[i]) || vboxVMStates.isStuck(vms[i]))
  1760. vboxVMActions.powerAction('powerdown','Power off selected virtual machines', vms[i]);
  1761. }
  1762. };
  1763. var vmNames = [];
  1764. var vms = vboxChooser.getSelectedVMsData();
  1765. for(var i = 0; i < vms.length; i++) {
  1766. if(vboxVMStates.isRunning(vms[i]) || vboxVMStates.isPaused(vms[i]) || vboxVMStates.isStuck(vms[i])) {
  1767. vmNames[vmNames.length] = vms[i].name;
  1768. }
  1769. }
  1770. if(vmNames.length) {
  1771. vmNames = '<b>'+vmNames.join('</b>, <b>')+'</b>';
  1772. vboxConfirm(trans("<p>Do you really want to power off the following virtual machines?</p>" +
  1773. "<p><b>%1</b></p><p>This will cause any unsaved data in applications " +
  1774. "running inside it to be lost.</p>", 'UIMessageCenter').replace('%1', vmNames), buttons);
  1775. }
  1776. }
  1777. },
  1778. /** Reset a VM */
  1779. reset: {
  1780. label: 'Reset',
  1781. icon: 'vm_reset',
  1782. name: 'reset',
  1783. enabled: function(){
  1784. return vboxChooser.isSelectedInState('Running');
  1785. },
  1786. click: function() {
  1787. var buttons = {};
  1788. buttons[trans('Reset','UIActionPool')] = function() {
  1789. $(this).remove();
  1790. var vms = vboxChooser.getSelectedVMsData();
  1791. for(var i = 0; i < vms.length; i++) {
  1792. if(vboxVMStates.isRunning(vms[i]))
  1793. vboxVMActions.powerAction('reset','Reset selected virtual machines', vms[i]);
  1794. }
  1795. };
  1796. var vmNames = [];
  1797. var vms = vboxChooser.getSelectedVMsData();
  1798. for(var i = 0; i < vms.length; i++) {
  1799. if(vboxVMStates.isRunning(vms[i])) {
  1800. vmNames[vmNames.length] = vms[i].name;
  1801. }
  1802. }
  1803. if(vmNames.length) {
  1804. vmNames = '<b>'+vmNames.join('</b>, <b>')+'</b>';
  1805. vboxConfirm(trans("<p>Do you really want to reset the following virtual machines?</p><p><b>%1</b></p><p>"+
  1806. "This will cause any unsaved data in applications running inside it to be lost.</p>",'UIMessageCenter').replace('%1',vmNames),buttons);
  1807. }
  1808. }
  1809. },
  1810. /** Stop actions list */
  1811. stop_actions: ['savestate','powerbutton','powerdown'],
  1812. /** Stop a VM */
  1813. stop: {
  1814. name: 'stop',
  1815. label: 'Stop',
  1816. language_context: 'VBoxSelectorWnd',
  1817. icon: 'vm_shutdown',
  1818. menu: true,
  1819. click: function () { return true; /* handled by stop context menu */ },
  1820. enabled: function () {
  1821. return (vboxChooser.isSelectedInState('Running') || vboxChooser.isSelectedInState('Paused') || vboxChooser.isSelectedInState('Stuck'));
  1822. }
  1823. },
  1824. /** Power Action Helper function */
  1825. powerAction: function(pa,pt,vm){
  1826. icon =null;
  1827. errorMsg = null;
  1828. switch(pa) {
  1829. case 'powerdown':
  1830. fn = 'powerDown';
  1831. icon='progress_poweroff_90px.png';
  1832. break;
  1833. case 'powerbutton':
  1834. fn = 'powerButton';
  1835. errorMsg = trans('Failed to send the ACPI Power Button press event to the virtual machine <b>%1</b>.','UIMessageCenter');
  1836. break;
  1837. case 'savestate':
  1838. fn = 'saveState';
  1839. icon='progress_state_save_90px.png';
  1840. break;
  1841. case 'pause':
  1842. fn = 'pause';
  1843. break;
  1844. case 'reset':
  1845. fn = 'reset';
  1846. break;
  1847. default:
  1848. return;
  1849. }
  1850. $.when(vboxAjaxRequest('machineSetState',{'vm':vm.id,'state':fn})).done(function(d){
  1851. if(!(d && d.success) && errorMsg) {
  1852. vboxAlert(errorMsg.replace('%1', vm.name));
  1853. return;
  1854. }
  1855. // check for progress operation
  1856. if(d && d.responseData && d.responseData.progress) {
  1857. vboxProgress({'progress':d.responseData.progress,'persist':d.persist},function(){
  1858. return;
  1859. },icon,trans(pt,'UIActionPool'), vm.name);
  1860. return;
  1861. }
  1862. });
  1863. }
  1864. };
  1865. /**
  1866. * Common Media functions object
  1867. *
  1868. * @namespace vboxMedia
  1869. */
  1870. var vboxMedia = {
  1871. /**
  1872. * Get encryption settings for medium
  1873. */
  1874. getEncryptionSettings: function(m) {
  1875. if(m && m.encryptionSettings) {
  1876. return m.encryptionSettings
  1877. }
  1878. return null;
  1879. },
  1880. /**
  1881. * Return a list of encrypted media and associated
  1882. * encryption ids
  1883. */
  1884. getEncryptedMedia: function(media) {
  1885. var encMedia = [];
  1886. for(var i = 0; i < media.length; i++) {
  1887. var e = vboxMedia.getEncryptionSettings(media[i]);
  1888. if(!e) continue;
  1889. encMedia.push({
  1890. medium: media[i].id,
  1891. id: e.id
  1892. });
  1893. }
  1894. return encMedia;
  1895. },
  1896. /**
  1897. * Return list of IDs and cypers for media list
  1898. */
  1899. getEncryptedMediaIds: function(media) {
  1900. var encryptIds = [];
  1901. var idsSeen = [];
  1902. for(var i = 0; i < media.length; i++) {
  1903. var e = vboxMedia.getEncryptionSettings(media[i]);
  1904. if(!e) continue;
  1905. if(jQuery.inArray(e.id, idsSeen) > -1) continue;
  1906. idsSeen.push(e.id);
  1907. encryptIds.push({id: e.id, cipher: e.cipher})
  1908. }
  1909. return encryptIds;
  1910. },
  1911. /**
  1912. * Return true if medium is a host drive
  1913. */
  1914. isHostDrive: function(m) {
  1915. return (m && m.hostDrive)
  1916. },
  1917. /**
  1918. * Return a printable string for medium m
  1919. *
  1920. * @static
  1921. */
  1922. mediumPrint: function(m,nosize,usehtml) {
  1923. var name = vboxMedia.getName(m);
  1924. var enc = vboxMedia.getEncryptionSettings(m);
  1925. if(nosize || !m || m.hostDrive) return name;
  1926. return name + ' (' + (m.deviceType == 'HardDisk' ? trans(m.type,'VBoxGlobal', null, 'MediumType') + ', ' + (enc && enc.id ? trans('Encrypted', 'VBoxGlobal') + ', ' : '') : '') + vboxMbytesConvert(m.logicalSize) + ')';
  1927. },
  1928. /**
  1929. * Return printable medium name
  1930. *
  1931. * @static
  1932. */
  1933. getName: function(m) {
  1934. if(!m) return trans('Empty','VBoxGlobal');
  1935. if(m.hostDrive) {
  1936. if (m.description && m.name) {
  1937. return trans('Host Drive %1 (%2)','VBoxGlobal').replace('%1',m.description).replace('%2',m.name);
  1938. } else if (m.location) {
  1939. return trans('Host Drive \'%1\'','VBoxGlobal').replace('%1',m.location);
  1940. } else {
  1941. return trans('Host Drive','VBoxGlobal');
  1942. }
  1943. }
  1944. return m.name;
  1945. },
  1946. /**
  1947. * Return printable medium type
  1948. *
  1949. * @static
  1950. */
  1951. getType: function(m) {
  1952. if(!m || !m.type) return trans('Normal', 'VBoxGlobal', null, 'MediumType');
  1953. if(m.type == 'Normal' && m.base && m.base != m.id) return trans('Differencing', 'VBoxGlobal', null, 'MediumType');
  1954. return trans(m.type,'VBoxGlobal', null, 'MediumType');
  1955. },
  1956. /**
  1957. * Return printable medium format
  1958. *
  1959. * @static
  1960. */
  1961. getFormat: function (m) {
  1962. if(!m) return '';
  1963. switch(m.format.toLowerCase()) {
  1964. case 'vdi':
  1965. return trans('VDI (VirtualBox Disk Image)','UIWizardNewVD');
  1966. case 'vmdk':
  1967. return trans('VMDK (Virtual Machine Disk)','UIWizardNewVD');
  1968. case 'vhd':
  1969. return trans('VHD (Virtual Hard Disk)','UIWizardNewVD');
  1970. case 'parallels':
  1971. case 'hdd':
  1972. return trans('HDD (Parallels Hard Disk)','UIWizardNewVD');
  1973. case 'qed':
  1974. return trans('QED (QEMU enhanced disk)','UIWizardNewVD');
  1975. case 'qcow':
  1976. return trans('QCOW (QEMU Copy-On-Write)','UIWizardNewVD');
  1977. }
  1978. return m.format;
  1979. },
  1980. /**
  1981. * Return true if a medium format supports
  1982. */
  1983. formatSupportsSplit: function(format) {
  1984. var format = format.toLowerCase();
  1985. var mfs = $('#vboxPane').data('vboxSystemProperties').mediumFormats;
  1986. for(var i = 0; i < mfs.length; i++) {
  1987. if(mfs[i].id.toLowerCase() == format) {
  1988. return (jQuery.inArray('CreateSplit2G',mfs[i].capabilities) > -1);
  1989. }
  1990. }
  1991. return false;
  1992. },
  1993. /**
  1994. * Return printable virtual hard disk variant
  1995. *
  1996. * @static
  1997. */
  1998. getHardDiskVariant: function(m) {
  1999. var variants = $('#vboxPane').data('vboxMediumVariants');
  2000. /*
  2001. * [Standard] => 0 [VmdkSplit2G] => 1 [VmdkRawDisk] => 2 [VmdkStreamOptimized] =>
  2002. * 4 [VmdkESX] => 8 [Fixed] => 65536 [Diff] => 131072 [NoCreateDir] =>
  2003. * 1073741824
  2004. */
  2005. switch(m.variant) {
  2006. case variants.Standard:
  2007. return trans("Dynamically allocated storage", "VBoxGlobal", null, 'MediumVariant');
  2008. case (variants.Standard | variants.Diff):
  2009. return trans("Dynamically allocated differencing storage", "VBoxGlobal"), null, 'MediumVariant';
  2010. case (variants.Standard | variants.Fixed):
  2011. return trans("Fixed size storage", "VBoxGlobal", null, 'MediumVariant');
  2012. case (variants.Standard | variants.VmdkSplit2G):
  2013. return trans("Dynamically allocated storage split into files of less than 2GB", "VBoxGlobal", null, 'MediumVariant');
  2014. case (variants.Standard | variants.VmdkSplit2G | variants.Diff):
  2015. return trans("Dynamically allocated differencing storage split into files of less than 2GB", "VBoxGlobal", null, 'MediumVariant');
  2016. case (variants.Standard | variants.Fixed | variants.VmdkSplit2G):
  2017. return trans("Fixed size storage split into files of less than 2GB", "VBoxGlobal", null, 'MediumVariant');
  2018. case (variants.Standard | variants.VmdkStreamOptimized):
  2019. return trans("Dynamically allocated compressed storage", "VBoxGlobal", null, 'MediumVariant');
  2020. case (variants.Standard | variants.VmdkStreamOptimized | variants.Diff):
  2021. return trans("Dynamically allocated differencing compressed storage", "VBoxGlobal", null, 'MediumVariant');
  2022. case (variants.Standard | variants.Fixed | variants.VmdkESX):
  2023. return trans("Fixed size ESX storage", "VBoxGlobal", null, 'MediumVariant');
  2024. case (variants.Standard | variants.Fixed | variants.VmdkRawDisk):
  2025. return trans("Fixed size storage on raw disk", "VBoxGlobal", null, 'MediumVariant');
  2026. default:
  2027. return trans("Dynamically allocated storage", "VBoxGlobal", null, 'MediumVariant');
  2028. }
  2029. },
  2030. /**
  2031. * Return media and drives available for attachment type
  2032. *
  2033. * @static
  2034. */
  2035. mediaForAttachmentType: function(t,children) {
  2036. var media = new Array();
  2037. // DVD Drives
  2038. if(t == 'DVD') { media = media.concat($('#vboxPane').data('vboxHostDetails').DVDDrives);
  2039. // Floppy Drives
  2040. } else if(t == 'Floppy') {
  2041. media = media.concat($('#vboxPane').data('vboxHostDetails').floppyDrives);
  2042. }
  2043. // media
  2044. return media.concat(vboxTraverse($('#vboxPane').data('vboxMedia'),'deviceType',t,true,(children ? 'children': '')));
  2045. },
  2046. /**
  2047. * Return a medium by its location
  2048. *
  2049. * @static
  2050. */
  2051. getMediumByLocation: function(p) {
  2052. // Fix this in windows version
  2053. if($('#vboxPane').data('vboxConfig').DSEP == '\\')
  2054. p = p.replace('\\.','/.');
  2055. return vboxTraverse($('#vboxPane').data('vboxMedia'),'location',p,false,'children');
  2056. },
  2057. /**
  2058. * Return a medium by its name, ignoring case and
  2059. * extension
  2060. *
  2061. * @static
  2062. */
  2063. getMediumByName: function(n) {
  2064. var meds = $('#vboxPane').data('vboxMedia');
  2065. for(var i = 0; i < meds.length; i++) {
  2066. if(n.toLowerCase() == meds[i].name.replace(/\.[^\.]+$/, "").toLowerCase())
  2067. return meds[i];
  2068. }
  2069. return null;
  2070. },
  2071. /**
  2072. * Elect a new hard disk name
  2073. */
  2074. electHardDiskName: function(rootName, start) {
  2075. /* Go through list of media and pick new hd name */
  2076. var number = (start ? start: 1);
  2077. var HDname = (rootName ? rootName: 'NewVirtualDisk');
  2078. var RetName = '';
  2079. var found = false;
  2080. do {
  2081. RetName = HDname + (number++);
  2082. found = vboxMedia.getMediumByName(RetName);
  2083. } while(found);
  2084. return RetName;
  2085. },
  2086. /**
  2087. * Return a medium by its ID
  2088. *
  2089. * @static
  2090. */
  2091. getMediumById: function(id) {
  2092. return vboxTraverse($('#vboxPane').data('vboxMedia').concat($('#vboxPane').data('vboxHostDetails').DVDDrives.concat($('#vboxPane').data('vboxHostDetails').floppyDrives)),'id',id,false,'children');
  2093. },
  2094. /**
  2095. * Return a printable list of machines and snapshots this a medium is
  2096. * attached to
  2097. *
  2098. * @static
  2099. */
  2100. attachedTo: function(m,nullOnNone) {
  2101. var s = new Array();
  2102. if(!m.attachedTo || !m.attachedTo.length) return (nullOnNone ? null: '<i>'+trans('Not Attached')+'</i>');
  2103. for(var i = 0; i < m.attachedTo.length; i++) {
  2104. s[s.length] = m.attachedTo[i].machine + (m.attachedTo[i].snapshots.length ? ' (' + m.attachedTo[i].snapshots.join(', ') + ')': '');
  2105. }
  2106. return s.join(', ');
  2107. },
  2108. /**
  2109. * Update recent media menu and global recent media list
  2110. *
  2111. * @static
  2112. */
  2113. updateRecent: function(m, skipPathAdd) {
  2114. // Only valid media that is not a host drive or iSCSI
  2115. if(!m || !m.location || m.hostDrive || m.format == 'iSCSI') return false;
  2116. // Update recent path
  2117. if(!skipPathAdd) {
  2118. vboxAjaxRequest('vboxRecentMediaPathSave',{'type':m.deviceType,'folder':vboxDirname(m.location)});
  2119. $('#vboxPane').data('vboxRecentMediaPaths')[m.deviceType] = vboxDirname(m.location);
  2120. }
  2121. // Update recent media
  2122. // ///////////////////////
  2123. // find position (if any) in current list
  2124. var pos = jQuery.inArray(m.location,$('#vboxPane').data('vboxRecentMedia')[m.deviceType]);
  2125. // Medium is already at first position, return
  2126. if(pos == 0) return false;
  2127. // Exists and not in position 0, remove from list
  2128. if(pos > 0) {
  2129. $('#vboxPane').data('vboxRecentMedia')[m.deviceType].splice(pos,1);
  2130. }
  2131. // Add to list
  2132. $('#vboxPane').data('vboxRecentMedia')[m.deviceType].splice(0,0,m.location);
  2133. // Pop() until list only contains 5 items
  2134. while($('#vboxPane').data('vboxRecentMedia')[m.deviceType].length > 5) {
  2135. $('#vboxPane').data('vboxRecentMedia')[m.deviceType].pop();
  2136. }
  2137. // Update Recent Media in background
  2138. vboxAjaxRequest('vboxRecentMediaSave',{'type':m.deviceType,'list':$('#vboxPane').data('vboxRecentMedia')[m.deviceType]});
  2139. return true;
  2140. },
  2141. /**
  2142. * List of actions performed on Media in phpVirtualBox
  2143. *
  2144. * @static
  2145. * @namespace
  2146. */
  2147. actions: {
  2148. /**
  2149. * Choose existing medium file
  2150. *
  2151. * @static
  2152. */
  2153. choose: function(path,type,callback) {
  2154. if(!path) path = $('#vboxPane').data('vboxRecentMediaPaths')[type];
  2155. title = null;
  2156. icon = null;
  2157. switch(type) {
  2158. case 'HardDisk':
  2159. title = trans('Choose a virtual hard disk file...','UIMachineSettingsStorage');
  2160. icon = 'images/vbox/hd_16px.png';
  2161. break;
  2162. case 'Floppy':
  2163. title = trans('Choose a virtual floppy disk file...','UIMachineSettingsStorage');
  2164. icon = 'images/vbox/fd_16px.png';
  2165. break;
  2166. case 'DVD':
  2167. title = trans('Choose a virtual optical disk file...','UIMachineSettingsStorage');
  2168. icon = 'images/vbox/cd_16px.png';
  2169. break;
  2170. }
  2171. vboxFileBrowser(path,function(f){
  2172. if(!f) return;
  2173. var med = vboxMedia.getMediumByLocation(f);
  2174. if(med && med.deviceType == type) {
  2175. vboxMedia.updateRecent(med);
  2176. callback(med);
  2177. return;
  2178. } else if(med) {
  2179. return;
  2180. }
  2181. var ml = new vboxLoader();
  2182. ml.add('mediumAdd',function(ret){
  2183. var l = new vboxLoader();
  2184. if(ret && ret.responseData.id) {
  2185. var med = vboxMedia.getMediumById(ret.responseData.id);
  2186. // Not registered yet. Refresh media.
  2187. if(!med)
  2188. l.add('vboxGetMedia',function(dret){$('#vboxPane').data('vboxMedia',dret.responseData);});
  2189. }
  2190. l.onLoad = function() {
  2191. if(ret && ret.responseData.id) {
  2192. var med = vboxMedia.getMediumById(ret.responseData.id);
  2193. if(med && med.deviceType == type) {
  2194. vboxMedia.updateRecent(med);
  2195. callback(med);
  2196. return;
  2197. }
  2198. }
  2199. };
  2200. l.run();
  2201. },{'path':f,'type':type});
  2202. ml.run();
  2203. },false,title,icon);
  2204. } // </ choose >
  2205. } // </ actions >
  2206. };
  2207. /**
  2208. * Base Wizard class (new HardDisk, VM, etc..)
  2209. *
  2210. * @class vboxWizard
  2211. * @constructor
  2212. */
  2213. function vboxWizard() {
  2214. var self = this;
  2215. /* Number of wizard steps */
  2216. this.steps = 0;
  2217. /* Wizard name - used to determine form name and HTML pane to load */
  2218. this.name = '';
  2219. /* Title of wizard */
  2220. this.title = '';
  2221. /* Wizard dialog icon image */
  2222. this.icon = null;
  2223. /* Width and height for Simple mode */
  2224. this.width = 700;
  2225. this.height = 400;
  2226. /* Width and height for expert mode */
  2227. this.widthAdvanced = 600;
  2228. this.heightAdvanced = 450;
  2229. /* Background image */
  2230. this.bg = null;
  2231. /* Text on Back button */
  2232. this.backText = trans('Back','QIArrowSplitter');
  2233. /* Text on Next button */
  2234. this.nextText = trans('Next','QIArrowSplitter');
  2235. /* Text on cancel button */
  2236. this.cancelText = trans('Cancel','QIMessageBox');
  2237. /* Text on finish button */
  2238. this.finishText = 'Finish';
  2239. /* Translation context */
  2240. this.context = '';
  2241. /* Arrow on back button */
  2242. this.backArrow = $('<div />').html('&laquo;').text();
  2243. /* Arrow on Next button */
  2244. this.nextArrow = $('<div />').html('&raquo;').text();
  2245. /* Mode of wizard */
  2246. this.mode = 'simple';
  2247. /* Data to load */
  2248. this.data = [];
  2249. /* Form object held to get values */
  2250. this.form = null;
  2251. /* Reference to dialog object created */
  2252. this.dialog = null;
  2253. /* Deferred object resolved when complete */
  2254. this.completed = $.Deferred();
  2255. /* Function to be run on cancel */
  2256. this.onCancel = null;
  2257. /* Function to run on finish */
  2258. this.onFinish = function() {
  2259. if(self.completed.state() == 'pending')
  2260. self.completed.resolve();
  2261. $(self.dialog).empty().remove();
  2262. };
  2263. /**
  2264. * Initialize / display wizard
  2265. *
  2266. * @memberOf vboxWizard
  2267. * @name vboxWizard.run
  2268. * @returns {Object} deferred promise
  2269. */
  2270. this.run = function() {
  2271. // Set mode
  2272. this.mode = (vboxGetLocalDataItem('vboxWizardMode'+this.name) == 'a' ? 'advanced': '');
  2273. this.dialog = $('<div />').attr({'id':this.name+'Dialog','style':'display: none','class':'vboxWizard'});
  2274. this.form = $('<form />').attr({'name':('frm'+this.name),'style':'height:100%;margin:0px;padding:0px;border:0px;'})
  2275. .on('submit',function(e){
  2276. self.displayNext();
  2277. e.stopPropagation();
  2278. e.preventDefault();
  2279. return false;
  2280. });
  2281. // main table
  2282. var tbl = $('<table />').attr({'class':'vboxWizard','style':'height: 100%; margin:0px; padding:0px;border:0px;'});
  2283. var tr = $('<tr />');
  2284. var td = $('<td />').attr({'id':this.name+'Content','class':'vboxWizardContent'});
  2285. if(this.bg) {
  2286. $(this.dialog).css({'background':'url('+this.bg+') ' + ((this.mode == 'advanced' ? this.widthAdvanced: this.width) - 360) +'px -60px no-repeat','background-color':'#fff'});
  2287. }
  2288. // Title and content table
  2289. $('<h3 />').attr('id',this.name+'Title').html(this.title).appendTo(td);
  2290. $(tr).append(td).appendTo(tbl);
  2291. this.form.append(tbl);
  2292. this.dialog.append(this.form).appendTo($('#vboxPane'));
  2293. // load data and panes
  2294. var l = new vboxLoader(this.name+'Loader');
  2295. for(var i = 0; i < this.data.length; i++) {
  2296. l.add(this.data[i].fn,this.data[i].callback,(this.data[i].args ? this.data[i].args: undefined));
  2297. }
  2298. l.addFileToDOM('panes/'+this.name+(this.mode == 'advanced' ? 'Advanced': '')+'.html',$('#'+this.name+'Content'));
  2299. l.onLoad = function(){
  2300. // Show / Hide description button
  2301. if(!self.stepButtons) self.stepButtons = [];
  2302. if(!self.noAdvanced) {
  2303. self.stepButtons = jQuery.merge([{
  2304. name: trans((self.mode == 'advanced' ? 'Guided Mode': 'Expert Mode'), 'UIWizard'),
  2305. click: function() {
  2306. // Unbind any old resize handlers
  2307. $('#'+self.name+'Dialog').off('dialogresizestop');
  2308. // Check mode
  2309. if(self.mode != 'advanced') {
  2310. // Now in advanced mode
  2311. self.mode = 'advanced';
  2312. // Hide title, remove current content and add
  2313. // advanced content
  2314. $('#'+self.name+'Title').hide().siblings().empty().remove();
  2315. // Hold old number of steps
  2316. self.simpleSteps = self.steps;
  2317. // resize dialog
  2318. $('#'+self.name+'Dialog').dialog('option', 'width', self.widthAdvanced)
  2319. .dialog('option', 'height', self.heightAdvanced)
  2320. .css({'background':'url('+self.bg+') ' + ((self.mode == 'advanced' ? self.widthAdvanced: self.width) - 360) +'px -60px no-repeat','background-color':'#fff'});
  2321. var vl = new vboxLoader();
  2322. vl.addFileToDOM('panes/'+self.name+'Advanced.html',$('#'+self.name+'Content'));
  2323. vl.onLoad = function() {
  2324. // Change this button text
  2325. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+trans('Expert Mode', 'UIWizard')+'")')
  2326. .html(trans('Guided Mode', 'UIWizard'));
  2327. for(var i = 0; i < self.stepButtons.length; i++) {
  2328. if(self.stepButtons[i].name == trans('Expert Mode', 'UIWizard')) {
  2329. self.stepButtons[i].name = trans('Guided Mode', 'UIWizard');
  2330. }
  2331. }
  2332. // Hide back button
  2333. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.backArrow + ' '+self.backText+'")').parent().hide();
  2334. // Translations and setup
  2335. vboxInitDisplay(self.name+'Content',self.context);
  2336. self.steps = 1;
  2337. // Go to last step
  2338. self.displayStep(1);
  2339. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.finishText+'")').parent().focus();
  2340. };
  2341. vl.run();
  2342. } else {
  2343. // Now in simple mode
  2344. self.mode = 'simple';
  2345. // Remove current content and show simple content
  2346. $('#'+self.name+'Title').show().siblings().empty().remove();
  2347. // resize dialog
  2348. $('#'+self.name+'Dialog').dialog('option', 'width', self.width)
  2349. .dialog('option', 'height', self.height)
  2350. .css({'background':'url('+self.bg+') ' + ((self.mode == 'advanced' ? self.widthAdvanced: self.width) - 360) +'px -60px no-repeat','background-color':'#fff'});
  2351. // Reset old number of steps
  2352. self.steps = self.simpleSteps;
  2353. var vl = new vboxLoader();
  2354. vl.addFileToDOM('panes/'+self.name+'.html',$('#'+self.name+'Content'));
  2355. vl.onLoad = function() {
  2356. // Change this button text
  2357. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane')
  2358. .find('span:contains("'+trans('Guided Mode', 'UIWizard')+'")')
  2359. .html(trans('Expert Mode', 'UIWizard'));
  2360. for(var i = 0; i < self.stepButtons.length; i++) {
  2361. if(self.stepButtons[i].name == trans('Guided Mode', 'UIWizard')) {
  2362. self.stepButtons[i].name = trans('Expert Mode', 'UIWizard');
  2363. }
  2364. }
  2365. // Translations
  2366. vboxInitDisplay(self.name+'Content',self.context);
  2367. // Show back button
  2368. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.backArrow + ' '+self.backText+'")').parent().show();
  2369. self.steps = self.simpleSteps;
  2370. self.displayStep(1);
  2371. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.nextArrow+'")').parent().focus();
  2372. };
  2373. vl.run();
  2374. }
  2375. vboxSetLocalDataItem('vboxWizardMode'+self.name, (self.mode == 'advanced' ? 'a': ''));
  2376. },
  2377. steps: [1]
  2378. }], self.stepButtons);
  2379. }
  2380. // buttons
  2381. var buttons = { };
  2382. if(self.stepButtons) {
  2383. for(var i = 0; i < self.stepButtons.length; i++) {
  2384. buttons[self.stepButtons[i].name] = self.stepButtons[i].click;
  2385. }
  2386. }
  2387. if(!self.noAdvanced || self.steps > 1)
  2388. buttons[self.backArrow + ' '+self.backText] = self.displayPrev;
  2389. buttons[(self.steps > 1 ? self.nextText +' '+self.nextArrow: self.finishText)] = self.displayNext;
  2390. buttons[self.cancelText] = self.cancel;
  2391. // Translations
  2392. vboxInitDisplay(self.name+'Content',self.context);
  2393. $(self.dialog).dialog({
  2394. 'closeOnEscape':true,
  2395. 'width':(self.mode == 'advanced' ? self.widthAdvanced: self.width),
  2396. 'height':(self.mode == 'advanced' ? self.heightAdvanced: self.height),
  2397. 'buttons':buttons,
  2398. 'modal':true,
  2399. 'autoOpen':true,
  2400. 'stack':true,
  2401. 'dialogClass':'vboxDialogContent vboxWizard',
  2402. 'open': function() {
  2403. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.nextArrow+'")').parent().focus();
  2404. },
  2405. 'title':(self.icon ? '<img src="images/vbox/'+self.icon+ ( (self.icon.indexOf('.png') == -1) ? '_16px.png': '') +'" class="vboxDialogTitleIcon" /> ': '') + self.title
  2406. }).on('dialogclose', function(){
  2407. // Reject if still pending
  2408. if(self.completed.state() == 'pending')
  2409. self.completed.reject();
  2410. $(this).empty().remove();
  2411. }).on('keyup',function(e) {
  2412. if (e.keyCode == 13) {
  2413. self.displayNext();
  2414. e.stopPropagation();
  2415. e.preventDefault();
  2416. return false;
  2417. }
  2418. });
  2419. // Setup if in advanced mode
  2420. if(self.mode == 'advanced') {
  2421. // Hold old number of steps
  2422. self.simpleSteps = self.steps;
  2423. self.steps = 1;
  2424. // Hide title
  2425. $('#'+self.name+'Title').hide();
  2426. // Hide back button
  2427. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.backArrow + ' '+self.backText+'")').parent().hide();
  2428. }
  2429. self.displayStep(1);
  2430. };
  2431. l.run();
  2432. return self.completed.promise();
  2433. };
  2434. /**
  2435. * Cancel wizard
  2436. *
  2437. * @memberOf vboxWizard
  2438. */
  2439. this.cancel = function() {
  2440. // Check for onCancel function
  2441. if(self.onCancel) {
  2442. self.onCancel();
  2443. }
  2444. // Reject if still pending
  2445. if(self.completed.state() == 'pending')
  2446. self.completed.reject();
  2447. $(self.dialog).empty().remove();
  2448. };
  2449. /**
  2450. * Display a step
  2451. *
  2452. * @memberOf vboxWizard
  2453. * @param {Integer}
  2454. * step - step to display
  2455. */
  2456. this.displayStep = function(step) {
  2457. self._curStep = step;
  2458. for(var i = 0; i < self.steps; i++) {
  2459. $('#'+self.name+'Step'+(i+1)).css({'display':'none'});
  2460. }
  2461. /* update buttons */
  2462. if(self.stepButtons) {
  2463. for(var i = 0; i < self.stepButtons.length; i++) {
  2464. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.stepButtons[i].name+'")').parent().css({'display':((step == self.steps && self.stepButtons[i].steps[0]==-1) || jQuery.inArray(step,self.stepButtons[i].steps) > -1 ? '': 'none')});
  2465. }
  2466. }
  2467. if(step == 1 && step != self.steps) {
  2468. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.backText+'")').parent().addClass('disabled').blur();
  2469. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.finishText+'")').html($('<div />').text((self.steps > 1 ? self.nextText+' '+self.nextArrow: self.finishText)).html());
  2470. } else {
  2471. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.backText+'")').parent().removeClass('disabled');
  2472. if(step == self.steps) {
  2473. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.nextArrow+'")').html($('<div />').text(self.finishText).html());
  2474. } else {
  2475. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.finishText+'")').html($('<div />').text(self.nextText+' '+self.nextArrow).html());
  2476. }
  2477. }
  2478. $('#'+self.name+'Title').html(trans($('#'+self.name+'Step'+step).attr('title'),self.context));
  2479. $('#'+self.name+'Step'+step).css({'display':''});
  2480. $('#'+self.name+'Step'+step).trigger('show',self);
  2481. };
  2482. /**
  2483. * Set current wizard step to be the last step in list
  2484. *
  2485. * @memberOf vboxWizard
  2486. */
  2487. this.setLast = function() {
  2488. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.nextText+'")').html($('<div />').text(self.finishText).html());
  2489. self._origSteps = self.steps;
  2490. self.steps = self._curStep;
  2491. };
  2492. /**
  2493. * Unset the current wizard step so that it is not forced to be the last one
  2494. * in the list
  2495. *
  2496. * @memberOf vboxWizard
  2497. */
  2498. this.unsetLast = function() {
  2499. $('#'+self.name+'Dialog').parent().find('.ui-dialog-buttonpane').find('span:contains("'+self.finishText+'")').html($('<div />').text(self.nextText+' '+self.nextArrow).html());
  2500. if(self._origSteps) self.steps = self._origSteps;
  2501. };
  2502. /**
  2503. * Display previous step
  2504. *
  2505. * @memberOf vboxWizard
  2506. */
  2507. this.displayPrev = function() {
  2508. if(self._curStep <= 1) return;
  2509. self.displayStep(self._curStep - 1);
  2510. };
  2511. /**
  2512. * Display next step
  2513. *
  2514. * @memberOf vboxWizard
  2515. */
  2516. this.displayNext = function() {
  2517. if(self._curStep >= self.steps) {
  2518. self.onFinish();
  2519. return;
  2520. }
  2521. self.displayStep(self._curStep + 1);
  2522. };
  2523. }
  2524. /**
  2525. * Common toolbar class
  2526. *
  2527. * @constructor
  2528. * @class vboxToolbar
  2529. * @options {Object}
  2530. * buttons - buttons to add to toolbar
  2531. * language_context - context to use for translations
  2532. * renderTo - element to render to
  2533. * buttonStyle - CSS to add to button elements
  2534. * size - size of button elements
  2535. */
  2536. function vboxToolbar(options) {
  2537. var self = this;
  2538. this.buttons = options.buttons || [];
  2539. this.size = options.size || 22;
  2540. this.addHeight = 24;
  2541. this.lastItem = null;
  2542. this.buttonStyle = options.buttonStyle;
  2543. this.enabled = true;
  2544. this.mutliSelect = false; // true if multiple items are selected
  2545. this._buttonElements = {}; // button elements by name
  2546. this.language_context = options.language_context;
  2547. /**
  2548. * Add buttons to this object
  2549. * @param {Array} buttons - buttons to add to toolbar
  2550. */
  2551. this.addButtons = function(buttons) {
  2552. this.buttons = buttons;
  2553. }
  2554. /**
  2555. * Update buttons to be enabled / disabled
  2556. *
  2557. * @memberOf vboxToolbar
  2558. * @param {Object|Null}
  2559. * item - item to check
  2560. */
  2561. this.update = function(item) {
  2562. // Event target or manually passed item
  2563. self.lastItem = item;
  2564. if(!self.enabled) return;
  2565. for(var i = 0; i < self.buttons.length; i++) {
  2566. if(self.buttons[i].enabled && !self.buttons[i].enabled(self.lastItem)) {
  2567. self.disableButton(self.buttons[i]);
  2568. } else {
  2569. self.enableButton(self.buttons[i]);
  2570. }
  2571. }
  2572. };
  2573. /**
  2574. * Enable entire toolbar. Calls self.update()
  2575. *
  2576. * @memberOf vboxToolbar
  2577. * @param {Object}
  2578. * e - event
  2579. * @param {Object}
  2580. * item - item to pass to update
  2581. */
  2582. this.enable = function(e, item) {
  2583. self.enabled = true;
  2584. self.update((item||self.lastItem));
  2585. };
  2586. /**
  2587. * Disable entire toolbar
  2588. *
  2589. * @memberOf vboxToolbar
  2590. */
  2591. this.disable = function() {
  2592. self.enabled = false;
  2593. for(var i = 0; i < self.buttons.length; i++) {
  2594. self.disableButton(self.buttons[i]);
  2595. }
  2596. };
  2597. /**
  2598. * Enable a single button
  2599. *
  2600. * @memberOf vboxToolbar
  2601. * @param {Object}
  2602. * b - button to enable
  2603. */
  2604. this.enableButton = function(b) {
  2605. this._buttonElements[b.name].addClass('vboxEnabled').removeClass('vboxDisabled disabled').children('img.vboxToolbarImg').attr('src','images/vbox/'+b.icon+'_'+self.size+'px.png');
  2606. };
  2607. /**
  2608. * Disable a single button
  2609. *
  2610. * @memberOf vboxToolbar
  2611. * @param {Object}
  2612. * b - button to disable
  2613. */
  2614. this.disableButton = function(b) {
  2615. this._buttonElements[b.name].addClass('vboxDisabled disabled').removeClass('vboxEnabled').children('img.vboxToolbarImg').attr('src','images/vbox/'+b.icon+'_disabled_'+self.size+'px.png').trigger('mouseleave');
  2616. };
  2617. /**
  2618. * Set button label
  2619. *
  2620. * @memberOf vboxToolbar
  2621. * @param {String}
  2622. * bname - name of button to set label for
  2623. * @param {String}
  2624. * l - new label for button
  2625. */
  2626. this.setButtonLabel = function(bname,l) {
  2627. this._buttonElements[b.name].find('span.vboxToolbarButtonLabel').html(l);
  2628. };
  2629. /**
  2630. * Return the button element by name
  2631. *
  2632. * @param {String}
  2633. * bname - button name
  2634. * @returns {HTMLNode}
  2635. */
  2636. this.getButtonElement = function(bname) {
  2637. return this._buttonElements[bname]
  2638. };
  2639. /**
  2640. * Generate HTML element for button
  2641. *
  2642. * @memberOf vboxToolbar
  2643. * @param {Object}
  2644. * b - button object containing various button parameters
  2645. * @return {HTMLNode} button element
  2646. */
  2647. this.buttonElement = function(b) {
  2648. // Pre-load disabled version of icon if enabled function exists
  2649. if(b.enabled) {
  2650. var a = new Image();
  2651. a.src = "images/vbox/"+b.icon+"_disabled_"+self.size+"px.png";
  2652. }
  2653. // TD
  2654. var label = String(trans(b.toolbar_label ? b.toolbar_label: b.label, b.language_context ? b.language_context : self.language_context)).replace(/\.+$/g,'')
  2655. var td = $('<td />').attr({'class':'vboxToolbarButton ui-corner-all vboxEnabled vboxToolbarButton'+self.size,
  2656. 'style':self.buttonStyle+'; min-width: '+(self.size+12)+'px;'
  2657. }).html('<img src="images/vbox/'+b.icon+'_'+self.size+'px.png" class="vboxToolbarImg" style="height:'+self.size+'px;width:'+self.size+'px;"/><br /><span class="vboxToolbarButtonLabel">' + label +'</span>').on('click',function(){
  2658. if($(this).hasClass('vboxDisabled')) return;
  2659. $(this).data('toolbar').click($(this).data('name'));
  2660. // store data
  2661. }).data(b);
  2662. if(!self.noHover) {
  2663. $(td).hover(
  2664. function(){if($(this).hasClass('vboxEnabled')){$(this).addClass('vboxToolbarButtonHover');}},
  2665. function(){$(this).removeClass('vboxToolbarButtonHover');}
  2666. ).mousedown(function(e){
  2667. if($.browser.msie && e.button == 1) e.button = 0;
  2668. if(e.button != 0 || $(this).hasClass('vboxDisabled')) return true;
  2669. $(this).addClass('vboxToolbarButtonDown');
  2670. var e = jQuery.Event("mouseup", {button:0});
  2671. $(this).siblings().trigger(e);
  2672. var btn = $(this);
  2673. $(document).one('mouseup',function(){
  2674. $(btn).removeClass('vboxToolbarButtonDown');
  2675. });
  2676. });
  2677. }
  2678. return td;
  2679. };
  2680. /**
  2681. * Render buttons to HTML node where id = id param
  2682. *
  2683. * @memberOf vboxToolbar
  2684. * @param {String|Object}
  2685. * node - HTMLNode or id to add buttons to
  2686. */
  2687. this.renderTo = function(node) {
  2688. if(typeof(node) == 'string') {
  2689. node = $('#'+node);
  2690. }
  2691. self.height = self.size + self.addHeight;
  2692. // Create table
  2693. var tbl = $('<table />').attr({'class':'vboxToolbar vboxToolbar'+this.size});
  2694. var tr = $('<tr />');
  2695. for(var i = 0; i < self.buttons.length; i++) {
  2696. if(self.buttons[i].separator) {
  2697. $('<td />').attr({'class':'vboxToolbarSeparator'}).html('<br />').appendTo(tr);
  2698. }
  2699. self.buttons[i].toolbar = self;
  2700. self._buttonElements[self.buttons[i].name] = self.buttonElement(self.buttons[i]);
  2701. $(tr).append(self._buttonElements[self.buttons[i].name]);
  2702. }
  2703. $(tbl).append(tr);
  2704. $(node).append(tbl).addClass('vboxToolbar vboxToolbar'+this.size).on('disable',self.disable).on('enable',self.enable);
  2705. // If button can be enabled / disabled, disable by default
  2706. for(var i = 0; i < self.buttons.length; i++) {
  2707. if(self.buttons[i].enabled) {
  2708. self.disableButton(self.buttons[i]);
  2709. }
  2710. }
  2711. return this;
  2712. };
  2713. /**
  2714. * Return button by name
  2715. *
  2716. * @memberOf vboxToolbar
  2717. * @param {String}
  2718. * n - button name
  2719. * @return {Object} button
  2720. */
  2721. this.getButtonByName = function(n) {
  2722. for(var i = 0; i < self.buttons.length; i++) {
  2723. if(self.buttons[i].name == n)
  2724. return self.buttons[i];
  2725. }
  2726. return null;
  2727. };
  2728. /**
  2729. * Trigger click event on button who's name = btn param
  2730. *
  2731. * @memberOf vboxToolbar
  2732. * @param {String}
  2733. * btn - name of button
  2734. * @return return value of .click() function performed on button
  2735. */
  2736. this.click = function(btn) {
  2737. var b = self.getButtonByName(btn);
  2738. return b.click(btn);
  2739. };
  2740. if(options.renderTo)
  2741. this.renderTo(options.renderTo);
  2742. }
  2743. /**
  2744. * Toolbar class for single button
  2745. *
  2746. * @constructor
  2747. * @class vboxToolbarSmall
  2748. * @super vboxToolbar
  2749. * @param {Object} options
  2750. * button - button for toolbar
  2751. * language_context - language context to use for translations
  2752. * renderTo - element to render toolbar to
  2753. *
  2754. */
  2755. function vboxToolbarSingle(options) {
  2756. var self = this;
  2757. this.parentClass = vboxToolbarSmall;
  2758. options.buttons = [options.button];
  2759. renderTo = options.renderTo;
  2760. options.renderTo = undefined;
  2761. this.parentClass(options);
  2762. this._buttonElement = this.buttonElement; /* copy orig */
  2763. /**
  2764. * Generate HTML element for button
  2765. *
  2766. * @memberOf vboxToolbarSingle
  2767. * @param {Object}
  2768. * b - button object containing various button parameters
  2769. * @return {HTMLNode} button element
  2770. */
  2771. this.buttonElement = function(b) {
  2772. var label = trans(b.toolbar_label ? b.toolbar_label: b.label, b.language_context ? b.language_context : self.language_context)
  2773. return this._buttonElement(b).attr({'title': label});
  2774. }
  2775. if(renderTo)
  2776. this.renderTo(renderTo);
  2777. }
  2778. /**
  2779. * Toolbar class for a small toolbar
  2780. *
  2781. * @constructor
  2782. * @class vboxToolbarSmall
  2783. * @super vboxToolbar
  2784. * @param {Options}
  2785. * buttons - list of buttons for toolbar
  2786. * language_context - context to use for translations
  2787. * renderTo - element to render to
  2788. * buttonStyle - style to use for button elements
  2789. * noHover - do not add hover styling
  2790. * size - button size
  2791. */
  2792. function vboxToolbarSmall(options) {
  2793. var self = this;
  2794. this.buttonStyle = options.buttonStyle;
  2795. this.buttonCSS = {};
  2796. renderTo = options.renderTo
  2797. options.renderTo = undefined
  2798. this.parentClass = vboxToolbar;
  2799. this.parentClass(options);
  2800. this.selected = null;
  2801. this.lastItem = null;
  2802. this.enabled = true;
  2803. this.size = options.size ? options.size : 16;
  2804. this.disabledString = 'disabled';
  2805. this.noHover = options.noHover;
  2806. this.language_context = options.language_context;
  2807. /**
  2808. * Enable a single button
  2809. *
  2810. * @memberOf vboxToolbarSmall
  2811. * @param {Object}
  2812. * b - button to enable
  2813. * @return null
  2814. */
  2815. this.enableButton = function(b) {
  2816. if(b.noDisabledIcon)
  2817. this._buttonElements[b.name].css('display','').prop('disabled',false);
  2818. else
  2819. this._buttonElements[b.name].css('background-image','url(images/vbox/' + b.icon + '_'+self.size+'px.png)').prop('disabled',false);
  2820. };
  2821. /**
  2822. * Disable a single button
  2823. *
  2824. * @memberOf vboxToolbarSmall
  2825. * @param {Object}
  2826. * b - button to disable
  2827. * @return null
  2828. */
  2829. this.disableButton = function(b) {
  2830. if(b.noDisabledIcon)
  2831. this._buttonElements[b.name].css('display','none').prop('disabled',false).removeClass('vboxToolbarSmallButtonHover').addClass('vboxToolbarSmallButton').trigger('mouseleave');
  2832. else
  2833. this._buttonElements[b.name].css('background-image','url(images/vbox/' + b.icon + '_'+self.disabledString+'_'+self.size+'px.png)').prop('disabled',true).removeClass('vboxToolbarSmallButtonHover').addClass('vboxToolbarSmallButton').trigger('mouseleave');
  2834. };
  2835. /**
  2836. * Add CSS to be applied to button
  2837. *
  2838. * @param {String}
  2839. * b button name
  2840. * @param {Object}
  2841. * css css to be applied to button
  2842. */
  2843. this.addButtonCSS = function(b, css) {
  2844. self.buttonCSS[b] = css;
  2845. };
  2846. /**
  2847. * Generate HTML element for button
  2848. *
  2849. * @memberOf vboxToolbarSmall
  2850. * @param {Object}
  2851. * b - button object containing various button parameters
  2852. * @return {HTMLNode} button element
  2853. */
  2854. this.buttonElement = function(b) {
  2855. // Pre-load disabled version of icon if enabled function exists
  2856. if(b.enabled && !b.noDisabledIcon) {
  2857. var a = new Image();
  2858. a.src = "images/vbox/" + b.icon + '_'+self.disabledString+'_'+self.size+'px.png';
  2859. }
  2860. var label = String(trans(b.toolbar_label ? b.toolbar_label: b.label, b.language_context ? b.language_context : self.language_context)).replace(/\.+$/g,'')
  2861. var btn = $('<input />').attr({'type':'button','value':'',
  2862. 'class': 'vboxImgButton vboxToolbarSmallButton ui-corner-all',
  2863. 'title': label,
  2864. 'style': self.buttonStyle+' background-image: url(images/vbox/' + b.icon + '_'+self.size+'px.png);'
  2865. }).click(b.click);
  2866. if(!self.noHover) {
  2867. $(btn).hover(
  2868. function(){if(!$(this).prop('disabled')){$(this).addClass('vboxToolbarSmallButtonHover').removeClass('vboxToolbarSmallButton');}},
  2869. function(){$(this).addClass('vboxToolbarSmallButton').removeClass('vboxToolbarSmallButtonHover');}
  2870. );
  2871. }
  2872. // Check for button specific CSS
  2873. if(self.buttonCSS[b.name]) btn.css(self.buttonCSS[b.name]);
  2874. return btn;
  2875. };
  2876. /**
  2877. * Render buttons to HTML node where id = id param
  2878. *
  2879. * @memberOf vboxToolbarSmall
  2880. * @param {String|Object}
  2881. * targetElm - HTMLNode or id to add buttons to
  2882. * @return null
  2883. */
  2884. this.renderTo = function(targetElm) {
  2885. if(typeof(targetElm) == 'string') {
  2886. targetElm = $('#'+targetElm);
  2887. }
  2888. if(!self.buttonStyle)
  2889. self.buttonStyle = 'height: ' + (self.size+8) + 'px; width: ' + (self.size+8) + 'px; ';
  2890. for(var i = 0; i < self.buttons.length; i++) {
  2891. if(self.buttons[i].separator) {
  2892. $(targetElm).append($('<hr />').attr({'style':'display: inline','class':'vboxToolbarSmall vboxSeparatorLine'}));
  2893. }
  2894. this._buttonElements[self.buttons[i].name] = self.buttonElement(self.buttons[i]);
  2895. $(targetElm).append(this._buttonElements[self.buttons[i].name]);
  2896. }
  2897. $(targetElm).attr({'name':self.name}).addClass('vboxToolbarSmall vboxEnablerTrigger vboxToolbarSmall'+self.size).on('disable',self.disable).on('enable',self.enable);
  2898. return this;
  2899. };
  2900. if(renderTo)
  2901. this.renderTo(renderTo);
  2902. }
  2903. /**
  2904. * Media menu button class
  2905. *
  2906. * @constructor
  2907. * @class vboxButtonMediaMenu
  2908. * @param {String} type - type of media to display
  2909. * @param {Function} callback - callback to run when media is selected
  2910. * @param {String} mediumPath - path to use when selecting media
  2911. */
  2912. function vboxButtonMediaMenu(type,callback,mediumPath) {
  2913. var self = this;
  2914. this.buttonStyle = '';
  2915. this.enabled = true;
  2916. this.size = 16;
  2917. this.disabledString = 'disabled';
  2918. this.type = type;
  2919. this.lastItem = null;
  2920. this._buttonElement = null; // holds button node
  2921. /** vboxMediaMenu to display when button is clicked */
  2922. this.mediaMenu = new vboxMediaMenu(type, callback, mediumPath);
  2923. /* Static button type list */
  2924. this.buttons = {
  2925. HardDisk: {
  2926. name: 'mselecthdbtn',
  2927. label: 'Set up the virtual hard disk',
  2928. language_context: 'UIMachineSettingsStorage',
  2929. icon: 'hd',
  2930. click: function () {
  2931. return;
  2932. }
  2933. },
  2934. DVD: {
  2935. name: 'mselectcdbtn',
  2936. label: 'Set up the virtual optical drive',
  2937. language_context: 'UIMachineSettingsStorage',
  2938. icon: 'cd',
  2939. click: function () {
  2940. return;
  2941. }
  2942. },
  2943. Floppy: {
  2944. name: 'mselectfdbtn',
  2945. label: 'Set up the virtual floppy drive',
  2946. language_context: 'UIMachineSettingsStorage',
  2947. icon: 'fd',
  2948. click: function () {
  2949. return;
  2950. }
  2951. }
  2952. };
  2953. // Set button based on passed type
  2954. this.button = self.buttons[self.type];
  2955. /**
  2956. * Update button to be enabled / disabled
  2957. *
  2958. * @memberOf vboxButtonMediaMenu
  2959. * @param {Object|Null}
  2960. * target - item to test in button's enabled() fuction
  2961. * @param {Object|Null}
  2962. * item - item to test in button's enabled() fuction
  2963. * @return null
  2964. */
  2965. this.update = function(target,item) {
  2966. if(!self.enabled) return;
  2967. self.lastItem = (item||target);
  2968. if(self.button.enabled && !self.button.enabled(self.lastItem)) {
  2969. self.disableButton();
  2970. } else {
  2971. self.enableButton();
  2972. }
  2973. };
  2974. /**
  2975. * Enable this button
  2976. *
  2977. * @memberOf vboxButtonMediaMenu
  2978. * @return null
  2979. */
  2980. this.enableButton = function() {
  2981. var b = self.button;
  2982. this._buttonElement.css('background-image','url(images/vbox/' + b.icon + '_'+self.size+'px.png)').removeClass('vboxDisabled').html('<img src="images/downArrow.png" style="margin:0px;padding:0px;float:right;width:6px;height:6px;" />');
  2983. };
  2984. /**
  2985. * Disable this button
  2986. *
  2987. * @memberOf vboxButtonMediaMenu
  2988. * @return null
  2989. */
  2990. this.disableButton = function() {
  2991. var b = self.button;
  2992. this._buttonElement.css('background-image','url(images/vbox/' + b.icon + '_'+self.disabledString+'_'+self.size+'px.png)').removeClass('vboxToolbarSmallButtonHover').addClass('vboxDisabled').html('').trigger('mouseleave');
  2993. };
  2994. /**
  2995. * Enable button and menu
  2996. *
  2997. * @memberOf vboxButtonMediaMenu
  2998. * @param {Object} e event object
  2999. * @param {Mixed} item test item passed to buttons .enabled() functions
  3000. * @return null
  3001. */
  3002. this.enable = function(e, item) {
  3003. self.enabled = true;
  3004. self.update((item||self.lastItem));
  3005. self.getButtonElm().enableContextMenu();
  3006. };
  3007. /**
  3008. * Disable button and menu
  3009. *
  3010. * @memberOf vboxButtonMediaMenu
  3011. * @return null
  3012. */
  3013. this.disable = function() {
  3014. self.enabled = false;
  3015. self.disableButton();
  3016. self.getButtonElm().disableContextMenu();
  3017. };
  3018. /**
  3019. * Generate HTML element for button
  3020. *
  3021. * @memberOf vboxButtonMediaMenu
  3022. * @return {HTMLNode}
  3023. */
  3024. this.buttonElement = function() {
  3025. var b = self.button;
  3026. // Pre-load disabled version of icon if enabled function exists
  3027. if(b.enabled) {
  3028. var a = new Image();
  3029. a.src = "images/vbox/" + b.icon + "_" + self.disabledString + "_" + self.size + "px.png";
  3030. }
  3031. var label = trans(b.label, b.language_context);
  3032. return $('<td />').attr({'type':'button','value':'',
  3033. 'class': 'vboxImgButton vboxToolbarSmallButton vboxButtonMenuButton ui-corner-all',
  3034. 'title': label,
  3035. 'style': self.buttonStyle+' background-image: url(images/vbox/' + b.icon + '_'+self.size+'px.png);text-align:right;vertical-align:bottom;'
  3036. }).click(function(e){
  3037. if($(this).hasClass('vboxDisabled')) return;
  3038. $(this).addClass('vboxButtonMenuButtonDown');
  3039. var tbtn = $(this);
  3040. e.stopPropagation();
  3041. e.preventDefault();
  3042. $(document).one('mouseup',function(){
  3043. $(tbtn).removeClass('vboxButtonMenuButtonDown');
  3044. });
  3045. }).html('<img src="images/downArrow.png" style="margin:0px;padding:0px;float:right;width:6px;height:6px;" />').hover(
  3046. function(){if(!$(this).hasClass('vboxDisabled')){$(this).addClass('vboxToolbarSmallButtonHover');}},
  3047. function(){$(this).removeClass('vboxToolbarSmallButtonHover');}
  3048. );
  3049. };
  3050. /**
  3051. * Return a jquery object containing button element.
  3052. *
  3053. * @memberOf vboxButtonMediaMenu
  3054. * @return {Object} jQuery object containing button element
  3055. */
  3056. this.getButtonElm = function () {
  3057. return self._buttonElement;
  3058. };
  3059. /**
  3060. * Render button to element with id
  3061. *
  3062. * @memberOf vboxButtonMediaMenu
  3063. * @param {String|Object}
  3064. * targetElm - HTMLNode node or id to add button to
  3065. */
  3066. this.renderTo = function(targetElm) {
  3067. if(typeof(targetElm) == 'string')
  3068. targetElm = $('#'+targetElm);
  3069. if(!self.buttonStyle)
  3070. self.buttonStyle = 'height: ' + (self.size + ($.browser.msie || $.browser.webkit ? 3: 7)) + 'px; width: ' + (self.size+10) + 'px; ';
  3071. this._buttonElement = self.buttonElement();
  3072. var tbl = $('<table />').attr({'style':'border:0px;margin:0px;padding:0px;'+self.buttonStyle});
  3073. $('<tr />').css({'vertical-align':'bottom'}).append(this._buttonElement).appendTo(tbl);
  3074. $(targetElm).attr({'name':self.name}).addClass('vboxToolbarSmall vboxButtonMenu vboxEnablerTrigger').on('disable',self.disable).on('enable',self.enable).append(tbl);
  3075. // Generate and attach menu
  3076. self.mediaMenu.menuElement();
  3077. self.getButtonElm().contextMenu({
  3078. menu: self.mediaMenu.menu_id(),
  3079. mode:'menu',
  3080. button: 0
  3081. },self.mediaMenu.menuCallback);
  3082. };
  3083. /**
  3084. * Update media menu
  3085. *
  3086. * @see vboxMediaMenu.menuUpdateMedia
  3087. */
  3088. this.menuUpdateMedia = self.mediaMenu.menuUpdateMedia;
  3089. }
  3090. /**
  3091. * Media menu class
  3092. *
  3093. * @constructor
  3094. * @class vboxMediaMenu
  3095. * @param {String}
  3096. * type - type of media to display
  3097. * @param {Function}
  3098. * callback - callback function to run when medium is selected
  3099. * @param {String}
  3100. * mediumPath - path to use when selecting media
  3101. */
  3102. function vboxMediaMenu(type,callback,mediumPath) {
  3103. var self = this;
  3104. this.type = type;
  3105. this.callback = callback;
  3106. this.mediumPath = mediumPath;
  3107. this.removeEnabled = true;
  3108. /**
  3109. * Generate menu element ID
  3110. *
  3111. * @memberOf vboxMediaMenu
  3112. * @return {String} string to use for menu node id
  3113. */
  3114. this.menu_id = function(){
  3115. return 'vboxMediaListMenu'+self.type;
  3116. };
  3117. /**
  3118. * Generate menu element
  3119. *
  3120. * @memberOf vboxMediaMenu
  3121. * @return {HTMLNode} menu element
  3122. */
  3123. this.menuElement = function() {
  3124. // Pointer already held
  3125. if(self._menuElm) return self._menuElm;
  3126. var id = self.menu_id();
  3127. // Hold pointer
  3128. self._menu = new vboxMenu({'name': id, 'id': id});
  3129. // Add menu
  3130. self._menu.addMenu(self.menuGetDefaults());
  3131. // Update recent list
  3132. self.menuUpdateRecent();
  3133. self._menu.update();
  3134. self._menuElm = $('#'+self.menu_id());
  3135. return self._menuElm;
  3136. };
  3137. /**
  3138. * Generate and return host drives
  3139. *
  3140. * @memberOf vboxMediaMenu
  3141. * @return {Array} array of objects that can be added to menu
  3142. */
  3143. this.menuGetDrives = function() {
  3144. var menu = [];
  3145. // Add host drives
  3146. var meds = vboxMedia.mediaForAttachmentType(self.type);
  3147. for(var i =0; i < meds.length; i++) {
  3148. if(!meds[i].hostDrive) continue;
  3149. menu[menu.length] = {'name':meds[i].id,'label':vboxMedia.getName(meds[i])};
  3150. }
  3151. return menu;
  3152. };
  3153. /**
  3154. * List of default menu items to use for media of type self.type
  3155. *
  3156. * @memberOf vboxMediaMenu
  3157. * @return {Array} List of default menu items to use for media of type
  3158. * self.type
  3159. */
  3160. this.menuGetDefaults = function () {
  3161. menus = [];
  3162. switch(self.type) {
  3163. // HardDisk defaults
  3164. case 'HardDisk':
  3165. // create hard disk
  3166. menus[menus.length] = {'name':'createD','icon':'hd_new','label':trans('Create a new hard disk...','UIMachineSettingsStorage')};
  3167. // choose hard disk
  3168. menus[menus.length] = {'name':'chooseD','icon':'select_file','label':trans('Choose a virtual hard disk file...','UIMachineSettingsStorage')};
  3169. // Add VMM?
  3170. if($('#vboxPane').data('vboxConfig').enableAdvancedConfig) {
  3171. menus[menus.length] = {'name':'vmm','icon':'diskimage','label':trans('Virtual Media Manager...','UIActionPool')};
  3172. }
  3173. // recent list place holder
  3174. menus[menus.length] = {'name':'vboxMediumRecentBefore','cssClass':'vboxMediumRecentBefore','enabled':function(){return false;},'hide_on_disabled':true};
  3175. break;
  3176. // CD/DVD Defaults
  3177. case 'DVD':
  3178. // Choose disk image
  3179. menus[menus.length] = {'name':'chooseD','icon':'select_file','label':trans('Choose a virtual optical disk file...','UIMachineSettingsStorage')};
  3180. // Add VMM?
  3181. if($('#vboxPane').data('vboxConfig').enableAdvancedConfig) {
  3182. menus[menus.length] = {'name':'vmm','icon':'diskimage','label':trans('Virtual Media Manager...','UIActionPool')};
  3183. }
  3184. // Add host drives
  3185. menus = menus.concat(self.menuGetDrives());
  3186. // Add remove drive
  3187. menus[menus.length] = {'name':'removeD','icon':'cd_unmount','cssClass':'vboxMediumRecentBefore',
  3188. 'label':trans('Remove disk from virtual drive','UIMachineSettingsStorage'),'separator':true,
  3189. 'enabled':function(){return self.removeEnabled;}};
  3190. break;
  3191. // Floppy defaults
  3192. default:
  3193. // Choose disk image
  3194. menus[menus.length] = {'name':'chooseD','icon':'select_file','label':trans('Choose a virtual floppy disk file...','UIMachineSettingsStorage')};
  3195. // Add VMM?
  3196. if($('#vboxPane').data('vboxConfig').enableAdvancedConfig) {
  3197. menus[menus.length] = {'name':'vmm','icon':'diskimage','label':trans('Virtual Media Manager...','UIActionPool')};
  3198. }
  3199. // Add host drives
  3200. menus = menus.concat(self.menuGetDrives());
  3201. // Add remove drive
  3202. menus[menus.length] = {'name':'removeD','icon':'fd_unmount','cssClass':'vboxMediumRecentBefore',
  3203. 'label':trans('Remove disk from virtual drive','UIMachineSettingsStorage'),'separator':true,
  3204. 'enabled':function(){return self.removeEnabled;}};
  3205. break;
  3206. }
  3207. return menus;
  3208. };
  3209. /**
  3210. * Update "recent" media list menu items
  3211. *
  3212. * @memberOf vboxMediaMenu
  3213. */
  3214. this.menuUpdateRecent = function() {
  3215. var elm = $('#'+self.menu_id());
  3216. var list = $('#vboxPane').data('vboxRecentMedia')[self.type];
  3217. elm.children('li.vboxMediumRecent').remove();
  3218. var ins = elm.children('li.vboxMediumRecentBefore').last();
  3219. for(var i = 0; i < list.length; i++) {
  3220. if(!list[i]) continue;
  3221. if(!vboxMedia.getMediumByLocation(list[i])) continue;
  3222. $('<li />').attr({'class':'vboxMediumRecent'}).append(
  3223. $('<a />').attr({
  3224. 'href': '#path:'+list[i],
  3225. 'title': list[i]
  3226. }).text(vboxBasename(list[i]))
  3227. ).insertBefore(ins);
  3228. }
  3229. };
  3230. /**
  3231. * Update media checkbox and "remove image from disk" menu item
  3232. *
  3233. * @memberOf vboxMediaMenu
  3234. * @param {String}
  3235. * medium - medium attached to controller
  3236. * @return null
  3237. */
  3238. this.menuUpdateMedia = function(medium) {
  3239. self.removeEnabled = (medium ? true: false);
  3240. if(!self._menu) self.menuElement();
  3241. else self._menu.update();
  3242. // Remove all 'attached' spans
  3243. var elm = $('#'+self.menu_id());
  3244. $(elm).find('a.vboxCheckMark').removeClass('vboxCheckMark').children('span.vboxCheckMark').remove();
  3245. if(medium) {
  3246. if(medium.hostDrive) {
  3247. $(elm).find('a[href="#'+medium.id+'"]').addClass('vboxCheckMark').prepend($('<span />').attr({'class':'vboxCheckMark'}).html('&#x2713;'));
  3248. } else {
  3249. $(elm).find('a[href="#path:'+medium.location+'"]').addClass('vboxCheckMark').prepend($('<span />').attr({'class':'vboxCheckMark'}).html('&#x2713;'));
  3250. }
  3251. }
  3252. };
  3253. /**
  3254. * Update recent media menu and global recent media list
  3255. *
  3256. * @memberOf vboxMediaMenu
  3257. * @param {Object}
  3258. * m - medium object
  3259. * @param {Boolean}
  3260. * skipPathAdd - don't add medium's path to vbox's list of recent
  3261. * media paths
  3262. */
  3263. this.updateRecent = function(m, skipPathAdd) {
  3264. if(vboxMedia.updateRecent(m, skipPathAdd)) { // returns true if
  3265. // recent media list has
  3266. // changed
  3267. // Update menu
  3268. self.menuUpdateRecent();
  3269. }
  3270. };
  3271. /**
  3272. * Function called when menu item is selected
  3273. *
  3274. * @memberOf vboxMediaMenu
  3275. * @param {String}
  3276. * action - menu item's href value (text in a href="#...")
  3277. */
  3278. this.menuCallback = function(action) {
  3279. switch(action) {
  3280. // Create hard disk
  3281. case 'createD':
  3282. $.when(new vboxWizardNewHDDialog({'path':(self.mediumPath ? self.mediumPath: $('#vboxPane').data('vboxRecentMediaPaths')[self.type])+$('#vboxPane').data('vboxConfig').DSEP}).run())
  3283. .done(function(id){
  3284. if(!id) return;
  3285. var med = vboxMedia.getMediumById(id);
  3286. self.callback(med);
  3287. self.menuUpdateRecent(med);
  3288. });
  3289. break;
  3290. // VMM
  3291. case 'vmm':
  3292. // vboxVMMDialog(select,type,hideDiff,mPath)
  3293. $.when(vboxVMMDialog(true,self.type,true,(self.mediumPath ? self.mediumPath: $('#vboxPane').data('vboxRecentMediaPaths')[self.type]))).done(function(m){
  3294. if(m) {
  3295. self.callback(vboxMedia.getMediumById(m));
  3296. self.menuUpdateRecent();
  3297. }
  3298. });
  3299. break;
  3300. // Choose medium file
  3301. case 'chooseD':
  3302. vboxMedia.actions.choose(self.mediumPath,self.type,function(med){
  3303. self.callback(med);
  3304. self.menuUpdateRecent();
  3305. });
  3306. break;
  3307. // Existing medium was selected
  3308. default:
  3309. if(action.indexOf('path:') == 0) {
  3310. var path = action.substring(5);
  3311. var med = vboxMedia.getMediumByLocation(path);
  3312. if(med && med.deviceType == self.type) {
  3313. self.callback(med);
  3314. self.updateRecent(med,true);
  3315. }
  3316. return;
  3317. }
  3318. var med = vboxMedia.getMediumById(action);
  3319. self.callback(med);
  3320. self.updateRecent(med,true);
  3321. }
  3322. };
  3323. }
  3324. /**
  3325. * Menu class for use with context or button menus
  3326. *
  3327. * @constructor
  3328. * @class vboxMenu
  3329. * @param {Object}
  3330. * name - name of menu
  3331. * id - optional HTMLNode id of menu to use
  3332. * menuItems - list of menu items to add
  3333. * language_context - translation language context
  3334. */
  3335. function vboxMenu(options) {
  3336. var self = this;
  3337. this.name = options.name;
  3338. this.menuItems = {};
  3339. this.iconStringDisabled = '_disabled';
  3340. this.id = options.id;
  3341. this.language_context = options.language_context;
  3342. /**
  3343. * return menu id
  3344. *
  3345. * @memberOf vboxMenu
  3346. * @return {String} the HTMLNode id of this menu
  3347. */
  3348. this.menuId = function() {
  3349. if(self.id) return self.id;
  3350. return self.name + 'Menu';
  3351. };
  3352. /**
  3353. * Add menu to menu object
  3354. *
  3355. * @memberOf vboxMenu
  3356. * @param {Object}
  3357. * m - menu configuration object
  3358. */
  3359. this.addMenu = function(m) {
  3360. $('#vboxPane').append(self.menuElement(m,self.menuId()));
  3361. };
  3362. /**
  3363. * Traverse menu configuration object and generate a
  3364. * <UL>
  3365. * containing menu items
  3366. *
  3367. * @memberOf vboxMenu
  3368. * @param {Object}
  3369. * m - menu configuration object
  3370. * @param {String}
  3371. * mid - the optional id to use for the generated HTMLNode
  3372. * @return {HTMLNode} menu
  3373. * <UL>
  3374. * node containing menu items and submenus
  3375. */
  3376. this.menuElement = function(m, mid) {
  3377. var ul = null;
  3378. if(mid) {
  3379. ul = $('#'+mid);
  3380. if(ul && ul.length) {
  3381. ul.empty();
  3382. } else {
  3383. ul = $('<ul />').attr({'id':mid,'style':'display: none;'});
  3384. }
  3385. } else {
  3386. ul = $('<ul />').attr({'style':'display: none;'});
  3387. }
  3388. ul.addClass('contextMenu');
  3389. for(var i in m) {
  3390. if(typeof m[i] == 'function') continue;
  3391. // get menu item
  3392. var item = self.menuItem(m[i]);
  3393. // Add to menu list
  3394. self.menuItems[m[i].name] = m[i];
  3395. // Children?
  3396. if(m[i].children && m[i].children.length) {
  3397. item.append(self.menuElement(m[i].children, self.menuId()+'-submenu-' + i));
  3398. }
  3399. ul.append(item);
  3400. }
  3401. return ul;
  3402. };
  3403. /**
  3404. * Menu click callback
  3405. *
  3406. * @memberOf vboxMenu
  3407. * @param {Integer}
  3408. * i - menu item index number
  3409. * @param {Object}
  3410. * item - optional selected item
  3411. * @return return value of menu item's click() function
  3412. */
  3413. this.menuClickCallback = function(i, item) {
  3414. return self.menuItems[i].click(item);
  3415. };
  3416. /**
  3417. * generate menu item HTML
  3418. *
  3419. * @memberOf vboxMenu
  3420. * @param {Object}
  3421. * i - menu item's configuration object
  3422. * @return {HTMLNode}
  3423. * <li> containing menu item
  3424. */
  3425. this.menuItem = function(i) {
  3426. var label = trans(i.label, i.language_context ? i.language_context : self.language_context);
  3427. return $('<li />').addClass((i.separator ? 'separator': '')).addClass((i.cssClass ? i.cssClass: '')).append($('<a />')
  3428. .html(label)
  3429. .attr({
  3430. 'style': (i.icon ? 'background-image: url('+self.menuIcon(i,false)+')': ''),
  3431. 'id': self.name+i.name,'href':'#'+i.name
  3432. }));
  3433. };
  3434. /**
  3435. * Return a URL to use for menu item's icon
  3436. *
  3437. * @memberOf vboxMenu
  3438. * @param {Object}
  3439. * i - menu item configuration object
  3440. * @param {Boolean}
  3441. * disabled - whether or not the icon should be disabled
  3442. * @return {String} url to icon to use
  3443. */
  3444. this.menuIcon = function(i,disabled) {
  3445. if(!i.icon) return '';
  3446. return 'images/vbox/' + i.icon + (disabled ? self.iconStringDisabled: '') + '_16px.png';
  3447. };
  3448. /**
  3449. * Update all menu items
  3450. *
  3451. * @memberOf vboxMenu
  3452. * @param {Object}
  3453. * testObj - object used to test for enabled()
  3454. * @return null
  3455. */
  3456. this.update = function(testObj) {
  3457. for(var i in self.menuItems) {
  3458. // If enabled function doesn't exist, there's nothing to do
  3459. if(!self.menuItems[i].enabled) continue;
  3460. var mi = $('#'+self.name+i);
  3461. // Disabled
  3462. if(!self.menuItems[i].enabled(testObj)) {
  3463. if(self.menuItems[i].hide_on_disabled) {
  3464. mi.parent().hide();
  3465. } else {
  3466. self.disableItem(i,mi);
  3467. }
  3468. // Enabled
  3469. } else {
  3470. if(self.menuItems[i].hide_on_disabled) {
  3471. mi.parent().show();
  3472. } else {
  3473. self.enableItem(i,mi);
  3474. }
  3475. }
  3476. }
  3477. };
  3478. /**
  3479. * Disable a single menu item
  3480. *
  3481. * @memberOf vboxMenu
  3482. * @param {String}
  3483. * i - menu item's name
  3484. * @param {Object}
  3485. * mi - optional menu item HTMLNode or jQuery object
  3486. */
  3487. this.disableItem = function(i, mi) {
  3488. if(!mi) mi = $('#'+self.name+i);
  3489. if(self.menuItems[i].icon)
  3490. mi.css({'background-image':'url('+self.menuIcon(self.menuItems[i],true)+')'}).parent().addClass('disabled');
  3491. else
  3492. mi.parent().addClass('disabled');
  3493. };
  3494. /**
  3495. * Enable a single menu item
  3496. *
  3497. * @memberOf vboxMenu
  3498. * @param {String}
  3499. * i - menu item's name
  3500. * @param {Object}
  3501. * mi - optional menu item HTMLNode or jQuery object
  3502. */
  3503. this.enableItem = function(i, mi) {
  3504. if(!mi) mi = $('#'+self.name+i);
  3505. if(self.menuItems[i].icon)
  3506. mi.css({'background-image':'url('+self.menuIcon(self.menuItems[i],false)+')'}).parent().removeClass('disabled');
  3507. else
  3508. mi.parent().removeClass('disabled');
  3509. };
  3510. // Just add menu items if there were passed
  3511. if(options.menuItems) self.addMenu(options.menuItems);
  3512. }
  3513. /**
  3514. * Menu bar class
  3515. *
  3516. * @constructor
  3517. * @class vboxMenuBar
  3518. * @param {String}
  3519. * name - name of this menu bar
  3520. */
  3521. function vboxMenuBar(options) {
  3522. var self = this;
  3523. this.name = options.name;
  3524. this.language_context = options.language_context;
  3525. this.menus = new Array();
  3526. this.menuClick = {};
  3527. this.iconStringDisabled = options.iconStringDisabled ? options.iconStringDisabled : '_disabled';
  3528. /**
  3529. * Add a menu to this object
  3530. *
  3531. * @memberOf vboxMenuBar
  3532. * @param {Object}
  3533. * m - menu configuration object
  3534. * @return void
  3535. */
  3536. this.addMenu = function(m) {
  3537. // Create menu object
  3538. m.menuObj = new vboxMenu({'name': m.name, language_context: m.language_context ? m.language_context : self.language_context});
  3539. // Propagate config
  3540. m.menuObj.iconStringDisabled = self.iconStringDisabled;
  3541. // Add menu
  3542. m.menuObj.addMenu(m.menu);
  3543. self.menus[self.menus.length] = m;
  3544. };
  3545. /**
  3546. * Render menu bar to element identified by ID
  3547. *
  3548. * @memberOf vboxMenuBar
  3549. * @param {String}
  3550. * id - HTMLNode id of node to add menu bar to
  3551. */
  3552. this.renderTo = function(id) {
  3553. $('#'+id).prepend($('<div />').attr({'class':'vboxMenuBar','id':self.name+'MenuBar'}));
  3554. for(var i = 0; i < self.menus.length; i++) {
  3555. var label = trans(self.menus[i].label, self.menus[i].language_context ? self.menus[i].language_context : self.language_context);
  3556. $('#'+self.name+'MenuBar').append(
  3557. $('<span />').attr({'id':'vboxMenuBarMenu'+self.name+self.menus[i].name}).html(label)
  3558. .contextMenu({
  3559. menu: self.menus[i].menuObj.menuId(),
  3560. button: 0,
  3561. mode: 'menu',
  3562. menusetup: function(el) {
  3563. $(el).parent().data('vboxMenubarActive', true);
  3564. $(document).one('mousedown',function(){
  3565. $(el).parent().data('vboxMenubarActive', false);
  3566. });
  3567. }
  3568. },
  3569. self.menus[i].menuObj.menuClickCallback
  3570. ).hover(
  3571. function(){
  3572. $(this).addClass('vboxBordered');
  3573. if($(this).parent().data('vboxMenubarActive')) {
  3574. // Hide any showing menu
  3575. var e = jQuery.Event("mouseup", {button:0});
  3576. $(this).trigger(e);
  3577. var e = jQuery.Event("mousedown", {button:0});
  3578. $(this).trigger(e);
  3579. var e = jQuery.Event("mouseup", {button:0});
  3580. $(this).trigger(e);
  3581. }
  3582. },
  3583. function(){
  3584. $(this).removeClass('vboxBordered');
  3585. }
  3586. ).disableSelection()
  3587. );
  3588. }
  3589. };
  3590. /**
  3591. * Update Menu items
  3592. *
  3593. * @memberOf vboxMenuBar
  3594. * @param {Object}
  3595. * item - item to use in menu configuration items' update() test
  3596. * @return void
  3597. */
  3598. this.update = function(item) {
  3599. for(var i = 0; i < self.menus.length; i++) {
  3600. // check for enabled function on entire menu object
  3601. if(self.menus[i].enabled) {
  3602. if(self.menus[i].enabled(item)) {
  3603. $('#vboxMenuBarMenu'+self.name+self.menus[i].name).show();
  3604. } else {
  3605. $('#vboxMenuBarMenu'+self.name+self.menus[i].name).hide();
  3606. continue;
  3607. }
  3608. }
  3609. self.menus[i].menuObj.update(item);
  3610. }
  3611. };
  3612. }
  3613. /**
  3614. * Loads data, scripts, and HTML files and optionally displays "Loading ..."
  3615. * screen until all items have completed loading
  3616. *
  3617. * @param {String} name - unique name for this loader. used to generate id
  3618. * of "Loading..." div
  3619. * @constructor
  3620. * @class vboxLoader
  3621. */
  3622. function vboxLoader(name) {
  3623. if(!name) name = '';
  3624. var self = this;
  3625. this._load = [];
  3626. this.onLoad = null;
  3627. this._loadStarted = {};
  3628. this.hideRoot = false;
  3629. this.noLoadingScreen = false;
  3630. this.name = name;
  3631. this._data = [];
  3632. this._files = [];
  3633. /**
  3634. * Add data item to list of items to load
  3635. *
  3636. * @memberOf vboxLoader
  3637. * @param {String}
  3638. * dataFunction - function to pass to vboxAjaxRequest()
  3639. * @param {Function}
  3640. * callback - callback to run when data is returned
  3641. * @param {Object}
  3642. * params - params to pass to vboxAjaxRequest()
  3643. * @see vboxAjaxRequest()
  3644. */
  3645. this.add = function(dataFunction, callback, params) {
  3646. if(!this.name) this.name = dataFunction + 'Loader';
  3647. this._data[this._data.length] = vboxAjaxRequest(dataFunction,params).done(callback);
  3648. };
  3649. /**
  3650. * Add file to list of items to load
  3651. *
  3652. * @memberOf vboxLoader
  3653. * @param {String}
  3654. * file - URL of file to load
  3655. * @param {Function}
  3656. * callback - callback to run when file is loaded
  3657. * @see vboxAjaxRequest()
  3658. */
  3659. this.addFile = function(file,callback) {
  3660. this._files[this._files.length] = {
  3661. 'callback': callback,
  3662. 'file': file
  3663. };
  3664. };
  3665. /**
  3666. * Add file to list of items to load. Append resulting file to element.
  3667. *
  3668. * @memberOf vboxLoader
  3669. * @param {String}
  3670. * file - URL of file to load
  3671. * @param {jQueryObject}
  3672. * elm - element to append file to
  3673. */
  3674. this.addFileToDOM = function(file,elm) {
  3675. if(elm === undefined) elm = $('#vboxPane');
  3676. var callback = function(f){elm.append(f);};
  3677. self.addFile(file,callback);
  3678. };
  3679. /**
  3680. * Show loading screen
  3681. *
  3682. */
  3683. this.showLoading = function() {
  3684. var div = $('<div />').attr({'id':'vboxLoaderDialog'+self.name,'title':'','style':'display: none;','class':'vboxLoaderDialog'});
  3685. var tbl = $('<table />');
  3686. var tr = $('<tr />');
  3687. $('<td />').attr('class', 'vboxLoaderSpinner').html('<img src="images/spinner.gif" width="36" height="39" />').appendTo(tr);
  3688. $('<td />').attr('class','vboxLoaderText').html(trans('Loading ...','UIVMDesktop')).appendTo(tr);
  3689. $(tbl).append(tr).appendTo(div);
  3690. if(self.hideRoot)
  3691. $('#vboxPane').css('display', 'none');
  3692. $(div).dialog({
  3693. 'dialogClass': 'vboxLoaderDialog',
  3694. 'width': 'auto',
  3695. 'height': 65,
  3696. 'modal': true,
  3697. 'resizable': false,
  3698. 'draggable': false,
  3699. 'closeOnEscape': false,
  3700. 'buttons': {}
  3701. });
  3702. };
  3703. /**
  3704. * Hide loading screen
  3705. */
  3706. this.removeLoading = function() {
  3707. $('#vboxLoaderDialog'+self.name).empty().remove();
  3708. };
  3709. /**
  3710. * Load data and optionally present "Loading..." screen
  3711. *
  3712. * @memberOf vboxLoader
  3713. * @return null
  3714. */
  3715. this.run = function() {
  3716. if(!self.noLoadingScreen) {
  3717. self.showLoading();
  3718. }
  3719. // Data first
  3720. $.when.apply($, self._data).done(function() {
  3721. // files
  3722. for(var i = 0; i < self._files.length; i++) {
  3723. self._files[i] = jQuery.get(self._files[i]['file'],self._files[i]['callback']).fail(function(d) {
  3724. // Check for error HTTP status
  3725. if(d && d.status && (String(d.status).substring(0,1) == '4' || String(d.status).substring(0,1) == '5')) {
  3726. var err = {error: 'HTTP error: ' + d.status + ' ' + d.statusText,details:''};
  3727. for(var i in d) {
  3728. if(typeof(d[i]) == 'function' || typeof(d[i]) == 'object') continue;
  3729. err.details += i + ': "' + d[i] + '"' + "\n";
  3730. }
  3731. vboxAlert(err);
  3732. }
  3733. });
  3734. }
  3735. $.when.apply($, self._files).done(function() {
  3736. self._stop();
  3737. });
  3738. });
  3739. };
  3740. /**
  3741. * Remove loading screen and show body
  3742. *
  3743. * @memberOf vboxLoader
  3744. */
  3745. this._stop = function() {
  3746. if(self.onLoad) self.onLoad(self);
  3747. if(!self.noLoadingScreen) self.removeLoading();
  3748. if(self.hideRoot) $('#vboxPane').css('display', '');
  3749. if(self.onShow) self.onShow();
  3750. };
  3751. }
  3752. /**
  3753. * Serial port namespace
  3754. *
  3755. * @namespace vboxSerialPorts
  3756. */
  3757. var vboxSerialPorts = {
  3758. ports: [
  3759. { 'name':"COM1", 'irq':4, 'port':'0x3F8' },
  3760. { 'name':"COM2", 'irq':3, 'port':'0x2F8' },
  3761. { 'name':"COM3", 'irq':4, 'port':'0x3E8' },
  3762. { 'name':"COM4", 'irq':3, 'port':'0x2E8' },
  3763. ],
  3764. /**
  3765. * Return port name based on irq and port
  3766. *
  3767. * @param {Integer}
  3768. * irq - irq number
  3769. * @param {String}
  3770. * port - IO port
  3771. * @return {String} port name
  3772. */
  3773. getPortName: function(irq,port) {
  3774. for(var i = 0; i < vboxSerialPorts.ports.length; i++) {
  3775. if(vboxSerialPorts.ports[i].irq == irq && vboxSerialPorts.ports[i].port.toUpperCase() == port.toUpperCase())
  3776. return vboxSerialPorts.ports[i].name;
  3777. }
  3778. return 'User-defined';
  3779. }
  3780. };
  3781. /**
  3782. * LPT port namespace
  3783. *
  3784. * @namespace vboxParallelPorts
  3785. */
  3786. var vboxParallelPorts = {
  3787. ports: [
  3788. { 'name':"LPT1", 'irq':7, 'port':'0x3BC' },
  3789. { 'name':"LPT2", 'irq':5, 'port':'0x378' },
  3790. { 'name':"LPT3", 'irq':5, 'port':'0x278' }
  3791. ],
  3792. /**
  3793. * Return port name based on irq and port
  3794. *
  3795. * @param {Integer}
  3796. * irq - irq number
  3797. * @param {String}
  3798. * port - IO port
  3799. * @return {String} port name
  3800. */
  3801. getPortName: function(irq,port) {
  3802. for(var i = 0; i < vboxParallelPorts.ports.length; i++) {
  3803. if(vboxParallelPorts.ports[i].irq == irq && vboxParallelPorts.ports[i].port.toUpperCase() == port.toUpperCase())
  3804. return vboxParallelPorts.ports[i].name;
  3805. }
  3806. return 'User-defined';
  3807. }
  3808. };
  3809. /**
  3810. * Common VM storage / controller functions namespace
  3811. *
  3812. * @namespace vboxStorage
  3813. *
  3814. 5.133.2 getDefaultIoCacheSettingForStorageController
  3815. 5.133.3 getDeviceTypesForStorageBus
  3816. 5.133.4 getMaxDevicesPerPortForStorageBus
  3817. 5.133.5 getMaxInstancesOfStorageBus
  3818. */
  3819. var vboxStorage = {
  3820. /**
  3821. * Return list of bus types
  3822. *
  3823. * @memberOf vboxStorage
  3824. * @static
  3825. * @return {Array} list of all storage bus types
  3826. */
  3827. getBusTypes: function() {
  3828. var busts = [];
  3829. for(var i in vboxStorage) {
  3830. if(typeof i == 'function') continue;
  3831. if(!vboxStorage[i].maxPortCount) continue;
  3832. busts[busts.length] = i;
  3833. }
  3834. return busts;
  3835. },
  3836. /**
  3837. * Return list of attached media for storage
  3838. * controllers of a VM
  3839. */
  3840. getAttachedBaseMedia: function(vm) {
  3841. var media = [];
  3842. for(var a = 0; a < vm.storageControllers.length; a++) {
  3843. var attch = vm.storageControllers[a].mediumAttachments;
  3844. for(var b = 0; b < attch.length; b++) {
  3845. var m = attch[b].medium;
  3846. if(!m) continue;
  3847. media.push(vboxMedia.getMediumById(m.base ? m.base: m.id));
  3848. }
  3849. }
  3850. return media;
  3851. },
  3852. /**
  3853. * Return icon name for bus
  3854. *
  3855. * @memberOf vboxStorage
  3856. * @param {Object} ma - medium attachment object
  3857. * @return {Array} options list
  3858. */
  3859. getMAOptions: function(ma) {
  3860. switch(ma.type) {
  3861. case 'HardDisk':
  3862. var opts = [{
  3863. label: trans('Solid-state Drive','UIMachineSettingsStorage'),
  3864. attrib: 'nonRotational'
  3865. }];
  3866. if($('#vboxPane').data('vboxConfig').enableHDFlushConfig) {
  3867. opts.push({
  3868. label: 'Ignore Flush Requests',
  3869. attrib: 'ignoreFlush',
  3870. runningEnabled: true,
  3871. });
  3872. }
  3873. return opts;
  3874. case 'DVD':
  3875. // Host drive
  3876. if(vboxMedia.isHostDrive(ma.medium)) {
  3877. return [{
  3878. label: trans('Passthrough','UIMachineSettingsStorage'),
  3879. attrib: 'passthrough'
  3880. }];
  3881. }
  3882. // Image
  3883. return [{
  3884. label: trans('Live CD/DVD','UIMachineSettingsStorage'),
  3885. attrib: 'temporaryEject',
  3886. runningEnabled: true
  3887. }];
  3888. default:
  3889. return []
  3890. }
  3891. },
  3892. /**
  3893. * Get medium attachment options for storage controller
  3894. *
  3895. * @memberOf vboxStorage
  3896. * @param {Object} sc - storage controller object
  3897. * @return {Array} options list
  3898. */
  3899. getMAOptionsForSC: function(sc) {
  3900. if(sc.bus == 'SATA' || sc.bus == 'USB') {
  3901. return [{
  3902. label: trans('Hot-pluggable','UIMachineSettingsStorage'),
  3903. attrib: 'hotPluggable'
  3904. }];
  3905. }
  3906. return [];
  3907. },
  3908. /**
  3909. * Return icon name for bus
  3910. *
  3911. * @memberOf vboxStorage
  3912. * @param {String} bus - bus type
  3913. * @return {String} icon name
  3914. */
  3915. getBusIconName: function(bus) {
  3916. if(vboxStorage[bus].displayInherit) bus = vboxStorage[bus].displayInherit
  3917. return bus.toLowerCase();
  3918. },
  3919. IDE: {
  3920. maxPortCount: 2,
  3921. limitOneInstance: true,
  3922. maxDevicesPerPortCount: 2,
  3923. types :['PIIX3','PIIX4','ICH6' ],
  3924. ignoreFlush: true,
  3925. slotName: function(p,d) {
  3926. switch(p+'-'+d) {
  3927. case '0-0': return (trans('IDE Primary Master','VBoxGlobal', null, 'StorageSlot'));
  3928. case '0-1': return (trans('IDE Primary Slave','VBoxGlobal', null, 'StorageSlot'));
  3929. case '1-0': return (trans('IDE Secondary Master','VBoxGlobal', null, 'StorageSlot'));
  3930. case '1-1': return (trans('IDE Secondary Slave','VBoxGlobal', null, 'StorageSlot'));
  3931. }
  3932. },
  3933. driveTypes: ['dvd','disk'],
  3934. slots: function() { return {
  3935. '0-0': (trans('IDE Primary Master','VBoxGlobal', null, 'StorageSlot')),
  3936. '0-1': (trans('IDE Primary Slave','VBoxGlobal', null, 'StorageSlot')),
  3937. '1-0': (trans('IDE Secondary Master','VBoxGlobal', null, 'StorageSlot')),
  3938. '1-1': (trans('IDE Secondary Slave','VBoxGlobal', null, 'StorageSlot'))
  3939. };
  3940. }
  3941. },
  3942. SATA: {
  3943. maxPortCount: 30,
  3944. maxDevicesPerPortCount: 1,
  3945. ignoreFlush: true,
  3946. types: ['IntelAhci'],
  3947. driveTypes: ['dvd','disk'],
  3948. slotName: function(p,d) { return trans('SATA Port %1','VBoxGlobal', null, 'StorageSlot').replace('%1',p); },
  3949. slots: function() {
  3950. var s = {};
  3951. for(var i = 0; i < 30; i++) {
  3952. s[i+'-0'] = trans('SATA Port %1','VBoxGlobal', null, 'StorageSlot').replace('%1',i);
  3953. }
  3954. return s;
  3955. }
  3956. },
  3957. SCSI: {
  3958. maxPortCount: 16,
  3959. maxDevicesPerPortCount: 1,
  3960. driveTypes: ['dvd','disk'],
  3961. types: ['LsiLogic','BusLogic'],
  3962. ignoreFlush: true,
  3963. slotName: function(p,d) { return trans('SCSI Port %1','VBoxGlobal', null, 'StorageSlot').replace('%1',p); },
  3964. slots: function() {
  3965. var s = {};
  3966. for(var i = 0; i < 16; i++) {
  3967. s[i+'-0'] = trans('SCSI Port %1','VBoxGlobal', null, 'StorageSlot').replace('%1',i);
  3968. }
  3969. return s;
  3970. }
  3971. },
  3972. SAS: {
  3973. maxPortCount: 8,
  3974. maxDevicesPerPortCount: 1,
  3975. types: ['LsiLogicSas'],
  3976. driveTypes: ['dvd','disk'],
  3977. slotName: function(p,d) { return trans('SAS Port %1','VBoxGlobal', null, 'StorageSlot').replace('%1',p); },
  3978. slots: function() {
  3979. var s = {};
  3980. for(var i = 0; i < 8; i++) {
  3981. s[i+'-0'] = trans('SAS Port %1','VBoxGlobal', null, 'StorageSlot').replace('%1',i);
  3982. }
  3983. return s;
  3984. },
  3985. displayInherit: 'SATA'
  3986. },
  3987. Floppy: {
  3988. maxPortCount: 1,
  3989. limitOneInstance: true,
  3990. maxDevicesPerPortCount: 2,
  3991. types: ['I82078'],
  3992. driveTypes: ['floppy'],
  3993. slotName: function(p,d) { return trans('Floppy Device %1','VBoxGlobal', null, 'StorageSlot').replace('%1',d); },
  3994. slots: function() { return { '0-0':trans('Floppy Device %1','VBoxGlobal', null, 'StorageSlot').replace('%1','0'),
  3995. '0-1' :trans('Floppy Device %1','VBoxGlobal', null, 'StorageSlot').replace('%1','1') }; }
  3996. },
  3997. USB: {
  3998. maxPortCount: 8,
  3999. maxDevicesPerPortCount: 1,
  4000. types: ['USB'],
  4001. driveTypes: ['dvd','disk'],
  4002. slotName: function(p,d) { return trans('USB Port %1','VBoxGlobal', null, 'StorageSlot').replace('%1',p); },
  4003. slots: function() {
  4004. var s = {};
  4005. for(var i = 0; i < 8; i++) {
  4006. s[i+'-0'] = trans('USB Port %1','VBoxGlobal', null, 'StorageSlot').replace('%1',i);
  4007. }
  4008. return s;
  4009. }
  4010. }
  4011. };
  4012. /**
  4013. * Storage Controller Types conversions
  4014. *
  4015. * @param {String}
  4016. * c - storage controller type
  4017. * @return {String} string used for translation
  4018. */
  4019. function vboxStorageControllerType(c) {
  4020. switch(c) {
  4021. case 'LsiLogic': return 'Lsilogic';
  4022. case 'LsiLogicSas': return 'LsiLogic SAS';
  4023. case 'IntelAhci': return 'AHCI';
  4024. }
  4025. return c;
  4026. }
  4027. /**
  4028. * Serial port mode conversions
  4029. *
  4030. * @param {String}
  4031. * m - serial port mode
  4032. * @return {String} string used for translation
  4033. */
  4034. function vboxSerialMode(m) {
  4035. switch(m) {
  4036. case 'HostPipe': return 'Host Pipe';
  4037. case 'HostDevice': return 'Host Device';
  4038. case 'RawFile': return 'Raw File';
  4039. }
  4040. return m;
  4041. }
  4042. /**
  4043. * Network adapter type conversions
  4044. *
  4045. * @param {String}
  4046. * t - network adapter type
  4047. * @return {String} string used for translation
  4048. */
  4049. function vboxNetworkAdapterType(t) {
  4050. switch(t) {
  4051. case 'Am79C970A': return 'PCnet-PCI II (Am79C970A)';
  4052. case 'Am79C973': return 'PCnet-FAST III (Am79C973)';
  4053. case 'I82540EM': return 'Intel PRO/1000 MT Desktop (82540EM)';
  4054. case 'I82543GC': return 'Intel PRO/1000 T Server (82543GC)';
  4055. case 'I82545EM': return 'Intel PRO/1000 MT Server (82545EM)';
  4056. case 'Virtio': return 'Paravirtualized Network (virtio-net)';
  4057. }
  4058. }
  4059. /**
  4060. * Audio controller conversions
  4061. *
  4062. * @param {String}
  4063. * c - audio controller type
  4064. * @return {String} string used for translation
  4065. */
  4066. function vboxAudioController(c) {
  4067. switch(c) {
  4068. case 'AC97': return 'ICH AC97';
  4069. case 'SB16': return 'SoundBlaster 16';
  4070. case 'HDA': return 'Intel HD Audio';
  4071. }
  4072. }
  4073. /**
  4074. * Audio driver conversions
  4075. *
  4076. * @param {String}
  4077. * d - audio driver type
  4078. * @return {String} string used for translation
  4079. */
  4080. function vboxAudioDriver(d) {
  4081. switch(d) {
  4082. case 'OSS': return 'OSS Audio Driver';
  4083. case 'ALSA': return 'ALSA Audio Driver';
  4084. case 'Pulse': return 'PulseAudio';
  4085. case 'WinMM': return 'Windows Multimedia';
  4086. case 'DirectSound': return 'Windows DirectSound';
  4087. case 'Null': return 'Null Audio Driver';
  4088. case 'SolAudio': return 'Solaris Audio';
  4089. }
  4090. return d;
  4091. }
  4092. /**
  4093. * VM storage device conversions
  4094. *
  4095. * @param {String}
  4096. * d - storage device type
  4097. * @return {String} string used for translation
  4098. */
  4099. function vboxDevice(d) {
  4100. switch(d) {
  4101. case 'DVD': return 'Optical';
  4102. case 'HardDisk': return 'Hard Disk';
  4103. }
  4104. return d;
  4105. }
  4106. /**
  4107. * VM State functions namespace
  4108. *
  4109. * @namespace vboxVMStates
  4110. */
  4111. var vboxVMStates = {
  4112. /* Return whether or not vm is running */
  4113. isRunning: function(vm) {
  4114. return (vm && jQuery.inArray(vm.state, ['Running','LiveSnapshotting','Teleporting']) > -1);
  4115. },
  4116. /* Return whether or not vm is inaccessible */
  4117. isInaccessible: function(vm) {
  4118. return (vm && !vm.accessible);
  4119. },
  4120. /* Return whether or not a vm is stuck */
  4121. isStuck: function (vm) {
  4122. return (vm && vm.state == 'Stuck');
  4123. },
  4124. /* Whether or not a vm is paused */
  4125. isPaused: function(vm) {
  4126. return (vm && jQuery.inArray(vm.state, ['Paused','TeleportingPausedVM']) > -1);
  4127. },
  4128. /* True if vm is powered off */
  4129. isPoweredOff: function(vm) {
  4130. return (vm && jQuery.inArray(vm.state, ['PoweredOff','Saved','Teleported', 'Aborted']) > -1);
  4131. },
  4132. /* True if vm is saved */
  4133. isSaved: function(vm) {
  4134. return (vm && vm.state == 'Saved');
  4135. },
  4136. /* True if vm is editable */
  4137. isEditable: function(vm) {
  4138. return (vm && vm.sessionState == 'Unlocked');
  4139. },
  4140. /* True if one VM in list matches item */
  4141. isOne: function(test, vmlist) {
  4142. for(var i = 0; i < vmlist.length; i++) {
  4143. if(vboxVMStates['is'+test](vmlist[i]))
  4144. return true;
  4145. }
  4146. return false;
  4147. },
  4148. /* Convert Machine state to translatable state */
  4149. convert: function(state) {
  4150. switch(state) {
  4151. case 'PoweredOff': return 'Powered Off';
  4152. case 'LiveSnapshotting': return 'Live Snapshotting';
  4153. case 'TeleportingPausedVM': return 'Teleporting Paused VM';
  4154. case 'TeleportingIn': return 'Teleporting In';
  4155. case 'TakingLiveSnapshot': return 'Taking Live Snapshot';
  4156. case 'RestoringSnapshot': return 'Restoring Snapshot';
  4157. case 'DeletingSnapshot': return 'Deleting Snapshot';
  4158. case 'SettingUp': return 'Setting Up';
  4159. default: return state;
  4160. }
  4161. }
  4162. };