Index: trunk/src/VBox/Frontends/VirtualBox/include/VBoxSnapshotsWgt.h
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox/include/VBoxSnapshotsWgt.h	(revision 24771)
+++ trunk/src/VBox/Frontends/VirtualBox/include/VBoxSnapshotsWgt.h	(revision 24774)
@@ -24,4 +24,7 @@
 #define __VBoxSnapshotsWgt_h__
 
+/* Global includes */
+#include <QTimer>
+
 /* Local includes */
 #include "VBoxSnapshotsWgt.gen.h"
@@ -31,4 +34,14 @@
 /* Local forwards */
 class SnapshotWgtItem;
+
+/* Snapshot age format */
+enum SnapshotAgeFormat
+{
+    AgeInSeconds,
+    AgeInMinutes,
+    AgeInHours,
+    AgeInDays,
+    AgeMax
+};
 
 class VBoxSnapshotsWgt : public QIWithRetranslateUI <QWidget>, public Ui::VBoxSnapshotsWgt
@@ -61,4 +74,6 @@
     void sessionStateChanged (const VBoxSessionStateChangeEvent &aEvent);
 
+    void updateSnapshotsAge();
+
 private:
 
@@ -67,4 +82,5 @@
     SnapshotWgtItem* curStateItem();
     void populateSnapshots (const CSnapshot &aSnapshot, QTreeWidgetItem *aItem);
+    SnapshotAgeFormat traverseSnapshotAge (QTreeWidgetItem *aParentItem);
 
     CMachine         mMachine;
@@ -81,4 +97,6 @@
     QAction         *mShowSnapshotDetailsAction;
     QAction         *mTakeSnapshotAction;
+
+    QTimer          mAgeUpdateTimer;
 };
 
Index: trunk/src/VBox/Frontends/VirtualBox/src/VBoxSnapshotsWgt.cpp
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox/src/VBoxSnapshotsWgt.cpp	(revision 24771)
+++ trunk/src/VBox/Frontends/VirtualBox/src/VBoxSnapshotsWgt.cpp	(revision 24774)
@@ -41,7 +41,9 @@
 public:
 
+    enum { ItemType = QTreeWidgetItem::UserType + 1 };
+
     /* Normal snapshot item (child of tree-widget) */
     SnapshotWgtItem (QTreeWidget *aTreeWidget, const CSnapshot &aSnapshot)
