')
.attr({'class':'contextMenu contextMenuNoBG','style':'display: none','id':'vboxDetailsPreviewMenu'})
.click(function(){$(this).hide();})
.on('contextmenu', function() { return false; })
// Menu setup for "open in new window"
.on('beforeshow', function(e, vmid) {
var d = vboxVMDataMediator.getVMData(vmid);
if(vboxVMStates.isRunning(d) || vboxVMStates.isSaved(d)) {
$('#vboxDetailsViewSavedSS')
.css('display','')
.data({'vmid':d.id});
} else {
$('#vboxDetailsViewSavedSS').css('display', 'none');
}
});
// Menu item to disable update
$('')
.hoverClass('vboxHover')
.append(
$('').append(
$('')
.attr({'class':'vboxRadio','type':'radio','name':'vboxPreviewRadio','value':0})
.click(function(){
vboxSetLocalDataItem('previewUpdateInterval','0');
vboxVMDetailsSections.preview._updateInterval = 0;
})
.prop('checked', parseInt(vboxVMDetailsSections.preview._updateInterval) == 0)
).append(
$('')
.html(trans('Update disabled','UIGMachinePreview'))
)
).appendTo(ul);
// Update intervals
var ints = [3,5,10,20,30,60];
// check for update interval
if(vboxVMDetailsSections.preview._updateInterval > 0 && jQuery.inArray(vboxVMDetailsSections.preview._updateInterval, ints) < 0) {
ints[ints.length] = vboxVMDetailsSections.preview._updateInterval;
}
ints.sort(function(a,b){
if(a == b) return 0;
return (a > b ? 1: -1);
});
// Add each interval to menu
for(var i = 0; i < ints.length; i++) {
var li = $('');
if(i==0) $(li).attr('class','separator');
var radio = $('').attr({'class':'vboxRadio','type':'radio','name':'vboxPreviewRadio','value':ints[i]}).click(function(){
var lastIntervalNone = (parseInt(vboxVMDetailsSections.preview._updateInterval) == 0);
vboxSetLocalDataItem('previewUpdateInterval',$(this).val());
vboxVMDetailsSections.preview._updateInterval = $(this).val();
// Kick off preview updates if the last interval was 0
if(lastIntervalNone) {
var selVMData = vboxChooser.getSelectedVMsData();
for(var i = 0; i < selVMData.length; i++) {
if(vboxVMStates.isRunning(selVMData[i]) || vboxVMStates.isSaved(selVMData[i]))
vboxVMDetailsSections.preview._drawPreview(selVMData[i].id);
}
}
}).prop('checked', parseInt(vboxVMDetailsSections.preview._updateInterval) == ints[i]);
$('')
.append(radio)
.append(
$('')
.html(trans('Every %1 seconds','UIGMachinePreview').replace('%1',ints[i]))
)
.appendTo(li);
$(ul).append(li);
}
/* Append "Open in new window" */
$('')
.attr({'id':'vboxDetailsViewSavedSS','class':'separator','style':'display:none;text-align: center;'})
.click(function(){
window.open(vboxEndpointConfig.screen+'?vm='+$(this).data('vmid')+'&full=1','vboxSC','toolbar=1,menubar=0,location=0,directories=0,status=true,resize=true');
}).append(
$('')
.html(trans('Open in new window','UIVMPreviewWindow'))
).appendTo(ul);
/* Hover */
$(ul).children().hoverClass('vboxHover');
$(document).click(function(e){if(e.button!=2)$(ul).hide();});
$('#vboxTabVMDetails').append(ul);
return $('#vboxDetailsPreviewMenu');
},
/**
* This is run when the preview screen is drawn
*/
onRender: function(d) {
// Not needed in canvas logic
if(isCanvasSupported()) return;
if(!vboxVMDetailsSections.preview._updateInterval || (!vboxVMStates.isRunning(d) && !vboxVMStates.isSaved(d))) {
var timer = $('#vboxPane').data('vboxPreviewTimer-'+d.id);
if(timer) {
$('#vboxPane').data('vboxPreviewTimer-'+d.id, null);
window.clearInterval(timer);
}
vboxVMDetailsSections.preview._drawPreview(d.id);
return;
}
vboxVMDetailsSections.preview._drawPreview(d.id);
if(vboxVMStates.isRunning(d)) {
var timer = $('#vboxPane').data('vboxPreviewTimer-'+d.id);
if(timer) window.clearInterval(timer);
$('#vboxPane').data('vboxPreviewTimer-'+d.id,
window.setInterval('vboxVMDetailsSections.preview._drawPreview("'+d.id+'")',
vboxVMDetailsSections.preview._updateInterval * 1000));
}
},
/**
* Draw the preview window from VM screenshot
*
*/
_drawPreview: function(vmid) {
// Does the target still exist?
if(!$('#vboxDetailsGeneralTable-'+vmid)[0]) {
var timer = $('#vboxPane').data('vboxPreviewTimer-'+vmid);
if(timer) window.clearInterval(timer);
$('#vboxPane').data('vboxPreviewTimer-'+vmid, null);
return;
}
var width = $('#vboxPane').data('vboxConfig')['previewWidth'];
// Get fresh VM data
var vm = vboxVMDataMediator.getVMData(vmid);
var __vboxDrawPreviewImg = new Image();
__vboxDrawPreviewImg.onload = function() {
// Does the target still exist?
if(!$('#vboxDetailsGeneralTable-'+vmid)[0]) {
var timer = $('#vboxPane').data('vboxPreviewTimer-'+vmid);
if(timer) window.clearInterval(timer);
$('#vboxPane').data('vboxPreviewTimer-'+vmid, null);
return;
}
// Set and cache dimensions
if(this.height > 0) {
// If width != requested width, it is scaled
if(this.width != $('#vboxPane').data('vboxConfig')['previewWidth']) {
height = this.height * (width / this.width);
// Not scaled
} else {
height = this.height;
}
vboxVMDetailsSections.preview._resolutionCache[vmid] = {
'height': height
};
// Height of image is 0
} else {
// Check for cached resolution
if(vboxVMDetailsSections.preview._resolutionCache[vmid]) {
height = vboxVMDetailsSections.preview._resolutionCache[vmid].height;
} else {
height = parseInt(width / $('#vboxPane').data('vboxConfig')['previewAspectRatio']);
}
// Clear interval if set
var timer = $('#vboxPane').data('vboxPreviewTimer-'+vmid);
if(timer) window.clearInterval(timer);
}
// Get fresh VM data
var vm = vboxVMDataMediator.getVMData(vmid);
// Return if this is stale
if(!vm) {
var timer = $('#vboxPane').data('vboxPreviewTimer-'+vmid);
if(timer) window.clearInterval(timer);
$('#vboxPane').data('vboxPreviewTimer-'+vmid, null);
return;
}
// Canvas redraw
if(isCanvasSupported()) {
// Reset height and width
$('#vboxPreviewCanvas-'+vmid).attr({'width':(width+(vboxVMDetailsSections.preview._screenPadding*2)),'height':(height+(vboxVMDetailsSections.preview._screenPadding*2))});
// Redraw preview
vboxDrawPreviewCanvas($('#vboxPreviewCanvas-'+vmid)[0], (this.height <= 1 ? null: this), vm.name, width, height);
// HTML update
} else {
var baseStr = 'vboxDetailsGeneralTable-'+vmid;
if(this.height <= 1) {
// IE uses filter
if($.browser.msie) {
$('#'+baseStr+' img.vboxDetailsPreviewImg').css({'display':'none',"filter":""})
.attr({'src':'images/vbox/blank.gif'}).parent().css({'background':'#000'});
} else {
$('#'+baseStr+' img.vboxDetailsPreviewImg').css({'display':'none'}).attr('src','images/vbox/blank.gif');
}
$('#'+baseStr+' div.vboxDetailsPreviewVMName').css('display','');
// Resize name?
$('#vboxDetailsGeneralTable-'+vmid+ ' div.vboxDetailsPreviewVMName span.textFill').textFill({maxFontPixels:20,'height':(height),'width':(width)});
} else {
$('#'+baseStr+' div.vboxDetailsPreviewVMName').css('display','none');
$('#'+baseStr+' img.vboxDetailsPreviewImg').css({'display':'','height':height+'px','width':width+'px'});
// IE uses filter
if($.browser.msie) {
if(vboxVMStates.isRunning(vm)) {
// Setting background URL keeps image from being
// requested again, but does not allow us to set
// the size of the image. This is fine, since the
// image is returned in the size requested.
$('#'+baseStr+' img.vboxDetailsPreviewImg').css({"filter":""}).parent().css({'background':'url('+this.src+')'});
} else {
// This causes the image to be requested again, but
// is the only way to size the background image.
// Saved preview images are not returned in the size
// requested and must be resized at runtime by
// the browser.
$('#'+baseStr+' img.vboxDetailsPreviewImg').css({"filter":"progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', src='"+this.src+"', sizingMethod='scale')"}).parent().css({'background':'#000'});
}
} else {
$('#'+baseStr+' img.vboxDetailsPreviewImg').css({'background-image':'url('+this.src+')','background-size':(width+1) +'px ' + (height+1)+'px'});
}
}
$('#'+baseStr+' div.vboxDetailsPreviewWrap').css({'height':height+'px','width':width+'px'});
$('#'+baseStr+' img.vboxPreviewMonitor').css('width',width+'px');
$('#'+baseStr+' img.vboxPreviewMonitorSide').css('height',height+'px');
}
};
// Update disabled? State not Running or Saved
if(!vboxVMDetailsSections.preview._updateInterval || (!vboxVMStates.isRunning(vm) && !vboxVMStates.isSaved(vm))) {
__vboxDrawPreviewImg.height = 0;
__vboxDrawPreviewImg.onload();
} else {
// Running VMs get random numbers.
// Saved are based on last state change to try to let the browser cache Saved screen shots
var randid = vm.lastStateChange;
if(vboxVMStates.isRunning(vm)) {
var currentTime = new Date();
randid = Math.floor(currentTime.getTime() / 1000);
}
__vboxDrawPreviewImg.src = vboxEndpointConfig.screen+'?width='+(width)+'&vm='+vmid+'&randid='+randid;
}
},
/**
* Rows wrapper
*/
rows: function(d) {
var timer = $('#vboxPane').data('vboxPreviewTimer-'+d.id);
if(timer) window.clearInterval(timer);
$('#vboxPane').data('vboxPreviewTimer-'+d.id, null);
return (isCanvasSupported() ? vboxVMDetailsSections.preview._rows_canvas(d): vboxVMDetailsSections.preview._rows_html(d));
},
/**
* Draws preview window in HTML
*/
_rows_html: function(d) {
var width = $('#vboxPane').data('vboxConfig')['previewWidth'];
if(!width) width = $('#vboxPane').data('vboxConfig')['previewWidth'] = 180;
width = parseInt(width);
var height = parseInt(width / $('#vboxPane').data('vboxConfig')['previewAspectRatio']);
// Check for cached resolution
if(vboxVMDetailsSections.preview._resolutionCache[d.id]) {
width = vboxVMDetailsSections.preview._resolutionCache[d.id].width;
height = vboxVMDetailsSections.preview._resolutionCache[d.id].height;
}
var divOut1 = "
" +
"
"+$('').html(d.name).text()+"
"+
"
";
return [
{
data: "
"+
"
"+
"
"+
"
"+
"
"+
"
"+
"
"+
"
"+
"
"+
"
"+
"
"+
""+
divOut1+
"
"+
"
"+
"
"+
"
"+
"
"+
"
"+
"
"+
"
"+
"
"+
"
"+
"
",
rawRow: true
}
];
},
/**
* Draws preview on canvas object
*/
_rows_canvas: function(d) {
var width = $('#vboxPane').data('vboxConfig')['previewWidth'];
if(!width) width = $('#vboxPane').data('vboxConfig')['previewWidth'] = 180;
width = parseInt(width);
var height = parseInt(width / $('#vboxPane').data('vboxConfig')['previewAspectRatio']);
// Check for cached resolution
if(vboxVMDetailsSections.preview._resolutionCache[d.id]) {
height = vboxVMDetailsSections.preview._resolutionCache[d.id].height;
}
// Create canvas and initially draw VM name
var previewCanvas = $('').attr({'id':'vboxPreviewCanvas-'+d.id,'width':(width+(vboxVMDetailsSections.preview._screenPadding*2)),'height':(height+(vboxVMDetailsSections.preview._screenPadding*2))});
vboxDrawPreviewCanvas(previewCanvas[0], null, d.name, width, height);
// Draw screenshot if it's running or saved
if(vboxVMDetailsSections.preview._updateInterval > 0 && (vboxVMStates.isRunning(d) || vboxVMStates.isSaved(d))) {
// Preview image kicks off timer when it is loaded
var preview = new Image();
preview.onload = function(){
// Set and cache dimensions
if(this.height > 0) {
// If width != requested width, it is scaled
if(this.width != $('#vboxPane').data('vboxConfig')['previewWidth']) {
height = this.height * (width/this.width);
// Not scaled
} else {
height = this.height;
}
$('#vboxPreviewCanvas-'+d.id).attr({'width':(width+(vboxVMDetailsSections.preview._screenPadding*2)),'height':(height+(vboxVMDetailsSections.preview._screenPadding*2))});
// Check for cached resolution
} else if(vboxVMDetailsSections.preview._resolutionCache[d.id]) {
height = vboxVMDetailsSections.preview._resolutionCache[d.id].height;
} else {
height = parseInt(width / $('#vboxPane').data('vboxConfig')['previewAspectRatio']);
}
vboxVMDetailsSections.preview._resolutionCache[d.id] = {'width':width,'height':height};
// Draw this screen shot
vboxDrawPreviewCanvas($('#vboxPreviewCanvas-'+d.id)[0], preview, d.name, width, height);
// Kick off timer if VM is running
if(vboxVMStates.isRunning(d)) {
window.setTimeout(function(){
$('#vboxPane').data('vboxPreviewTimer-'+d.id, window.setInterval('vboxVMDetailsSections.preview._drawPreview("'+d.id+'")',vboxVMDetailsSections.preview._updateInterval*1000));
},vboxVMDetailsSections.preview._updateInterval*1000);
}
};
var randid = d.lastStateChange;
if(vboxVMStates.isRunning(d)) {
var currentTime = new Date();
randid = Math.floor(currentTime.getTime() / 1000);
}
preview.src = vboxEndpointConfig.screen+'?width='+(width)+'&vm='+d.id+'&randid='+randid;
}
/* Return row */
return [ {
data: $('')
.attr({'class':'vboxInvisble'})
.append(previewCanvas),
rawRow: true
}];
}
},
/*
* Display
*/
display: {
title: 'Display',
icon: 'vrdp_16px.png',
settingsLink: 'Display',
redrawMachineEvents: ['OnVRDEServerInfoChanged','OnVRDEServerChanged','OnMachineStateChanged'],
rows: [
{
title: "Video Memory",
callback: function(d) {
return trans('%1 MB').replace('%1',d['VRAMSize']);
}
},{
title: 'Remote Desktop Server Port',
callback: function(d) {
var chost = vboxGetVRDEHost(d);
// Get ports
var rowStr = d['VRDEServer']['ports'];
// Just this for snapshots
if(d._isSnapshot) return rowStr;
// Display links?
if((d['state'] == 'Running' || d['state'] == 'Paused') && d['VRDEServerInfo']) {
if(d['VRDEServerInfo']['port'] <= 0) {
rowStr = '' + rowStr + '';
// RDP
} else if(d['VRDEServer']['VRDEExtPack'].indexOf("VNC") == -1) {
rowStr = " " + d['VRDEServerInfo']['port'] + "";
rowStr += ' (' + chost + ':' + d['VRDEServerInfo']['port'] + ')';
// VNC
} else {
rowStr = " " + d['VRDEServerInfo']['port'] + "";
rowStr += ' (' + chost + ':' + d['VRDEServerInfo']['port'] + ')';
}
} else {
rowStr += ' ('+chost+')';
}
return rowStr;
},
html: true,
condition: function(d) {
// Running and paused states have real-time console info
if(!d._isSnapshot && (d['state'] == 'Running' || d['state'] == 'Paused')) {
return d.VRDEServer && (d.VRDEServer.enabled);
}
return (d['VRDEServer'] && (d._isSnapshot || d['VRDEServer']['VRDEExtPack']) && d['VRDEServer']['enabled'] && d['VRDEServer']['ports']);
}
},{
title: "Remote Desktop Server",
callback: function(d) {
return trans('Disabled','VBoxGlobal',null,'details report (VRDE Server)');
},
condition: function(d) {
return !(vboxVMDetailsSections.display.rows[1].condition(d));
}
}
]
},
/*
* Storage controllers
*/
storage: {
title: 'Storage',
icon: 'hd_16px.png',
settingsLink: 'Storage',
redrawMachineEvents: ['OnMediumChanged', 'OnMachineStateChanged'],
_refreshVMMedia: function(vmid, mid) {
// See if medium is there
var mRefresh = true;
if(!vboxMedia.getMediumById(mid)) {
mRefresh = vboxAjaxRequest('vboxGetMedia');
}
var l = new vboxLoader();
l.showLoading();
$.when(mRefresh, vboxVMDataMediator.refreshVMData(vmid)).done(function(d){
if(d && d.responseData) $('#vboxPane').data('vboxMedia',d.responseData);
}).always(function(){
l.removeLoading();
});
},
rows: function(d) {
var rows = new Array();
for(var a = 0; a < d['storageControllers'].length; a++) {
var con = d['storageControllers'][a];
// Controller name
rows[rows.length] = {
title: trans('Controller: %1','UIMachineSettingsStorage').replace('%1',$('').text(con.name).html()),
callback: function(){return'';}
};
// Each attachment.
for(var b = 0; b < d['storageControllers'][a]['mediumAttachments'].length; b++) {
var portName = vboxStorage[d['storageControllers'][a].bus].slotName(d['storageControllers'][a]['mediumAttachments'][b].port, d['storageControllers'][a]['mediumAttachments'][b].device);
// Medium / host device info
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);
// Do we need to reload media?
if(d['storageControllers'][a]['mediumAttachments'][b].medium && d['storageControllers'][a]['mediumAttachments'][b].medium.id && medium === null) {
if(!d._isSnapshot) {
portDesc = '"+trans('Refresh','UIVMLogViewer')+"";
} else {
portDesc = trans('Refresh','UIVMLogViewer');
}
} else {
// Get base medium (snapshot -> virtual disk file)
var it = false;
if(medium && medium.base && (medium.base != medium.id)) {
it = true;
medium = vboxMedia.getMediumById(medium.base);
}
portDesc = vboxMedia.mediumPrint(medium,false,it);
}
rows[rows.length] = {
title: portName,
indented: true,
data: (d['storageControllers'][a]['mediumAttachments'][b].type == 'DVD' ? trans('[Optical Drive]','UIGDetails') + ' ': '') + portDesc,
html: true
};
}
}
return rows;
}
},
/*
* Audio
*/
audio: {
title: 'Audio',
icon: 'sound_16px.png',
settingsLink: 'Audio',
rows: [
{
title: "Disabled",
language_context: ['VBoxGlobal', null, 'details report (audio)'],
cssClass: 'vboxDetailsNone',
condition: function(d) { return !d['audioAdapter']['enabled']; },
data: ''
},{
title: "Host Driver",
language_context: 'VBoxGlobal',
callback: function(d) {
return trans(vboxAudioDriver(d['audioAdapter']['audioDriver']),'VBoxGlobal');
},
condition: function(d) { return d['audioAdapter']['enabled']; }
},{
title: "Controller",
language_context: 'VBoxGlobal',
callback: function (d) {
return trans(vboxAudioController(d['audioAdapter']['audioController']),'VBoxGlobal');
},
condition: function(d) { return d['audioAdapter']['enabled']; }
}
]
},
/*
* Network adapters
*/
network: {
icon: 'nw_16px.png',
title: 'Network',
redrawMachineEvents: ['OnNetworkAdapterChanged','OnMachineStateChanged'],
settingsLink: 'Network',
rows: function(d) {
var vboxDetailsTableNics = 0;
var rows = [];
for(var i = 0; i < d['networkAdapters'].length; i++) {
nic = d['networkAdapters'][i];
// compose extra info
var adp = '';
if(nic.enabled) {
vboxDetailsTableNics++;
switch(nic.attachmentType) {
case 'Null':
adp = trans('Not attached','VBoxGlobal');
break;
case 'Bridged':
adp = trans('Bridged adapter, %1').replace('%1', nic.bridgedInterface);
break;
case 'HostOnly':
adp = trans('Host-only adapter, \'%1\'').replace('%1', nic.hostOnlyInterface);
break;
case 'NAT':
// 'NATNetwork' ?
adp = trans('NAT','VBoxGlobal');
break;
case 'Internal':
adp = trans('Internal network, \'%1\'').replace('%1', $('').text(nic.internalNetwork).html());
break;
case 'Generic':
// Check for properties
if(nic.properties) {
adp = trans('Generic Driver, \'%1\' { %2 }','UIGDetails').replace('%1', $('').text(nic.genericDriver).html());
var np = nic.properties.split("\n");
adp = adp.replace('%2', np.join(" ,"));
break;
}
adp = trans('Generic Driver, \'%1\'','UIGDetails').replace('%1', $('').text(nic.genericDriver).html());
break;
case 'VDE':
adp = trans('VDE network, \'%1\'').replace('%1', $('').text(nic.VDENetwork).html());
break;
case 'NATNetwork':
adp = trans('NAT Network, \'%1\'','UIGDetails').replace('%1', $('').text(nic.NATNetwork).html());
break;
}
rows[rows.length] = {
title: trans("Adapter %1").replace('%1',(i + 1)),
data: trans(vboxNetworkAdapterType(nic.adapterType)).replace(/\(.*\)/,'') + ' (' + adp + ')'
};
}
}
// No enabled nics
if(vboxDetailsTableNics == 0) {
rows[rows.length] = {
title: trans('Disabled','VBoxGlobal',null,'details report (network)'),
cssClass: 'vboxDetailsNone'
};
// Link nic to guest networking info?
} else if(d['state'] == 'Running') {
rows[rows.length] = {
title: '',
data: '('+trans('Guest Network Adapters')+')',
html: true
};
}
return rows;
}
},
/*
* Serial Ports
*/
serialports: {
title: 'Serial Ports',
icon: 'serial_port_16px.png',
settingsLink: 'SerialPorts',
rows: function(d) {
var rows = [];
var vboxDetailsTableSPorts = 0;
for(var i = 0; i < d['serialPorts'].length; i++) {
p = d['serialPorts'][i];
if(!p.enabled) continue;
// compose extra info
var xtra = vboxSerialPorts.getPortName(p.IRQ,p.IOBase);
var mode = p.hostMode;
xtra += ', ' + trans(vboxSerialMode(mode),'VBoxGlobal');
if(mode != 'Disconnected') {
xtra += ' (' + $('').text(p.path).html() + ')';
}
rows[rows.length] = {
title: trans("Port %1",'VBoxGlobal',null,'details report (serial ports)').replace('%1',(i + 1)),
data: xtra,
html: true
};
vboxDetailsTableSPorts++;
}
if(vboxDetailsTableSPorts == 0) {
rows[rows.length] = {
title: trans('Disabled','VBoxGlobal',null,'details report (serial ports)'),
cssClass: 'vboxDetailsNone'
};
}
return rows;
}
},
/*
* Parallel ports
*/
parallelports: {
title: 'Parallel Ports',
language_context: 'UISettingsDialogMachine',
icon: 'parallel_port_16px.png',
settingsLink: 'ParallelPorts',
condition: function() { return $('#vboxPane').data('vboxConfig').enableLPTConfig; },
rows: function(d) {
var rows = [];
var vboxDetailsTableSPorts = 0;
for(var i = 0; i < d['parallelPorts'].length; i++) {
p = d['parallelPorts'][i];
if(!p.enabled) continue;
// compose extra info
var xtra = trans(vboxParallelPorts.getPortName(p.IRQ,p.IOBase));
xtra += ' (' + $('').text(p.path).html() + ')';
rows[rows.length] = {
title: trans("Port %1",'VBoxGlobal',null,'details report (parallel ports)').replace('%1',(i + 1)),
data: xtra
};
vboxDetailsTableSPorts++;
}
if(vboxDetailsTableSPorts == 0) {
rows[0] = {
title: trans('Disabled','VBoxGlobal',null,'details report (parallel ports)'),
cssClass: 'vboxDetailsNone'
};
}
return rows;
}
},
/*
* USB
*/
usb: {
icon: 'usb_16px.png',
title: 'USB',
language_context: 'UIGDetails',
settingsLink: 'USB',
rows: function(d) {
var rows = [];
var usbEnabled = false;
var usbType = 'OHCI';
for(var i = 0; i < d.USBControllers.length; i++) {
var listUSBType = d.USBControllers[i].type;
if(listUSBType == 'OHCI') {
usbEnabled = true;
}
switch(listUSBType) {
case 'OHCI':
if(usbType == 'EHCI')
break;
case 'EHCI':
if(usbType == 'XHCI')
break;
default:
usbType = listUSBType;
}
}
if(usbEnabled) {
rows.push({
title: trans("USB Controller", 'UIGDetails', null, 'details (usb)'),
data: usbType
});
var tot = 0;
var act = 0;
for(var i = 0; i < d.USBDeviceFilters.length; i++) {
tot++;
if(d.USBDeviceFilters[i].active) act++;
}
rows.push({
title: trans("Device Filters", 'UIGDetails', null, 'details (usb)'),
data: trans('%1 (%2 active)', 'UIGDetails', null, 'details (usb)').replace('%1',tot).replace('%2',act)
});
} else {
rows.push({
title: trans("Disabled", 'UIGDetails', null, 'details report (USB)'),
cssClass: 'vboxDetailsNone'
});
}
return rows;
}
},
/*
* Shared folders list
*/
sharedfolders: {
title: 'Shared Folders',
language_context: 'UIGDetails',
icon: 'sf_16px.png',
settingsLink: 'SharedFolders',
rows: function(d) {
if(!d['sharedFolders'] || d['sharedFolders'].length < 1) {
return [{
title: trans('None',null,null,'details report (shared folders)'),
cssClass: 'vboxDetailsNone'
}];
}
return [{
title: trans('Shared Folders', 'UIGDetails'),
data: d['sharedFolders'].length
}];
}
},
/*
* VM Description
*/
description: {
icon: 'description_16px.png',
title: 'Description',
language_context: 'UIGDetails',
settingsLink: 'General:2',
rows: function(d) {
return [{
title: '',
data: $('
').attr({'class':'vboxDetailRow'}).append(
$('
').attr({'class':'vboxDetailDescriptionCell','colspan':'2'})
.html(d.description.length ? $('').text(d.description).html(): ''+trans("None",null,null,'details report (description)')+'')
),
rawRow: true
}];
}
}
};
/**
* Common VM Group Actions - most of these are passed off
* to the vboxChooser object
*
* @namespace vboxVMGroupActions
*/
var vboxVMGroupActions = {
'newmachine': {
label: 'New Machine...',
icon: 'vm_new',
name: 'new',
click: function(){
vboxVMActions['new'].click(true);
},
enabled: function() {
return $('#vboxPane').data('vboxSession').admin;
}
},
addmachine: {
label: 'Add Machine...',
icon: 'vm_add',
name: 'add',
click: function() {
vboxVMActions['add'].click(true);
},
enabled: function() {
return $('#vboxPane').data('vboxSession').admin;
}
},
rename: {
label: 'Rename Group...',
icon: 'vm_group_name',
name: 'rename_group',
enabled: function() {
if(!$('#vboxPane').data('vboxSession').admin) return false;
if(!vboxChooser._editable) return false;
var gElm = vboxChooser.getSelectedGroupElements()[0];
if(!gElm) return false;
if($('#vboxPane').data('vboxConfig')['phpVboxGroups']) return true;
if($(gElm).find('td.vboxVMSessionOpen')[0]) return false;
return true;
},
click: function() {
vboxChooser.renameSelectedGroup();
}
},
ungroup: {
label: 'Ungroup',
icon: 'vm_group_remove',
name: 'remove_group',
enabled: function() {
if(!vboxChooser._editable) return false;
if(!$('#vboxPane').data('vboxSession').admin) return false;
var gElm = vboxChooser.getSelectedGroupElements()[0];
if(!gElm) return false;
if($('#vboxPane').data('vboxConfig')['phpVboxGroups']) return true;
if($(gElm).find('td.vboxVMSessionOpen')[0]) return false;
return true;
},
click: function() {
vboxChooser.unGroupSelectedGroup();
}
},
'sort': {
label: 'Sort',
icon:'sort',
name: 'sort_group',
click: function() {
vboxChooser.sortSelectedGroup();
},
enabled: function() {
if(!vboxChooser._editable) return false;
return $('#vboxPane').data('vboxSession').admin;
}
}
};
/**
* Common VM Actions - These assume that they will be run on the selected VM as
* stored in vboxChooser.getSingleSelected()
*
* @namespace vboxVMActions
*/
var vboxVMActions = {
/** Invoke the new virtual machine wizard */
'new':{
label: 'New...',
icon: 'vm_new',
name: 'new',
click: function(fromGroup){
new vboxWizardNewVMDialog((fromGroup ? $(vboxChooser.getSelectedGroupElements()[0]).data('vmGroupPath'): '')).run();
}
},
/** Add a virtual machine via its settings file */
add: {
label: 'Add...',
icon: 'vm_add',
name: 'add',
click: function(){
vboxFileBrowser($('#vboxPane').data('vboxSystemProperties').defaultMachineFolder,function(f){
if(!f) return;
var l = new vboxLoader();
l.add('machineAdd',function(){return;},{'file':f});
l.onLoad = function(){
var lm = new vboxLoader();
lm.add('vboxGetMedia',function(d){$('#vboxPane').data('vboxMedia',d.responseData);});
lm.run();
};
l.run();
},false,trans('Add existing virtual machine','UIActionPool'),'images/vbox/machine_16px.png',true);
}
},
/** Start VM */
start: {
label: 'Start',
name: 'start',
icon: 'vm_start',
_startedVMs: {},
/*
* Subscribe to machine state changes to remove from _startedVMs
*
*/
_subscribedStateChanges: false,
_subscribeStateChanges: function() {
if(vboxVMActions.start._subscribedStateChanges)
return;
vboxVMActions.start._subscribedStateChanges = true;
$('#vboxPane').on('vboxOnMachineStateChanged', function(e, eventData) {
// We did not start this VM
if(!vboxVMActions.start._startedVMs[eventData.machineId])
return;
var vmState = {'state': eventData.state};
if(vboxVMStates.isPaused(vmState) || vboxVMStates.isStuck(vmState) || vboxVMStates.isPoweredOff(vmState)) {
delete vboxVMActions.start._startedVMs[eventData.machineId];
}
});
},
/*
* Subscribe to machine runtime errors to ask for medium
* encryption password(s)
*/
_subscribedRuntimeErrors: false,
_subscribeRuntimeErrors: function() {
if(vboxVMActions.start._subscribedRuntimeErrors)
return;
vboxVMActions.start._subscribedRuntimeErrors = true;
// Trigger VM media encryption password dialog
$('#vboxPane').on('vboxOnRuntimeError',function(e, eventData) {
// We did not start this VM
if(!vboxVMActions.start._startedVMs[eventData.machineId])
return;
// Disk encryption missing
if(eventData.id == "DrvVD_DEKMISSING") {
// Encryption passwords are needed to start VM
var vmData = vboxVMDataMediator.getVMDetails(eventData.machineId);
vboxVMActions.start._getEncryptionPasswordsStartVM(vmData);
return;
}
// Display runtime error
var message = vboxVMDataMediator.getVMData(eventData.machineId).title + ' - ' +
eventData.message;
vboxAlert(message);
});
},
/* Get passwords and start VM Logic */
_getEncryptionPasswordsStartVM: function(vm, validIds) {
// Encrypted media
var encIds = vboxMedia.getEncryptedMediaIds(
vboxStorage.getAttachedBaseMedia(vm)
);
// Get encryption password(s)
var pwPromise = vboxMediumEncryptionPasswordsDialog(vm.name, encIds, validIds);
$.when(pwPromise).done(function(pwdata) {
// vboxVMActions.start._getEncryptionPasswordsStartVM(vm);
$.when(vboxAjaxRequest('consoleAddDiskEncryptionPasswords',
{'vm':vm.id,'passwords':pwdata}))
.done(function(retData) {
if(!retData)
return;
var failed = retData.responseData.failed.length;
var valid = retData.responseData.accepted;
if(failed) {
var acknowledged = vboxAlert(trans('Unable to enter password!')+
'
'+retData.responseData.errors.join(' ')+'
');
$.when(acknowledged).done(function(){
vboxVMActions.start._getEncryptionPasswordsStartVM(vm, valid);
})
}
// VMs will be started automatically if the password(s) supplied were correct
})
}).fail(function(){
// Clicked cancel
// TODO: "Close VM" dialog
});
},
/* Start a single VM */
_startVM: function(vm) {
var reqPromise = $.Deferred();
$.when(vm,vboxAjaxRequest('machineSetState',{'vm':vm.id,'state':'powerUp'}))
// VM started and / or progress op returned
.done(function(evm,d){
// check for progress operation
if(d && d.responseData && d.responseData.progress) {
if(vboxVMStates.isSaved(evm)) icon = 'progress_state_restore_90px.png';
else icon = 'progress_start_90px.png';
reqPromise.resolve();
vboxProgress({'progress':d.responseData.progress,'persist':d.persist}, function(){return;},
icon, trans('Start selected virtual machines','UIActionPool'), evm.name);
} else {
reqPromise.reject();
}
});
return reqPromise;
},
click: function (btn) {
// Setup
vboxVMActions.start._subscribeRuntimeErrors();
vboxVMActions.start._subscribeStateChanges();
// Should the "First Run" wizard be started
////////////////////////////////////////////
var firstRun = function(vm) {
var frDef = $.Deferred();
$.when(vboxVMDataMediator.getVMDetails(vm.id)).done(function(d) {
// Not first run?
if(d.GUI.FirstRun != 'yes') {
// Just resolve, nothing to do
frDef.resolve(d);
return;
}
// Check for CD/DVD drive attachment that has no CD/DVD
var cdFound = false;
for(var i = 0; i < d.storageControllers.length; i++) {
for(var a = 0; a < d.storageControllers[i].mediumAttachments.length; a++) {
if(d.storageControllers[i].mediumAttachments[a].type == "DVD" &&
d.storageControllers[i].mediumAttachments[a].medium == null) {
cdFound = true;
break;
}
}
}
// No CD/DVD attachment
if(!cdFound) {
// Just resolve, nothing to do
frDef.resolve(d);
return;
}
// First time run
$.when(d, new vboxWizardFirstRunDialog(d).run()).done(function(vm2start){
frDef.resolve(vm2start);
});
});
return frDef.promise();
};
// Start each eligable selected vm
//////////////////////////////////////
var startVMs = function() {
var vms = vboxChooser.getSelectedVMsData();
var vmsToStart = [];
for(var i = 0; i < vms.length; i++) {
if(vboxVMStates.isPaused(vms[i]) || vboxVMStates.isPoweredOff(vms[i]) || vboxVMStates.isSaved(vms[i])) {
vmsToStart[vmsToStart.length] = vms[i];
}
}
(function runVMsToStart(vms){
(vms.length && $.when(firstRun(vms.shift())).done(function(vm){
// Save the fact that we started this VM
vboxVMActions.start._startedVMs[vm.id] = true;
$.when(vboxVMActions.start._startVM(vm)).done(function() {
// Loop
runVMsToStart(vms);
});
}));
})(vmsToStart);
};
// Check for memory limit
// Paused VMs are already using all their memory
if($('#vboxPane').data('vboxConfig').vmMemoryStartLimitWarn) {
var freeMem = 0;
var baseMem = 0;
// Host memory needs to be checked
var loadData = [vboxAjaxRequest('hostGetMeminfo')];
// Load details of each machine to get memory info
var vms = vboxChooser.getSelectedVMsData();
for(var i = 0; i < vms.length; i++) {
if(vboxVMStates.isPoweredOff(vms[i]) || vboxVMStates.isSaved(vms[i]))
loadData[loadData.length] = vboxVMDataMediator.getVMDataCombined(vms[i].id);
}
// Show loading screen while this is occuring
var l = new vboxLoader('vboxHostMemCheck');
l.showLoading();
// Load all needed data
$.when.apply($, loadData).done(function() {
// Remove loading screen
l.removeLoading();
// First result is host memory info
freeMem = arguments[0].responseData;
// Add memory of each VM
for(var i = 1; i < arguments.length; i++) {
// Paused VMs are already using their memory
if(vboxVMStates.isPaused(arguments[i])) continue;
// memory + a little bit of overhead
baseMem += (arguments[i].memorySize + 50);
}
// subtract offset
if($('#vboxPane').data('vboxConfig').vmMemoryOffset)
freeMem -= $('#vboxPane').data('vboxConfig').vmMemoryOffset;
// Memory breaches warning threshold
if(baseMem >= freeMem) {
var buttons = {};
buttons[trans('Yes','QIMessageBox')] = function(){
$(this).remove();
startVMs();
};
freeMem = Math.max(0,freeMem);
vboxConfirm('
The selected virtual machine(s) require(s) approximately ' + baseMem +
'MB of memory, but your VirtualBox host only has ' + freeMem + 'MB '+
($('#vboxPane').data('vboxConfig').vmMemoryOffset ? ' (-'+$('#vboxPane').data('vboxConfig').vmMemoryOffset+'MB)': '') +
' free.
Are you sure you want to start the virtual machine(s)?
',buttons,trans('No','QIMessageBox'));
// Memory is fine. Start vms.
} else {
startVMs();
}
});
// No memory limit warning configured
} else {
startVMs();
}
},
enabled: function () {
return (vboxChooser.isSelectedInState('Paused') || vboxChooser.isSelectedInState('PoweredOff') || vboxChooser.isSelectedInState('Saved'));
}
},
/** Invoke VM settings dialog */
settings: {
label: 'Settings...',
icon: 'vm_settings',
name: 'settings',
click: function(){
vboxVMsettingsDialog(vboxChooser.getSingleSelectedId());
},
enabled: function () {
return vboxChooser && vboxChooser.selectionMode == vboxSelectionModeSingleVM &&
(vboxChooser.isSelectedInState('Running') || vboxChooser.isSelectedInState('Paused') || vboxChooser.isSelectedInState('Editable'));
}
},
/** Clone a VM */
clone: {
label: 'Clone...',
icon: 'vm_clone',
name: 'clone',
click: function(){
new vboxWizardCloneVMDialog({vm:vboxChooser.getSingleSelected()}).run();
},
enabled: function () {
return (vboxChooser.selectionMode == vboxSelectionModeSingleVM && vboxChooser.isSelectedInState('PoweredOff'));
}
},
/** Refresh a VM's details */
refresh: {
label: 'Refresh',
language_context: 'UIVMLogViewer',
icon:'refresh',
name: 'refresh',
click:function(){
var vmid = vboxChooser.getSingleSelectedId();
var l = new vboxLoader();
l.showLoading();
$.when(vboxVMDataMediator.refreshVMData(vmid)).done(function(){
l.removeLoading();
});
},
enabled: function () {return(vboxChooser.selectedVMs.length ==1);}
},
/** Delete / Remove a VM */
remove: {
label: 'Remove...',
icon: 'vm_delete',
name: 'remove_vm',
click:function(){
///////////////////
// Remove VMs
//////////////////
var removeCopies = function() {
var vmList = [];
var vmNames = [];
var vms = vboxChooser.getSelectedVMsData();
for(var i = 0; i < vms.length; i++) {
if(vboxVMStates.isPoweredOff(vms[i]) && vboxChooser.vmHasUnselectedCopy(vms[i].id)) {
vmList[vmList.length] = vms[i].id;
vmNames[vmNames.length] = vms[i].name;
}
}
if(vmList.length) {
var rcDef = $.Deferred();
var buttons = {};
buttons[trans('Remove', 'UIMessageCenter')] = function() {
$(this).empty().remove();
vboxChooser.removeVMs(vmList);
rcDef.resolve();
}
vmNames = ''+vmNames.join(', ')+'';
var q = trans('
You are about to remove following virtual machine items from the machine list:
%1
Do you wish to proceed?
','UIMessageCenter').replace('%1',vmNames);
vboxConfirm(q,buttons,undefined,function(){
rcDef.resolve();
});
return rcDef.promise();
}
return true;
}
//////////////////
// Unregister VMs
///////////////////
$.when(removeCopies()).done(function() {
var unregisterVMs = function(keepFiles, vms) {
var vms = vboxChooser.getSelectedVMsData();
for(var i = 0; i < vms.length; i++) {
if(vboxVMStates.isPoweredOff(vms[i]) || vboxVMStates.isInaccessible(vms[i])) {
// Remove each selected vm
$.when(vms[i].name, vboxAjaxRequest('machineRemove',
{'vm':vms[i].id,'delete':(keepFiles ? '0': '1')}))
.done(function(vmname, d){
// check for progress operation
if(d && d.responseData && d.responseData.progress) {
vboxProgress({'progress':d.responseData.progress,'persist':d.persist},function(){return;},'progress_delete_90px.png',
trans('Remove selected virtual machines', 'UIActionPool'), vmname);
}
});
}
}
};
var buttons = {};
buttons[trans('Delete all files','UIMessageCenter')] = function(){
$(this).empty().remove();
unregisterVMs(false);
};
buttons[trans('Remove only','UIMessageCenter')] = function(){
$(this).empty().remove();
unregisterVMs(true);
};
var vmNames = [];
var vms = vboxChooser.getSelectedVMsData();
for(var i = 0; i < vms.length; i++) {
if((vboxVMStates.isPoweredOff(vms[i]) || vboxVMStates.isInaccessible(vms[i])) && !vboxChooser.vmHasUnselectedCopy(vms[i].id)) {
vmNames[vmNames.length] = vms[i].name;
}
}
if(vmNames.length) {
vmNames = ''+vmNames.join(', ')+'';
var q = trans('
You are about to remove following virtual machines from the machine list:
%1
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.
','UIMessageCenter').replace('%1',vmNames);
vboxConfirm(q,buttons);
}
});
},
enabled: function () {
if(!vboxChooser._editable) return false;
return (vboxChooser.isSelectedInState('PoweredOff') || vboxChooser.isSelectedInState('Inaccessible'));
}
},
/** Create a group from VM * */
group: {
label: 'Group',
icon: 'vm_group_create',
name: 'create_group',
click: function() {
vboxChooser.groupSelectedItems();
},
enabled: function() {
if(!$('#vboxPane').data('vboxSession').admin)
return false;
if (!vboxChooser || (vboxChooser.getSingleSelectedId() == 'host'))
return false;
if(!vboxChooser._editable) return false;
return vboxChooser.isSelectedInState('Editable');
}
},
/** Discard VM State */
discard: {
label: 'Discard Saved State...',
icon: 'vm_discard',
name: 'discard',
click: function(){
var buttons = {};
buttons[trans('Discard','UIMessageCenter')] = function(){
$(this).empty().remove();
var vms = vboxChooser.getSelectedVMsData();
for(var i = 0; i < vms.length; i++) {
if(vboxVMStates.isSaved(vms[i])) {
vboxAjaxRequest('machineSetState',{'vm':vms[i].id,'state':'discardSavedState'});
}
}
};
var vmNames = [];
var vms = vboxChooser.getSelectedVMsData();
for(var i = 0; i < vms.length; i++) {
if(vboxVMStates.isSaved(vms[i])) {
vmNames[vmNames.length] = vms[i].name;
}
}
if(vmNames.length) {
vmNames = ''+vmNames.join(', ')+'';
vboxConfirm(trans('
Are you sure you want to discard the saved state of the following virtual machines?
%1
This operation is equivalent to resetting or powering off the machine without doing a proper shutdown of the guest OS.
','UIMessageCenter').replace('%1',vmNames),buttons);
}
},
enabled:function(){
return vboxChooser.isSelectedInState('Saved');
}
},
/** Install Guest Additions **/
guestAdditionsInstall: {
label: 'Install Guest Additions...',
icon: 'guesttools',
name: 'guesttools',
click: function(vmid, mount_only) {
if(!vmid)
vmid = vboxChooser.getSingleSelected().id;
$.when(vboxAjaxRequest('consoleGuestAdditionsInstall',{'vm':vmid,'mount_only':mount_only})).done(function(d){
// Progress operation returned. Guest Additions are being updated.
if(d && d.responseData && d.responseData.progress) {
vboxProgress({'progress':d.responseData.progress,'persist':d.persist,'catcherrs':1},function(d){
// Error updating guest additions
if(!d.responseData.result && d.responseData.error && d.responseData.error.err) {
if(d.responseData.error.err != 'VBOX_E_NOT_SUPPORTED') {
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});
}
vboxVMActions['guestAdditionsInstall'].click(vmid, true);
return;
}
},'progress_install_guest_additions_90px.png',trans('Install Guest Additions...','UIActionPool').replace(/\./g,''));
// Media was mounted
} else if(d.responseData && d.responseData.result && d.responseData.result == 'mounted') {
// Media must be refreshed
var ml = new vboxLoader();
ml.add('vboxGetMedia',function(dat){$('#vboxPane').data('vboxMedia',dat.responseData);});
ml.run();
if(d.responseData.errored)
vboxAlert(trans('Failed to update Guest Additions. The Guest Additions installation image will be mounted to provide a manual installation.','UIMessageCenter'));
// There's no CDROM drive
} else if(d.responseData && d.responseData.result && d.responseData.result == 'nocdrom') {
var vm = vboxVMDataMediator.getVMData(vmid);
vboxAlert(trans("
Could not insert the VirtualBox Guest Additions " +
"installer CD image into the virtual machine %1, as the machine " +
"has no CD/DVD-ROM drives. Please add a drive using the " +
"storage page of the virtual machine settings dialog.
').css({'vertical-align':'bottom'}).append(this._buttonElement).appendTo(tbl);
$(targetElm).attr({'name':self.name}).addClass('vboxToolbarSmall vboxButtonMenu vboxEnablerTrigger').on('disable',self.disable).on('enable',self.enable).append(tbl);
// Generate and attach menu
self.mediaMenu.menuElement();
self.getButtonElm().contextMenu({
menu: self.mediaMenu.menu_id(),
mode:'menu',
button: 0
},self.mediaMenu.menuCallback);
};
/**
* Update media menu
*
* @see vboxMediaMenu.menuUpdateMedia
*/
this.menuUpdateMedia = self.mediaMenu.menuUpdateMedia;
}
/**
* Media menu class
*
* @constructor
* @class vboxMediaMenu
* @param {String}
* type - type of media to display
* @param {Function}
* callback - callback function to run when medium is selected
* @param {String}
* mediumPath - path to use when selecting media
*/
function vboxMediaMenu(type,callback,mediumPath) {
var self = this;
this.type = type;
this.callback = callback;
this.mediumPath = mediumPath;
this.removeEnabled = true;
/**
* Generate menu element ID
*
* @memberOf vboxMediaMenu
* @return {String} string to use for menu node id
*/
this.menu_id = function(){
return 'vboxMediaListMenu'+self.type;
};
/**
* Generate menu element
*
* @memberOf vboxMediaMenu
* @return {HTMLNode} menu element
*/
this.menuElement = function() {
// Pointer already held
if(self._menuElm) return self._menuElm;
var id = self.menu_id();
// Hold pointer
self._menu = new vboxMenu({'name': id, 'id': id});
// Add menu
self._menu.addMenu(self.menuGetDefaults());
// Update recent list
self.menuUpdateRecent();
self._menu.update();
self._menuElm = $('#'+self.menu_id());
return self._menuElm;
};
/**
* Generate and return host drives
*
* @memberOf vboxMediaMenu
* @return {Array} array of objects that can be added to menu
*/
this.menuGetDrives = function() {
var menu = [];
// Add host drives
var meds = vboxMedia.mediaForAttachmentType(self.type);
for(var i =0; i < meds.length; i++) {
if(!meds[i].hostDrive) continue;
menu[menu.length] = {'name':meds[i].id,'label':vboxMedia.getName(meds[i])};
}
return menu;
};
/**
* List of default menu items to use for media of type self.type
*
* @memberOf vboxMediaMenu
* @return {Array} List of default menu items to use for media of type
* self.type
*/
this.menuGetDefaults = function () {
menus = [];
switch(self.type) {
// HardDisk defaults
case 'HardDisk':
// create hard disk
menus[menus.length] = {'name':'createD','icon':'hd_new','label':trans('Create a new hard disk...','UIMachineSettingsStorage')};
// choose hard disk
menus[menus.length] = {'name':'chooseD','icon':'select_file','label':trans('Choose a virtual hard disk file...','UIMachineSettingsStorage')};
// Add VMM?
if($('#vboxPane').data('vboxConfig').enableAdvancedConfig) {
menus[menus.length] = {'name':'vmm','icon':'diskimage','label':trans('Virtual Media Manager...','UIActionPool')};
}
// recent list place holder
menus[menus.length] = {'name':'vboxMediumRecentBefore','cssClass':'vboxMediumRecentBefore','enabled':function(){return false;},'hide_on_disabled':true};
break;
// CD/DVD Defaults
case 'DVD':
// Choose disk image
menus[menus.length] = {'name':'chooseD','icon':'select_file','label':trans('Choose a virtual optical disk file...','UIMachineSettingsStorage')};
// Add VMM?
if($('#vboxPane').data('vboxConfig').enableAdvancedConfig) {
menus[menus.length] = {'name':'vmm','icon':'diskimage','label':trans('Virtual Media Manager...','UIActionPool')};
}
// Add host drives
menus = menus.concat(self.menuGetDrives());
// Add remove drive
menus[menus.length] = {'name':'removeD','icon':'cd_unmount','cssClass':'vboxMediumRecentBefore',
'label':trans('Remove disk from virtual drive','UIMachineSettingsStorage'),'separator':true,
'enabled':function(){return self.removeEnabled;}};
break;
// Floppy defaults
default:
// Choose disk image
menus[menus.length] = {'name':'chooseD','icon':'select_file','label':trans('Choose a virtual floppy disk file...','UIMachineSettingsStorage')};
// Add VMM?
if($('#vboxPane').data('vboxConfig').enableAdvancedConfig) {
menus[menus.length] = {'name':'vmm','icon':'diskimage','label':trans('Virtual Media Manager...','UIActionPool')};
}
// Add host drives
menus = menus.concat(self.menuGetDrives());
// Add remove drive
menus[menus.length] = {'name':'removeD','icon':'fd_unmount','cssClass':'vboxMediumRecentBefore',
'label':trans('Remove disk from virtual drive','UIMachineSettingsStorage'),'separator':true,
'enabled':function(){return self.removeEnabled;}};
break;
}
return menus;
};
/**
* Update "recent" media list menu items
*
* @memberOf vboxMediaMenu
*/
this.menuUpdateRecent = function() {
var elm = $('#'+self.menu_id());
var list = $('#vboxPane').data('vboxRecentMedia')[self.type];
elm.children('li.vboxMediumRecent').remove();
var ins = elm.children('li.vboxMediumRecentBefore').last();
for(var i = 0; i < list.length; i++) {
if(!list[i]) continue;
if(!vboxMedia.getMediumByLocation(list[i])) continue;
$('').attr({'class':'vboxMediumRecent'}).append(
$('').attr({
'href': '#path:'+list[i],
'title': list[i]
}).text(vboxBasename(list[i]))
).insertBefore(ins);
}
};
/**
* Update media checkbox and "remove image from disk" menu item
*
* @memberOf vboxMediaMenu
* @param {String}
* medium - medium attached to controller
* @return null
*/
this.menuUpdateMedia = function(medium) {
self.removeEnabled = (medium ? true: false);
if(!self._menu) self.menuElement();
else self._menu.update();
// Remove all 'attached' spans
var elm = $('#'+self.menu_id());
$(elm).find('a.vboxCheckMark').removeClass('vboxCheckMark').children('span.vboxCheckMark').remove();
if(medium) {
if(medium.hostDrive) {
$(elm).find('a[href="#'+medium.id+'"]').addClass('vboxCheckMark').prepend($('').attr({'class':'vboxCheckMark'}).html('✓'));
} else {
$(elm).find('a[href="#path:'+medium.location+'"]').addClass('vboxCheckMark').prepend($('').attr({'class':'vboxCheckMark'}).html('✓'));
}
}
};
/**
* Update recent media menu and global recent media list
*
* @memberOf vboxMediaMenu
* @param {Object}
* m - medium object
* @param {Boolean}
* skipPathAdd - don't add medium's path to vbox's list of recent
* media paths
*/
this.updateRecent = function(m, skipPathAdd) {
if(vboxMedia.updateRecent(m, skipPathAdd)) { // returns true if
// recent media list has
// changed
// Update menu
self.menuUpdateRecent();
}
};
/**
* Function called when menu item is selected
*
* @memberOf vboxMediaMenu
* @param {String}
* action - menu item's href value (text in a href="#...")
*/
this.menuCallback = function(action) {
switch(action) {
// Create hard disk
case 'createD':
$.when(new vboxWizardNewHDDialog({'path':(self.mediumPath ? self.mediumPath: $('#vboxPane').data('vboxRecentMediaPaths')[self.type])+$('#vboxPane').data('vboxConfig').DSEP}).run())
.done(function(id){
if(!id) return;
var med = vboxMedia.getMediumById(id);
self.callback(med);
self.menuUpdateRecent(med);
});
break;
// VMM
case 'vmm':
// vboxVMMDialog(select,type,hideDiff,mPath)
$.when(vboxVMMDialog(true,self.type,true,(self.mediumPath ? self.mediumPath: $('#vboxPane').data('vboxRecentMediaPaths')[self.type]))).done(function(m){
if(m) {
self.callback(vboxMedia.getMediumById(m));
self.menuUpdateRecent();
}
});
break;
// Choose medium file
case 'chooseD':
vboxMedia.actions.choose(self.mediumPath,self.type,function(med){
self.callback(med);
self.menuUpdateRecent();
});
break;
// Existing medium was selected
default:
if(action.indexOf('path:') == 0) {
var path = action.substring(5);
var med = vboxMedia.getMediumByLocation(path);
if(med && med.deviceType == self.type) {
self.callback(med);
self.updateRecent(med,true);
}
return;
}
var med = vboxMedia.getMediumById(action);
self.callback(med);
self.updateRecent(med,true);
}
};
}
/**
* Menu class for use with context or button menus
*
* @constructor
* @class vboxMenu
* @param {Object}
* name - name of menu
* id - optional HTMLNode id of menu to use
* menuItems - list of menu items to add
* language_context - translation language context
*/
function vboxMenu(options) {
var self = this;
this.name = options.name;
this.menuItems = {};
this.iconStringDisabled = '_disabled';
this.id = options.id;
this.language_context = options.language_context;
/**
* return menu id
*
* @memberOf vboxMenu
* @return {String} the HTMLNode id of this menu
*/
this.menuId = function() {
if(self.id) return self.id;
return self.name + 'Menu';
};
/**
* Add menu to menu object
*
* @memberOf vboxMenu
* @param {Object}
* m - menu configuration object
*/
this.addMenu = function(m) {
$('#vboxPane').append(self.menuElement(m,self.menuId()));
};
/**
* Traverse menu configuration object and generate a
*
* containing menu items
*
* @memberOf vboxMenu
* @param {Object}
* m - menu configuration object
* @param {String}
* mid - the optional id to use for the generated HTMLNode
* @return {HTMLNode} menu
*
* node containing menu items and submenus
*/
this.menuElement = function(m, mid) {
var ul = null;
if(mid) {
ul = $('#'+mid);
if(ul && ul.length) {
ul.empty();
} else {
ul = $('
').attr({'id':mid,'style':'display: none;'});
}
} else {
ul = $('
').attr({'style':'display: none;'});
}
ul.addClass('contextMenu');
for(var i in m) {
if(typeof m[i] == 'function') continue;
// get menu item
var item = self.menuItem(m[i]);
// Add to menu list
self.menuItems[m[i].name] = m[i];
// Children?
if(m[i].children && m[i].children.length) {
item.append(self.menuElement(m[i].children, self.menuId()+'-submenu-' + i));
}
ul.append(item);
}
return ul;
};
/**
* Menu click callback
*
* @memberOf vboxMenu
* @param {Integer}
* i - menu item index number
* @param {Object}
* item - optional selected item
* @return return value of menu item's click() function
*/
this.menuClickCallback = function(i, item) {
return self.menuItems[i].click(item);
};
/**
* generate menu item HTML
*
* @memberOf vboxMenu
* @param {Object}
* i - menu item's configuration object
* @return {HTMLNode}
*
containing menu item
*/
this.menuItem = function(i) {
var label = trans(i.label, i.language_context ? i.language_context : self.language_context);
return $('
').addClass((i.separator ? 'separator': '')).addClass((i.cssClass ? i.cssClass: '')).append($('')
.html(label)
.attr({
'style': (i.icon ? 'background-image: url('+self.menuIcon(i,false)+')': ''),
'id': self.name+i.name,'href':'#'+i.name
}));
};
/**
* Return a URL to use for menu item's icon
*
* @memberOf vboxMenu
* @param {Object}
* i - menu item configuration object
* @param {Boolean}
* disabled - whether or not the icon should be disabled
* @return {String} url to icon to use
*/
this.menuIcon = function(i,disabled) {
if(!i.icon) return '';
return 'images/vbox/' + i.icon + (disabled ? self.iconStringDisabled: '') + '_16px.png';
};
/**
* Update all menu items
*
* @memberOf vboxMenu
* @param {Object}
* testObj - object used to test for enabled()
* @return null
*/
this.update = function(testObj) {
for(var i in self.menuItems) {
// If enabled function doesn't exist, there's nothing to do
if(!self.menuItems[i].enabled) continue;
var mi = $('#'+self.name+i);
// Disabled
if(!self.menuItems[i].enabled(testObj)) {
if(self.menuItems[i].hide_on_disabled) {
mi.parent().hide();
} else {
self.disableItem(i,mi);
}
// Enabled
} else {
if(self.menuItems[i].hide_on_disabled) {
mi.parent().show();
} else {
self.enableItem(i,mi);
}
}
}
};
/**
* Disable a single menu item
*
* @memberOf vboxMenu
* @param {String}
* i - menu item's name
* @param {Object}
* mi - optional menu item HTMLNode or jQuery object
*/
this.disableItem = function(i, mi) {
if(!mi) mi = $('#'+self.name+i);
if(self.menuItems[i].icon)
mi.css({'background-image':'url('+self.menuIcon(self.menuItems[i],true)+')'}).parent().addClass('disabled');
else
mi.parent().addClass('disabled');
};
/**
* Enable a single menu item
*
* @memberOf vboxMenu
* @param {String}
* i - menu item's name
* @param {Object}
* mi - optional menu item HTMLNode or jQuery object
*/
this.enableItem = function(i, mi) {
if(!mi) mi = $('#'+self.name+i);
if(self.menuItems[i].icon)
mi.css({'background-image':'url('+self.menuIcon(self.menuItems[i],false)+')'}).parent().removeClass('disabled');
else
mi.parent().removeClass('disabled');
};
// Just add menu items if there were passed
if(options.menuItems) self.addMenu(options.menuItems);
}
/**
* Menu bar class
*
* @constructor
* @class vboxMenuBar
* @param {String}
* name - name of this menu bar
*/
function vboxMenuBar(options) {
var self = this;
this.name = options.name;
this.language_context = options.language_context;
this.menus = new Array();
this.menuClick = {};
this.iconStringDisabled = options.iconStringDisabled ? options.iconStringDisabled : '_disabled';
/**
* Add a menu to this object
*
* @memberOf vboxMenuBar
* @param {Object}
* m - menu configuration object
* @return void
*/
this.addMenu = function(m) {
// Create menu object
m.menuObj = new vboxMenu({'name': m.name, language_context: m.language_context ? m.language_context : self.language_context});
// Propagate config
m.menuObj.iconStringDisabled = self.iconStringDisabled;
// Add menu
m.menuObj.addMenu(m.menu);
self.menus[self.menus.length] = m;
};
/**
* Render menu bar to element identified by ID
*
* @memberOf vboxMenuBar
* @param {String}
* id - HTMLNode id of node to add menu bar to
*/
this.renderTo = function(id) {
$('#'+id).prepend($('').attr({'class':'vboxMenuBar','id':self.name+'MenuBar'}));
for(var i = 0; i < self.menus.length; i++) {
var label = trans(self.menus[i].label, self.menus[i].language_context ? self.menus[i].language_context : self.language_context);
$('#'+self.name+'MenuBar').append(
$('').attr({'id':'vboxMenuBarMenu'+self.name+self.menus[i].name}).html(label)
.contextMenu({
menu: self.menus[i].menuObj.menuId(),
button: 0,
mode: 'menu',
menusetup: function(el) {
$(el).parent().data('vboxMenubarActive', true);
$(document).one('mousedown',function(){
$(el).parent().data('vboxMenubarActive', false);
});
}
},
self.menus[i].menuObj.menuClickCallback
).hover(
function(){
$(this).addClass('vboxBordered');
if($(this).parent().data('vboxMenubarActive')) {
// Hide any showing menu
var e = jQuery.Event("mouseup", {button:0});
$(this).trigger(e);
var e = jQuery.Event("mousedown", {button:0});
$(this).trigger(e);
var e = jQuery.Event("mouseup", {button:0});
$(this).trigger(e);
}
},
function(){
$(this).removeClass('vboxBordered');
}
).disableSelection()
);
}
};
/**
* Update Menu items
*
* @memberOf vboxMenuBar
* @param {Object}
* item - item to use in menu configuration items' update() test
* @return void
*/
this.update = function(item) {
for(var i = 0; i < self.menus.length; i++) {
// check for enabled function on entire menu object
if(self.menus[i].enabled) {
if(self.menus[i].enabled(item)) {
$('#vboxMenuBarMenu'+self.name+self.menus[i].name).show();
} else {
$('#vboxMenuBarMenu'+self.name+self.menus[i].name).hide();
continue;
}
}
self.menus[i].menuObj.update(item);
}
};
}
/**
* Loads data, scripts, and HTML files and optionally displays "Loading ..."
* screen until all items have completed loading
*
* @param {String} name - unique name for this loader. used to generate id
* of "Loading..." div
* @constructor
* @class vboxLoader
*/
function vboxLoader(name) {
if(!name) name = '';
var self = this;
this._load = [];
this.onLoad = null;
this._loadStarted = {};
this.hideRoot = false;
this.noLoadingScreen = false;
this.name = name;
this._data = [];
this._files = [];
/**
* Add data item to list of items to load
*
* @memberOf vboxLoader
* @param {String}
* dataFunction - function to pass to vboxAjaxRequest()
* @param {Function}
* callback - callback to run when data is returned
* @param {Object}
* params - params to pass to vboxAjaxRequest()
* @see vboxAjaxRequest()
*/
this.add = function(dataFunction, callback, params) {
if(!this.name) this.name = dataFunction + 'Loader';
this._data[this._data.length] = vboxAjaxRequest(dataFunction,params).done(callback);
};
/**
* Add file to list of items to load
*
* @memberOf vboxLoader
* @param {String}
* file - URL of file to load
* @param {Function}
* callback - callback to run when file is loaded
* @see vboxAjaxRequest()
*/
this.addFile = function(file,callback) {
this._files[this._files.length] = {
'callback': callback,
'file': file
};
};
/**
* Add file to list of items to load. Append resulting file to element.
*
* @memberOf vboxLoader
* @param {String}
* file - URL of file to load
* @param {jQueryObject}
* elm - element to append file to
*/
this.addFileToDOM = function(file,elm) {
if(elm === undefined) elm = $('#vboxPane');
var callback = function(f){elm.append(f);};
self.addFile(file,callback);
};
/**
* Show loading screen
*
*/
this.showLoading = function() {
var div = $('').attr({'id':'vboxLoaderDialog'+self.name,'title':'','style':'display: none;','class':'vboxLoaderDialog'});
var tbl = $('