Index: /trunk/src/VBox/Frontends/VirtualBox/src/UIVMLogViewer.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/UIVMLogViewer.cpp	(revision 58266)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/UIVMLogViewer.cpp	(revision 58267)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2008-2012 Oracle Corporation
+ * Copyright (C) 2010-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -22,4 +22,5 @@
 /* Qt includes: */
 # include <QCheckBox>
+# include <QComboBox>
 # include <QDateTime>
 # include <QDir>
@@ -46,6 +47,6 @@
 #endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
 
-
-/* VM Log Viewer search panel: */
+/** QWidget extension
+  * providing GUI for search-panel in VM Log-Viewer. */
 class UIVMLogViewerSearchPanel : public QIWithRetranslateUI<QWidget>
 {
@@ -54,5 +55,6 @@
 public:
 
-    /* Constructor: */
+    /** Constructs search-panel by passing @a pParent to the QWidget base-class constructor.
+      * @a pViewer is the instance of VM Log-Viewer. */
     UIVMLogViewerSearchPanel(QWidget *pParent, UIVMLogViewer *pViewer)
         : QIWithRetranslateUI<QWidget>(pParent)
@@ -64,15 +66,82 @@
         , m_pWarningSpacer(0), m_pWarningIcon(0), m_pWarningLabel(0)
     {
-        /* Close button: */
+        /* Prepare: */
+        prepare();
+    }
+
+private slots:
+
+    /** Handles find next/back action triggering.
+      * @a iButton specifies id of next/back button. */
+    void find(int iButton)
+    {
+        if (iButton)
+            findNext();
+        else
+            findBack();
+    }
+
+    /** Handles textchanged event from search-editor.
+      * @a strSearchString specifies the search-string. */
+    void findCurrent(const QString &strSearchString)
+    {
+        m_pNextPrevButtons->setEnabled(0, strSearchString.length());
+        m_pNextPrevButtons->setEnabled(1, strSearchString.length());
+        toggleWarning(!strSearchString.length());
+        if (strSearchString.length())
+            search(true, true);
+        else
+        {
+            QTextEdit *pBrowser = m_pViewer->currentLogPage();
+            if (pBrowser && pBrowser->textCursor().hasSelection())
+            {
+                QTextCursor cursor = pBrowser->textCursor();
+                cursor.setPosition(cursor.anchor());
+                pBrowser->setTextCursor(cursor);
+            }
+        }
+    }
+
+private:
+
+    /** Prepares search-panel. */
+    void prepare()
+    {
+        /* Prepare widgets: */
+        prepareWidgets();
+
+        /* Prepare main-layout: */
+        prepareMainLayout();
+
+        /* Prepare connections: */
+        prepareConnections();
+
+        /* Retranslate finally: */
+        retranslateUi();
+    }
+
+    /** Prepares widgets. */
+    void prepareWidgets()
+    {
+        /* Create close-button: */
         m_pCloseButton = new UIMiniCancelButton(this);
-
-        /* Search field: */
+        AssertPtrReturnVoid(m_pCloseButton);
+
+        /* Create search-editor: */
+        m_pSearchEditor = new UISearchField(this);
+        AssertPtrReturnVoid(m_pSearchEditor);
+        /* Prepare search-editor: */
+        m_pSearchEditor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+        /* Create search-label: */
         m_pSearchLabel = new QLabel(this);
-        m_pSearchEditor = new UISearchField(this);
-        m_pSearchEditor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+        AssertPtrReturnVoid(m_pSearchLabel);
+        /* Prepare search-label: */
         m_pSearchLabel->setBuddy(m_pSearchEditor);
 
-        /* Next/Previous buttons: */
+        /* Create Next/Prev button-box: */
         m_pNextPrevButtons = new UIRoundRectSegmentedButton(this, 2);
+        AssertPtrReturnVoid(m_pNextPrevButtons);
+        /* Prepare Next/Prev button-box: */
         m_pNextPrevButtons->setEnabled(0, false);
         m_pNextPrevButtons->setEnabled(1, false);
@@ -83,18 +152,34 @@
 #endif /* !Q_WS_MAC */
 
-        /* Case sensitive check-box: */
+        /* Create case-sensitive checkbox: */
         m_pCaseSensitiveCheckBox = new QCheckBox(this);
-
-        /* Warning label: */
+        AssertPtrReturnVoid(m_pCaseSensitiveCheckBox);
+        /* Setup focus proxy: */
+        setFocusProxy(m_pCaseSensitiveCheckBox);
+
+        /* Create warning-spacer: */
         m_pWarningSpacer = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Minimum);
+        AssertPtrReturnVoid(m_pWarningSpacer);
+
+        /* Create warning-icon: */
         m_pWarningIcon = new QLabel(this);
+        AssertPtrReturnVoid(m_pWarningIcon);
+        /* Prepare warning-icon: */
         m_pWarningIcon->hide();
         QIcon icon = UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_MessageBoxWarning, this);
         if (!icon.isNull())
             m_pWarningIcon->setPixmap(icon.pixmap(16, 16));
