VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/activity/overview/UIVMActivityOverviewModelView.cpp

Last change on this file was 106061, checked in by vboxsync, 2 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.0 KB
Line 
1/* $Id: UIVMActivityOverviewModelView.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIVMActivityOverviewModelView class implementation.
4 */
5
6/*
7 * Copyright (C) 2009-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QApplication>
30#include <QHeaderView>
31#include <QMouseEvent>
32#include <QTimer>
33
34/* GUI includes: */
35#include "UIConverter.h"
36#include "UIExtraDataDefs.h"
37#include "UIGlobalSession.h"
38#include "UILocalMachineStuff.h"
39#include "UIMonitorCommon.h"
40#include "UITranslator.h"
41#include "UIVirtualBoxEventHandler.h"
42#include "UIVirtualMachineItemCloud.h"
43#include "UIVMActivityOverviewModelView.h"
44
45
46#ifdef VBOX_WS_MAC
47# include "UIWindowMenuManager.h"
48#endif /* VBOX_WS_MAC */
49
50/* COM includes: */
51#include "CConsole.h"
52#include "CGuest.h"
53#include "CMachine.h"
54#include "CMachineDebugger.h"
55#include "CSession.h"
56#include "KMetricType.h"
57
58/*********************************************************************************************************************************
59* UIVMActivityOverviewCell definition. *
60*********************************************************************************************************************************/
61
62class UIVMActivityOverviewCell : public QITableViewCell
63{
64
65 Q_OBJECT;
66
67public:
68
69 UIVMActivityOverviewCell(QITableViewRow *pRow);
70 virtual QString text() const RT_OVERRIDE RT_FINAL;
71 int columnLength(int iColumnIndex) const;
72 void setText(const QString &strText);
73
74private:
75
76 QString m_strText;
77};
78
79
80/*********************************************************************************************************************************
81* UIVMActivityOverviewRow definition. *
82*********************************************************************************************************************************/
83
84class UIVMActivityOverviewRow : public QITableViewRow
85{
86
87 Q_OBJECT;
88
89public:
90
91 UIVMActivityOverviewRow(QITableView *pTableView, const QUuid &uMachineId,
92 const QString &strMachineName);
93
94 const QUuid &machineId() const;
95
96 virtual void setMachineState(int iState) = 0;
97 virtual bool isRunning() const = 0;
98 virtual bool isCloudVM() const = 0;
99
100 virtual ~UIVMActivityOverviewRow();
101 virtual int childCount() const RT_OVERRIDE RT_FINAL;
102
103 virtual QITableViewCell *childItem(int iIndex) const RT_OVERRIDE RT_FINAL;
104 int columnLength(int iColumnIndex) const;
105 QString cellText(int iColumn) const;
106 virtual QString machineStateString() const = 0;
107
108protected:
109 void updateCellText(int /*VMActivityOverviewColumn*/ iColumnIndex, const QString &strText);
110 QUuid m_uMachineId;
111 /* Key is VMActivityOverviewColumn enum item. */
112 QMap<int, UIVMActivityOverviewCell*> m_cells;
113
114 QString m_strMachineName;
115 quint64 m_uTotalRAM;
116
117private:
118
119 void initCells();
120};
121
122/*********************************************************************************************************************************
123* UIVMActivityOverviewRowLocal definition. *
124*********************************************************************************************************************************/
125
126class UIVMActivityOverviewRowLocal : public UIVMActivityOverviewRow
127{
128
129 Q_OBJECT;
130
131public:
132
133 UIVMActivityOverviewRowLocal(QITableView *pTableView, const QUuid &uMachineId,
134 const QString &strMachineName, KMachineState enmMachineState);
135 ~UIVMActivityOverviewRowLocal();
136 virtual void setMachineState(int iState) RT_OVERRIDE RT_FINAL;
137
138 virtual bool isRunning() const RT_OVERRIDE RT_FINAL;
139 virtual bool isCloudVM() const RT_OVERRIDE RT_FINAL;
140 virtual QString machineStateString() const RT_OVERRIDE RT_FINAL;
141 void resetDebugger();
142 void updateCells();
143 bool isWithGuestAdditions();
144 void setTotalRAM(quint64 uTotalRAM);
145 void setFreeRAM(quint64 uFreeRAM);
146
147private:
148
149 KMachineState m_enmMachineState;
150 CMachineDebugger m_comDebugger;
151 CSession m_comSession;
152 CGuest m_comGuest;
153 quint64 m_uFreeRAM;
154 quint64 m_uNetworkDownTotal;
155 quint64 m_uNetworkUpTotal;
156 quint64 m_uVMExitTotal;
157 quint64 m_uDiskWriteTotal;
158 quint64 m_uDiskReadTotal;
159};
160
161
162/*********************************************************************************************************************************
163* UIVMActivityOverviewRowCloud definition. *
164*********************************************************************************************************************************/
165
166/* A UIVMActivityOverviewItem derivation to show cloud vms in the table view: */
167class UIVMActivityOverviewRowCloud : public UIVMActivityOverviewRow
168{
169 Q_OBJECT;
170
171public:
172
173 UIVMActivityOverviewRowCloud(QITableView *pTableView, const QUuid &uMachineId,
174 const QString &strMachineName, CCloudMachine &comCloudMachine);
175 void updateMachineState();
176 virtual bool isRunning() const RT_OVERRIDE RT_FINAL;
177 virtual bool isCloudVM() const RT_OVERRIDE RT_FINAL;
178 virtual QString machineStateString() const RT_OVERRIDE RT_FINAL;
179 virtual void setMachineState(int iState) RT_OVERRIDE RT_FINAL;
180
181private slots:
182
183 void sltTimeout();
184 void sltMetricNameListingComplete(QVector<QString> metricNameList);
185 void sltMetricDataReceived(KMetricType enmMetricType,
186 const QVector<QString> &data, const QVector<QString> &timeStamps);
187private:
188
189 void getMetricList();
190 void resetColumData();
191
192 QTimer *m_pTimer;
193 CCloudMachine m_comCloudMachine;
194 KCloudMachineState m_enmMachineState;
195 QVector<KMetricType> m_availableMetricTypes;
196};
197
198
199/*********************************************************************************************************************************
200* UIVMActivityOverviewCell implementation. *
201*********************************************************************************************************************************/
202
203UIVMActivityOverviewCell::UIVMActivityOverviewCell(QITableViewRow *pRow)
204 :QITableViewCell(pRow)
205{
206}
207
208QString UIVMActivityOverviewCell::text() const
209{
210 return m_strText;
211}
212
213int UIVMActivityOverviewCell::columnLength(int /*iColumnIndex*/) const
214{
215 return 0;
216}
217
218void UIVMActivityOverviewCell::setText(const QString &strText)
219{
220 m_strText = strText;
221}
222
223/*********************************************************************************************************************************
224* UIVMActivityOverviewRow implementation. *
225*********************************************************************************************************************************/
226
227UIVMActivityOverviewRow::UIVMActivityOverviewRow(QITableView *pTableView, const QUuid &uMachineId,
228 const QString &strMachineName)
229 : QITableViewRow(pTableView)
230 , m_uMachineId(uMachineId)
231 , m_strMachineName(strMachineName)
232 , m_uTotalRAM(0)
233{
234 initCells();
235}
236
237int UIVMActivityOverviewRow::childCount() const
238{
239 return m_cells.size();
240}
241
242QITableViewCell *UIVMActivityOverviewRow::childItem(int iIndex) const
243{
244 return m_cells.value(iIndex, 0);
245}
246
247QString UIVMActivityOverviewRow::cellText(int iColumn) const
248{
249 if (!m_cells.contains(iColumn))
250 return QString();
251 if (!m_cells[iColumn])
252 return QString();
253 return m_cells[iColumn]->text();
254}
255
256int UIVMActivityOverviewRow::columnLength(int iColumnIndex) const
257{
258 UIVMActivityOverviewCell *pCell = m_cells.value(iColumnIndex, 0);
259 if (!pCell)
260 return 0;
261 return pCell->text().length();
262}
263
264UIVMActivityOverviewRow::~UIVMActivityOverviewRow()
265{
266 qDeleteAll(m_cells);
267}
268
269void UIVMActivityOverviewRow::initCells()
270{
271 for (int i = (int) VMActivityOverviewColumn_Name; i < (int) VMActivityOverviewColumn_Max; ++i)
272 m_cells[i] = new UIVMActivityOverviewCell(this);
273 m_cells[VMActivityOverviewColumn_Name]->setText(m_strMachineName);
274}
275
276const QUuid &UIVMActivityOverviewRow::machineId() const
277{
278 return m_uMachineId;
279}
280
281void UIVMActivityOverviewRow::updateCellText(int /*VMActivityOverviewColumn*/ enmColumnIndex, const QString &strText)
282{
283 if (m_cells.value(enmColumnIndex, 0))
284 m_cells[enmColumnIndex]->setText(strText);
285}
286
287/*********************************************************************************************************************************
288* UIVMActivityOverviewRowLocal implementation. *
289*********************************************************************************************************************************/
290
291UIVMActivityOverviewRowLocal::UIVMActivityOverviewRowLocal(QITableView *pTableView, const QUuid &uMachineId,
292 const QString &strMachineName, KMachineState enmMachineState)
293 : UIVMActivityOverviewRow(pTableView, uMachineId, strMachineName)
294 , m_enmMachineState(enmMachineState)
295 , m_uFreeRAM(0)
296 , m_uNetworkDownTotal(0)
297 , m_uNetworkUpTotal(0)
298 , m_uVMExitTotal(0)
299 , m_uDiskWriteTotal(0)
300 , m_uDiskReadTotal(0)
301{
302 if (m_enmMachineState == KMachineState_Running)
303 resetDebugger();
304}
305
306void UIVMActivityOverviewRowLocal::updateCells()
307{
308 /* CPU Load: */
309 ULONG aPctHalted;
310 ULONG uCPUGuestLoad;
311 ULONG uCPUVMMLoad;
312 m_comDebugger.GetCPULoad(0x7fffffff, uCPUGuestLoad, aPctHalted, uCPUVMMLoad);
313 updateCellText(VMActivityOverviewColumn_CPUVMMLoad, QString("%1%").arg(QString::number(uCPUVMMLoad)));
314 updateCellText(VMActivityOverviewColumn_CPUGuestLoad, QString("%1%").arg(QString::number(uCPUGuestLoad)));
315
316 /* RAM Utilization: */
317 QString strRAMUsage;
318 QString strRAMPercentage;
319 int iDecimalCount = 2;
320 quint64 uUsedRAM = m_uTotalRAM - m_uFreeRAM;
321 float m_fRAMUsagePercentage = 0;
322
323 if (m_uTotalRAM != 0)
324 m_fRAMUsagePercentage = 100.f * (uUsedRAM / (float)m_uTotalRAM);
325
326 if (isWithGuestAdditions())
327 {
328 strRAMUsage =
329 QString("%1/%2").arg(UITranslator::formatSize(_1K * uUsedRAM, iDecimalCount)).
330 arg(UITranslator::formatSize(_1K * m_uTotalRAM, iDecimalCount));
331 strRAMPercentage =
332 QString("%1%").arg(QString::number(m_fRAMUsagePercentage, 'f', 2));
333 }
334 else
335 {
336 strRAMPercentage = QApplication::translate("UIVMActivityOverviewWidget", "N/A");
337 strRAMUsage = QApplication::translate("UIVMActivityOverviewWidget", "N/A");
338 }
339
340 updateCellText(VMActivityOverviewColumn_RAMUsedAndTotal, strRAMUsage);
341 updateCellText(VMActivityOverviewColumn_RAMUsedPercentage, strRAMPercentage);
342
343 /* Network rate: */
344 quint64 uPrevDownTotal = m_uNetworkDownTotal;
345 quint64 uPrevUpTotal = m_uNetworkUpTotal;
346 UIMonitorCommon::getNetworkLoad(m_comDebugger, m_uNetworkDownTotal, m_uNetworkUpTotal);
347 quint64 uNetworkDownRate = m_uNetworkDownTotal - uPrevDownTotal;
348 quint64 uNetworkUpRate = m_uNetworkUpTotal - uPrevUpTotal;
349
350 updateCellText(VMActivityOverviewColumn_NetworkUpRate, QString("%1").arg(UITranslator::formatSize(uNetworkUpRate, iDecimalCount)));
351 updateCellText(VMActivityOverviewColumn_NetworkDownRate,QString("%1").arg(UITranslator::formatSize(uNetworkDownRate, iDecimalCount)));
352 updateCellText(VMActivityOverviewColumn_NetworkUpTotal, QString("%1").arg(UITranslator::formatSize(m_uNetworkUpTotal, iDecimalCount)));
353 updateCellText(VMActivityOverviewColumn_NetworkDownTotal, QString("%1").arg(UITranslator::formatSize(m_uNetworkDownTotal, iDecimalCount)));
354
355 /* IO rate: */
356 quint64 uPrevWriteTotal = m_uDiskWriteTotal;
357 quint64 uPrevReadTotal = m_uDiskReadTotal;
358 UIMonitorCommon::getDiskLoad(m_comDebugger, m_uDiskWriteTotal, m_uDiskReadTotal);
359 quint64 uDiskWriteRate = m_uDiskWriteTotal - uPrevWriteTotal;
360 quint64 uDiskReadRate = m_uDiskReadTotal - uPrevReadTotal;
361 updateCellText(VMActivityOverviewColumn_DiskIOReadRate,QString("%1").arg(UITranslator::formatSize(uDiskReadRate, iDecimalCount)));
362 updateCellText(VMActivityOverviewColumn_DiskIOWriteRate,QString("%1").arg(UITranslator::formatSize(uDiskWriteRate, iDecimalCount)));
363 updateCellText(VMActivityOverviewColumn_DiskIOReadTotal, QString("%1").arg(UITranslator::formatSize(m_uDiskReadTotal, iDecimalCount)));
364 updateCellText(VMActivityOverviewColumn_DiskIOWriteTotal, QString("%1").arg(UITranslator::formatSize(m_uDiskWriteTotal, iDecimalCount)));
365
366 /* VM Exits: */
367 quint64 uPrevVMExitsTotal = m_uVMExitTotal;
368 UIMonitorCommon::getVMMExitCount(m_comDebugger, m_uVMExitTotal);
369 quint64 uVMExitRate = m_uVMExitTotal - uPrevVMExitsTotal;
370 updateCellText(VMActivityOverviewColumn_VMExits, QString("%1/%2").arg(UITranslator::addMetricSuffixToNumber(uVMExitRate)).
371 arg(UITranslator::addMetricSuffixToNumber(m_uVMExitTotal)));
372}
373
374UIVMActivityOverviewRowLocal::~UIVMActivityOverviewRowLocal()
375{
376 if (!m_comSession.isNull())
377 m_comSession.UnlockMachine();
378}
379
380void UIVMActivityOverviewRowLocal::resetDebugger()
381{
382 m_comSession = openSession(m_uMachineId, KLockType_Shared);
383 if (!m_comSession.isNull())
384 {
385 CConsole comConsole = m_comSession.GetConsole();
386 if (!comConsole.isNull())
387 {
388 m_comGuest = comConsole.GetGuest();
389 m_comDebugger = comConsole.GetDebugger();
390 }
391 }
392}
393
394void UIVMActivityOverviewRowLocal::setMachineState(int iState)
395{
396 if (iState <= KMachineState_Null || iState >= KMachineState_Max)
397 return;
398 KMachineState enmState = static_cast<KMachineState>(iState);
399 if (m_enmMachineState == enmState)
400 return;
401 m_enmMachineState = enmState;
402 if (m_enmMachineState == KMachineState_Running)
403 resetDebugger();
404}
405
406bool UIVMActivityOverviewRowLocal::isRunning() const
407{
408 return m_enmMachineState == KMachineState_Running;
409}
410
411bool UIVMActivityOverviewRowLocal::isCloudVM() const
412{
413 return false;
414}
415
416bool UIVMActivityOverviewRowLocal::isWithGuestAdditions()
417{
418 if (m_comGuest.isNull())
419 return false;
420 return m_comGuest.GetAdditionsStatus(m_comGuest.GetAdditionsRunLevel());
421}
422
423void UIVMActivityOverviewRowLocal::setTotalRAM(quint64 uTotalRAM)
424{
425 m_uTotalRAM = uTotalRAM;
426}
427
428void UIVMActivityOverviewRowLocal::setFreeRAM(quint64 uFreeRAM)
429{
430 m_uFreeRAM = uFreeRAM;
431}
432
433QString UIVMActivityOverviewRowLocal::machineStateString() const
434{
435 return gpConverter->toString(m_enmMachineState);
436}
437
438/*********************************************************************************************************************************
439* UIVMActivityOverviewRowCloud implementation. *
440*********************************************************************************************************************************/
441
442UIVMActivityOverviewRowCloud::UIVMActivityOverviewRowCloud(QITableView *pTableView, const QUuid &uMachineId,
443 const QString &strMachineName, CCloudMachine &comCloudMachine)
444 : UIVMActivityOverviewRow(pTableView, uMachineId, strMachineName)
445 , m_comCloudMachine(comCloudMachine)
446{
447 updateMachineState();
448 m_pTimer = new QTimer(this);
449 if (m_pTimer)
450 {
451 connect(m_pTimer, &QTimer::timeout, this, &UIVMActivityOverviewRowCloud::sltTimeout);
452 m_pTimer->setInterval(60 * 1000);
453 }
454 resetColumData();
455}
456
457void UIVMActivityOverviewRowCloud::updateMachineState()
458{
459 if (m_comCloudMachine.isOk())
460 setMachineState(m_comCloudMachine.GetState());
461}
462
463bool UIVMActivityOverviewRowCloud::isRunning() const
464{
465 return m_enmMachineState == KCloudMachineState_Running;
466}
467
468bool UIVMActivityOverviewRowCloud::isCloudVM() const
469{
470 return true;
471}
472
473QString UIVMActivityOverviewRowCloud::machineStateString() const
474{
475 if (!m_comCloudMachine.isOk())
476 return QString();
477 return gpConverter->toString(m_comCloudMachine.GetState());
478}
479
480void UIVMActivityOverviewRowCloud::sltTimeout()
481{
482 int iDataSize = 1;
483 foreach (const KMetricType &enmMetricType, m_availableMetricTypes)
484 {
485 UIProgressTaskReadCloudMachineMetricData *pTask = new UIProgressTaskReadCloudMachineMetricData(this, m_comCloudMachine,
486 enmMetricType, iDataSize);
487 connect(pTask, &UIProgressTaskReadCloudMachineMetricData::sigMetricDataReceived,
488 this, &UIVMActivityOverviewRowCloud::sltMetricDataReceived);
489 pTask->start();
490 }
491}
492
493void UIVMActivityOverviewRowCloud::sltMetricDataReceived(KMetricType enmMetricType,
494 const QVector<QString> &data, const QVector<QString> &timeStamps)
495{
496 Q_UNUSED(timeStamps);
497 if (data.isEmpty())
498 return;
499
500 if (data[0].toFloat() < 0)
501 return;
502
503 int iDecimalCount = 2;
504 QLocale locale;
505 if (enmMetricType == KMetricType_CpuUtilization)
506 {
507 updateCellText(VMActivityOverviewColumn_CPUGuestLoad, QString("%1%").arg(locale.toString(data[0].toFloat(), 'f', iDecimalCount)));
508 }
509 else if (enmMetricType == KMetricType_MemoryUtilization)
510 {
511 if (m_uTotalRAM != 0)
512 {
513 quint64 uUsedRAM = (quint64)data[0].toFloat() * (m_uTotalRAM / 100.f);
514 updateCellText(VMActivityOverviewColumn_RAMUsedAndTotal,
515 QString("%1/%2").arg(UITranslator::formatSize(_1K * uUsedRAM, iDecimalCount)).
516 arg(UITranslator::formatSize(_1K * m_uTotalRAM, iDecimalCount)));
517 }
518 updateCellText(VMActivityOverviewColumn_RAMUsedPercentage,
519 QString("%1%").arg(QString::number(data[0].toFloat(), 'f', iDecimalCount)));
520 }
521 else if (enmMetricType == KMetricType_NetworksBytesOut)
522 updateCellText(VMActivityOverviewColumn_NetworkUpRate,
523 UITranslator::formatSize((quint64)data[0].toFloat(), iDecimalCount));
524 else if (enmMetricType == KMetricType_NetworksBytesIn)
525 updateCellText(VMActivityOverviewColumn_NetworkDownRate,
526 UITranslator::formatSize((quint64)data[0].toFloat(), iDecimalCount));
527 else if (enmMetricType == KMetricType_DiskBytesRead)
528 updateCellText(VMActivityOverviewColumn_DiskIOReadRate,
529 UITranslator::formatSize((quint64)data[0].toFloat(), iDecimalCount));
530 else if (enmMetricType == KMetricType_DiskBytesWritten)
531 updateCellText(VMActivityOverviewColumn_DiskIOWriteRate,
532 UITranslator::formatSize((quint64)data[0].toFloat(), iDecimalCount));
533
534 sender()->deleteLater();
535}
536
537void UIVMActivityOverviewRowCloud::setMachineState(int iState)
538{
539 if (iState <= KCloudMachineState_Invalid || iState >= KCloudMachineState_Max)
540 return;
541 KCloudMachineState enmState = static_cast<KCloudMachineState>(iState);
542 if (m_enmMachineState == enmState)
543 return;
544 m_enmMachineState = enmState;
545 if (isRunning())
546 {
547 getMetricList();
548 if (m_uTotalRAM == 0)
549 m_uTotalRAM = UIMonitorCommon::determineTotalRAMAmount(m_comCloudMachine);
550 }
551 else
552 {
553 if (m_pTimer)
554 m_pTimer->stop();
555 }
556}
557
558void UIVMActivityOverviewRowCloud::resetColumData()
559{
560 for (int i = (int) VMActivityOverviewColumn_CPUGuestLoad;
561 i < (int)VMActivityOverviewColumn_Max; ++i)
562 updateCellText(i, QApplication::translate("UIVMActivityOverviewWidget", "N/A"));
563}
564
565void UIVMActivityOverviewRowCloud::getMetricList()
566{
567 if (!isRunning())
568 return;
569 UIProgressTaskReadCloudMachineMetricList *pReadListProgressTask =
570 new UIProgressTaskReadCloudMachineMetricList(this, m_comCloudMachine);
571 AssertPtrReturnVoid(pReadListProgressTask);
572 connect(pReadListProgressTask, &UIProgressTaskReadCloudMachineMetricList::sigMetricListReceived,
573 this, &UIVMActivityOverviewRowCloud::sltMetricNameListingComplete);
574 pReadListProgressTask->start();
575}
576
577void UIVMActivityOverviewRowCloud::sltMetricNameListingComplete(QVector<QString> metricNameList)
578{
579 AssertReturnVoid(m_pTimer);
580 m_availableMetricTypes.clear();
581 foreach (const QString &strName, metricNameList)
582 m_availableMetricTypes << gpConverter->fromInternalString<KMetricType>(strName);
583
584 if (!m_availableMetricTypes.isEmpty())
585 {
586 /* Dont wait 60 secs: */
587 sltTimeout();
588 m_pTimer->start();
589 }
590 else
591 {
592 m_pTimer->stop();
593 resetColumData();
594 }
595
596 if (sender())
597 sender()->deleteLater();
598
599}
600
601
602/*********************************************************************************************************************************
603* UIVMActivityOverviewTableView implementation. *
604*********************************************************************************************************************************/
605
606UIVMActivityOverviewTableView::UIVMActivityOverviewTableView(QWidget *pParent)
607 : QITableView(pParent)
608{
609}
610
611void UIVMActivityOverviewTableView::updateColumVisibility()
612{
613 UIVMActivityOverviewProxyModel *pProxyModel = qobject_cast<UIVMActivityOverviewProxyModel*>(model());
614 if (!pProxyModel)
615 return;
616 UIVMActivityOverviewModel *pModel = qobject_cast<UIVMActivityOverviewModel*>(pProxyModel->sourceModel());
617 QHeaderView *pHeader = horizontalHeader();
618
619 if (!pModel || !pHeader)
620 return;
621 for (int i = (int)VMActivityOverviewColumn_Name; i < (int)VMActivityOverviewColumn_Max; ++i)
622 {
623 if (!pModel->columnVisible(i))
624 pHeader->hideSection(i);
625 else
626 pHeader->showSection(i);
627 }
628 resizeHeaders();
629}
630
631int UIVMActivityOverviewTableView::selectedItemIndex() const
632{
633 UIVMActivityOverviewProxyModel *pModel = qobject_cast<UIVMActivityOverviewProxyModel*>(model());
634 if (!pModel)
635 return -1;
636
637 QItemSelectionModel *pSelectionModel = selectionModel();
638 if (!pSelectionModel)
639 return -1;
640 QModelIndexList selectedItemIndices = pSelectionModel->selectedRows();
641 if (selectedItemIndices.isEmpty())
642 return -1;
643
644 /* just use the the 1st index: */
645 QModelIndex modelIndex = pModel->mapToSource(selectedItemIndices[0]);
646
647 if (!modelIndex.isValid())
648 return -1;
649 return modelIndex.row();
650}
651
652bool UIVMActivityOverviewTableView::hasSelection() const
653{
654 if (!selectionModel())
655 return false;
656 return selectionModel()->hasSelection();
657}
658
659void UIVMActivityOverviewTableView::setMinimumColumnWidths(const QMap<int, int>& widths)
660{
661 m_minimumColumnWidths = widths;
662 resizeHeaders();
663}
664
665void UIVMActivityOverviewTableView::resizeEvent(QResizeEvent *pEvent)
666{
667 resizeHeaders();
668 QTableView::resizeEvent(pEvent);
669}
670
671void UIVMActivityOverviewTableView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
672{
673 emit sigSelectionChanged(selected, deselected);
674 QTableView::selectionChanged(selected, deselected);
675}
676
677void UIVMActivityOverviewTableView::mousePressEvent(QMouseEvent *pEvent)
678{
679 if (!indexAt(pEvent->position().toPoint()).isValid())
680 clearSelection();
681 QTableView::mousePressEvent(pEvent);
682}
683
684void UIVMActivityOverviewTableView::resizeHeaders()
685{
686 QHeaderView* pHeader = horizontalHeader();
687 if (!pHeader || pHeader->count() <= 0)
688 return;
689 int iSectionCount = pHeader->count();
690 int iHiddenSectionCount = pHeader->hiddenSectionCount();
691 if (iSectionCount == iHiddenSectionCount)
692 return;
693 int iWidth = width() / (iSectionCount - iHiddenSectionCount);
694 for (int i = 0; i < iSectionCount; ++i)
695 {
696 if (pHeader->isSectionHidden(i))
697 continue;
698 int iMinWidth = m_minimumColumnWidths.value((VMActivityOverviewColumn)i, 0);
699 pHeader->resizeSection(i, iWidth < iMinWidth ? iMinWidth : iWidth);
700 }
701}
702
703/*********************************************************************************************************************************
704* UIVMActivityOverviewModel implementation. *
705*********************************************************************************************************************************/
706
707UIVMActivityOverviewModel::UIVMActivityOverviewModel(QObject *pParent, QITableView *pView)
708 :QAbstractTableModel(pParent)
709 , m_pTableView(pView)
710 , m_pLocalVMUpdateTimer(new QTimer(this))
711{
712 initialize();
713}
714
715void UIVMActivityOverviewModel::setCloudMachineItems(const QList<UIVirtualMachineItemCloud*> &cloudItems)
716{
717 QVector<QUuid> newIds;
718 foreach (const UIVirtualMachineItemCloud* pItem, cloudItems)
719 {
720 if (!pItem)
721 continue;
722 QUuid id = pItem->machineId();
723 if (id.isNull())
724 continue;
725 newIds << id;
726 }
727 QVector<UIVMActivityOverviewRow*> originalItemList = m_rows;
728
729 /* Remove m_rows items that are not in @cloudItems: */
730 QMutableVectorIterator<UIVMActivityOverviewRow*> iterator(m_rows);
731 while (iterator.hasNext())
732 {
733 UIVMActivityOverviewRow *pItem = iterator.next();
734 if (!pItem->isCloudVM())
735 continue;
736 if (pItem && !newIds.contains(pItem->machineId()))
737 iterator.remove();
738 }
739
740 /* Add items that are not in m_rows: */
741 foreach (const UIVirtualMachineItemCloud* pItem, cloudItems)
742 {
743 if (!pItem)
744 continue;
745 CCloudMachine comMachine = pItem->machine();
746 if (!comMachine.isOk())
747 continue;
748 QUuid id = comMachine.GetId();
749 /* Linearly search for the vm with th same id. I cannot make QVector::contain work since we store pointers: */
750 bool fFound = false;
751 for (int i = 0; i < m_rows.size() && !fFound; ++i)
752 {
753 if (m_rows[i] && m_rows[i]->machineId() == id)
754 fFound = true;
755 }
756 if (!fFound)
757 m_rows.append(new UIVMActivityOverviewRowCloud(m_pTableView, id, comMachine.GetName(), comMachine));
758 }
759
760 /* Update cloud machine states: */
761 for (int i = 0; i < m_rows.size(); ++i)
762 {
763 if (!m_rows[i] || !m_rows[i]->isCloudVM())
764 continue;
765 UIVMActivityOverviewRowCloud *pItem = qobject_cast<UIVMActivityOverviewRowCloud*>(m_rows[i]);
766 if (!pItem)
767 continue;
768 pItem->updateMachineState();
769 }
770}
771
772void UIVMActivityOverviewModel::setColumnVisible(const QMap<int, bool>& columnVisible)
773{
774 m_columnVisible = columnVisible;
775}
776
777bool UIVMActivityOverviewModel::columnVisible(int iColumnId) const
778{
779 return m_columnVisible.value(iColumnId, true);
780}
781
782
783bool UIVMActivityOverviewModel::isVMRunning(int rowIndex) const
784{
785 if (rowIndex >= m_rows.size() || rowIndex < 0 || !m_rows[rowIndex])
786 return false;
787 return m_rows[rowIndex]->isRunning();
788}
789
790bool UIVMActivityOverviewModel::isCloudVM(int rowIndex) const
791{
792 if (rowIndex >= m_rows.size() || rowIndex < 0 || !m_rows[rowIndex])
793 return false;
794 return m_rows[rowIndex]->isCloudVM();
795}
796
797void UIVMActivityOverviewModel::setupPerformanceCollector()
798{
799 m_nameList.clear();
800 m_objectList.clear();
801 /* Initialize and configure CPerformanceCollector: */
802 const ULONG iPeriod = 1;
803 const int iMetricSetupCount = 1;
804 if (m_performanceCollector.isNull())
805 m_performanceCollector = gpGlobalSession->virtualBox().GetPerformanceCollector();
806 for (int i = 0; i < m_rows.size(); ++i)
807 m_nameList << "Guest/RAM/Usage*";
808 /* This is for the host: */
809 m_nameList << "CPU*";
810 m_nameList << "FS*";
811 m_objectList = QVector<CUnknown>(m_nameList.size(), CUnknown());
812 m_performanceCollector.SetupMetrics(m_nameList, m_objectList, iPeriod, iMetricSetupCount);
813}
814
815void UIVMActivityOverviewModel::clearData()
816{
817 /* We have a request to detach COM stuff,
818 * first of all we are removing all the items,
819 * this will detach COM wrappers implicitly: */
820 qDeleteAll(m_rows);
821 m_rows.clear();
822 /* Detaching perf. collector finally,
823 * please do not use it after all: */
824 m_performanceCollector.detach();
825}
826
827UIVMActivityOverviewModel::~UIVMActivityOverviewModel()
828{
829 clearData();
830}
831
832void UIVMActivityOverviewModel::setShouldUpdate(bool fShouldUpdate)
833{
834 if (m_pLocalVMUpdateTimer)
835 {
836 if (fShouldUpdate)
837 m_pLocalVMUpdateTimer->start();
838 else
839 m_pLocalVMUpdateTimer->stop();
840 }
841}
842
843QModelIndex UIVMActivityOverviewModel::index(int iRow, int iColumn, const QModelIndex &parentIdx /* = QModelIndex() */) const
844{
845 /* No index for unknown items: */
846 if (!hasIndex(iRow, iColumn, parentIdx))
847 return QModelIndex();
848
849 /* Provide index users with packed item pointer: */
850 UIVMActivityOverviewRow *pItem = iRow >= 0 && iRow < m_rows.size() ? m_rows.at(iRow) : 0;
851 return pItem ? createIndex(iRow, iColumn, pItem) : QModelIndex();
852}
853
854int UIVMActivityOverviewModel::rowCount(const QModelIndex &parent) const
855{
856 Q_UNUSED(parent);
857 return m_rows.size();
858}
859
860int UIVMActivityOverviewModel::columnCount(const QModelIndex &parent) const
861{
862 Q_UNUSED(parent);
863 if (m_rows.isEmpty())
864 return 0;
865 if (m_rows[0])
866 return m_rows[0]->childCount();
867 return 0;
868}
869
870QVariant UIVMActivityOverviewModel::data(const QModelIndex &index, int role) const
871{
872 int iRow = index.row();
873 if (iRow < 0 || iRow >= m_rows.size())
874 return QVariant();
875 if (!m_rows[iRow])
876 return QVariant();
877
878 if (role == Qt::DisplayRole)
879 {
880 return m_rows[iRow]->cellText(index.column());
881
882 }
883 return QVariant();
884}
885
886const QMap<int, int> UIVMActivityOverviewModel::dataLengths() const
887{
888 return m_columnDataMaxLength;
889}
890
891void UIVMActivityOverviewModel::initialize()
892{
893 for (int i = 0; i < (int)VMActivityOverviewColumn_Max; ++i)
894 m_columnDataMaxLength[i] = 0;
895
896 if (m_pLocalVMUpdateTimer)
897 {
898 connect(m_pLocalVMUpdateTimer, &QTimer::timeout, this, &UIVMActivityOverviewModel::sltLocalVMUpdateTimeout);
899 m_pLocalVMUpdateTimer->start(1000);
900 }
901
902 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMachineStateChange,
903 this, &UIVMActivityOverviewModel::sltMachineStateChanged);
904 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMachineRegistered,
905 this, &UIVMActivityOverviewModel::sltMachineRegistered);
906 foreach (const CMachine &comMachine, gpGlobalSession->virtualBox().GetMachines())
907 {
908 if (!comMachine.isNull())
909 addRow(comMachine.GetId(), comMachine.GetName(), comMachine.GetState());
910 }
911 setupPerformanceCollector();
912}
913
914void UIVMActivityOverviewModel::addRow(const QUuid& uMachineId, const QString& strMachineName, KMachineState enmState)
915{
916 //QVector<UIVMActivityOverviewRow*> m_rows;
917 m_rows << new UIVMActivityOverviewRowLocal(m_pTableView, uMachineId, strMachineName, enmState);
918}
919
920QVariant UIVMActivityOverviewModel::headerData(int section, Qt::Orientation orientation, int role) const
921{
922 if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
923 return m_columnTitles.value((VMActivityOverviewColumn)section, QString());;
924 return QVariant();
925}
926
927void UIVMActivityOverviewModel::setColumnCaptions(const QMap<int, QString>& captions)
928{
929 m_columnTitles = captions;
930}
931
932
933void UIVMActivityOverviewModel::sltMachineStateChanged(const QUuid &uId, const KMachineState state)
934{
935 int iIndex = itemIndex(uId);
936 if (iIndex != -1 && iIndex < m_rows.size())
937 {
938 UIVMActivityOverviewRowLocal *pItem = qobject_cast<UIVMActivityOverviewRowLocal*>(m_rows[iIndex]);
939 if (pItem)
940 {
941 pItem->setMachineState(state);
942 if (state == KMachineState_Running)
943 pItem->resetDebugger();
944 }
945 }
946}
947
948void UIVMActivityOverviewModel::sltMachineRegistered(const QUuid &uId, bool fRegistered)
949{
950 if (fRegistered)
951 {
952 CMachine comMachine = gpGlobalSession->virtualBox().FindMachine(uId.toString());
953 if (!comMachine.isNull())
954 addRow(uId, comMachine.GetName(), comMachine.GetState());
955 }
956 else
957 removeRow(uId);
958 emit sigDataUpdate();
959}
960
961void UIVMActivityOverviewModel::getHostRAMStats()
962{
963 CHost comHost = gpGlobalSession->host();
964 m_hostStats.m_iRAMTotal = _1M * (quint64)comHost.GetMemorySize();
965 m_hostStats.m_iRAMFree = _1M * (quint64)comHost.GetMemoryAvailable();
966}
967
968void UIVMActivityOverviewModel::sltLocalVMUpdateTimeout()
969{
970 /* Host's RAM usage is obtained from IHost not from IPerformanceCollector: */
971 getHostRAMStats();
972
973 /* Use IPerformanceCollector to update VM RAM usage and Host CPU and file IO stats: */
974 queryPerformanceCollector();
975
976 for (int i = 0; i < m_rows.size(); ++i)
977 {
978 UIVMActivityOverviewRowLocal *pItem = qobject_cast<UIVMActivityOverviewRowLocal*>(m_rows[i]);
979 if (!pItem || !pItem->isRunning())
980 continue;
981 pItem->updateCells();
982 }
983
984 for (int i = 0; i < (int)VMActivityOverviewColumn_Max; ++i)
985 {
986 for (int j = 0; j < m_rows.size(); ++j)
987 if (m_columnDataMaxLength.value(i, 0) < m_rows[j]->columnLength(i))
988 m_columnDataMaxLength[i] = m_rows[j]->columnLength(i);
989 }
990
991 emit sigDataUpdate();
992 emit sigHostStatsUpdate(m_hostStats);
993}
994
995int UIVMActivityOverviewModel::itemIndex(const QUuid &uid)
996{
997 for (int i = 0; i < m_rows.size(); ++i)
998 {
999 if (!m_rows[i])
1000 continue;
1001 if (m_rows[i]->machineId() == uid)
1002 return i;
1003 }
1004 return -1;
1005}
1006
1007QUuid UIVMActivityOverviewModel::itemUid(int iIndex)
1008{
1009 if (iIndex >= m_rows.size() || !m_rows[iIndex])
1010 return QUuid();
1011 return m_rows[iIndex]->machineId();
1012}
1013
1014void UIVMActivityOverviewModel::removeRow(const QUuid& uMachineId)
1015{
1016 int iIndex = itemIndex(uMachineId);
1017 if (iIndex == -1)
1018 return;
1019 delete m_rows[iIndex];
1020 m_rows.remove(iIndex);
1021}
1022
1023void UIVMActivityOverviewModel::queryPerformanceCollector()
1024{
1025 QVector<QString> aReturnNames;
1026 QVector<CUnknown> aReturnObjects;
1027 QVector<QString> aReturnUnits;
1028 QVector<ULONG> aReturnScales;
1029 QVector<ULONG> aReturnSequenceNumbers;
1030 QVector<ULONG> aReturnDataIndices;
1031 QVector<ULONG> aReturnDataLengths;
1032
1033 QVector<LONG> returnData = m_performanceCollector.QueryMetricsData(m_nameList,
1034 m_objectList,
1035 aReturnNames,
1036 aReturnObjects,
1037 aReturnUnits,
1038 aReturnScales,
1039 aReturnSequenceNumbers,
1040 aReturnDataIndices,
1041 aReturnDataLengths);
1042 /* Parse the result we get from CPerformanceCollector to get respective values: */
1043 for (int i = 0; i < aReturnNames.size(); ++i)
1044 {
1045 if (aReturnDataLengths[i] == 0)
1046 continue;
1047 /* Read the last of the return data disregarding the rest since we are caching the data in GUI side: */
1048 float fData = returnData[aReturnDataIndices[i] + aReturnDataLengths[i] - 1] / (float)aReturnScales[i];
1049 if (aReturnNames[i].contains("RAM", Qt::CaseInsensitive) && !aReturnNames[i].contains(":"))
1050 {
1051 if (aReturnNames[i].contains("Total", Qt::CaseInsensitive) || aReturnNames[i].contains("Free", Qt::CaseInsensitive))
1052 {
1053 {
1054 CMachine comMachine = (CMachine)aReturnObjects[i];
1055 if (comMachine.isNull())
1056 continue;
1057 int iIndex = itemIndex(comMachine.GetId());
1058 if (iIndex == -1 || iIndex >= m_rows.size() || !m_rows[iIndex])
1059 continue;
1060
1061 UIVMActivityOverviewRowLocal *pItem = qobject_cast<UIVMActivityOverviewRowLocal*>(m_rows[iIndex]);
1062 if (!pItem)
1063 continue;
1064 if (aReturnNames[i].contains("Total", Qt::CaseInsensitive))
1065 pItem->setTotalRAM((quint64)fData);
1066 else
1067 pItem->setFreeRAM((quint64)fData);
1068 }
1069 }
1070 }
1071 else if (aReturnNames[i].contains("CPU/Load/User", Qt::CaseInsensitive) && !aReturnNames[i].contains(":"))
1072 {
1073 CHost comHost = (CHost)aReturnObjects[i];
1074 if (!comHost.isNull())
1075 m_hostStats.m_iCPUUserLoad = fData;
1076 }
1077 else if (aReturnNames[i].contains("CPU/Load/Kernel", Qt::CaseInsensitive) && !aReturnNames[i].contains(":"))
1078 {
1079 CHost comHost = (CHost)aReturnObjects[i];
1080 if (!comHost.isNull())
1081 m_hostStats.m_iCPUKernelLoad = fData;
1082 }
1083 else if (aReturnNames[i].contains("CPU/MHz", Qt::CaseInsensitive) && !aReturnNames[i].contains(":"))
1084 {
1085 CHost comHost = (CHost)aReturnObjects[i];
1086 if (!comHost.isNull())
1087 m_hostStats.m_iCPUFreq = fData;
1088 }
1089 else if (aReturnNames[i].contains("FS", Qt::CaseInsensitive) &&
1090 aReturnNames[i].contains("Total", Qt::CaseInsensitive) &&
1091 !aReturnNames[i].contains(":"))
1092 {
1093 CHost comHost = (CHost)aReturnObjects[i];
1094 if (!comHost.isNull())
1095 m_hostStats.m_iFSTotal = _1M * fData;
1096 }
1097 else if (aReturnNames[i].contains("FS", Qt::CaseInsensitive) &&
1098 aReturnNames[i].contains("Free", Qt::CaseInsensitive) &&
1099 !aReturnNames[i].contains(":"))
1100 {
1101 CHost comHost = (CHost)aReturnObjects[i];
1102 if (!comHost.isNull())
1103 m_hostStats.m_iFSFree = _1M * fData;
1104 }
1105 }
1106}
1107
1108/*********************************************************************************************************************************
1109* UIVMActivityOverviewProxyModel implementation. *
1110*********************************************************************************************************************************/
1111
1112UIVMActivityOverviewProxyModel::UIVMActivityOverviewProxyModel(QObject *pParent /* = 0 */)
1113 : QSortFilterProxyModel(pParent)
1114{
1115}
1116
1117void UIVMActivityOverviewProxyModel::dataUpdate()
1118{
1119 if (sourceModel())
1120 emit dataChanged(index(0,0), index(sourceModel()->rowCount(), sourceModel()->columnCount()));
1121 invalidate();
1122}
1123
1124void UIVMActivityOverviewProxyModel::setNotRunningVMVisibility(bool fShow)
1125{
1126 if (m_fShowNotRunningVMs == fShow)
1127 return;
1128 m_fShowNotRunningVMs = fShow;
1129 invalidateFilter();
1130}
1131
1132
1133void UIVMActivityOverviewProxyModel::setCloudVMVisibility(bool fShow)
1134{
1135 if (m_fShowCloudVMs == fShow)
1136 return;
1137 m_fShowCloudVMs = fShow;
1138 invalidateFilter();
1139}
1140
1141bool UIVMActivityOverviewProxyModel::filterAcceptsRow(int iSourceRow, const QModelIndex &sourceParent) const
1142{
1143 Q_UNUSED(sourceParent);
1144 if (m_fShowNotRunningVMs && m_fShowCloudVMs)
1145 return true;
1146 UIVMActivityOverviewModel *pModel = qobject_cast<UIVMActivityOverviewModel*>(sourceModel());
1147 if (!pModel)
1148 return true;
1149
1150 if (!m_fShowNotRunningVMs && !pModel->isVMRunning(iSourceRow))
1151 return false;
1152 if (!m_fShowCloudVMs && pModel->isCloudVM(iSourceRow))
1153 return false;
1154 return true;
1155}
1156
1157bool UIVMActivityOverviewProxyModel::lessThan(const QModelIndex &sourceLeftIndex, const QModelIndex &sourceRightIndex) const
1158{
1159 UIVMActivityOverviewModel *pModel = qobject_cast<UIVMActivityOverviewModel*>(sourceModel());
1160 if (pModel)
1161 {
1162 /* Keep running vm always on top of the list: */
1163 bool fLeftRunning = pModel->isVMRunning(sourceLeftIndex.row());
1164 bool fRightRunning = pModel->isVMRunning(sourceRightIndex.row());
1165 if (fLeftRunning && !fRightRunning)
1166 {
1167 if (sortOrder() == Qt::AscendingOrder)
1168 return true;
1169 else
1170 return false;
1171 }
1172 if (!fLeftRunning && fRightRunning)
1173 {
1174 if (sortOrder() == Qt::AscendingOrder)
1175 return false;
1176 else
1177 return true;
1178 }
1179 }
1180 return QSortFilterProxyModel::lessThan(sourceLeftIndex, sourceRightIndex);
1181}
1182
1183
1184#include "UIVMActivityOverviewModelView.moc"
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette