玉兔远程控制 0.1.0-bate6
载入中...
搜索中...
未找到
FrmRecent.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QVBoxLayout>
4#include <QDateTime>
5#include <QStandardItem>
6#include <QDir>
7#include <QHeaderView>
8#include <QMenu>
9#include <QFile>
10#include <QMessageBox>
11#include <QLoggingCategory>
12#include "mainwindow.h"
13#include "FrmRecent.h"
14#include "RabbitCommonDir.h"
15
16static Q_LOGGING_CATEGORY(log, "App.FrmListRecent")
17
19 MainWindow *pMainWindow, CManager *pManager, CRecentDatabase *pDb,
20 CParameterApp &parameterApp, bool bDock, QWidget *parent)
21 : QWidget(parent)
22 , m_pMainWindow(pMainWindow)
23 , m_ParameterApp(parameterApp)
24 , m_pToolBar(nullptr)
25 , m_ptbOperate(nullptr)
26 , m_pMenuNew(nullptr)
27 , m_pDatabase(pDb)
28 , m_pModel(nullptr)
29 , m_pManager(pManager)
30 , m_bDock(bDock)
31 , m_pDockTitleBar(nullptr)
32 , m_pExport(nullptr)
33 , m_pImport(nullptr)
34{
35 bool check = false;
36 //setFocusPolicy(Qt::NoFocus);
37 setAttribute(Qt::WA_DeleteOnClose);
38 setLayout(new QVBoxLayout(this));
39 setWindowTitle(tr("Recently list"));
40
41 m_pToolBar = new QToolBar(this);
42
43 m_pStart = m_pToolBar->addAction(
44 QIcon::fromTheme("media-playback-start"), tr("Start"),
45 this, SLOT(slotStart()));
46 m_pStart->setStatusTip(tr("Start"));
47 m_pStart->setToolTip(tr("Start"));
48 m_pEditOperate = m_pToolBar->addAction(
49 QIcon::fromTheme("edit-connect"), tr("Edit and Start"),
50 this, SLOT(slotEditConnect()));
51 m_pEditOperate->setStatusTip(tr("Edit and Start"));
52 m_pEditOperate->setToolTip(tr("Edit and Start"));
53 m_pToolBar->addSeparator();
54
55 m_ptbOperate = new QToolButton(m_pToolBar);
56 m_ptbOperate->setFocusPolicy(Qt::NoFocus);
57 m_ptbOperate->setPopupMode(QToolButton::InstantPopup);
58 //m_ptbOperate->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
59 m_pMenuNew = new QMenu(tr("New"), this);
60 m_pMenuNew->setIcon(QIcon::fromTheme("add"));
61 m_ptbOperate->setMenu(m_pMenuNew);
62 m_ptbOperate->setIcon(m_pMenuNew->icon());
63 m_ptbOperate->setText(tr("New"));
64 m_ptbOperate->setToolTip(tr("New"));
65 m_ptbOperate->setStatusTip(tr("New"));
66 m_pToolBar->addWidget(m_ptbOperate);
67 check = connect(&m_ParameterApp, SIGNAL(sigStartByTypeChanged()),
68 this, SLOT(slotStartByType()));
69 Q_ASSERT(check);
70
71 m_pEdit = m_pToolBar->addAction(QIcon::fromTheme("edit"), tr("Edit"),
72 this, SLOT(slotEdit()));
73 m_pEdit->setStatusTip(tr("Edit"));
74 m_pEdit->setToolTip(tr("Edit"));
75 m_pCopy = m_pToolBar->addAction(QIcon::fromTheme("edit-copy"), tr("Copy"),
76 this, SLOT(slotCopy()));
77 m_pCopy->setStatusTip(tr("Copy"));
78 m_pCopy->setToolTip(tr("Copy"));
79 m_pDelete = m_pToolBar->addAction(
80 QIcon::fromTheme("edit-delete"), tr("Delete"),
81 this, SLOT(slotDelete()));
82 m_pDelete->setToolTip(tr("Delete"));
83 m_pDelete->setStatusTip(tr("Delete"));
84 m_pDetail = m_pToolBar->addAction(
85 QIcon::fromTheme("dialog-information"), tr("Detail"),
86 this, SLOT(slotDetail()));
87 m_pDetail->setCheckable(true);
88 m_pDetail->setChecked(false);
89 m_pDetail->setToolTip(tr("Detail"));
90 m_pDetail->setStatusTip(tr("Detail"));
91 m_pToolBar->addSeparator();
92 m_pAddToFavorite = m_pToolBar->addAction(
93 QIcon::fromTheme("emblem-favorite"), tr("Add to favorite"),
94 this, SLOT(slotAddToFavorite()));
95 m_pAddToFavorite->setStatusTip(m_pAddToFavorite->text());
96 m_pAddToFavorite->setToolTip(m_pAddToFavorite->text());
97 if(m_bDock) {
98 m_pRefresh = m_pToolBar->addAction(
99 QIcon::fromTheme("view-refresh"),
100 tr("Refresh"),
101 this, SLOT(slotRefresh()));
102 m_pRefresh->setToolTip(tr("Refresh"));
103 m_pRefresh->setStatusTip(tr("Refresh"));
104 } else {
105 QAction* pClose = m_pToolBar->addAction(
106 QIcon::fromTheme("window-close"), tr("Close"),
107 this, SLOT(close()));
108 pClose->setStatusTip(tr("Close"));
109 pClose->setToolTip(tr("Close"));
110 }
111 m_pToolBar->addSeparator();
112 m_pImport = m_pToolBar->addAction(QIcon::fromTheme("import"), tr("Import"),
113 this, &CFrmRecent::slotImport);
114 m_pExport = m_pToolBar->addAction(QIcon::fromTheme("export"), tr("Export"),
115 this, &CFrmRecent::slotExport);
116
117 layout()->addWidget(m_pToolBar);
118
119 if(bDock) {
120 m_pDockTitleBar = new RabbitCommon::CTitleBar(parent);
121 // Create tools pushbutton in title bar
122 QMenu* pMenu = new QMenu(tr("Tools"), m_pDockTitleBar);
123 QPushButton* pTools = m_pDockTitleBar->CreateSmallPushButton(
124 QIcon::fromTheme("tools"), m_pDockTitleBar);
125 pTools->setToolTip(tr("Tools"));
126 pTools->setMenu(pMenu);
127 QList<QWidget*> lstWidget;
128 lstWidget << pTools;
129 m_pDockTitleBar->AddWidgets(lstWidget);
130
131 pMenu->addAction(m_pStart);
132 pMenu->addAction(m_pEditOperate);
133 pMenu->addMenu(m_pMenuNew);
134 pMenu->addAction(m_pEdit);
135 pMenu->addAction(m_pCopy);
136 pMenu->addAction(m_pDelete);
137 pMenu->addAction(m_pDetail);
138 pMenu->addSeparator();
139 pMenu->addAction(m_pAddToFavorite);
140 pMenu->addAction(m_pRefresh);
141 pMenu->addSeparator();
142 pMenu->addAction(m_pImport);
143 pMenu->addAction(m_pExport);
144 pMenu->addSeparator();
145 auto pShowToolBar = pMenu->addAction(tr("Show tool bar"), this, [&](){
146 QAction* a = (QAction*)sender();
147 if(a) {
148 m_pToolBar->setVisible(a->isChecked());
149 m_ParameterApp.SetDockListRecentShowToolBar(a->isChecked());
150 m_ParameterApp.Save();
151 }
152 });
153 pShowToolBar->setCheckable(true);
154 pShowToolBar->setChecked(m_ParameterApp.GetDockListRecentShowToolBar());
155 m_pToolBar->setVisible(m_ParameterApp.GetDockListRecentShowToolBar());
156 }
157
158 Q_ASSERT(m_pManager);
159 m_pTableView = new QTableView(this);
160 m_pTableView->setContextMenuPolicy(Qt::CustomContextMenu);
161 check = connect(m_pTableView,
162 SIGNAL(customContextMenuRequested(const QPoint &)),
163 this, SLOT(slotCustomContextMenu(const QPoint &)));
164 Q_ASSERT(check);
165 check = connect(m_pTableView, SIGNAL(doubleClicked(const QModelIndex &)),
166 this, SLOT(slotDoubleClicked(const QModelIndex&)));
167 Q_ASSERT(check);
168 layout()->addWidget(m_pTableView);
169
170 m_pModel = new CRecentModel(&m_ParameterApp, m_pDatabase, m_pTableView);
171 m_pTableView->setModel(m_pModel);
172 m_pTableView->verticalHeader()->hide();
173 m_pTableView->setSelectionMode(QAbstractItemView::SingleSelection);
174 m_pTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
175 m_pTableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
176 if(!m_pDetail->isChecked()) {
177 m_pTableView->hideColumn(CRecentModel::ColumnNo::ID);
178 m_pTableView->hideColumn(CRecentModel::ColumnNo::File);
179 }
180
181 check = connect(m_pDatabase, &CRecentDatabase::sigChanged,
182 this, &CFrmRecent::slotRefresh);
183 Q_ASSERT(check);
184
185 // if(!bDock)
186 // slotLoadFiles();
187
188 //必须在 setModel 后,才能应用
189 /*第二个参数可以为:
190 QHeaderView::Interactive :0 用户可设置,也可被程序设置成默认大小
191 QHeaderView::Fixed :2 用户不可更改列宽
192 QHeaderView::Stretch :1 根据空间,自动改变列宽,用户与程序不能改变列宽
193 QHeaderView::ResizeToContents:3 根据内容改变列宽,用户与程序不能改变列宽
194 */
195 m_pTableView->horizontalHeader()->setSectionResizeMode(
196#if defined(DEBUG) && !defined(Q_OS_ANDROID)
197 0,
198#endif
199 QHeaderView::Interactive);
200 //以下设置列宽函数必须要数据加载完成后使用,才能应用
201 //See: https://blog.csdn.net/qq_40450386/article/details/86083759
202 //m_pTableView->resizeColumnsToContents(); //设置所有列宽度自适应内容
203 //m_pTableView->resizeColumnToContents(0); //设置第0列宽度自适应内容
204 //m_pTableView->resizeColumnToContents(2); //设置第1列宽度自适应内容
205 //m_pTableView->resizeColumnToContents(3); //设置第1列宽度自适应内容
206}
207
208CFrmRecent::~CFrmRecent()
209{
210}
211
212int CFrmRecent::Init()
213{
214 m_pManager->EnumPlugins(this);
215 slotRefresh();
216 return 0;
217}
218
219void CFrmRecent::slotRefresh()
220{
221 if(!m_pModel) return;
222 m_pModel->refresh(m_ParameterApp.GetRecentMenuMaxCount() << 1);
223
224 //以下设置列宽函数必须要数据加载完成后使用,才能应用
225 //See: https://blog.csdn.net/qq_40450386/article/details/86083759
226 m_pTableView->resizeColumnsToContents(); //设置所有列宽度自适应内容
227
228 QItemSelectionModel* pSelect = m_pTableView->selectionModel();
229 QModelIndexList lstIndex;
230 if(pSelect)
231 lstIndex = pSelect->selectedRows();
232 if(m_pModel->rowCount() > 0 && lstIndex.isEmpty())
233 {
234 m_pTableView->selectRow(0);
235 }
236 return;
237}
238
239int CFrmRecent::InsertItem(COperate *c, QString& szFile)
240{
242 item.icon = c->Icon();
243 item.szName = c->Name();
244 item.szProtocol = c->Protocol();
245 item.szType = c->GetTypeName();
246 item.szFile = szFile;
247 m_pModel->addItem(item);
248
249 m_pTableView->selectRow(0);
250 return 0;
251}
252
253void CFrmRecent::slotStartByType()
254{
255 qDebug(log) << Q_FUNC_INFO;
256 auto m = m_pMenuNew->actions();
257 foreach(auto a, m) {
258 a->deleteLater();
259 }
260 foreach (auto a, m_MenuStartByType) {
261 a->deleteLater();
262 }
263 m_pMenuNew->clear();
264 m_MenuStartByType.clear();
265 m_pManager->EnumPlugins(this);
266}
267
268int CFrmRecent::onProcess(const QString &id, CPlugin *pPlugin)
269{
270 // Connect menu and toolbar
271 QMenu* m = m_pMenuNew;
272 if(m_ParameterApp.GetStartByType()) {
273 auto it = m_MenuStartByType.find(pPlugin->Type());
274 if(it == m_MenuStartByType.end()) {
275 m = new QMenu(pPlugin->TypeName(pPlugin->Type()), m_pMenuNew);
276 m_MenuStartByType[pPlugin->Type()] = m;
277 m_pMenuNew->addMenu(m);
278 } else
279 m = *it;
280 }
281 // Start menu and toolbar
282 QAction* p = m_pMainWindow->GetStartAction(m, pPlugin);
283 bool check = connect(p, SIGNAL(triggered()), this, SLOT(slotNew()));
284 Q_ASSERT(check);
285 return 0;
286}
287
288void CFrmRecent::slotNew()
289{
290 QAction* pAction = dynamic_cast<QAction*>(this->sender());
291 if(!pAction || pAction->data().toString().isEmpty())
292 return;
293 COperate* pOperate = m_pManager->CreateOperate(pAction->data().toString());
294 if(nullptr == pOperate) return;
295
296 int nRet = pOperate->OpenDialogSettings(this);
297 switch(nRet)
298 {
299 case QDialog::Rejected:
300 break;
301 case QDialog::Accepted:
302 {
303 QString szFile = pOperate->GetSettingsFile();
304 QDir d;
305 if(d.exists(szFile)) {
306 QMessageBox::StandardButton ret
307 = QMessageBox::warning(
308 this, tr("Warning"),
309 tr("The file is exists. whether to overwrite it?\nFile: %1").arg(szFile),
310 QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::No,
311 QMessageBox::StandardButton::No);
312 if(QMessageBox::StandardButton::Ok != ret)
313 {
314 break;
315 }
316 }
317
318 int nRet = 0;
319 bool bRet = QMetaObject::invokeMethod(
320 m_pMainWindow,
321 "Start",
322 Qt::DirectConnection,
323 Q_RETURN_ARG(int, nRet),
324 Q_ARG(COperate*, pOperate),
325 Q_ARG(bool, false),
326 Q_ARG(QString, szFile)
327 );
328 if(!bRet)
329 qCritical(log) << "Failed to call MainWindow::Start()";
330 return;
331 }
332 }
333
334 m_pManager->DeleteOperate(pOperate);
335}
336
337void CFrmRecent::slotEdit()
338{
339 QItemSelectionModel* pSelect = m_pTableView->selectionModel();
340 QModelIndexList lstIndex = pSelect->selectedRows();
341 foreach(auto index, lstIndex)
342 {
343 auto item = m_pModel->getItem(index);
344 QString szFile = item.szFile;
345 if(szFile.isEmpty()) continue;
346 COperate* pOperate = m_pManager->LoadOperate(szFile);
347 int nRet = pOperate->OpenDialogSettings(this);
348 switch(nRet)
349 {
350 case QDialog::Rejected:
351 break;
352 case QDialog::Accepted:
353 m_pManager->SaveOperate(pOperate);
354 break;
355 }
356 m_pManager->DeleteOperate(pOperate);
357 }
358}
359
360void CFrmRecent::slotEditConnect()
361{
362 QItemSelectionModel* pSelect = m_pTableView->selectionModel();
363 QModelIndexList lstIndex = pSelect->selectedRows();
364 foreach(auto index, lstIndex)
365 {
366 auto item = m_pModel->getItem(index);
367 QString szFile = item.szFile;
368 if(szFile.isEmpty()) continue;
369 COperate* c = m_pManager->LoadOperate(szFile);
370 int nRet = c->OpenDialogSettings(this);
371 switch(nRet)
372 {
373 case QDialog::Rejected:
374 break;
375 case QDialog::Accepted:
376 m_pManager->SaveOperate(c);
377 emit sigStart(szFile);
378 break;
379 }
380 m_pManager->DeleteOperate(c);
381 }
382 if(!m_bDock)
383 close();
384}
385
386void CFrmRecent::slotCopy()
387{
388 QItemSelectionModel* pSelect = m_pTableView->selectionModel();
389 QModelIndexList lstIndex = pSelect->selectedRows();
390 foreach(auto index, lstIndex)
391 {
392 auto item = m_pModel->getItem(index);
393 QString szFile = item.szFile;
394 if(szFile.isEmpty()) continue;
395 COperate* pOperate = m_pManager->LoadOperate(szFile);
396
397 bool bExit = true;
398 do {
399 bExit = true;
400 int nRet = pOperate->OpenDialogSettings(this);
401 switch(nRet)
402 {
403 case QDialog::Rejected:
404 break;
405 case QDialog::Accepted:
406 {
407 szFile = RabbitCommon::CDir::Instance()->GetDirUserData()
408 + QDir::separator()
409 + pOperate->Id()
410 + ".rrc";
411 QDir d(szFile);
412 if(d.exists(szFile)) {
413 QMessageBox::StandardButton r
414 = QMessageBox::warning(
415 this,
416 tr("Warning"),
417 tr("The file is exists. whether to overwrite it?"
418 " If select No, please modify the name."),
419 QMessageBox::StandardButton::Ok
420 | QMessageBox::StandardButton::No
421 | QMessageBox::StandardButton::Cancel,
422 QMessageBox::StandardButton::No);
423 if(QMessageBox::StandardButton::No == r)
424 {
425 bExit = false;
426 break;
427 }
428 if(QMessageBox::StandardButton::Cancel == r)
429 break;
430 }
431
432 int nRet = 0;
433 bool bRet = QMetaObject::invokeMethod(
434 m_pMainWindow,
435 "Start",
436 Qt::DirectConnection,
437 Q_RETURN_ARG(int, nRet),
438 Q_ARG(COperate*, pOperate),
439 Q_ARG(bool, false),
440 Q_ARG(QString, szFile)
441 );
442 if(!bRet)
443 qCritical(log) << "Failed to call MainWindow::Start()";
444 return;
445 }
446 }
447
448 } while(1 && !bExit);
449
450 m_pManager->DeleteOperate(pOperate);
451 }
452}
453
454void CFrmRecent::slotDelete()
455{
456 if(!m_pModel || !m_pTableView) return;
457 QItemSelectionModel* pSelect = m_pTableView->selectionModel();
458 QModelIndexList lstIndex = pSelect->selectedRows();
459 foreach(auto index, lstIndex)
460 {
461 /*
462 auto item = m_pModel->getItem(index);
463 QString szFile = item.szFile;
464 if(szFile.isEmpty()) continue;
465 QDir d(szFile);
466 if(d.remove(szFile)) //*/
467 m_pModel->removeRow(index.row());
468 }
469 slotRefresh();
470}
471
472void CFrmRecent::slotStart()
473{
474 if(!m_pModel || !m_pTableView) return;
475 QItemSelectionModel* pSelect = m_pTableView->selectionModel();
476 QModelIndexList lstIndex = pSelect->selectedRows();
477 foreach(auto index, lstIndex)
478 {
479 auto item = m_pModel->getItem(index);
480 QString szFile = item.szFile;
481 if(szFile.isEmpty()) continue;
482 emit sigStart(szFile);
483 }
484 if(!m_bDock) close();
485}
486
487void CFrmRecent::slotDetail()
488{
489 if(!m_pDetail || !m_pTableView) return;
490 if(m_pDetail->isChecked()) {
491 m_pTableView->showColumn(CRecentModel::ColumnNo::ID);
492 m_pTableView->showColumn(CRecentModel::ColumnNo::File);
493 } else {
494 m_pTableView->hideColumn(CRecentModel::ColumnNo::ID);
495 m_pTableView->hideColumn(CRecentModel::ColumnNo::File);
496 }
497}
498
499void CFrmRecent::slotCustomContextMenu(const QPoint &pos)
500{
501 QMenu menu(this);
502
503 menu.addAction(m_pStart);
504 menu.addAction(m_pStart);
505 menu.addSeparator();
506 menu.addMenu(m_pMenuNew);
507 menu.addAction(m_pEdit);
508 menu.addAction(m_pCopy);
509 menu.addAction(m_pDelete);
510 menu.addSeparator();
511 menu.addAction(m_pAddToFavorite);
512 menu.addSeparator();
513 menu.addAction(m_pImport);
514 menu.addAction(m_pExport);
515 if(m_bDock)
516 menu.addAction(m_pRefresh);
517
518 menu.exec(mapToGlobal(pos));
519}
520
521void CFrmRecent::slotDoubleClicked(const QModelIndex& index)
522{
523 if(!m_pModel) return;
524 if(!index.isValid()) return;
525 auto item = m_pModel->getItem(index);
526 QString szFile = item.szFile;
527 if(szFile.isEmpty()) return;
528 emit sigStart(szFile);
529 if(!m_bDock) close();
530}
531
532void CFrmRecent::slotAddToFavorite()
533{
534 QItemSelectionModel* pSelect = m_pTableView->selectionModel();
535 QModelIndexList lstIndex = pSelect->selectedRows();
536 foreach(auto index, lstIndex)
537 {
538 if(!index.isValid()) continue;
539 auto item = m_pModel->getItem(index);
540 QFileInfo fi(item.szFile);
541 if(0 == item.id || item.szFile.isEmpty() || !fi.exists()) continue;
542 QString szName = item.szName;
543 QIcon icon = item.icon;
544 QString szDescription = item.szDescription;
545 QString szFile = item.szFile;
546 emit sigAddToFavorite(szFile, szName, szDescription, icon);
547 }
548}
549
550void CFrmRecent::slotImport()
551{
552 QString filename = QFileDialog::getOpenFileName(
553 this, tr("Import recent"),
554 RabbitCommon::CDir::Instance()->GetDirUserDocument(),
555 tr("JSON (*.json)"));
556
557 if (!filename.isEmpty()) {
558 QFileInfo fi(filename);
559 if(0 == fi.suffix().compare("json", Qt::CaseInsensitive)) {
560 if (m_pDatabase->ImportFromJsonFile(filename)) {
561 slotRefresh();
562 QMessageBox::information(
563 this, tr("Success"),
564 tr("Successfully imported recent from json file"));
565 } else {
566 QMessageBox::warning(
567 this, tr("Failure"),
568 tr("Failed to import recent from json file"));
569 }
570 return;
571 }
572 }
573}
574
575void CFrmRecent::slotExport()
576{
577 QString filename = QFileDialog::getSaveFileName(
578 this, tr("Export recent"),
579 RabbitCommon::CDir::Instance()->GetDirUserDocument(),
580 tr("JSON (*.json)"));
581
582 if (!filename.isEmpty()) {
583 QFileInfo fi(filename);
584 if(0 == fi.suffix().compare("json", Qt::CaseInsensitive)) {
585 if (m_pDatabase->ExportToJsonFile(filename)) {
586 QMessageBox::information(
587 this, tr("Success"),
588 tr("Successfully exported recent to json file"));
589 } else {
590 QMessageBox::warning(
591 this, tr("Failure"),
592 tr("Failed to export recent to json file"));
593 }
594 return;
595 }
596 }
597}
列出存在的连接配置
Definition FrmRecent.h:23
virtual int onProcess(const QString &id, CPlugin *pPlugin) override
Process plugins
管理插件
Definition Manager.h:48
virtual int EnumPlugins(Handle *handle)
Enum plugins
Definition Manager.cpp:604
virtual COperate * CreateOperate(const QString &id)
新建 COperate 指针,所有者是调用者。 当不在使用时,调用者必调用 DeteleOperate() 须释放指针。 调用者必须连接信号 COperate::sigFinished 。 释放指针 (...
Definition Manager.cpp:340
virtual COperate * LoadOperate(const QString &szFile)
从文件中新建 COperate 指针,所有者是调用者。 当不再使用时,调用者必须负责调用 DeleteOperate() 删除此指针。 调用者必须连接信号 COperate::sigFinished 。...
Definition Manager.cpp:401
virtual int DeleteOperate(COperate *p)
Delete COperate
Definition Manager.cpp:368
virtual int SaveOperate(COperate *pOperate)
保存连接参数到文件
Definition Manager.cpp:451
操作接口。
Definition Operate.h:51
virtual int OpenDialogSettings(QWidget *parent=nullptr)
打开设置对话框
Definition Operate.cpp:90
virtual const QIcon Icon() const
Icon
Definition Operate.cpp:85
virtual const QString Protocol() const
Protocol
Definition Operate.cpp:74
virtual const QString Name()
Name
Definition Operate.cpp:44
virtual const QString Id()
Identity
Definition Operate.cpp:34
virtual const QString GetTypeName() const
Get type name
Definition Operate.cpp:79
插件接口
Definition Plugin.h:15
The MainWindow class
Definition mainwindow.h:36