+
+        /* Create warning-label: */
         m_pWarningLabel = new QLabel(this);
+        AssertPtrReturnVoid(m_pWarningLabel);
+        /* Prepare warning-label: */
         m_pWarningLabel->hide();
-        QSpacerItem *pSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
-
+
+        /* Create spacer-item: */
+        m_pSpacerItem = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
+        AssertPtrReturnVoid(m_pSpacerItem);
+
+        /* Prepare fonts: */
 #ifdef VBOX_DARWIN_USE_NATIVE_CONTROLS
         QFont font = m_pSearchLabel->font();
@@ -104,68 +189,38 @@
         m_pWarningLabel->setFont(font);
 #endif /* VBOX_DARWIN_USE_NATIVE_CONTROLS */
-
-        /* Placing widgets: */
+    }
+
+    /** Prepares main-layout. */
+    void prepareMainLayout()
+    {
+        /* Create main-layout: */
         QHBoxLayout *pMainLayout = new QHBoxLayout(this);
-        pMainLayout->setSpacing(5);
-        pMainLayout->setContentsMargins(0, 0, 0, 0);
-        pMainLayout->addWidget(m_pCloseButton);
-        pMainLayout->addWidget(m_pSearchLabel);
-        pMainLayout->addWidget(m_pSearchEditor);
-        pMainLayout->addWidget(m_pNextPrevButtons);
-        pMainLayout->addWidget(m_pCaseSensitiveCheckBox);
-        pMainLayout->addItem(m_pWarningSpacer);
-        pMainLayout->addWidget(m_pWarningIcon);
-        pMainLayout->addWidget(m_pWarningLabel);
-        pMainLayout->addItem(pSpacer);
-
-        /* Setup focus proxy: */
-        setFocusProxy(m_pCaseSensitiveCheckBox);
-
-        /* Setup connections: */
+        AssertPtrReturnVoid(pMainLayout);
+        {
+            /* Prepare main-layout: */
+            pMainLayout->setSpacing(5);
+            pMainLayout->setContentsMargins(0, 0, 0, 0);
+            pMainLayout->addWidget(m_pCloseButton);
+            pMainLayout->addWidget(m_pSearchLabel);
+            pMainLayout->addWidget(m_pSearchEditor);
+            pMainLayout->addWidget(m_pNextPrevButtons);
+            pMainLayout->addWidget(m_pCaseSensitiveCheckBox);
+            pMainLayout->addItem(m_pWarningSpacer);
+            pMainLayout->addWidget(m_pWarningIcon);
+            pMainLayout->addWidget(m_pWarningLabel);
+            pMainLayout->addItem(m_pSpacerItem);
+        }
+    }
+
+    /** Prepares connections. */
+    void prepareConnections()
+    {
         connect(m_pCloseButton, SIGNAL(clicked()), this, SLOT(hide()));
         connect(m_pSearchEditor, SIGNAL(textChanged(const QString &)),
                 this, SLOT(findCurrent(const QString &)));
         connect(m_pNextPrevButtons, SIGNAL(clicked(int)), this, SLOT(find(int)));
-
-        /* Retranslate finally: */
-        retranslateUi();
-    }
-
-private slots:
-
-    /* Slot to find specified tag,
-     * called by next/previous buttons: */
-    void find(int iButton)
-    {
-        if (iButton)
-            findNext();
-        else
-            findBack();
-    }
-
-    /* Slot to find specified tag,
-     * called when text changed in search editor: */
-    void findCurrent(const QString &strSearchString)
-    {
-        m_pNextPrevButtons->setEnabled(0, strSearchString.length());
-        m_pNextPrevButtons->setEnabled(1, strSearchString.length());
-        toggleWarning(!strSearchString.length());
-        if (strSearchString.length())
-            search(true, true);
-        else
-        {
-            QTextEdit *pBrowser = m_pViewer->currentLogPage();
-            if (pBrowser && pBrowser->textCursor().hasSelection())
-            {
-                QTextCursor cursor = pBrowser->textCursor();
-                cursor.setPosition(cursor.anchor());
-                pBrowser->setTextCursor(cursor);
-            }
-        }
-    }
-
-private:
-
-    /* Translation stuff: */
+    }
+
+    /** Handles translation event. */
     void retranslateUi()
     {
@@ -186,5 +241,5 @@
     }
 
-    /* Key press filter: */
+    /** Handles Qt key-press @a pEevent. */
     void keyPressEvent(QKeyEvent *pEvent)
     {
@@ -210,5 +265,5 @@
     }
 
