VBoxSnapshotsWgt.cpp revision 0f730ab371ac7844978aa70d4c5eaf209a8fa515
/* $Id$ */
/** @file
*
* VBox frontends: Qt4 GUI ("VirtualBox"):
* VBoxSnapshotsWgt class implementation
*/
/*
* Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
# include "precomp.h"
#else /* !VBOX_WITH_PRECOMPILED_HEADERS */
/* Qt includes: */
#include <QDateTime>
#include <QHeaderView>
#include <QMenu>
#include <QScrollBar>
#include <QWindowsStyle>
#include <QPointer>
/* GUI includes: */
#include "UIIconPool.h"
#include "UIMessageCenter.h"
#include "VBoxSnapshotDetailsDlg.h"
#include "VBoxSnapshotsWgt.h"
#include "VBoxTakeSnapshotDlg.h"
#include "UIWizardCloneVM.h"
#include "UIToolBar.h"
#include "UIVirtualBoxEventHandler.h"
#include "UIConverter.h"
#include "UIModalWindowManager.h"
/* COM includes: */
#include "CConsole.h"
#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
/**
* QTreeWidgetItem subclass for snapshots items
*/
class SnapshotWgtItem : public QTreeWidgetItem
{
public:
/* Normal snapshot item (child of tree-widget) */
, mIsCurrentState (false)
{
}
/* Normal snapshot item (child of tree-widget-item) */
, mIsCurrentState (false)
{
}
/* Current state item (child of tree-widget) */
, mIsCurrentState (true)
{
}
/* Current state item (child of tree-widget-item) */
, mIsCurrentState (true)
{
}
{
switch (aRole)
{
case Qt::DisplayRole:
default:
break;
}
}
{
}
bool isCurrentStateItem() const
{
}
int level()
{
QTreeWidgetItem *item = this;
int result = 0;
{
++ result;
}
return result;
}
{
adjustText();
}
{
adjustText();
}
void recache()
{
if (mIsCurrentState)
{
setText (0, mCurStateModified ?
parent() != 0 ?
VBoxSnapshotsWgt::tr ("The current state is identical to the state stored in the current snapshot") :
}
else
{
mCurStateModified = false;
}
adjustText();
}
{
return KMachineState_Null;
return mMachineState;
}
{
return;
}
{
/* Age: [date time|%1d ago|%1h ago|%1min ago|%1sec ago] */
{
}
{
age = VBoxSnapshotsWgt::tr (" (%1 ago)").arg(VBoxGlobal::daysToString(mTimestamp.secsTo (QDateTime::currentDateTime()) / 60 / 60 / 24));
}
{
age = VBoxSnapshotsWgt::tr (" (%1 ago)").arg(VBoxGlobal::hoursToString(mTimestamp.secsTo (QDateTime::currentDateTime()) / 60 / 60));
}
{
age = VBoxSnapshotsWgt::tr (" (%1 ago)").arg(VBoxGlobal::minutesToString(mTimestamp.secsTo (QDateTime::currentDateTime()) / 60));
}
else
{
age = VBoxSnapshotsWgt::tr (" (%1 ago)").arg(VBoxGlobal::secondsToString(mTimestamp.secsTo (QDateTime::currentDateTime())));
}
/* Update data */
return ageFormat;
}
private:
void adjustText()
{
if (!treeWidget()) return; /* only for initialised items */
2 * 2 /* 2 pixel per margin */;
16 /* icon */;
}
void recacheToolTip()
{
{
/* The current snapshot is always bold */
if (bold())
else
details = " (";
if (dateTimeToday)
else
}
else
{
}
setToolTip (0, toolTip);
}
bool mIsCurrentState;
bool mOnline;
bool mCurStateModified;
};
/**
* Simple guard block to prevent cyclic call caused by:
* changing tree-widget item content (rename) leads to snapshot update &
* snapshot update leads to changing tree-widget item content.
*/
class SnapshotEditBlocker
{
public:
SnapshotEditBlocker (bool &aProtector)
: mProtector (aProtector)
{
mProtector = true;
}
{
mProtector = false;
}
private:
bool &mProtector;
};
, mCurSnapshotItem (0)
, mEditProtector (false)
, mSnapshotActionGroup (new QActionGroup (this))
, mCurStateActionGroup (new QActionGroup (this))
{
/* Apply UI decorations */
/* The snapshots widget is not very useful if there are a lot
* of snapshots in a tree and the current Qt style decides not
* to draw lines (branches) between the snapshot nodes; it is
* then often unclear which snapshot is a child of another.
* So on platforms whose styles do not normally draw branches,
* we use QWindowsStyle which is present on every platform and
* draws required thing like we want. */
// #if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
// #endif
/* ToolBar creation */
toolBar->setUsesTextLabel (false);
toolBar->addSeparator();
toolBar->addSeparator();
toolBar->addSeparator();
/* Setup actions */
":/discard_cur_state_22px.png", ":/discard_cur_state_16px.png", // TODO: Update Icons!
":/discard_cur_state_dis_22px.png", ":/discard_cur_state_dis_16px.png")); // TODO: Update Icons!
":/delete_snapshot_22px.png", ":/delete_snapshot_16px.png",
":/delete_snapshot_dis_22px.png", ":/delete_snapshot_dis_16px.png"));
":/show_snapshot_details_22px.png", ":/show_snapshot_details_16px.png",
":/show_snapshot_details_dis_22px.png", ":/show_snapshot_details_dis_16px.png"));
":/take_snapshot_22px.png", ":/take_snapshot_16px.png",
":/take_snapshot_dis_22px.png", ":/take_snapshot_dis_16px.png"));
":/vm_clone_16px.png", ":/vm_clone_disabled_16px.png"));
mAgeUpdateTimer.setSingleShot (true);
/* Setup connections */
}
{
{
}
else
{
}
refreshAll();
}
void VBoxSnapshotsWgt::retranslateUi()
{
/* Translate uic generated strings */
mShowSnapshotDetailsAction->setToolTip (mShowSnapshotDetailsAction->text().remove ('&').remove ('.') +
}
{
/* Make the selected item visible */
if (item)
{
}
/* Whether another direct session is open or not */
/* Machine state of the current state item */
if (curStateItem())
s = curStateItem()->getCurrentState();
/* Whether taking or deleting snapshots is possible right now */
bool canTakeDeleteSnapshot = !busy
|| s == KMachineState_PoweredOff
|| s == KMachineState_Saved
|| s == KMachineState_Aborted
|| s == KMachineState_Running
|| s == KMachineState_Paused;
mRestoreSnapshotAction->setEnabled (!busy && mCurSnapshotItem && item && !item->isCurrentStateItem());
|| (item && !mCurSnapshotItem));
}
{
if (!snapshotItem)
return;
{
menu.addSeparator();
menu.addSeparator();
}
else
{
menu.addSeparator();
}
}
{
if (mEditProtector)
return;
if (item)
{
CSnapshot snap = item->snapshotId().isNull() ? CSnapshot() : mMachine.FindSnapshot(item->snapshotId());
}
}
void VBoxSnapshotsWgt::sltTakeSnapshot()
{
takeSnapshot();
}
void VBoxSnapshotsWgt::sltRestoreSnapshot()
{
/* Get currently chosen item: */
SnapshotWgtItem *pItem = mTreeWidget->currentItem() ? static_cast<SnapshotWgtItem*>(mTreeWidget->currentItem()) : 0;
AssertReturn(pItem, (void)0);
/* Detemine snapshot id: */
/* Get currently desired snapshot: */
/* Ask the user if he really wants to restore the snapshot: */
int iResultCode = msgCenter().askAboutSnapshotRestoring(snapshot.GetName(), mMachine.GetCurrentStateModified());
return;
/* If user also confirmed new snapshot creation: */
{
/* Take snapshot of changed current state: */
if (!takeSnapshot())
return;
}
/* Open a direct session (this call will handle all errors): */
return;
/* Restore chosen snapshot: */
{
msgCenter().showModalProgressDialog(progress, mMachine.GetName(), ":/progress_snapshot_restore_90px.png",
msgCenter().mainWindowShown(), true);
if (progress.GetResultCode() != 0)
}
else
/* Unlock machine finally: */
}
void VBoxSnapshotsWgt::sltDeleteSnapshot()
{
AssertReturn (item, (void) 0);
return;
/** @todo check available space on the target filesystem etc etc. */
#if 0
"59 GiB",
"15 GiB"))
return;
#endif
/* Open a direct session (this call will handle all errors) */
if (busy)
else
return;
{
/* Show the progress dialog */
msgCenter().showModalProgressDialog (progress, mMachine.GetName(), ":/progress_snapshot_discard_90px.png",
msgCenter().mainWindowShown(), true);
if (progress.GetResultCode() != 0)
}
else
}
{
AssertReturn (item, (void) 0);
VBoxSnapshotDetailsDlg dlg (this);
}
void VBoxSnapshotsWgt::sltCloneSnapshot()
{
AssertReturn (item, (void) 0);
if (item->isCurrentStateItem())
else
{
}
/* Show Clone VM wizard: */
if (pWizard)
delete pWizard;
}
{
if (strId != mMachineId)
return;
curStateItem()->recache();
}
{
if (strId != mMachineId)
return;
curStateItem()->recache();
}
{
if (strId != mMachineId)
return;
}
void VBoxSnapshotsWgt::updateSnapshotsAge()
{
if (mAgeUpdateTimer.isActive())
switch (age)
{
case AgeInSeconds:
break;
case AgeInMinutes:
break;
case AgeInHours:
break;
case AgeInDays:
break;
default:
break;
}
if (mAgeUpdateTimer.interval() > 0)
}
bool VBoxSnapshotsWgt::takeSnapshot()
{
/* Prepare result: */
bool fIsValid = true;
/* Get currently chosen item: */
SnapshotWgtItem *pItem = mTreeWidget->currentItem() ? static_cast<SnapshotWgtItem*>(mTreeWidget->currentItem()) : 0;
AssertReturn(pItem, (bool)0);
/* Open a session to work with corresponding VM: */
if (mSessionState != KSessionState_Unlocked)
else
if (fIsValid)
{
/* Get corresponding console object also: */
/* Remember runtime state: */
/* Remember paused state: */
/* Pause VM if necessary: */
{
/* Pausing VM: */
{
fIsValid = false;
}
}
if (fIsValid)
{
/* Create take-snapshot dialog: */
/* Assign corresponding icon: */
/* Search for the max available snapshot index: */
int iMaxSnapShotIndex = 0;
while (*iterator)
{
if (pos != -1)
iMaxSnapShotIndex = regExp.cap(1).toInt() > iMaxSnapShotIndex ? regExp.cap(1).toInt() : iMaxSnapShotIndex;
++iterator;
}
/* Exec the dialog: */
/* Is the dialog still valid? */
if (pDlg)
{
/* Acquire variables: */
/* Destroy dialog early: */
delete pDlg;
/* Was the dialog accepted? */
if (fDialogAccepted)
{
/* Prepare the take-snapshot progress: */
{
/* Show the take-snapshot progress: */
msgCenter().showModalProgressDialog(progress, mMachine.GetName(), ":/progress_snapshot_create_90px.png",
msgCenter().mainWindowShown(), true);
if (progress.GetResultCode() != 0)
{
fIsValid = false;
}
}
else
{
fIsValid = false;
}
}
else
fIsValid = false;
}
else
fIsValid = false;
}
/* Resume VM if necessary: */
{
/* Resuming VM: */
{
fIsValid = false;
}
}
/* Unlock machine finally: */
}
/* Return result: */
return fIsValid;
}
void VBoxSnapshotsWgt::refreshAll()
{
{
return;
}
if (cur)
{
}
mTreeWidget->clear();
/* Get the first snapshot */
if (mMachine.GetSnapshotCount() > 0)
{
populateSnapshots (snapshot, 0);
/* Add the "current state" item */
if (cur == 0)
if (cur == 0)
cur = curStateItem();
}
else
{
mCurSnapshotItem = 0;
/* Add the "current state" item */
}
/* Updating age */
}
{
while (*it)
{
return lvi;
++ it;
}
return 0;
}
{
return static_cast <SnapshotWgtItem*> (csi);
}
{
{
}
item->setExpanded (true);
}
{
static_cast <SnapshotWgtItem*> (aParentItem) : 0;
for (int i = 0; i < aParentItem->childCount(); ++ i)
{
}
return age;
}