-        : QTreeWidgetItem (aTreeWidget)
+        : QTreeWidgetItem (aTreeWidget, ItemType)
         , mSnapshot (aSnapshot)
     {
@@ -50,5 +52,5 @@
     /* Normal snapshot item (child of tree-widget-item) */
     SnapshotWgtItem (QTreeWidgetItem *aRootItem, const CSnapshot &aSnapshot)
-        : QTreeWidgetItem (aRootItem)
+        : QTreeWidgetItem (aRootItem, ItemType)
         , mSnapshot (aSnapshot)
     {
@@ -57,5 +59,5 @@
     /* Current state item (child of tree-widget) */
     SnapshotWgtItem (QTreeWidget *aTreeWidget, const CMachine &aMachine)
-        : QTreeWidgetItem (aTreeWidget)
+        : QTreeWidgetItem (aTreeWidget, ItemType)
         , mMachine (aMachine)
     {
@@ -65,8 +67,25 @@
     /* Current state item (child of tree-widget-item) */
     SnapshotWgtItem (QTreeWidgetItem *aRootItem, const CMachine &aMachine)
-        : QTreeWidgetItem (aRootItem)
+        : QTreeWidgetItem (aRootItem, ItemType)
         , mMachine (aMachine)
     {
         updateCurrentState (mMachine.GetState());
+    }
+
+    QVariant data (int aColumn, int aRole) const
+    {
+        switch (aRole)
+        {
+            case Qt::DisplayRole:
+                return QVariant (QString ("%1%2").arg (QTreeWidgetItem::data (aColumn, aRole).toString()).arg (mAge));
+            default:
+                break;
+        }
+        return QTreeWidgetItem::data (aColumn, aRole);
+    }
+
+    QString text (int aColumn) const
+    {
+        return QTreeWidgetItem::data (aColumn, Qt::DisplayRole).toString();
     }
 
@@ -148,4 +167,42 @@
     }
 
+    SnapshotAgeFormat updateAge()
+    {
+        QString oldAge (mAge);
+
+        /* Age: [date time|%1d ago|%1h ago|%1min ago|%1sec ago] */
+        SnapshotAgeFormat ageFormat;
+        if (mTimestamp.daysTo (QDateTime::currentDateTime()) > 30)
+        {
+            mAge = VBoxSnapshotsWgt::tr (" [%1]").arg (mTimestamp.toString (Qt::LocalDate));
+            ageFormat = AgeMax;
+        }
+        else if (mTimestamp.secsTo (QDateTime::currentDateTime()) > 60 * 60 * 24)
+        {
+            mAge = VBoxSnapshotsWgt::tr (" [%1d ago]").arg (mTimestamp.secsTo (QDateTime::currentDateTime()) / 60 / 60 / 24);
+            ageFormat = AgeInDays;
+        }
+        else if (mTimestamp.secsTo (QDateTime::currentDateTime()) > 60 * 60)
+        {
+            mAge = VBoxSnapshotsWgt::tr (" [%1h ago]").arg (mTimestamp.secsTo (QDateTime::currentDateTime()) / 60 / 60);
+            ageFormat = AgeInHours;
+        }
+        else if (mTimestamp.secsTo (QDateTime::currentDateTime()) > 60)
+        {
+            mAge = VBoxSnapshotsWgt::tr (" [%1min ago]").arg (mTimestamp.secsTo (QDateTime::currentDateTime()) / 60);
+            ageFormat = AgeInMinutes;
+        }
+        else
+        {
+            mAge = VBoxSnapshotsWgt::tr (" [%1sec ago]").arg (mTimestamp.secsTo (QDateTime::currentDateTime()));
+            ageFormat = AgeInSeconds;
+        }
+
+        if (mAge != oldAge)
+            emitDataChanged();
+
+        return ageFormat;
+    }
+
 private:
 
@@ -211,4 +268,5 @@
     QString mDesc;
     QDateTime mTimestamp;
+    QString mAge;
 
     bool mCurStateModified;
@@ -308,4 +366,6 @@
     mTakeSnapshotAction->setShortcut (QString ("Ctrl+Shift+S"));
 
+    mAgeUpdateTimer.setSingleShot (true);
+
     /* Setup connections */
     connect (mTreeWidget, SIGNAL (currentItemChanged (QTreeWidgetItem*, QTreeWidgetItem*)),
@@ -328,4 +388,6 @@
              this, SLOT (sessionStateChanged (const VBoxSessionStateChangeEvent&)));
 
+    connect (&mAgeUpdateTimer, SIGNAL (timeout()), this, SLOT (updateSnapshotsAge()));
+
     retranslateUi();
 }
@@ -406,5 +468,5 @@
     if (item)
     {
-        CSnapshot snap = mMachine.GetSnapshot (item->snapshotId());
+        CSnapshot snap = item->snapshotId().isNull() ? CSnapshot() : mMachine.GetSnapshot (item->snapshotId());
         if (!snap.isNull() && snap.isOk() && snap.GetName() != item->text (0))
             snap.SetName (item->text (0));
@@ -518,5 +580,5 @@
     while (*iterator)
     {
-        QString snapShot = (*iterator)->text (0);
+        QString snapShot = static_cast <SnapshotWgtItem*> (*iterator)->text (0);
         int pos = regExp.indexIn (snapShot);
         if (pos != -1)
@@ -584,4 +646,34 @@
     mSessionState = aEvent.state;
     onCurrentChanged (mTreeWidget->currentItem());
+}
+
+void VBoxSnapshotsWgt::updateSnapshotsAge()
+{
+    if (mAgeUpdateTimer.isActive())
+        mAgeUpdateTimer.stop();
+
+    SnapshotAgeFormat age = traverseSnapshotAge (mTreeWidget->invisibleRootItem());
+
+    switch (age)
+    {
+        case AgeInSeconds:
+            mAgeUpdateTimer.setInterval (5 * 1000);
+            break;
+        case AgeInMinutes:
+            mAgeUpdateTimer.setInterval (60 * 1000);
+            break;
+        case AgeInHours:
+            mAgeUpdateTimer.setInterval (60 * 60 * 1000);
+            break;
+        case AgeInDays:
+            mAgeUpdateTimer.setInterval (24 * 60 * 60 * 1000);
+            break;
+        default:
+            mAgeUpdateTimer.setInterval (0);
+            break;
+    }
+
+    if (mAgeUpdateTimer.interval() > 0)
+        mAgeUpdateTimer.start();
 }
 
@@ -669,4 +761,7 @@
     }
 
+    /* Updating age */
+    updateSnapshotsAge();
+
     mTreeWidget->resizeColumnToContents (0);
 }
@@ -715,2 +810,17 @@
 }
 
+SnapshotAgeFormat VBoxSnapshotsWgt::traverseSnapshotAge (QTreeWidgetItem *aParentItem)
+{
+    SnapshotWgtItem *parentItem = aParentItem->type() == SnapshotWgtItem::ItemType ?
+                                  static_cast <SnapshotWgtItem*> (aParentItem) : 0;
+
+    SnapshotAgeFormat age = parentItem ? parentItem->updateAge() : AgeMax;
+    for (int i = 0; i < aParentItem->childCount(); ++ i)
+    {
+        SnapshotAgeFormat newAge = traverseSnapshotAge (aParentItem->child (i));
+        age = newAge < age ? newAge : age;
+    }
+
+    return age;
+}
+