-    /* Event filter, used for keyboard processing: */
+    /** Handles Qt @a pEvent, used for keyboard processing. */
     bool eventFilter(QObject *pObject, QEvent *pEvent)
     {
@@ -270,5 +325,5 @@
     }
 
-    /* Show event reimplementation: */
+    /** Handles Qt show @a pEvent. */
     void showEvent(QShowEvent *pEvent)
     {
@@ -278,14 +333,16 @@
     }
 
-    /* Hide event reimplementation: */
+    /** Handles Qt hide @a pEvent. */
     void hideEvent(QHideEvent *pEvent)
     {
         QWidget *pFocus = QApplication::focusWidget();
         if (pFocus && pFocus->parent() == this)
-           focusNextPrevChild(true);
+            focusNextPrevChild(true);
         QWidget::hideEvent(pEvent);
     }
 
-    /* Search routine: */
+    /** Search routine.
+      * @a fForward specifies the direction of search.
+      * @a fStartCurrent specifies if the search should start from beginning of log. */
     void search(bool fForward, bool fStartCurrent = false)
     {
@@ -333,9 +390,11 @@
     }
 
-    /* Search routine wrappers: */
+    /** Forward search routine wrapper. */
     void findNext() { search(true); }
+
+    /** Backward search routine wrapper. */
     void findBack() { search(false); }
 
-    /* Function to show/hide search border warning: */
+    /** Shows/hides the search border warning using @a fHide as hint. */
     void toggleWarning(bool fHide)
     {
@@ -349,17 +408,243 @@
     }
 
-    /* Widgets: */
+    /** Holds the reference to the VM Log-Viewer this search-panel belongs to. */
     UIVMLogViewer *m_pViewer;
+    /** Holds the instance of close-button we create. */
     UIMiniCancelButton *m_pCloseButton;
+    /** Holds the instance of search-label we create. */
     QLabel *m_pSearchLabel;
+    /** Holds the instance of search-editor we create. */
     UISearchField *m_pSearchEditor;
+    /** Holds the instance of next/back button-box we create. */
     UIRoundRectSegmentedButton *m_pNextPrevButtons;
+    /** Holds the instance of case-sensitive checkbox we create. */
     QCheckBox *m_pCaseSensitiveCheckBox;
+    /** Holds the instance of warning spacer-item we create. */
     QSpacerItem *m_pWarningSpacer;
+    /** Holds the instance of warning icon we create. */
     QLabel *m_pWarningIcon;
+    /** Holds the instance of warning label we create. */
     QLabel *m_pWarningLabel;
+    /** Holds the instance of spacer item we create. */
+    QSpacerItem *m_pSpacerItem;
 };
 
