- Timestamp:
- Mar 27, 2013 11:03:05 AM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 84561
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp
r45193 r45203 251 251 pEvent->ignore(); 252 252 253 /* Should we close application? */ 254 bool fCloseApplication = false; 255 switch (uisession()->machineState()) 256 { 257 case KMachineState_Running: 258 case KMachineState_Paused: 259 case KMachineState_Stuck: 260 case KMachineState_LiveSnapshotting: 261 case KMachineState_Teleporting: // TODO: Test this! 262 case KMachineState_TeleportingPausedVM: // TODO: Test this! 253 /* Should we shutdown UI session? */ 254 bool fShutdownSession = false; 255 256 /* Make sure machine is in one of the allowed states: */ 257 KMachineState machineState = uisession()->machineState(); 258 if ( machineState != KMachineState_Running 259 && machineState != KMachineState_Paused 260 && machineState != KMachineState_Stuck 261 && machineState != KMachineState_LiveSnapshotting 262 && machineState != KMachineState_Teleporting 263 && machineState != KMachineState_TeleportingPausedVM) 264 return; 265 266 /* Get the machine: */ 267 CMachine m = machine(); 268 269 /* If there is a close hook script defined: */ 270 const QString& strScript = m.GetExtraData(GUI_CloseActionHook); 271 if (!strScript.isEmpty()) 272 { 273 /* Execute asynchronously and leave: */ 274 QProcess::startDetached(strScript, QStringList() << m.GetId()); 275 return; 276 } 277 278 /* Prepare close-dialog: */ 279 QWidget *pParentDlg = mwManager().realParentWindow(this); 280 QPointer<UIVMCloseDialog> pCloseDlg = new UIVMCloseDialog(pParentDlg); 281 mwManager().registerNewParent(pCloseDlg, pParentDlg); 282 283 /* Assign close-dialog pixmap: */ 284 pCloseDlg->pmIcon->setPixmap(vboxGlobal().vmGuestOSTypeIcon(m.GetOSTypeId())); 285 286 /* Check which close-actions are resticted: */ 287 QStringList restictedActionsList = m.GetExtraData(GUI_RestrictedCloseActions).split(','); 288 bool fIsStateSavingAllowed = !restictedActionsList.contains("SaveState", Qt::CaseInsensitive); 289 bool fIsACPIShutdownAllowed = !restictedActionsList.contains("Shutdown", Qt::CaseInsensitive); 290 bool fIsPowerOffAllowed = !restictedActionsList.contains("PowerOff", Qt::CaseInsensitive); 291 bool fIsPowerOffAndRestoreAllowed = fIsPowerOffAllowed && !restictedActionsList.contains("Restore", Qt::CaseInsensitive); 292 293 /* Make 'Save state' button visible/hidden depending on restriction: */ 294 pCloseDlg->mRbSave->setVisible(fIsStateSavingAllowed); 295 pCloseDlg->mTxSave->setVisible(fIsStateSavingAllowed); 296 /* Make 'Save state' button enabled/disabled depending on machine-state: */ 297 pCloseDlg->mRbSave->setEnabled(machineState != KMachineState_Stuck); 298 299 /* Make 'ACPI shutdown button' visible/hidden depending on restriction: */ 300 pCloseDlg->mRbShutdown->setVisible(fIsACPIShutdownAllowed); 301 pCloseDlg->mTxShutdown->setVisible(fIsACPIShutdownAllowed); 302 /* Make 'ACPI shutdown button' enabled/disabled depending on ACPI-state & machine-state: */ 303 bool fIsACPIEnabled = session().GetConsole().GetGuestEnteredACPIMode(); 304 pCloseDlg->mRbShutdown->setEnabled(fIsACPIEnabled && machineState != KMachineState_Stuck); 305 306 /* Make 'Power off' button visible/hidden depending on restriction: */ 307 pCloseDlg->mRbPowerOff->setVisible(fIsPowerOffAllowed); 308 pCloseDlg->mTxPowerOff->setVisible(fIsPowerOffAllowed); 309 310 /* Make the Restore Snapshot checkbox visible/hidden depending on snapshot count & restrictions: */ 311 pCloseDlg->mCbDiscardCurState->setVisible(fIsPowerOffAndRestoreAllowed && m.GetSnapshotCount() > 0); 312 if (!m.GetCurrentSnapshot().isNull()) 313 pCloseDlg->mCbDiscardCurState->setText(pCloseDlg->mCbDiscardCurState->text().arg(m.GetCurrentSnapshot().GetName())); 314 315 /* Possible extra-data option values for close-dialog: */ 316 QString strSave("save"); 317 QString strShutdown("shutdown"); 318 QString strPowerOff("powerOff"); 319 QString strDiscardCurState("discardCurState"); 320 321 /* Read the last user's choice for the given VM: */ 322 QStringList lastAction = m.GetExtraData(GUI_LastCloseAction).split(','); 323 324 /* Check which button should be initially chosen: */ 325 QRadioButton *pRadioButtonToChoose = 0; 326 327 /* If choosing 'last choice' is possible: */ 328 if (lastAction[0] == strSave && fIsStateSavingAllowed) 329 { 330 pRadioButtonToChoose = pCloseDlg->mRbSave; 331 } 332 else if (lastAction[0] == strShutdown && fIsACPIShutdownAllowed && fIsACPIEnabled) 333 { 334 pRadioButtonToChoose = pCloseDlg->mRbShutdown; 335 } 336 else if (lastAction[0] == strPowerOff && fIsPowerOffAllowed) 337 { 338 pRadioButtonToChoose = pCloseDlg->mRbPowerOff; 339 if (fIsPowerOffAndRestoreAllowed) 340 pCloseDlg->mCbDiscardCurState->setChecked(lastAction.count() > 1 && lastAction[1] == strDiscardCurState); 341 } 342 /* Else 'default choice' will be used: */ 343 else 344 { 345 if (fIsACPIShutdownAllowed && fIsACPIEnabled) 346 pRadioButtonToChoose = pCloseDlg->mRbShutdown; 347 else if (fIsPowerOffAllowed) 348 pRadioButtonToChoose = pCloseDlg->mRbPowerOff; 349 else if (fIsStateSavingAllowed) 350 pRadioButtonToChoose = pCloseDlg->mRbSave; 351 } 352 353 /* If some radio button chosen: */ 354 if (pRadioButtonToChoose) 355 { 356 /* Check and focus it: */ 357 pRadioButtonToChoose->setChecked(true); 358 pRadioButtonToChoose->setFocus(); 359 } 360 /* If no one of radio buttons was chosen: */ 361 else 362 { 363 /* Destroy and leave: */ 364 delete pCloseDlg; 365 return; 366 } 367 368 /* This flag will keep the status of every further logical operation: */ 369 bool fSuccess = true; 370 /* This flag determines if VM was paused before we called for close-event: */ 371 bool fWasPaused = uisession()->isPaused(); 372 373 if (fSuccess) 374 { 375 /* Pause VM if necessary: */ 376 if (!fWasPaused) 377 fSuccess = uisession()->pause(); 378 } 379 380 if (fSuccess) 381 { 382 /* Preventing auto-closure: */ 383 machineLogic()->setPreventAutoClose(true); 384 385 /* Show the close-dialog: */ 386 bool fDialogAccepted = pCloseDlg->exec() == QDialog::Accepted; 387 388 /* What was the decision? */ 389 enum DialogDecision { DD_Cancel, DD_Save, DD_Shutdown, DD_PowerOff }; 390 DialogDecision decision; 391 if (!fDialogAccepted) 392 decision = DD_Cancel; 393 else if (pCloseDlg->mRbSave->isChecked()) 394 decision = DD_Save; 395 else if (pCloseDlg->mRbShutdown->isChecked()) 396 decision = DD_Shutdown; 397 else 398 decision = DD_PowerOff; 399 bool fDiscardCurState = pCloseDlg->mCbDiscardCurState->isChecked(); 400 bool fDiscardCheckboxVisible = pCloseDlg->mCbDiscardCurState->isVisibleTo(pCloseDlg); 401 402 /* Destroy the dialog early: */ 403 delete pCloseDlg; 404 405 /* Was dialog accepted? */ 406 if (fDialogAccepted) 263 407 { 264 /* Get the machine: */ 265 CMachine m = machine(); 266 267 /* Check if there is a close hook script defined. */ 268 const QString& strScript = m.GetExtraData(GUI_CloseActionHook); 269 if (!strScript.isEmpty()) 408 /* Process decision: */ 409 CConsole console = session().GetConsole(); 410 switch (decision) 270 411 { 271 QProcess::startDetached(strScript, QStringList() << m.GetId()); 272 return; 412 case DD_Save: 413 { 414 /* Prepare the saving progress: */ 415 CProgress progress = console.SaveState(); 416 fSuccess = console.isOk(); 417 if (fSuccess) 418 { 419 /* Show the saving progress dialog: */ 420 msgCenter().showModalProgressDialog(progress, m.GetName(), ":/progress_state_save_90px.png", this); 421 fSuccess = progress.GetResultCode() == 0; 422 if (fSuccess) 423 fShutdownSession = true; 424 else 425 msgCenter().cannotSaveMachineState(progress); 426 } 427 else 428 msgCenter().cannotSaveMachineState(console); 429 break; 430 } 431 case DD_Shutdown: 432 { 433 /* Unpause VM to let it grab the ACPI shutdown event: */ 434 fSuccess = uisession()->unpause(); 435 if (fSuccess) 436 { 437 /* Prevent subsequent unpause request: */ 438 fWasPaused = true; 439 /* Signal ACPI shutdown (if there is no ACPI device, the operation will fail): */ 440 console.PowerButton(); 441 fSuccess = console.isOk(); 442 if (!fSuccess) 443 msgCenter().cannotACPIShutdownMachine(console); 444 } 445 break; 446 } 447 case DD_PowerOff: 448 { 449 /* Prepare the power down progress: */ 450 CProgress progress = console.PowerDown(); 451 fSuccess = console.isOk(); 452 if (fSuccess) 453 { 454 /* Show the power down progress: */ 455 msgCenter().showModalProgressDialog(progress, m.GetName(), ":/progress_poweroff_90px.png", this); 456 fSuccess = progress.GetResultCode() == 0; 457 if (fSuccess) 458 { 459 /* Discard the current state if requested: */ 460 if (fDiscardCurState && fDiscardCheckboxVisible) 461 { 462 /* Prepare the snapshot discard progress: */ 463 CSnapshot snapshot = m.GetCurrentSnapshot(); 464 CProgress progress = console.RestoreSnapshot(snapshot); 465 fSuccess = console.isOk(); 466 if (fSuccess) 467 { 468 /* Show the snapshot discard progress: */ 469 msgCenter().showModalProgressDialog(progress, m.GetName(), ":/progress_snapshot_discard_90px.png", this); 470 fSuccess = progress.GetResultCode() == 0; 471 if (!fSuccess) 472 msgCenter().cannotRestoreSnapshot(progress, snapshot.GetName()); 473 } 474 else 475 msgCenter().cannotRestoreSnapshot(console, snapshot.GetName()); 476 } 477 if (fSuccess) 478 fShutdownSession = true; 479 } 480 else 481 msgCenter().cannotStopMachine(progress); 482 } 483 else 484 { 485 /* This can happen if VBoxSVC is not running: */ 486 COMResult res(console); 487 if (FAILED_DEAD_INTERFACE(res.rc())) 488 fShutdownSession = true; 489 else 490 msgCenter().cannotStopMachine(console); 491 } 492 break; 493 } 494 default: 495 break; 273 496 } 274 275 /* Prepare close-dialog: */276 QWidget *pDlgParent = mwManager().realParentWindow(this);277 UIVMCloseDialog *pDlg = new UIVMCloseDialog(pDlgParent);278 mwManager().registerNewParent(pDlg, pDlgParent);279 280 /* Assign close-dialog pixmap: */281 pDlg->pmIcon->setPixmap(vboxGlobal().vmGuestOSTypeIcon(m.GetOSTypeId()));282 283 /* Check which close actions are disallowed: */284 QStringList restictedActionsList = m.GetExtraData(GUI_RestrictedCloseActions).split(',');285 bool fIsStateSavingAllowed = !restictedActionsList.contains("SaveState", Qt::CaseInsensitive);286 bool fIsACPIShutdownAllowed = !restictedActionsList.contains("Shutdown", Qt::CaseInsensitive);287 bool fIsPowerOffAllowed = !restictedActionsList.contains("PowerOff", Qt::CaseInsensitive);288 bool fIsPowerOffAndRestoreAllowed = fIsPowerOffAllowed && !restictedActionsList.contains("Restore", Qt::CaseInsensitive);289 290 /* Make Save State button visible/hidden depending on restriction: */291 pDlg->mRbSave->setVisible(fIsStateSavingAllowed);292 pDlg->mTxSave->setVisible(fIsStateSavingAllowed);293 /* Make Save State button enabled/disabled depending on machine state: */294 pDlg->mRbSave->setEnabled(uisession()->machineState() != KMachineState_Stuck);295 296 /* Make ACPI shutdown button visible/hidden depending on restriction: */297 pDlg->mRbShutdown->setVisible(fIsACPIShutdownAllowed);298 pDlg->mTxShutdown->setVisible(fIsACPIShutdownAllowed);299 /* Make ACPI shutdown button enabled/disabled depending on ACPI state & machine state: */300 bool isACPIEnabled = session().GetConsole().GetGuestEnteredACPIMode();301 pDlg->mRbShutdown->setEnabled(isACPIEnabled && uisession()->machineState() != KMachineState_Stuck);302 303 /* Make Power Off button visible/hidden depending on restriction: */304 pDlg->mRbPowerOff->setVisible(fIsPowerOffAllowed);305 pDlg->mTxPowerOff->setVisible(fIsPowerOffAllowed);306 307 /* Make the Restore Snapshot checkbox visible/hidden depending on snapshots count & restrictions: */308 pDlg->mCbDiscardCurState->setVisible(fIsPowerOffAndRestoreAllowed && m.GetSnapshotCount() > 0);309 if (!m.GetCurrentSnapshot().isNull())310 pDlg->mCbDiscardCurState->setText(pDlg->mCbDiscardCurState->text().arg(m.GetCurrentSnapshot().GetName()));311 312 /* Choice string tags for close-dialog: */313 QString strSave("save");314 QString strShutdown("shutdown");315 QString strPowerOff("powerOff");316 QString strDiscardCurState("discardCurState");317 318 /* Read the last user's choice for the given VM: */319 QStringList lastAction = m.GetExtraData(GUI_LastCloseAction).split(',');320 321 /* Check which button should be initially chosen: */322 QRadioButton *pRadioButton = 0;323 324 /* If choosing 'last choice' is possible: */325 if (lastAction[0] == strSave && fIsStateSavingAllowed)326 {327 pRadioButton = pDlg->mRbSave;328 }329 else if (lastAction[0] == strShutdown && fIsACPIShutdownAllowed && isACPIEnabled)330 {331 pRadioButton = pDlg->mRbShutdown;332 }333 else if (lastAction[0] == strPowerOff && fIsPowerOffAllowed)334 {335 pRadioButton = pDlg->mRbPowerOff;336 if (fIsPowerOffAndRestoreAllowed)337 pDlg->mCbDiscardCurState->setChecked(lastAction.count() > 1 && lastAction[1] == strDiscardCurState);338 }339 /* Else 'default choice' will be used: */340 else341 {342 if (fIsACPIShutdownAllowed && isACPIEnabled)343 pRadioButton = pDlg->mRbShutdown;344 else if (fIsPowerOffAllowed)345 pRadioButton = pDlg->mRbPowerOff;346 else if (fIsStateSavingAllowed)347 pRadioButton = pDlg->mRbSave;348 }349 350 /* If some radio button was chosen: */351 if (pRadioButton)352 {353 /* Check and focus it: */354 pRadioButton->setChecked(true);355 pRadioButton->setFocus();356 }357 /* If no one of radio buttons was chosen: */358 else359 {360 /* Just break and leave: */361 delete pDlg;362 pDlg = 0;363 break;364 }365 366 /* This flag will keep the status of every further logical operation: */367 bool fSuccess = true;368 369 /* This flag is set if we must terminate the VM, even if server calls fail */370 bool fForce = false;371 372 /* Pause before showing dialog if necessary: */373 bool fWasPaused = uisession()->isPaused() || uisession()->machineState() == KMachineState_Stuck;374 if (!fWasPaused)375 fSuccess = uisession()->pause();376 497 377 498 if (fSuccess) 378 499 { 379 /* Preventing auto-closure: */ 380 machineLogic()->setPreventAutoClose(true); 381 382 /* Show the close-dialog: */ 383 bool fDialogAccepted = pDlg->exec() == QDialog::Accepted; 384 385 /* What was the decision? */ 386 enum DialogDecision { DD_Cancel, DD_Save, DD_Shutdown, DD_PowerOff }; 387 DialogDecision decision; 388 if (!fDialogAccepted) 389 decision = DD_Cancel; 390 else if (pDlg->mRbSave->isChecked()) 391 decision = DD_Save; 392 else if (pDlg->mRbShutdown->isChecked()) 393 decision = DD_Shutdown; 394 else 395 decision = DD_PowerOff; 396 bool fDiscardCurState = pDlg->mCbDiscardCurState->isChecked(); 397 bool fDiscardCheckboxVisible = pDlg->mCbDiscardCurState->isVisibleTo(pDlg); 398 399 /* Destroy the dialog early: */ 400 delete pDlg; 401 pDlg = 0; 402 403 /* Was dialog accepted? */ 404 if (fDialogAccepted) 500 /* Read the last user's choice for the given VM: */ 501 QStringList prevAction = m.GetExtraData(GUI_LastCloseAction).split(','); 502 /* Memorize the last user's choice for the given VM: */ 503 QString strLastAction = strPowerOff; 504 switch (decision) 405 505 { 406 /* Process decision: */ 407 CConsole console = session().GetConsole(); 408 fSuccess = false; 409 switch (decision) 506 case DD_Save: strLastAction = strSave; break; 507 case DD_Shutdown: strLastAction = strShutdown; break; 508 case DD_PowerOff: 410 509 { 411 case DD_Save: 412 { 413 /* Prepare the saving progress: */ 414 CProgress progress = console.SaveState(); 415 if (console.isOk()) 416 { 417 /* Show the saving progress dialog: */ 418 msgCenter().showModalProgressDialog(progress, m.GetName(), ":/progress_state_save_90px.png", this); 419 if (progress.GetResultCode() == 0) 420 fSuccess = true; 421 else 422 msgCenter().cannotSaveMachineState(progress); 423 } 424 else 425 msgCenter().cannotSaveMachineState(console); 426 if (fSuccess) 427 fCloseApplication = true; 428 break; 429 } 430 case DD_Shutdown: 431 { 432 /* Unpause the VM to let it grab the ACPI shutdown event: */ 433 uisession()->unpause(); 434 /* Prevent the subsequent unpause request: */ 435 fWasPaused = true; 436 /* Signal ACPI shutdown (if there is no ACPI device, the operation will fail): */ 437 console.PowerButton(); 438 if (console.isOk()) 439 fSuccess = true; 440 else 441 msgCenter().cannotACPIShutdownMachine(console); 442 break; 443 } 444 case DD_PowerOff: 445 { 446 /* Prepare the power down progress: */ 447 CProgress progress = console.PowerDown(); 448 if (console.isOk()) 449 { 450 /* Show the power down progress: */ 451 msgCenter().showModalProgressDialog(progress, m.GetName(), ":/progress_poweroff_90px.png", this); 452 if (progress.GetResultCode() == 0) 453 fSuccess = true; 454 else 455 msgCenter().cannotStopMachine(progress); 456 } 457 else 458 { 459 COMResult res(console); 460 /* This can happen if VBoxSVC is not running */ 461 if (FAILED_DEAD_INTERFACE(res.rc())) 462 fForce = true; 463 else 464 msgCenter().cannotStopMachine(console); 465 } 466 if (fSuccess) 467 { 468 /* Discard the current state if requested: */ 469 if (fDiscardCurState && fDiscardCheckboxVisible) 470 { 471 /* Prepare the snapshot discard progress: */ 472 CSnapshot snapshot = m.GetCurrentSnapshot(); 473 CProgress progress = console.RestoreSnapshot(snapshot); 474 if (console.isOk()) 475 { 476 /* Show the snapshot discard progress: */ 477 msgCenter().showModalProgressDialog(progress, m.GetName(), ":/progress_snapshot_discard_90px.png", this); 478 if (progress.GetResultCode() != 0) 479 msgCenter().cannotRestoreSnapshot(progress, snapshot.GetName()); 480 } 481 else 482 msgCenter().cannotRestoreSnapshot(console, snapshot.GetName()); 483 } 484 } 485 if (fSuccess || fForce) 486 fCloseApplication = true; 487 break; 488 } 489 default: 490 break; 510 if (prevAction[0] == strShutdown && !fIsACPIEnabled) 511 strLastAction = strShutdown; 512 else 513 strLastAction = strPowerOff; 514 break; 491 515 } 492 493 if (fSuccess) 494 { 495 /* Read the last user's choice for the given VM: */ 496 QStringList prevAction = m.GetExtraData(GUI_LastCloseAction).split(','); 497 /* Memorize the last user's choice for the given VM: */ 498 QString lastAction = strPowerOff; 499 switch (decision) 500 { 501 case DD_Save: lastAction = strSave; break; 502 case DD_Shutdown: lastAction = strShutdown; break; 503 case DD_PowerOff: 504 { 505 if (prevAction[0] == strShutdown && !isACPIEnabled) 506 lastAction = strShutdown; 507 else 508 lastAction = strPowerOff; 509 break; 510 } 511 default: break; 512 } 513 /* Memorize additional options for the given VM: */ 514 if (fDiscardCurState) 515 (lastAction += ",") += strDiscardCurState; 516 m.SetExtraData(GUI_LastCloseAction, lastAction); 517 } 516 default: break; 518 517 } 519 520 /* Restore the running state if needed: */ 521 if (fSuccess && !fCloseApplication && !fWasPaused && uisession()->machineState() == KMachineState_Paused) 522 uisession()->unpause(); 523 524 /* Allowing auto-closure: */ 525 machineLogic()->setPreventAutoClose(false); 518 /* Memorize additional options for the given VM: */ 519 if (fDiscardCurState) 520 (strLastAction += ",") += strDiscardCurState; 521 /* Save the last user's choice for the given VM: */ 522 m.SetExtraData(GUI_LastCloseAction, strLastAction); 526 523 } 527 break;528 524 } 529 default: 530 break; 531 } 532 if (fCloseApplication) 525 526 /* Restore the running state if needed: */ 527 if (fSuccess && !fShutdownSession && !fWasPaused && uisession()->machineState() == KMachineState_Paused) 528 uisession()->unpause(); 529 530 /* Allowing auto-closure: */ 531 machineLogic()->setPreventAutoClose(false); 532 } 533 534 if (fShutdownSession) 533 535 { 534 536 /* VM has been powered off or saved. We must *safely* close VM window(s): */
Note:
See TracChangeset
for help on using the changeset viewer.