-/* VM Log Viewer array: */
+/** QWidget extension
+  * providing GUI for filter panel in VM Log Viewer. */
+class UIVMLogViewerFilterPanel : public QIWithRetranslateUI<QWidget>
+{
+    Q_OBJECT;
+
+public:
+
+    /** Constructs the filter-panel by passing @a pParent to the QWidget base-class constructor.
+      * @a pViewer specifies the reference to the VM Log-Viewer this filter-panel belongs to. */
+    UIVMLogViewerFilterPanel(QWidget *pParent, UIVMLogViewer *pViewer)
+        : QIWithRetranslateUI<QWidget>(pParent)
+        , m_pViewer(pViewer)
+        , m_pCloseButton(0)
+        , m_pFilterLabel(0), m_pFilterComboBox(0)
+    {
+        /* Prepare: */
+        prepare();
+    }
+
+public slots:
+
+    /** Applies filter settings and filters the current log-page.
+      * @a iCurrentIndex specifies index of current log-page, but it is actually not used in the method. */
+    void applyFilter(const int iCurrentIndex = 0)
+    {
+        Q_UNUSED(iCurrentIndex);
+        QTextEdit *pCurrentPage = m_pViewer->currentLogPage();
+        AssertReturnVoid(pCurrentPage);
+        const QString *pCurrentLog = m_pViewer->currentLog();
+        if (pCurrentLog)
+        {
+            QString strInputText(pCurrentLog->data());
+            /* Prepare filter-data: */
+            QString strFilteredText;
+            const QRegExp rxFilterExp(m_strFilterText, Qt::CaseInsensitive);
+
+            /* If filter regular-expression is not empty and valid, filter the log: */
+            if (!rxFilterExp.isEmpty() && rxFilterExp.isValid())
+            {
+                while (!strInputText.isEmpty())
+                {
+                    /* Read each line and check if it matches regular-expression: */
+                    const int index = strInputText.indexOf('\n');
+                    if (index > 0)
+                    {
+                        QString strLine = strInputText.left(index + 1);
+                        if (strLine.contains(rxFilterExp))
+                            strFilteredText.append(strLine);
+                    }
+                    strInputText.remove(0, index + 1);
+                }
+                pCurrentPage->setPlainText(strFilteredText);
+            }
+            /* Restore entire log when filter regular expression is empty or not valid: */
+            else
+                pCurrentPage->setPlainText(strInputText);
+
+            /* Move the cursor position to end: */
+            QTextCursor cursor = pCurrentPage->textCursor();
+            cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
+            pCurrentPage->setTextCursor(cursor);
+        }
+    }
+
+private slots:
+
+    /** Handles the textchanged event from filter editor. */
+    void filter(const QString &strSearchString)
+    {
+        m_strFilterText = strSearchString;
+        applyFilter();
+    }
+
+private:
+
+    /** Prepares filter-panel. */
+    void prepare()
+    {
+        /* Prepare widgets: */
+        prepareWidgets();
+
+        /* Prepare main-layout: */
+        prepareMainLayout();
+
+        /* Prepare connections: */
+        prepareConnections();
+
+        /* Retranslate finally: */
+        retranslateUi();
+    }
+
+    /** Prepares widgets. */
+    void prepareWidgets()
+    {
+        /* Create close-button: */
+        m_pCloseButton = new UIMiniCancelButton(this);
+        AssertPtrReturnVoid(m_pCloseButton);
+
+        /* Create filter-combobox: */
+        m_pFilterComboBox = new QComboBox(this);
+        AssertPtrReturnVoid(m_pFilterComboBox);
+        /* Prepare filter-combobox: */
+        m_pFilterComboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+        m_pFilterComboBox->setEditable(true);
+        QStringList strFilterPresets;
+        strFilterPresets << "" << "GUI" << "NAT" << "AHCI" << "VD" << "Audio" << "VUSB" << "SUP" << "PGM" << "HDA"
+                         << "HM" << "VMM" << "GIM" << "CPUM";
+        strFilterPresets.sort();
+        m_pFilterComboBox->addItems(strFilterPresets);
+
+        /* Create filter-label: */
+        m_pFilterLabel = new QLabel(this);
+        AssertPtrReturnVoid(m_pFilterLabel);
+        /* Prepare filter-label: */
+        m_pFilterLabel->setBuddy(m_pFilterComboBox);
+#ifdef VBOX_DARWIN_USE_NATIVE_CONTROLS
+        QFont font = m_pFilterLabel->font();
+        font.setPointSize(::darwinSmallFontSize());
+        m_pFilterLabel->setFont(font);
+#endif /* VBOX_DARWIN_USE_NATIVE_CONTROLS */
+    }
+
+    /** Prepares main-layout. */
+    void prepareMainLayout()
+    {
+        /* Create main-layout: */
+        QHBoxLayout *pMainLayout = new QHBoxLayout(this);
+        AssertPtrReturnVoid(pMainLayout);
+        {
+            /* Prepare main-layout: */
+            pMainLayout->setSpacing(5);
+            pMainLayout->setContentsMargins(0, 0, 0, 0);
+            pMainLayout->addWidget(m_pCloseButton);
+            pMainLayout->addWidget(m_pFilterLabel);
+            pMainLayout->addWidget(m_pFilterComboBox);
+        }
+    }
+
+    /** Prepares connections. */
+    void prepareConnections()
+    {
+        connect(m_pCloseButton, SIGNAL(clicked()), this, SLOT(hide()));
+        connect(m_pFilterComboBox, SIGNAL(editTextChanged(const QString &)),
+                this, SLOT(filter(const QString &)));
+    }
+
+    /** Handles the translation event. */
+    void retranslateUi()
+    {
+        m_pCloseButton->setToolTip(UIVMLogViewer::tr("Close the search panel"));
+        m_pFilterLabel->setText(UIVMLogViewer::tr("Filter"));
+        m_pFilterComboBox->setToolTip(UIVMLogViewer::tr("Enter filtering string here"));
+    }
+
+    /** Handles Qt @a pEvent, used for keyboard processing. */
+    bool eventFilter(QObject *pObject, QEvent *pEvent)
+    {
+        /* Depending on event-type: */
+        switch (pEvent->type())
+        {
+            /* Process key press only: */
+            case QEvent::KeyPress:
+            {
+                /* Cast to corresponding key press event: */
+                QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
+
+                /* Handle Ctrl+T key combination as a shortcut to focus search field: */
+                if (pKeyEvent->QInputEvent::modifiers() == Qt::ControlModifier &&
+                         pKeyEvent->key() == Qt::Key_T)
+                {
+                    if (m_pViewer->currentLogPage())
+                    {
+                        if (isHidden())
+                            show();
+                        m_pFilterComboBox->setFocus();
+                        return true;
+                    }
+                }
+                break;
+            }
+            default:
+                break;
+        }
+        /* Call to base-class: */
+        return QWidget::eventFilter(pObject, pEvent);
+    }
+
+    /** Handles the Qt show @a pEvent. */
+    void showEvent(QShowEvent *pEvent)
+    {
+        QWidget::showEvent(pEvent);
+        m_pFilterComboBox->setFocus();
+    }
+
+    /** Handles the Qt hide @a pEvent. */
+    void hideEvent(QHideEvent *pEvent)
+    {
+        QWidget *pFocus = QApplication::focusWidget();
+        if (pFocus && pFocus->parent() == this)
+            focusNextPrevChild(true);
+        QWidget::hideEvent(pEvent);
+    }
+
+    /** Holds the reference to VM Log-Viewer this filter-panel belongs to. */
+    UIVMLogViewer *m_pViewer;
+    /** Holds the instance of close-button we create. */
+    UIMiniCancelButton *m_pCloseButton;
+    /** Holds the instance of filter-label we create. */
+    QLabel *m_pFilterLabel;
+    /** Holds instance of filter combo-box we create. */
+    QComboBox *m_pFilterComboBox;
+    /** Holds the filter text. */
+    QString m_strFilterText;
+};
+
+/** Holds the VM Log-Viewer array. */
 VMLogViewerMap UIVMLogViewer::m_viewers = VMLogViewerMap();
 
@@ -388,64 +673,12 @@
     , m_machine(machine)
 {
-    /* Apply UI decorations: */
-    Ui::UIVMLogViewer::setupUi(this);
-
-    /* Apply window icons: */
-    setWindowIcon(UIIconPool::iconSetFull(":/vm_show_logs_32px.png", ":/vm_show_logs_16px.png"));
-
-    /* Create VM Log Vewer container: */
-    m_pViewerContainer = new QITabWidget(centralWidget());
-    m_pMainLayout->insertWidget(0, m_pViewerContainer);
-
-    /* Create VM Log Vewer search panel: */
-    m_pSearchPanel = new UIVMLogViewerSearchPanel(centralWidget(), this);
-    centralWidget()->installEventFilter(m_pSearchPanel);
-    m_pSearchPanel->hide();
-    m_pMainLayout->insertWidget(1, m_pSearchPanel);
-
-    /* Add missing buttons & retrieve standard buttons: */
-    mBtnHelp = m_pButtonBox->button(QDialogButtonBox::Help);
-    mBtnFind = m_pButtonBox->addButton(QString::null, QDialogButtonBox::ActionRole);
-    mBtnRefresh = m_pButtonBox->addButton(QString::null, QDialogButtonBox::ActionRole);
-    mBtnClose = m_pButtonBox->button(QDialogButtonBox::Close);
-    mBtnSave = m_pButtonBox->button(QDialogButtonBox::Save);
-
-    /* Setup connections: */
-    connect(m_pButtonBox, SIGNAL(helpRequested()), &msgCenter(), SLOT(sltShowHelpHelpDialog()));
-    connect(mBtnFind, SIGNAL(clicked()), this, SLOT(search()));
-    connect(mBtnRefresh, SIGNAL(clicked()), this, SLOT(refresh()));
-    connect(mBtnClose, SIGNAL(clicked()), this, SLOT(close()));
-    connect(mBtnSave, SIGNAL(clicked()), this, SLOT(save()));
-
-    /* Reading log files: */
-    refresh();
-
-    /* Load settings: */
-    loadSettings();
-
-    /* Loading language constants */
-    retranslateUi();
+    /* Prepare VM Log-Viewer: */
+    prepare();
 }
 
 UIVMLogViewer::~UIVMLogViewer()
 {
-    /* Save settings: */
-    saveSettings();
-
-    if (!m_machine.isNull())
-        m_viewers.remove(m_machine.GetName());
-}
-
-QTextEdit* UIVMLogViewer::currentLogPage()
-{
-    if (m_pViewerContainer->isEnabled())
-    {
-        QWidget *pContainer = m_pViewerContainer->currentWidget();
-        QTextEdit *pBrowser = pContainer->findChild<QTextEdit*>();
-        Assert(pBrowser);
-        return pBrowser ? pBrowser : 0;
-    }
-    else
-        return 0;
+    /* Cleanup VM Log-Viewer: */
+    cleanup();
 }
 
@@ -457,6 +690,16 @@
 void UIVMLogViewer::refresh()
 {
+    /* Disconnect this connection to avoid initial signals during page creation/deletion: */
+    disconnect(m_pViewerContainer, SIGNAL(currentChanged(int)), m_pFilterPanel, SLOT(applyFilter(int)));
+
     /* Clearing old data if any: */
+    for (int index = 0; index < m_book.count(); index++)
+    {
+        QTextEdit* pLogPage = m_book.at(index).second;
+        if (pLogPage)
+            delete m_logMap[pLogPage];
+    }
     m_book.clear();
+    m_logMap.clear();
     m_pViewerContainer->setEnabled(true);
     while (m_pViewerContainer->count())
@@ -500,4 +743,6 @@
                 /* Add the actual file name and the QTextEdit containing the content to a list: */
                 m_book << qMakePair(strFileName, pLogViewer);
+                /* Add the log-text to the map: */
+                m_logMap[pLogViewer] = new QString(strText);
                 isAnyLogPresent = true;
             }
@@ -523,7 +768,14 @@
     m_pViewerContainer->setCurrentIndex(0);
 
+    /* Apply the filter settings: */
+    m_pFilterPanel->applyFilter();
+
+    /* Setup this connection after refresh to avoid initial signals during page creation: */
+    connect(m_pViewerContainer, SIGNAL(currentChanged(int)), m_pFilterPanel, SLOT(applyFilter(int)));
+
     /* Enable/Disable save button & tab widget according log presence: */
-    mBtnFind->setEnabled(isAnyLogPresent);
-    mBtnSave->setEnabled(isAnyLogPresent);
+    m_pButtonFind->setEnabled(isAnyLogPresent);
+    m_pButtonSave->setEnabled(isAnyLogPresent);
+    m_pButtonFilter->setEnabled(isAnyLogPresent);
     m_pViewerContainer->setEnabled(isAnyLogPresent);
 }
@@ -550,4 +802,102 @@
 }
 
+void UIVMLogViewer::filter()
+{
+    m_pFilterPanel->isHidden() ? m_pFilterPanel->show() : m_pFilterPanel->hide();
+}
+
+void UIVMLogViewer::prepare()
+{
+    /* Apply UI decorations: */
+    Ui::UIVMLogViewer::setupUi(this);
+
+    /* Apply window icons: */
+    setWindowIcon(UIIconPool::iconSetFull(":/vm_show_logs_32px.png", ":/vm_show_logs_16px.png"));
+
+    /* Prepare widgets: */
+    prepareWidgets();
+
+    /* Prepare connections: */
+    prepareConnections();
+
+    /* Reading log files: */
+    refresh();
+
+    /* Load settings: */
+    loadSettings();
+
+    /* Loading language constants */
+    retranslateUi();
+}
+
+void UIVMLogViewer::prepareWidgets()
+{
+    /* Create VM Log-Viewer container: */
+    m_pViewerContainer = new QITabWidget(centralWidget());
+    AssertPtrReturnVoid(m_pViewerContainer);
+    /* Layout VM Log-Viewer container: */
+    m_pMainLayout->insertWidget(0, m_pViewerContainer);
+
+    /* Create VM Log-Viewer search-panel: */
+    m_pSearchPanel = new UIVMLogViewerSearchPanel(centralWidget(), this);
+    AssertPtrReturnVoid(m_pSearchPanel);
+    /* Prepare VM Log-Viewer search-panel: */
+    centralWidget()->installEventFilter(m_pSearchPanel);
+    m_pSearchPanel->hide();
+    /* Layout VM Log-Viewer search-panel: */
+    m_pMainLayout->insertWidget(1, m_pSearchPanel);
+
+    /* Create VM Log-Viewer filter-panel: */
+    m_pFilterPanel = new UIVMLogViewerFilterPanel(centralWidget(), this);
+    AssertPtrReturnVoid(m_pFilterPanel);
+    /* Prepare VM Log-Viewer filter-panel: */
+    centralWidget()->installEventFilter(m_pFilterPanel);
+    m_pFilterPanel->hide();
+    /* Layout VM Log-Viewer filter-panel: */
+    m_pMainLayout->insertWidget(2, m_pFilterPanel);
+
+    /* Create/Prepare standard buttons from button-box: */
+    m_pButtonHelp = m_pButtonBox->button(QDialogButtonBox::Help);
+    AssertPtrReturnVoid(m_pButtonHelp);
+    m_pButtonFind = m_pButtonBox->addButton(QString::null, QDialogButtonBox::ActionRole);
+    AssertPtrReturnVoid(m_pButtonFind);
+    m_pButtonFilter = m_pButtonBox->addButton(QString::null, QDialogButtonBox::ActionRole);
+    AssertPtrReturnVoid(m_pButtonFilter);
+    m_pButtonClose = m_pButtonBox->button(QDialogButtonBox::Close);
+    AssertPtrReturnVoid(m_pButtonClose);
+    m_pButtonSave = m_pButtonBox->button(QDialogButtonBox::Save);
+    AssertPtrReturnVoid(m_pButtonSave);
+    m_pButtonRefresh = m_pButtonBox->addButton(QString::null, QDialogButtonBox::ActionRole);
+    AssertPtrReturnVoid(m_pButtonRefresh);
+}
+
+void UIVMLogViewer::prepareConnections()
+{
+    /* Prepare connections: */
+    connect(m_pButtonBox, SIGNAL(helpRequested()), &msgCenter(), SLOT(sltShowHelpHelpDialog()));
+    connect(m_pButtonFind, SIGNAL(clicked()), this, SLOT(search()));
+    connect(m_pButtonRefresh, SIGNAL(clicked()), this, SLOT(refresh()));
+    connect(m_pButtonClose, SIGNAL(clicked()), this, SLOT(close()));
+    connect(m_pButtonSave, SIGNAL(clicked()), this, SLOT(save()));
+    connect(m_pButtonFilter, SIGNAL(clicked()), this, SLOT(filter()));
+}
+
+void UIVMLogViewer::cleanup()
+{
+    /* Save settings: */
+    saveSettings();
+
+    /* Delete the log if not already: */
+    for (int index = 0; index < m_book.count(); index++)
+    {
+        QTextEdit* pLogPage = m_book.at(index).second;
+        if (pLogPage)
+            delete m_logMap[pLogPage];
+    }
+
+    if (!m_machine.isNull())
+        m_viewers.remove(m_machine.GetName());
+}
+
 void UIVMLogViewer::retranslateUi()
 {
@@ -560,8 +910,9 @@
 
     /* Translate other tags: */
-    mBtnFind->setText(tr("&Find"));
-    mBtnRefresh->setText(tr("&Refresh"));
-    mBtnSave->setText(tr("&Save"));
-    mBtnClose->setText(tr("Close"));
+    m_pButtonFind->setText(tr("&Find"));
+    m_pButtonRefresh->setText(tr("&Refresh"));
+    m_pButtonSave->setText(tr("&Save"));
+    m_pButtonClose->setText(tr("Close"));
+    m_pButtonFilter->setText(tr("Fil&ter"));
 }
 
@@ -574,5 +925,5 @@
      * the widget style & layout are not fully done, at least the minimum
      * size hint is not properly calculated. Since this is sometimes necessary,
-     * we provide our own "polish" implementation. */
+     * we provide our own "polish" implementation: */
 
     if (m_fIsPolished)
@@ -581,5 +932,5 @@
     m_fIsPolished = true;   
 
-    /* Make sure the log view widget has the focus */
+    /* Make sure the log view widget has the focus: */
     QWidget *pCurrentLogPage = currentLogPage();
     if (pCurrentLogPage)
@@ -595,5 +946,5 @@
         case Qt::Key_Escape:
         {
-            mBtnClose->animateClick();
+            m_pButtonClose->animateClick();
             return;
         }
@@ -624,4 +975,17 @@
 }
 
+QTextEdit* UIVMLogViewer::currentLogPage()
+{
+    if (m_pViewerContainer->isEnabled())
+    {
+        QWidget *pContainer = m_pViewerContainer->currentWidget();
+        QTextEdit *pBrowser = pContainer->findChild<QTextEdit*>();
+        Assert(pBrowser);
+        return pBrowser ? pBrowser : 0;
+    }
+    else
+        return 0;
+}
+
 QTextEdit* UIVMLogViewer::createLogPage(const QString &strName)
 {
@@ -641,4 +1005,9 @@
     m_pViewerContainer->addTab(pPageContainer, strName);
     return pLogViewer;
+}
+
+const QString* UIVMLogViewer::currentLog()
+{
+    return m_logMap[currentLogPage()];
 }
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/UIVMLogViewer.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/UIVMLogViewer.h	(revision 58266)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/UIVMLogViewer.h	(revision 58267)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2008-2012 Oracle Corporation
+ * Copyright (C) 2010-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -16,6 +16,6 @@
  */
 
-#ifndef __UIVMLogViewer_h__
-#define __UIVMLogViewer_h__
+#ifndef ___UIVMLogViewer_h___
+#define ___UIVMLogViewer_h___
 
 /* Qt includes: */
@@ -25,6 +25,6 @@
 
 /* GUI includes: */
+#include "QIWithRetranslateUI.h"
 #include "UIVMLogViewer.gen.h"
-#include "QIWithRetranslateUI.h"
 
 /* COM includes: */
@@ -33,16 +33,20 @@
 
 /* Forward declarations: */
+class QComboBox;
+class QITabWidget;
 class QPushButton;
 class QTextEdit;
-class QITabWidget;
 class UIVMLogViewer;
+class UIVMLogViewerFilterPanel;
 class UIVMLogViewerSearchPanel;
 
-/* Typedefs: */
+/* Type definitions: */
 typedef QMap<QString, UIVMLogViewer*> VMLogViewerMap;
 typedef QPair<QString, QTextEdit*> LogPage;
 typedef QList<LogPage> LogBook;
+typedef QMap<QTextEdit*, QString*> VMLogMap;
 
-/* VM Log Viewer window: */
+/** QMainWindow extension
+  * providing GUI with VirtualBox LogViewer. */
 class UIVMLogViewer : public QIWithRetranslateUI2<QMainWindow>,
                       public Ui::UIVMLogViewer
@@ -52,33 +56,59 @@
 public:
 
-    /* Static method to create/show VM Log Viewer: */
+    /** Static method to create/show VM Log Viewer by passing @a pParent to QWidget base-class constructor.
+      * @a machine specifies the machine for which VM Log-Viewer is requested. */
     static void showLogViewerFor(QWidget *pParent, const CMachine &machine);
 
 protected:
 
-    /* Constructor/destructor: */
+    /** Constructs the VM Log-Viewer by passing @a pParent to QWidget base-class constructor.
+      * @a flags specifies Qt window flags.
+      * @a machine specifies the machine for which VM Log-Viewer is requested. */
     UIVMLogViewer(QWidget *pParent, Qt::WindowFlags flags, const CMachine &machine);
+    /** Destructs the VM Log-Viewer. */
     ~UIVMLogViewer();
 
 private slots:
 
-    /* Button slots: */
+    /** Handles search action triggering. */
     void search();
+    /** Handles search action triggering. */
     void refresh();
+    /** Handles close action triggering. */
     bool close();
+    /** Handles save action triggering. */
     void save();
+    /** Handles filter action triggering. */
+    void filter();
 
 private:
 
-    /* Translation stuff: */
+    /** Prepares VM Log-Viewer. */
+    void prepare();
+
+    /** Prepares widgets. */
+    void prepareWidgets();
+
+    /** Prepares connections. */
+    void prepareConnections();
+
+    /** Cleanups VM Log-Viewer. */
+    void cleanup();
+
+    /** Handles translation event. */
     void retranslateUi();
 
-    /* Event handlers: */
-    void showEvent(QShowEvent *aEvent);
+    /** Handles Qt show @a pEvent. */
+    void showEvent(QShowEvent *pEvent);
+
+    /** Handles Qt key-press @a pEvent. */
     void keyPressEvent(QKeyEvent *pEvent);
 
-    /* Various helpers: */
+    /** Returns the current log-page. */
     QTextEdit* currentLogPage();
+    /** Returns the newly created log-page using @a strPage filename. */
     QTextEdit* createLogPage(const QString &strPage);
+    /** Returns the content of current log-page. */
+    const QString* currentLog();
 
     /** Load settings helper. */
@@ -88,28 +118,48 @@
     void saveSettings();
 
-    /* Array containing all VM Log Viewers: */
+    /** Holds the list of all VM Log Viewers. */
     static VMLogViewerMap m_viewers;
 
-    /* VM Log Viewer variables: */
+    /** Holds whether the dialog is polished. */
     bool m_fIsPolished;
+
+    /** Holds the machine instance. */
     CMachine m_machine;
+
+    /** Holds container for log-pages. */
     QITabWidget *m_pViewerContainer;
+
+    /** Holds the instance of search panel. */
     UIVMLogViewerSearchPanel *m_pSearchPanel;
+
+    /** Holds the list of log-pages. */
     LogBook m_book;
+
+    /** Holds the instance of filter panel. */
+    UIVMLogViewerFilterPanel *m_pFilterPanel;
+
+    /** Holds the list of log-content. */
+    VMLogMap m_logMap;
 
     /** Current dialog geometry. */
     QRect m_geometry;
 
-    /* Buttons: */
-    QPushButton *mBtnHelp;
-    QPushButton *mBtnFind;
-    QPushButton *mBtnRefresh;
-    QPushButton *mBtnClose;
-    QPushButton *mBtnSave;
+    /** Holds the help button instance. */
+    QPushButton *m_pButtonHelp;
+    /** Holds the find button instance. */
+    QPushButton *m_pButtonFind;
+    /** Holds the refresh button instance. */
+    QPushButton *m_pButtonRefresh;
+    /** Holds the close button instance. */
+    QPushButton *m_pButtonClose;
+    /** Holds the save button instance. */
+    QPushButton *m_pButtonSave;
+    /** Holds the filter button instance. */
+    QPushButton *m_pButtonFilter;
 
-    /* Friends: */
     friend class UIVMLogViewerSearchPanel;
+    friend class UIVMLogViewerFilterPanel;
 };
 
-#endif // __UIVMLogViewer_h__
+#endif /* !___UIVMLogViewer_h___ */
 
