diff --git a/HardwareAccountingClient.pro b/HardwareAccountingClient.pro new file mode 100644 index 0000000..32c3dd8 --- /dev/null +++ b/HardwareAccountingClient.pro @@ -0,0 +1,52 @@ +QT += core gui httpserver + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++17 + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + apiclient.cpp \ + main.cpp \ + mainwindow.cpp \ + models/baseentity.cpp \ + models/department.cpp \ + models/device.cpp \ + models/devicemodel.cpp \ + models/devicestructureelement.cpp \ + models/devicetype.cpp \ + models/filterparams.cpp \ + models/location.cpp \ + models/manufacturer.cpp \ + presenter.cpp \ + utils/buttonhoverwatcher.cpp + +HEADERS += \ + apiclient.h \ + mainwindow.h \ + models/baseentity.h \ + models/department.h \ + models/device.h \ + models/devicemodel.h \ + models/devicestructureelement.h \ + models/devicetype.h \ + models/filterparams.h \ + models/location.h \ + models/manufacturer.h \ + models/types.h \ + presenter.h \ + utils/buttonhoverwatcher.h + +FORMS += \ + mainwindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +RESOURCES += \ + resources/resources.qrc diff --git a/apiclient.cpp b/apiclient.cpp new file mode 100644 index 0000000..11e2582 --- /dev/null +++ b/apiclient.cpp @@ -0,0 +1,109 @@ +#include "apiclient.h" + +ApiClient::ApiClient(QObject *parent) + : QObject{parent}, networkManager(new QNetworkAccessManager(this)) +{} + +void ApiClient::getFilteredDevices(bool isWorking, double priceFrom, double priceTo, bool applyFilters, bool disregardState, int entityId, int currentEntity, + const QString &searchText, const QString &sortOrder) +{ + QString url = QString("/api/devices?isWorking=%1&priceFrom=%2&priceTo=%3&applyFilters=%4&disregardState=%5&entityId=%6¤tEntity=%7&searchText=%8&sortOrder=%9") + .arg(isWorking ? "true" : "false") + .arg(priceFrom) + .arg(priceTo) + .arg(applyFilters ? "true" : "false") + .arg(disregardState ? "true" : "false") + .arg(entityId) + .arg(currentEntity) + .arg(searchText) + .arg(sortOrder); + + QNetworkRequest request(baseUrl + url); + QNetworkReply *reply = networkManager->get(request); + + connect(reply, &QNetworkReply::finished, this, [this, reply]() { + parseData(reply); + }); + connect(reply, &QNetworkReply::errorOccurred, this, &ApiClient::handleError); +} + +void ApiClient::getEntities(const QString &url) +{ + QNetworkRequest request(baseUrl + url); + QNetworkReply *reply = networkManager->get(request); + connect(reply, &QNetworkReply::finished, this, [this, reply]() { + parseData(reply); + }); + connect(reply, &QNetworkReply::errorOccurred, this, &ApiClient::handleError); +} + +void ApiClient::updateDevice(int id, const Device &device) +{ + QString url = QString("/api/devices/%1").arg(id); + QNetworkRequest request(baseUrl + url); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + QJsonDocument doc(device.toJson()); + QByteArray data = doc.toJson(); + + QNetworkReply *reply = networkManager->put(request, data); + connect(reply, &QNetworkReply::finished, this, [this, reply]() { + handleDeviceUpdated(reply); + }); + connect(reply, &QNetworkReply::errorOccurred, this, &ApiClient::handleError); +} + +void ApiClient::parseData(QNetworkReply *reply) +{ + if (reply->error() == QNetworkReply::NoError) { + QByteArray data = reply->readAll(); + + QString urlPath = reply->url().path(); + + if (urlPath.contains("/api/devices")) { + QJsonDocument doc = QJsonDocument::fromJson(data); + QJsonArray devicesArray = doc.object().value("devices").toArray(); + QList devices; + for (const QJsonValue &value : devicesArray) { + devices.append(deserializeDevice(value.toObject())); + } + emit devicesReceived(devices); + } + if (urlPath.contains("/api/locations")) { + emit locationsReceived(deserializeEntities(data, "locations")); + } + if (urlPath.contains("/api/departments")) { + emit departmentsReceived(deserializeEntities(data, "departments")); + } + if (urlPath.contains("/api/manufacturers")) { + emit manufacturersReceived(deserializeEntities(data, "manufacturers")); + } + if (urlPath.contains("/api/devicetypes")) { + emit deviceTypesReceived(deserializeEntities(data, "deviceTypes")); + } + if (urlPath.contains("/api/devicemodels")) { + emit deviceModelsReceived(deserializeEntities(data, "deviceModels")); + } + } +} + +void ApiClient::handleDeviceUpdated(QNetworkReply *reply) +{ + if (reply->error() == QNetworkReply::NoError) { + emit deviceUpdated(true); + } else { + emit deviceUpdated(false); + } +} + +void ApiClient::handleError(QNetworkReply::NetworkError error) +{ + qWarning() << "Network error:" << error; +} + +Device ApiClient::deserializeDevice(const QJsonObject &json) +{ + Device device; + device.fromJson(json); + return device; +} diff --git a/apiclient.h b/apiclient.h new file mode 100644 index 0000000..a6b630f --- /dev/null +++ b/apiclient.h @@ -0,0 +1,62 @@ +#ifndef APICLIENT_H +#define APICLIENT_H + +#include +#include +#include + +#include "models/types.h" // IWYU pragma: keep + +class ApiClient : public QObject +{ + Q_OBJECT +public: + explicit ApiClient(QObject *parent = nullptr); + + void getEntities(const QString &url); + void getFilteredDevices(bool isWorking, double priceFrom, double priceTo, bool applyFilters, + bool disregardState, int entityId, int currentEntity, const QString &searchText, + const QString &sortOrder); + void updateDevice(int id, const Device &device); + +signals: + void departmentsReceived(const QMap &departments); + void deviceModelsReceived(const QMap &deviceModels); + void deviceTypesReceived(const QMap &deviceType); + void locationsReceived(const QMap &locations); + void manufacturersReceived(const QMap &manufacturers); + void devicesReceived(const QList &devices); + void deviceUpdated(bool success); + +private slots: + void parseData(QNetworkReply *reply); + void handleDeviceUpdated(QNetworkReply *reply); + void handleError(QNetworkReply::NetworkError error); + +private: + QNetworkAccessManager *networkManager; + + const QString baseUrl = "http://localhost:8080"; + + template + QMap deserializeEntities(const QByteArray &data, const QString &itemsKey); + Device deserializeDevice(const QJsonObject &json); +}; + +template +QMap ApiClient::deserializeEntities(const QByteArray &data, const QString &itemsKey) +{ + QMap entities; + QJsonDocument doc = QJsonDocument::fromJson(data); + QJsonArray itemsArray = doc.object().value(itemsKey).toArray(); + + for (const QJsonValue &value : itemsArray) { + T entity; + entity.fromJson(value.toObject()); + entities.insert(entity.id(), entity); + } + + return entities; +} + +#endif // APICLIENT_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..5ea4a48 --- /dev/null +++ b/main.cpp @@ -0,0 +1,11 @@ +#include "presenter.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + new Presenter(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..7da3d5e --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,640 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + setWindowIcon(QIcon(":/images/mw-icon.png")); + + int width = frameGeometry().width(); + int height = frameGeometry().height(); + QScreen *screen = qApp->primaryScreen(); + int screenWidth = screen->geometry().width(); + int screenHeight = screen->geometry().height(); + setGeometry((screenWidth/2)-(width/2), (screenHeight/2)-(height/2), width, height); + + returnToDeviceList(); + + ui->tableWidget->verticalHeader()->setVisible(false); + ui->tableWidget->setColumnCount(2); + QStringList headers = QString("ID, Название").split(','); + ui->tableWidget->setHorizontalHeaderLabels(headers); + QHeaderView *header = ui->tableWidget->horizontalHeader(); + header->setSectionResizeMode(0, QHeaderView::Stretch); + header->setSectionResizeMode(1, QHeaderView::Stretch); + QFont headerFont = header->font(); + headerFont.setBold(true); + header->setFont(headerFont); + ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); + + ui->listWidgetDevices->setSpacing(10); + + ui->checkBoxIsWorking->setAttribute(Qt::WA_TransparentForMouseEvents); + ui->checkBoxIsWorking->setFocusPolicy(Qt::NoFocus); + + QStringList filterItems = { + "Все устройства", + "Типы устройств", + "Помещения", + "Отделы", + "Производители", + "Модели устройств" + }; + + ui->comboBoxFilters->addItems(filterItems); + + QStringList sortItems = { + "Сначала новые", + "Сначала старые", + "Сначала дешевые", + "Сначала дорогие", + "Сначала с лайком" + }; + + ui->comboBoxSort->addItems(sortItems); + + QLineEdit *searchEdit = ui->lineEditSearch; + QPushButton *searchButton = new QPushButton(this); + + ButtonHoverWatcher *watcher = new ButtonHoverWatcher(this); + searchButton->installEventFilter(watcher); + searchButton->setCursor(Qt::PointingHandCursor); + searchButton->setStyleSheet("background: transparent; border: none;"); + searchButton->setIcon(QIcon(":/images/search.png")); + searchButton->setFixedSize(22, 22); + + QMargins margins = searchEdit->textMargins(); + searchEdit->setTextMargins(margins.left(), margins.top(), searchButton->width(), margins.bottom()); + searchEdit->setPlaceholderText(QStringLiteral("Поиск устройств по модели, типу или серийному номеру...")); + searchEdit->setMaxLength(200); + + QHBoxLayout *searchLayout = new QHBoxLayout(); + searchLayout->addStretch(); + searchLayout->addWidget(searchButton); + searchLayout->setSpacing(0); + searchLayout->setContentsMargins(3, 2, 3, 2); + searchEdit->setLayout(searchLayout); + + QButtonGroup *buttonGroup = new QButtonGroup(this); + buttonGroup->addButton(ui->radioButtonWorking); + buttonGroup->addButton(ui->radioButtonNotWorking); + buttonGroup->addButton(ui->radioButtonDisregard); + ui->radioButtonWorking->setChecked(true); + + connect(ui->comboBoxFilters, SIGNAL(activated(int)), this, SLOT(updateTableWidget(int))); + connect(ui->comboBoxSort, SIGNAL(activated(int)), this, SLOT(changeSortOrder())); + connect(ui->tableWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(updateListWidget())); + connect(ui->listWidgetDevices, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(showItemInfo(QListWidgetItem*))); + connect(ui->pushButtonBack, SIGNAL(clicked()), this, SLOT(pushButtonBackClicked())); + connect(ui->pushButtonClear, SIGNAL(clicked()), this, SLOT(pushButtonClearClicked())); + connect(searchEdit, SIGNAL(returnPressed()), this, SLOT(pushButtonSearchClicked())); + connect(searchButton, SIGNAL(clicked()), this, SLOT(pushButtonSearchClicked())); + connect(ui->pushButtonApplyFilters, SIGNAL(clicked()), this, SLOT(pushButtonApplyFiltersClicked())); + connect(ui->pushButtonCancelFilters, SIGNAL(clicked()), this, SLOT(pushButtonCancelFiltersClicked())); + connect(ui->pushButtonDefault, SIGNAL(clicked()), this, SLOT(pushButtonDefaultClicked())); + connect(ui->pushButtonStructure, SIGNAL(clicked()), this, SLOT(pushButtonStructureClicked())); + connect(ui->pushButtonCharacteristics, SIGNAL(clicked()), this, SLOT(pushButtonCharacteristicsClicked())); + + QFile *styleFile = new QFile(":/styles.qss"); + if (styleFile->open(QFile::ReadOnly)) { + QTextStream ts(styleFile); + QString style = ts.readAll(); + qApp->setStyleSheet(style); + } +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::updateTableWidget(int index) +{ + returnToDeviceList(); + + ui->tableWidget->clearContents(); + ui->tableWidget->setRowCount(0); + + switch (index) { + case 0: // Все устройства + clearDevicesOutputSettings(); + updateListWidgetDevices(0); + break; + case 1: // Типы устройств + fillTable(mapDeviceTypes); + break; + case 2: // Помещения + fillTable(mapLocations); + break; + case 3: // Отделы + fillTable(mapDepartments); + break; + case 4: // Производители + fillTable(mapManufacturers); + break; + case 5: // Модели устройств + fillTable(mapDeviceModels); + break; + default: + break; + } +} + +void MainWindow::updateListWidget() +{ + returnToDeviceList(); + + int selectedEntityId = getSelectedIndex(); + + if (selectedEntityId == -1) + return; + + clearDevicesOutputSettings(); + updateListWidgetDevices(selectedEntityId); +} + +template +void MainWindow::fillTable(const QMap &map) +{ + int row = 0; + for (auto &item : map) { + ui->tableWidget->insertRow(row); + + QTableWidgetItem *idItem = new QTableWidgetItem(QString::number(item.id())); + QTableWidgetItem *nameItem = new QTableWidgetItem(item.name()); + + idItem->setFlags(idItem->flags() & ~Qt::ItemIsEditable); + nameItem->setFlags(nameItem->flags() & ~Qt::ItemIsEditable); + + ui->tableWidget->setItem(row, 0, idItem); + ui->tableWidget->setItem(row, 1, nameItem); + + idItem->setTextAlignment(Qt::AlignCenter); + nameItem->setTextAlignment(Qt::AlignCenter); + + row++; + } +} + +void MainWindow::updateListWidgetDevices(int entityId) +{ + client->getFilteredDevices( + filterParams.isWorking(), + filterParams.priceFrom(), + filterParams.priceTo(), + filterParams.getApllyFilters(), + filterParams.getDisregardState(), + entityId, + ui->comboBoxFilters->currentIndex(), + searchInfo, + ui->comboBoxSort->currentText() + ); +} + +QWidget *MainWindow::createMessageEmptyCard() +{ + QWidget *cardWidget = new QWidget(ui->listWidgetDevices); + QVBoxLayout *cardLayout = new QVBoxLayout(cardWidget); + + QLabel *titleLabel = new QLabel("По заданным параметрам ничего не найдено", cardWidget); + QFont titleFont("Arial", 17, QFont::Bold); + titleLabel->setFont(titleFont); + + cardLayout->addWidget(titleLabel, 0, Qt::AlignCenter); + + cardLayout->setSpacing(12); + + QLabel *imageLabel = new QLabel(cardWidget); + QPixmap pixmap(":/images/question.png"); + imageLabel->setPixmap(pixmap.scaled(256, 256, Qt::KeepAspectRatio)); + + cardLayout->addWidget(imageLabel, 0, Qt::AlignCenter); + + return cardWidget; +} + +QWidget *MainWindow::createDeviceCard(const Device &device) +{ + QWidget *cardWidget = new QWidget(ui->listWidgetDevices); + QVBoxLayout *cardLayout = new QVBoxLayout(cardWidget); + + QFrame *topBorder = new QFrame(cardWidget); + topBorder->setFrameShape(QFrame::HLine); + topBorder->setFrameShadow(QFrame::Sunken); + + cardLayout->addWidget(topBorder); + + QHBoxLayout *iconTextlayout = new QHBoxLayout(); + + QLabel *imageLabel = new QLabel(cardWidget); + QString imagePath = deviceTypeImages[device.deviceModel().idType()]; + QPixmap pixmap(imagePath); + imageLabel->setPixmap(pixmap.scaled(100, 100, Qt::KeepAspectRatio)); + + iconTextlayout->addWidget(imageLabel); + + QVBoxLayout *textLayout = new QVBoxLayout(); + + QLabel *serialNumberLabel = new QLabel(device.serialNumber(), cardWidget); + QFont serialNumberFont("Arial", 14, QFont::Bold); + serialNumberLabel->setFont(serialNumberFont); + textLayout->addWidget(serialNumberLabel); + + QFont generalFont("Arial", 11); + + QString typeName = device.deviceModel().nameType(); + typeName = typeName.left(typeName.length() - 1); + if (typeName == "Персональные компьютер") + typeName = "Персональный компьютер"; + QLabel *typeNameLabel = new QLabel(typeName + ": " + device.deviceModel().name(), cardWidget); + typeNameLabel->setFont(generalFont); + textLayout->addWidget(typeNameLabel); + + QLabel *statusLabel = new QLabel(device.isWorking() ? "Работает" : "Сломано", cardWidget); + statusLabel->setFont(generalFont); + textLayout->addWidget(statusLabel); + + QHBoxLayout *priceLikeLayout = new QHBoxLayout(); + priceLikeLayout->setSpacing(100); + + QLabel *priceLabel = new QLabel(QString::number(device.price()) + " ₽", cardWidget); + priceLabel->setFont(generalFont); + priceLabel->setFixedWidth(100); + priceLikeLayout->addWidget(priceLabel); + + priceLikeLayout->addSpacerItem(new QSpacerItem(40, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); + + QCheckBox *likeCheckBox = new QCheckBox("Нравится", cardWidget); + likeCheckBox->setChecked(device.isLiked()); + likeCheckBox->setFont(generalFont); + likeCheckBox->setStyleSheet(likeCheckBox->isChecked() ? "color: green;" : "color: black;"); + + connect(likeCheckBox, &QCheckBox::toggled, this, [this, device, likeCheckBox](bool checked) { + Device updDevice = device; + updDevice.setIsLiked(checked); + client->updateDevice(updDevice.id(), updDevice); + + connect(client, &ApiClient::deviceUpdated, this, [this, checked, device, likeCheckBox](bool success) { + disconnect(client, &ApiClient::deviceUpdated, this, nullptr); + + if (success) { + QString message = checked ? "Устройство добавлено в избранное." : "Устройство удалено из избранного."; + QMessageBox::information(this, "Обновление", message); + + Device& deviceRef = mapDevices[device.id()]; + deviceRef.setIsLiked(checked); + + likeCheckBox->setStyleSheet(checked ? "color: green;" : "color: black;"); + } else { + QMessageBox::critical(this, "Ошибка", "Не удалось изменить состояние устройства."); + } + }); + }); + + priceLikeLayout->addWidget(likeCheckBox); + + textLayout->addLayout(priceLikeLayout); + + iconTextlayout->addSpacerItem(new QSpacerItem(40, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); + iconTextlayout->addLayout(textLayout); + + cardLayout->addLayout(iconTextlayout); + + QFrame *bottomBorder = new QFrame(cardWidget); + bottomBorder->setFrameShape(QFrame::HLine); + bottomBorder->setFrameShadow(QFrame::Sunken); + cardLayout->addWidget(bottomBorder); + + cardLayout->setContentsMargins(2, 0, 2, 0); + + return cardWidget; +} + +void MainWindow::addDeviceToList(const Device &device) +{ + QListWidgetItem *item = new QListWidgetItem(ui->listWidgetDevices); + ui->listWidgetDevices->addItem(item); + + QWidget *cardWidget = createDeviceCard(device); + + item->setSizeHint(cardWidget->minimumSizeHint()); + ui->listWidgetDevices->setItemWidget(item, cardWidget); + + item->setData(Qt::UserRole, device.id()); +} + +void MainWindow::returnToDeviceList() +{ + idCard = 0; + ui->stackedWidget->setCurrentIndex(0); +} + +void MainWindow::showItemInfo(QListWidgetItem *item) +{ + if (!item) + return; + + int deviceId = item->data(Qt::UserRole).toInt(); + Device device = mapDevices[deviceId]; + + idCard = deviceId; + + ui->lineEditId->setText(QString::number(device.id())); + ui->lineEditSerialNum->setText(device.serialNumber()); + ui->lineEditPurchaseDate->setText(device.purchaseDate().toString("dd.MM.yyyy HH:mm:ss")); + ui->lineEditPrice->setText(QString::number(device.price(), 'f', 2)); + ui->lineEditWarranty->setText(device.warrantyExpireDate().toString("dd.MM.yyyy HH:mm:ss")); + ui->lineEditLocation->setText(device.nameLocation()); + ui->lineEditEmployee->setText(device.nameEmployee()); + ui->lineEditDepartment->setText(device.nameDepartment()); + ui->lineEditModel->setText(device.deviceModel().name()); + ui->lineEditType->setText(device.deviceModel().nameType()); + ui->lineEditManuf->setText(device.deviceModel().nameManuf()); + ui->textEditFurtherInformation->setPlainText(device.furtherInformation()); + ui->checkBoxIsWorking->setChecked(device.isWorking()); + + ui->stackedWidget->setCurrentIndex(1); +} + +void MainWindow::showTableWithStructureElements(const QList &elements) +{ + QDialog* dialog = new QDialog(this); + dialog->setWindowTitle("Элементы структуры устройства"); + dialog->resize(1100, 600); + + QTableWidget* tableWidget = new QTableWidget(dialog); + tableWidget->setColumnCount(5); + + QFont font("Arial", 12); + tableWidget->setFont(font); + + QStringList headers = {"Название модели", "Производитель", "Описание элемента", "Тип элемента", "Количество"}; + tableWidget->setHorizontalHeaderLabels(headers); + + QFont headerFont("Arial", 12, QFont::Bold); + for (int i = 0; i < tableWidget->columnCount(); i++) { + tableWidget->horizontalHeaderItem(i)->setFont(headerFont); + } + + tableWidget->setRowCount(elements.size()); + for (int row = 0; row < elements.size(); row++) { + const DeviceStructureElement& element = elements[row]; + + tableWidget->setItem(row, 0, new QTableWidgetItem(element.nameModel())); + tableWidget->setItem(row, 1, new QTableWidgetItem(element.nameManuf())); + tableWidget->setItem(row, 2, new QTableWidgetItem(element.description())); + tableWidget->setItem(row, 3, new QTableWidgetItem(element.nameType())); + tableWidget->setItem(row, 4, new QTableWidgetItem(QString::number(element.count()))); + + for (int col = 0; col < tableWidget->columnCount(); col++) { + tableWidget->item(row, col)->setFlags(tableWidget->item(row, col)->flags() & ~Qt::ItemIsEditable); + } + } + + connect(tableWidget, &QTableWidget::cellClicked, [tableWidget](int row, int col) { + QString text = tableWidget->item(row, col)->text(); + QToolTip::showText(QCursor::pos(), text); + }); + + tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + tableWidget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); + tableWidget->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Interactive); + tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch); + tableWidget->horizontalHeader()->setSectionResizeMode(4, QHeaderView::ResizeToContents); + tableWidget->setColumnWidth(2, tableWidget->columnWidth(0) * 2); + + tableWidget->setFocusPolicy(Qt::NoFocus); + + QVBoxLayout* layout = new QVBoxLayout(dialog); + layout->addWidget(tableWidget); + + dialog->setLayout(layout); + dialog->exec(); +} + +void MainWindow::showTableWithDeviceModelCharacteristics(const DeviceModel &model) +{ + QDialog* dialog = new QDialog(this); + dialog->setWindowTitle("Характеристики устройства"); + dialog->setFixedSize(1200, 75); + + QTableWidget* tableWidget = new QTableWidget(dialog); + tableWidget->setColumnCount(6); + + QFont font("Arial", 11); + tableWidget->setFont(font); + + QStringList headers = {"Эффективность работы", "Надежность", "Энергоэффективность", "Удобство использования", "Долговечность", "Эстетические качества"}; + tableWidget->setHorizontalHeaderLabels(headers); + + QFont headerFont("Arial", 11, QFont::Bold); + for (int i = 0; i < tableWidget->columnCount(); i++) { + tableWidget->horizontalHeaderItem(i)->setFont(headerFont); + } + + tableWidget->setRowCount(1); + tableWidget->setItem(0, 0, new QTableWidgetItem(QString::number(model.workEfficiency()))); + tableWidget->setItem(0, 1, new QTableWidgetItem(QString::number(model.reliability()))); + tableWidget->setItem(0, 2, new QTableWidgetItem(QString::number(model.energyEfficiency()))); + tableWidget->setItem(0, 3, new QTableWidgetItem(QString::number(model.userFriendliness()))); + tableWidget->setItem(0, 4, new QTableWidgetItem(QString::number(model.durability()))); + tableWidget->setItem(0, 5, new QTableWidgetItem(QString::number(model.aestheticQualities()))); + + for (int col = 0; col < tableWidget->columnCount(); col++) { + tableWidget->item(0, col)->setFlags(tableWidget->item(0, col)->flags() & ~Qt::ItemIsEditable); + tableWidget->item(0, col)->setTextAlignment(Qt::AlignCenter); + tableWidget->horizontalHeader()->setSectionResizeMode(col, QHeaderView::Stretch); + } + + tableWidget->verticalHeader()->setVisible(false); + tableWidget->setFocusPolicy(Qt::NoFocus); + + QVBoxLayout* layout = new QVBoxLayout(dialog); + layout->addWidget(tableWidget); + + dialog->setLayout(layout); + dialog->exec(); +} + +void MainWindow::clearFilters() +{ + ui->radioButtonWorking->setChecked(true); + ui->doubleSpinBoxFrom->setValue(0.00); + ui->doubleSpinBoxTo->setValue(0.00); + filterParams.setIsWorking(true); + filterParams.setPriceFrom(-1); + filterParams.setPriceTo(-1); + filterParams.setDisregardState(false); + filterParams.setApllyFilters(false); +} + +void MainWindow::clearDevicesOutputSettings() +{ + ui->comboBoxSort->setCurrentIndex(0); + + ui->lineEditSearch->setText(""); + searchInfo = ""; + + clearFilters(); +} + +int MainWindow::getSelectedIndex() +{ + QModelIndexList selectedIndexes = ui->tableWidget->selectionModel()->selectedRows(); + + if (selectedIndexes.isEmpty()) { + return -1; + } + + int rowIndex = selectedIndexes.first().row(); + + return ui->tableWidget->item(rowIndex, 0)->text().toInt(); +} + +void MainWindow::pushButtonBackClicked() +{ + returnToDeviceList(); +} + +void MainWindow::pushButtonClearClicked() +{ + ui->lineEditSearch->setText(""); +} + +void MainWindow::changeSortOrder() +{ + updateListWidgetDevices(getSelectedIndex()); +} + +void MainWindow::pushButtonSearchClicked() +{ + searchInfo = ui->lineEditSearch->text(); + if (searchInfo.isEmpty()) { + QMessageBox::warning(this, "Ошибка", "Пожалуйста, введите текст для поиска."); + return; + } + ui->comboBoxSort->setCurrentIndex(0); + clearFilters(); + updateListWidgetDevices(getSelectedIndex()); +} + +void MainWindow::pushButtonApplyFiltersClicked() +{ + double priceFrom = ui->doubleSpinBoxFrom->value(); + double priceTo = ui->doubleSpinBoxTo->value(); + if (priceFrom > priceTo) { + QMessageBox::warning(this, "Ошибка", "Начальное значение диапазона не может быть больше конечного значения."); + + ui->doubleSpinBoxFrom->setValue(filterParams.priceFrom()); + ui->doubleSpinBoxTo->setValue(filterParams.priceTo()); + + return; + } + + filterParams.setApllyFilters(true); + filterParams.setDisregardState(ui->radioButtonDisregard->isChecked()); + filterParams.setIsWorking(ui->radioButtonWorking->isChecked()); + + if (priceFrom == 0.00 && priceTo == 0.00) { + filterParams.setPriceFrom(0.00); + filterParams.setPriceTo(std::numeric_limits::max()); + } else { + filterParams.setPriceFrom(priceFrom); + filterParams.setPriceTo(priceTo); + } + + updateListWidgetDevices(getSelectedIndex()); +} + +void MainWindow::pushButtonCancelFiltersClicked() +{ + clearFilters(); + updateListWidgetDevices(getSelectedIndex()); +} + +void MainWindow::pushButtonStructureClicked() +{ + showTableWithStructureElements(mapDevices[idCard].deviceModel().structureElements()); +} + +void MainWindow::pushButtonCharacteristicsClicked() +{ + showTableWithDeviceModelCharacteristics(mapDevices[idCard].deviceModel()); +} + +void MainWindow::pushButtonDefaultClicked() +{ + clearDevicesOutputSettings(); + updateListWidgetDevices(getSelectedIndex()); +} + +QMap MainWindow::getMapDeviceModels() const +{ + return mapDeviceModels; +} + +void MainWindow::setMapDevices(const QMap &newMapDevices) +{ + mapDevices = newMapDevices; + updateTableWidget(0); + connect(client, &ApiClient::devicesReceived, this, [this](const QList &filteredDevices) { + ui->listWidgetDevices->clear(); + if (filteredDevices.isEmpty()) { + QListWidgetItem *item = new QListWidgetItem(ui->listWidgetDevices); + ui->listWidgetDevices->addItem(item); + QWidget *cardWidget = createMessageEmptyCard(); + item->setSizeHint(cardWidget->minimumSizeHint()); + item->setFlags(item->flags() & ~Qt::ItemIsEnabled); + ui->listWidgetDevices->setItemWidget(item, cardWidget); + } else { + for (const auto &device : filteredDevices) { + int deviceModelId = device.deviceModel().id(); + if (mapDeviceModels.contains(deviceModelId)) { + Device updatedDevice = device; + updatedDevice.setDeviceModel(mapDeviceModels[deviceModelId]); + addDeviceToList(updatedDevice); + } else { + addDeviceToList(device); + } + } + } + }); +} + +void MainWindow::setMapDeviceModels(const QMap &newMapDeviceModels) +{ + mapDeviceModels = newMapDeviceModels; +} + +void MainWindow::setMapDeviceTypes(const QMap &newMapDeviceTypes) +{ + mapDeviceTypes = newMapDeviceTypes; + for (int i = 1; i <= mapDeviceTypes.size(); i++) { + QString imagePath = QString(":/images/device-type-%1.png").arg(i); + deviceTypeImages[i] = imagePath; + } +} + +void MainWindow::setMapManufacturers(const QMap &newMapManufacturers) +{ + mapManufacturers = newMapManufacturers; +} + +void MainWindow::setMapDepartments(const QMap &newMapDepartments) +{ + mapDepartments = newMapDepartments; +} + +void MainWindow::setMapLocations(const QMap &newMapLocations) +{ + mapLocations = newMapLocations; +} + +void MainWindow::setClient(ApiClient *newClient) +{ + client = newClient; +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..0ca6e52 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,97 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apiclient.h" +#include "models/types.h" // IWYU pragma: keep +#include "models/filterparams.h" +#include "utils/buttonhoverwatcher.h" // IWYU pragma: keep + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + + void setClient(ApiClient *newClient); + + void setMapLocations(const QMap &newMapLocations); + + void setMapDepartments(const QMap &newMapDepartments); + + void setMapManufacturers(const QMap &newMapManufacturers); + + void setMapDeviceTypes(const QMap &newMapDeviceTypes); + + QMap getMapDeviceModels() const; + void setMapDeviceModels(const QMap &newMapDeviceModels); + + void setMapDevices(const QMap &newMapDevices); + +private: + template + void fillTable(const QMap &map); + void updateListWidgetDevices(int entityId); + QWidget* createMessageEmptyCard(); + QWidget* createDeviceCard(const Device &device); + void addDeviceToList(const Device &device); + void returnToDeviceList(); + void showTableWithStructureElements(const QList& elements); + void showTableWithDeviceModelCharacteristics(const DeviceModel& model); + void clearFilters(); + void clearDevicesOutputSettings(); + int getSelectedIndex(); + +private slots: + void updateTableWidget(int index); + void updateListWidget(); + void showItemInfo(QListWidgetItem*); + void changeSortOrder(); + void pushButtonBackClicked(); + void pushButtonClearClicked(); + void pushButtonSearchClicked(); + void pushButtonApplyFiltersClicked(); + void pushButtonCancelFiltersClicked(); + void pushButtonStructureClicked(); + void pushButtonCharacteristicsClicked(); + void pushButtonDefaultClicked(); + +private: + Ui::MainWindow *ui; + + ApiClient *client; + + QString searchInfo = ""; + FilterParams filterParams; + + int idCard = 0; + + QMap deviceTypeImages; + + QMap mapLocations; + QMap mapDepartments; + QMap mapManufacturers; + QMap mapDeviceTypes; + QMap mapDeviceModels; + QMap mapDevices; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..51836ab --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,1088 @@ + + + MainWindow + + + + 0 + 0 + 1136 + 875 + + + + + 0 + 0 + + + + + Arial + + + + Список устройств + + + + data/images/mw-icon.pngdata/images/mw-icon.png + + + true + + + + + + 10 + 12 + 481 + 25 + + + + + 0 + 0 + + + + + Arial + 11 + + + + + + + 10 + 44 + 481 + 820 + + + + + 0 + 0 + + + + + Arial + 11 + + + + QAbstractItemView::SelectionMode::SingleSelection + + + + + + 530 + 12 + 595 + 851 + + + + + 0 + 0 + + + + + Arial + 10 + + + + 0 + + + + + + 0 + 8 + 591 + 16 + + + + + Arial + 12 + true + + + + Устройства + + + Qt::AlignmentFlag::AlignCenter + + + + + + 11 + 80 + 571 + 461 + + + + + + + 11 + 42 + 321 + 25 + + + + + Arial + 11 + + + + + + + 11 + 557 + 461 + 25 + + + + + Arial + 11 + + + + + + + 491 + 556 + 91 + 28 + + + + + Arial + 11 + + + + PointingHandCursor + + + Очистить + + + + + + 11 + 600 + 571 + 242 + + + + + + + + + 210 + 200 + 181 + 31 + + + + + Arial + 11 + + + + PointingHandCursor + + + Применить фильтрацию + + + + + + 410 + 200 + 151 + 31 + + + + + Arial + 11 + + + + PointingHandCursor + + + Отменить фильтры + + + + + + 10 + 10 + 561 + 16 + + + + + Arial + 12 + true + + + + Фильтры + + + Qt::AlignmentFlag::AlignCenter + + + + + + 10 + 37 + 751 + 16 + + + + + Arial + 11 + true + + + + Состояние + + + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter + + + + + + 10 + 137 + 751 + 16 + + + + + Arial + 11 + true + + + + Цена + + + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter + + + + + + 10 + 67 + 89 + 20 + + + + + Arial + 10 + + + + Работает + + + + + + 10 + 102 + 89 + 20 + + + + + Arial + 10 + + + + Сломано + + + + + + 40 + 167 + 151 + 22 + + + + + Arial + 10 + + + + 2 + + + 1000000000000000000000.000000000000000 + + + + + + 240 + 167 + 151 + 22 + + + + + Arial + 10 + + + + 1000000000000000000000.000000000000000 + + + + + + 10 + 170 + 21 + 16 + + + + + Arial + 11 + + + + от + + + + + + 210 + 170 + 21 + 16 + + + + + Arial + 11 + + + + до + + + + + + 120 + 67 + 111 + 20 + + + + + Arial + 10 + + + + Не учитывать + + + + + + + 422 + 39 + 161 + 30 + + + + + Arial + 11 + + + + PointingHandCursor + + + Вывод по умолчанию + + + + + + + + 0 + 4 + 571 + 20 + + + + + Arial + 12 + true + + + + Информация об устройстве + + + Qt::AlignmentFlag::AlignCenter + + + + + + 10 + 47 + 574 + 22 + + + + + Arial + 11 + + + + true + + + + + + 10 + 22 + 111 + 20 + + + + + Arial + 11 + + + + Идентификатор + + + + + + 10 + 107 + 574 + 22 + + + + + Arial + 11 + + + + true + + + + + + 10 + 82 + 121 + 20 + + + + + Arial + 11 + + + + Серийный номер + + + + + + 10 + 142 + 121 + 20 + + + + + Arial + 11 + + + + Дата покупки + + + + + + 10 + 167 + 574 + 22 + + + + + Arial + 11 + + + + true + + + + + + 10 + 202 + 121 + 20 + + + + + Arial + 11 + + + + Цена покупки + + + + + + 10 + 227 + 574 + 22 + + + + + Arial + 11 + + + + true + + + + + + 10 + 262 + 121 + 20 + + + + + Arial + 11 + + + + Конец гарантии + + + + + + 10 + 287 + 574 + 22 + + + + + Arial + 11 + + + + true + + + + + + 10 + 322 + 121 + 20 + + + + + Arial + 11 + + + + Помещение + + + + + + 10 + 347 + 574 + 22 + + + + + Arial + 11 + + + + true + + + + + + 10 + 382 + 121 + 20 + + + + + Arial + 11 + + + + Отв. сотрудник + + + + + + 10 + 407 + 574 + 22 + + + + + Arial + 11 + + + + true + + + + + + 10 + 467 + 574 + 22 + + + + + Arial + 11 + + + + true + + + + + + 10 + 442 + 121 + 20 + + + + + Arial + 11 + + + + Отдел + + + + + + 10 + 502 + 121 + 20 + + + + + Arial + 11 + + + + Модель + + + + + + 10 + 527 + 574 + 22 + + + + + Arial + 11 + + + + true + + + + + + 10 + 562 + 121 + 20 + + + + + Arial + 11 + + + + Тип + + + + + + 10 + 587 + 574 + 22 + + + + + Arial + 11 + + + + true + + + + + + 10 + 622 + 121 + 20 + + + + + Arial + 11 + + + + Производитель + + + + + + 10 + 647 + 574 + 22 + + + + + Arial + 11 + + + + true + + + + + + 10 + 707 + 574 + 63 + + + + + Arial + 11 + + + + true + + + + + + 10 + 682 + 211 + 20 + + + + + Arial + 11 + + + + <html><head/><body><p>Дополнительная информация</p></body></html> + + + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter + + + + + true + + + + 10 + 780 + 20 + 20 + + + + + Arial + 11 + + + + + + + true + + + + + + 30 + 780 + 71 + 16 + + + + + Arial + 11 + + + + Работает + + + + + + 10 + 809 + 151 + 30 + + + + + Arial + 11 + + + + PointingHandCursor + + + Структура + + + + + + 190 + 809 + 151 + 30 + + + + + Arial + 11 + + + + PointingHandCursor + + + Характеристики + + + + + + 483 + 809 + 101 + 30 + + + + + Arial + 11 + + + + PointingHandCursor + + + Назад + + + + + + + + + 0 + 0 + 1136 + 20 + + + + + + + diff --git a/models/baseentity.cpp b/models/baseentity.cpp new file mode 100644 index 0000000..db5aa17 --- /dev/null +++ b/models/baseentity.cpp @@ -0,0 +1,14 @@ +#include "baseentity.h" + +BaseEntity::BaseEntity() +{} + +int BaseEntity::id() const +{ + return _id; +} + +void BaseEntity::setId(int newId) +{ + _id = newId; +} diff --git a/models/baseentity.h b/models/baseentity.h new file mode 100644 index 0000000..beebd43 --- /dev/null +++ b/models/baseentity.h @@ -0,0 +1,21 @@ +#ifndef BASEENTITY_H +#define BASEENTITY_H + +#include + +class BaseEntity +{ +public: + BaseEntity(); + + int id() const; + void setId(int newId); + + virtual void fromJson(const QJsonObject &) {} + virtual QJsonObject toJson() const = 0; + +private: + int _id = 0; +}; + +#endif // BASEENTITY_H diff --git a/models/department.cpp b/models/department.cpp new file mode 100644 index 0000000..2456e90 --- /dev/null +++ b/models/department.cpp @@ -0,0 +1,31 @@ +#include "department.h" + +Department::Department() +{} + +Department::~Department() +{} + +QString Department::name() const +{ + return _name; +} + +void Department::setName(const QString &newName) +{ + _name = newName; +} + +void Department::fromJson(const QJsonObject &json) +{ + setId(json["id"].toInt()); + setName(json["name"].toString()); +} + +QJsonObject Department::toJson() const +{ + QJsonObject obj; + obj["id"] = id(); + obj["name"] = name(); + return obj; +} diff --git a/models/department.h b/models/department.h new file mode 100644 index 0000000..5b39401 --- /dev/null +++ b/models/department.h @@ -0,0 +1,24 @@ +#ifndef DEPARTMENT_H +#define DEPARTMENT_H + +#include + +#include "baseentity.h" + +class Department : public BaseEntity +{ +public: + Department(); + virtual ~Department(); + + QString name() const; + void setName(const QString &newName); + + void fromJson(const QJsonObject &json) override; + QJsonObject toJson() const override; + +private: + QString _name = ""; +}; + +#endif // DEPARTMENT_H diff --git a/models/device.cpp b/models/device.cpp new file mode 100644 index 0000000..a834707 --- /dev/null +++ b/models/device.cpp @@ -0,0 +1,190 @@ +#include "device.h" + +Device::Device() +{} + +Device::~Device() +{} + +QString Device::serialNumber() const +{ + return _serialNumber; +} + +void Device::setSerialNumber(const QString &newSerialNumber) +{ + _serialNumber = newSerialNumber; +} + +QDateTime Device::purchaseDate() const +{ + return _purchaseDate; +} + +void Device::setPurchaseDate(const QDateTime &newPurchaseDate) +{ + _purchaseDate = newPurchaseDate; +} + +double Device::price() const +{ + return _price; +} + +void Device::setPrice(double newPrice) +{ + _price = newPrice; +} + +QDateTime Device::warrantyExpireDate() const +{ + return _warrantyExpireDate; +} + +void Device::setWarrantyExpireDate(const QDateTime &newWarrantyExpireDate) +{ + _warrantyExpireDate = newWarrantyExpireDate; +} + +bool Device::isWorking() const +{ + return _isWorking; +} + +void Device::setIsWorking(bool newIsWorking) +{ + _isWorking = newIsWorking; +} + +QString Device::furtherInformation() const +{ + return _furtherInformation; +} + +void Device::setFurtherInformation(const QString &newFurtherInformation) +{ + _furtherInformation = newFurtherInformation; +} + +int Device::idLocation() const +{ + return _idLocation; +} + +void Device::setIdLocation(int newIdLocation) +{ + _idLocation = newIdLocation; +} + +QString Device::nameLocation() const +{ + return _nameLocation; +} + +void Device::setNameLocation(const QString &newNameLocation) +{ + _nameLocation = newNameLocation; +} + +int Device::idEmployee() const +{ + return _idEmployee; +} + +void Device::setIdEmployee(int newIdEmployee) +{ + _idEmployee = newIdEmployee; +} + +QString Device::nameEmployee() const +{ + return _nameEmployee; +} + +void Device::setNameEmployee(const QString &newNameEmployee) +{ + _nameEmployee = newNameEmployee; +} + +int Device::idDepartment() const +{ + return _idDepartment; +} + +void Device::setIdDepartment(int newIdDepartment) +{ + _idDepartment = newIdDepartment; +} + +QString Device::nameDepartment() const +{ + return _nameDepartment; +} + +void Device::setNameDepartment(const QString &newNameDepartment) +{ + _nameDepartment = newNameDepartment; +} + +DeviceModel Device::deviceModel() const +{ + return _deviceModel; +} + +void Device::setDeviceModel(const DeviceModel &newDeviceModel) +{ + _deviceModel = newDeviceModel; +} + +bool Device::isLiked() const +{ + return _isLiked; +} + +void Device::setIsLiked(bool newIsLiked) +{ + _isLiked = newIsLiked; +} + +void Device::fromJson(const QJsonObject &json) +{ + setId(json["id"].toInt()); + setSerialNumber(json["serialNumber"].toString()); + setPurchaseDate(QDateTime::fromString(json["purchaseDate"].toString(), Qt::ISODate)); + setPrice(json["price"].toDouble()); + setWarrantyExpireDate(QDateTime::fromString(json["warrantyExpireDate"].toString(), Qt::ISODate)); + setIsWorking(json["isWorking"].toBool()); + setFurtherInformation(json["furtherInformation"].toString()); + setIdLocation(json["idLocation"].toInt()); + setNameLocation(json["nameLocation"].toString()); + setIdEmployee(json["idEmployee"].toInt()); + setNameEmployee(json["nameEmployee"].toString()); + setIdDepartment(json["idDepartment"].toInt()); + setNameDepartment(json["nameDepartment"].toString()); + setIsLiked(json["isLiked"].toBool()); + + DeviceModel model; + model.setId(json["idDeviceModel"].toInt()); + setDeviceModel(model); +} + +QJsonObject Device::toJson() const +{ + QJsonObject obj; + obj["id"] = id(); + obj["serialNumber"] = serialNumber(); + obj["purchaseDate"] = purchaseDate().toString(Qt::ISODate); + obj["price"] = price(); + obj["warrantyExpireDate"] = warrantyExpireDate().toString(Qt::ISODate); + obj["isWorking"] = isWorking(); + obj["furtherInformation"] = furtherInformation(); + obj["idLocation"] = idLocation(); + obj["nameLocation"] = nameLocation(); + obj["idEmployee"] = idEmployee(); + obj["nameEmployee"] = nameEmployee(); + obj["idDepartment"] = idDepartment(); + obj["nameDepartment"] = nameDepartment(); + obj["idDeviceModel"] = deviceModel().id(); + obj["isLiked"] = isLiked(); + return obj; +} diff --git a/models/device.h b/models/device.h new file mode 100644 index 0000000..590611e --- /dev/null +++ b/models/device.h @@ -0,0 +1,78 @@ +#ifndef DEVICE_H +#define DEVICE_H + +#include +#include + +#include "devicemodel.h" +#include "baseentity.h" + +class Device : public BaseEntity +{ +public: + Device(); + virtual ~Device(); + + QString serialNumber() const; + void setSerialNumber(const QString &newSerialNumber); + + QDateTime purchaseDate() const; + void setPurchaseDate(const QDateTime &newPurchaseDate); + + double price() const; + void setPrice(double newPrice); + + QDateTime warrantyExpireDate() const; + void setWarrantyExpireDate(const QDateTime &newWarrantyExpireDate); + + bool isWorking() const; + void setIsWorking(bool newIsWorking); + + QString furtherInformation() const; + void setFurtherInformation(const QString &newFurtherInformation); + + int idLocation() const; + void setIdLocation(int newIdLocation); + + QString nameLocation() const; + void setNameLocation(const QString &newNameLocation); + + int idEmployee() const; + void setIdEmployee(int newIdEmployee); + + QString nameEmployee() const; + void setNameEmployee(const QString &newNameEmployee); + + int idDepartment() const; + void setIdDepartment(int newIdDepartment); + + QString nameDepartment() const; + void setNameDepartment(const QString &newNameDepartment); + + DeviceModel deviceModel() const; + void setDeviceModel(const DeviceModel &newDeviceModel); + + bool isLiked() const; + void setIsLiked(bool newIsLiked); + + void fromJson(const QJsonObject &json) override; + QJsonObject toJson() const override; + +private: + QString _serialNumber = ""; + QDateTime _purchaseDate = QDateTime(); + double _price = 1; + QDateTime _warrantyExpireDate = QDateTime(); + bool _isWorking = true; + QString _furtherInformation = ""; + int _idLocation = 0; + QString _nameLocation = ""; + int _idEmployee = 0; + QString _nameEmployee = ""; + int _idDepartment = 0; + QString _nameDepartment = ""; + DeviceModel _deviceModel; + bool _isLiked = false; +}; + +#endif // DEVICE_H diff --git a/models/devicemodel.cpp b/models/devicemodel.cpp new file mode 100644 index 0000000..d132f9f --- /dev/null +++ b/models/devicemodel.cpp @@ -0,0 +1,190 @@ +#include "devicemodel.h" + +DeviceModel::DeviceModel() +{} + +DeviceModel::~DeviceModel() +{} + +QString DeviceModel::name() const +{ + return _name; +} + +void DeviceModel::setName(const QString &newName) +{ + _name = newName; +} + +QString DeviceModel::description() const +{ + return _description; +} + +void DeviceModel::setDescription(const QString &newDescription) +{ + _description = newDescription; +} + +int DeviceModel::workEfficiency() const +{ + return _workEfficiency; +} + +void DeviceModel::setWorkEfficiency(int newWorkEfficiency) +{ + _workEfficiency = newWorkEfficiency; +} + +int DeviceModel::reliability() const +{ + return _reliability; +} + +void DeviceModel::setReliability(int newReliability) +{ + _reliability = newReliability; +} + +int DeviceModel::energyEfficiency() const +{ + return _energyEfficiency; +} + +void DeviceModel::setEnergyEfficiency(int newEnergyEfficiency) +{ + _energyEfficiency = newEnergyEfficiency; +} + +int DeviceModel::userFriendliness() const +{ + return _userFriendliness; +} + +void DeviceModel::setUserFriendliness(int newUserFriendliness) +{ + _userFriendliness = newUserFriendliness; +} + +int DeviceModel::durability() const +{ + return _durability; +} + +void DeviceModel::setDurability(int newDurability) +{ + _durability = newDurability; +} + +int DeviceModel::aestheticQualities() const +{ + return _aestheticQualities; +} + +void DeviceModel::setAestheticQualities(int newAestheticQualities) +{ + _aestheticQualities = newAestheticQualities; +} + +int DeviceModel::idType() const +{ + return _idType; +} + +void DeviceModel::setIdType(int newIdType) +{ + _idType = newIdType; +} + +QString DeviceModel::nameType() const +{ + return _nameType; +} + +void DeviceModel::setNameType(const QString &newNameType) +{ + _nameType = newNameType; +} + +int DeviceModel::idManuf() const +{ + return _idManuf; +} + +void DeviceModel::setIdManuf(int newIdManuf) +{ + _idManuf = newIdManuf; +} + +QString DeviceModel::nameManuf() const +{ + return _nameManuf; +} + +void DeviceModel::setNameManuf(const QString &newNameManuf) +{ + _nameManuf = newNameManuf; +} + +QList DeviceModel::structureElements() const +{ + return _structureElements; +} + +void DeviceModel::setStructureElements(const QList &newStructureElements) +{ + _structureElements = newStructureElements; +} + +void DeviceModel::fromJson(const QJsonObject &json) +{ + setId(json["id"].toInt()); + setName(json["name"].toString()); + setDescription(json["description"].toString()); + setWorkEfficiency(json["workEfficiency"].toInt()); + setReliability(json["reliability"].toInt()); + setEnergyEfficiency(json["energyEfficiency"].toInt()); + setUserFriendliness(json["userFriendliness"].toInt()); + setDurability(json["durability"].toInt()); + setAestheticQualities(json["aestheticQualities"].toInt()); + setIdType(json["idType"].toInt()); + setNameType(json["nameType"].toString()); + setIdManuf(json["idManuf"].toInt()); + setNameManuf(json["nameManuf"].toString()); + + QJsonArray structureElementsArray = json["structureElements"].toArray(); + QList elements; + for (const QJsonValue &value : structureElementsArray) { + DeviceStructureElement element; + element.fromJson(value.toObject()); + elements.append(element); + } + setStructureElements(elements); +} + +QJsonObject DeviceModel::toJson() const +{ + QJsonObject obj; + + obj["id"] = id(); + obj["name"] = name(); + obj["description"] = description(); + obj["workEfficiency"] = workEfficiency(); + obj["reliability"] = reliability(); + obj["energyEfficiency"] = energyEfficiency(); + obj["userFriendliness"] = userFriendliness(); + obj["durability"] = durability(); + obj["aestheticQualities"] = aestheticQualities(); + obj["idType"] = idType(); + obj["nameType"] = nameType(); + obj["idManuf"] = idManuf(); + obj["nameManuf"] = nameManuf(); + + QJsonArray structureElementsArray; + for (const DeviceStructureElement &element : structureElements()) { + structureElementsArray.append(element.toJson()); + } + obj["structureElements"] = structureElementsArray; + + return obj; +} diff --git a/models/devicemodel.h b/models/devicemodel.h new file mode 100644 index 0000000..8b860b9 --- /dev/null +++ b/models/devicemodel.h @@ -0,0 +1,75 @@ +#ifndef DEVICEMODEL_H +#define DEVICEMODEL_H + +#include +#include +#include + +#include "baseentity.h" +#include "devicestructureelement.h" + +class DeviceModel : public BaseEntity +{ +public: + DeviceModel(); + virtual ~DeviceModel(); + + QString name() const; + void setName(const QString &newName); + + QString description() const; + void setDescription(const QString &newDescription); + + int workEfficiency() const; + void setWorkEfficiency(int newWorkEfficiency); + + int reliability() const; + void setReliability(int newReliability); + + int energyEfficiency() const; + void setEnergyEfficiency(int newEnergyEfficiency); + + int userFriendliness() const; + void setUserFriendliness(int newUserFriendliness); + + int durability() const; + void setDurability(int newDurability); + + int aestheticQualities() const; + void setAestheticQualities(int newAestheticQualities); + + int idType() const; + void setIdType(int newIdType); + + QString nameType() const; + void setNameType(const QString &newNameType); + + int idManuf() const; + void setIdManuf(int newIdManuf); + + QString nameManuf() const; + void setNameManuf(const QString &newNameManuf); + + QList structureElements() const; + void setStructureElements(const QList &newStructureElements); + + void fromJson(const QJsonObject &json) override; + QJsonObject toJson() const override; + +private: + QString _name = ""; + QString _description = ""; + int _workEfficiency = 0; + int _reliability = 0; + int _energyEfficiency = 0; + int _userFriendliness = 0; + int _durability = 0; + int _aestheticQualities = 0; + int _idType = 0; + QString _nameType = ""; + int _idManuf = 0; + QString _nameManuf = ""; + QList _structureElements; +}; + +#endif // DEVICEMODEL_H diff --git a/models/devicestructureelement.cpp b/models/devicestructureelement.cpp new file mode 100644 index 0000000..52fcfb8 --- /dev/null +++ b/models/devicestructureelement.cpp @@ -0,0 +1,79 @@ +#include "devicestructureelement.h" + +DeviceStructureElement::DeviceStructureElement() +{} + +DeviceStructureElement::~DeviceStructureElement() +{} + +QString DeviceStructureElement::nameModel() const +{ + return _nameModel; +} + +void DeviceStructureElement::setNameModel(const QString &newNameModel) +{ + _nameModel = newNameModel; +} + +QString DeviceStructureElement::nameManuf() const +{ + return _nameManuf; +} + +void DeviceStructureElement::setNameManuf(const QString &newNameManuf) +{ + _nameManuf = newNameManuf; +} + +QString DeviceStructureElement::description() const +{ + return _description; +} + +void DeviceStructureElement::setDescription(const QString &newDescription) +{ + _description = newDescription; +} + +QString DeviceStructureElement::nameType() const +{ + return _nameType; +} + +void DeviceStructureElement::setNameType(const QString &newNameType) +{ + _nameType = newNameType; +} + +int DeviceStructureElement::count() const +{ + return _count; +} + +void DeviceStructureElement::setCount(int newCount) +{ + _count = newCount; +} + +void DeviceStructureElement::fromJson(const QJsonObject &json) +{ + setId(json["id"].toInt()); + setNameModel(json["nameModel"].toString()); + setNameManuf(json["nameManuf"].toString()); + setDescription(json["description"].toString()); + setNameType(json["nameType"].toString()); + setCount(json["count"].toInt()); +} + +QJsonObject DeviceStructureElement::toJson() const +{ + QJsonObject obj; + obj["id"] = id(); + obj["nameModel"] = nameModel(); + obj["nameManuf"] = nameManuf(); + obj["description"] = description(); + obj["nameType"] = nameType(); + obj["count"] = count(); + return obj; +} diff --git a/models/devicestructureelement.h b/models/devicestructureelement.h new file mode 100644 index 0000000..dfb2c2b --- /dev/null +++ b/models/devicestructureelement.h @@ -0,0 +1,40 @@ +#ifndef DEVICESTRUCTUREELEMENT_H +#define DEVICESTRUCTUREELEMENT_H + +#include + +#include "baseentity.h" + +class DeviceStructureElement : public BaseEntity +{ +public: + DeviceStructureElement(); + virtual ~DeviceStructureElement(); + + QString nameModel() const; + void setNameModel(const QString &newNameModel); + + QString nameManuf() const; + void setNameManuf(const QString &newNameManuf); + + QString description() const; + void setDescription(const QString &newDescription); + + QString nameType() const; + void setNameType(const QString &newNameType); + + int count() const; + void setCount(int newCount); + + void fromJson(const QJsonObject &json) override; + QJsonObject toJson() const override; + +private: + QString _nameModel = ""; + QString _nameManuf = ""; + QString _description = ""; + QString _nameType = ""; + int _count = 1; +}; + +#endif // DEVICESTRUCTUREELEMENT_H diff --git a/models/devicetype.cpp b/models/devicetype.cpp new file mode 100644 index 0000000..5985e77 --- /dev/null +++ b/models/devicetype.cpp @@ -0,0 +1,31 @@ +#include "devicetype.h" + +DeviceType::DeviceType() +{} + +DeviceType::~DeviceType() +{} + +QString DeviceType::name() const +{ + return _name; +} + +void DeviceType::setName(const QString &newName) +{ + _name = newName; +} + +void DeviceType::fromJson(const QJsonObject &json) +{ + setId(json["id"].toInt()); + setName(json["name"].toString()); +} + +QJsonObject DeviceType::toJson() const +{ + QJsonObject obj; + obj["id"] = id(); + obj["name"] = name(); + return obj; +} diff --git a/models/devicetype.h b/models/devicetype.h new file mode 100644 index 0000000..f655cc7 --- /dev/null +++ b/models/devicetype.h @@ -0,0 +1,24 @@ +#ifndef DEVICETYPE_H +#define DEVICETYPE_H + +#include + +#include "baseentity.h" + +class DeviceType : public BaseEntity +{ +public: + DeviceType(); + virtual ~DeviceType(); + + QString name() const; + void setName(const QString &newName); + + void fromJson(const QJsonObject &json) override; + QJsonObject toJson() const override; + +private: + QString _name = ""; +}; + +#endif // DEVICETYPE_H diff --git a/models/filterparams.cpp b/models/filterparams.cpp new file mode 100644 index 0000000..6fe84aa --- /dev/null +++ b/models/filterparams.cpp @@ -0,0 +1,54 @@ +#include "filterparams.h" + +FilterParams::FilterParams() +{} + +bool FilterParams::isWorking() const +{ + return _isWorking; +} + +void FilterParams::setIsWorking(bool newIsWorking) +{ + _isWorking = newIsWorking; +} + +double FilterParams::priceFrom() const +{ + return _priceFrom; +} + +void FilterParams::setPriceFrom(double newPriceFrom) +{ + _priceFrom = newPriceFrom; +} + +double FilterParams::priceTo() const +{ + return _priceTo; +} + +void FilterParams::setPriceTo(double newPriceTo) +{ + _priceTo = newPriceTo; +} + +bool FilterParams::getDisregardState() const +{ + return disregardState; +} + +void FilterParams::setDisregardState(bool newDisregardState) +{ + disregardState = newDisregardState; +} + +bool FilterParams::getApllyFilters() const +{ + return apllyFilters; +} + +void FilterParams::setApllyFilters(bool newApllyFilters) +{ + apllyFilters = newApllyFilters; +} diff --git a/models/filterparams.h b/models/filterparams.h new file mode 100644 index 0000000..5267e90 --- /dev/null +++ b/models/filterparams.h @@ -0,0 +1,32 @@ +#ifndef FILTERPARAMS_H +#define FILTERPARAMS_H + +class FilterParams +{ +public: + FilterParams(); + + bool isWorking() const; + void setIsWorking(bool newIsWorking); + + double priceFrom() const; + void setPriceFrom(double newPriceFrom); + + double priceTo() const; + void setPriceTo(double newPriceTo); + + bool getDisregardState() const; + void setDisregardState(bool newDisregardState); + + bool getApllyFilters() const; + void setApllyFilters(bool newApllyFilters); + +private: + bool _isWorking = true; + double _priceFrom = -1; + double _priceTo = -1; + bool disregardState = false; + bool apllyFilters = false; +}; + +#endif // FILTERPARAMS_H diff --git a/models/location.cpp b/models/location.cpp new file mode 100644 index 0000000..0928550 --- /dev/null +++ b/models/location.cpp @@ -0,0 +1,31 @@ +#include "location.h" + +Location::Location() +{} + +Location::~Location() +{} + +QString Location::name() const +{ + return _name; +} + +void Location::setName(const QString &newName) +{ + _name = newName; +} + +void Location::fromJson(const QJsonObject &json) +{ + setId(json["id"].toInt()); + setName(json["name"].toString()); +} + +QJsonObject Location::toJson() const +{ + QJsonObject obj; + obj["id"] = id(); + obj["name"] = name(); + return obj; +} diff --git a/models/location.h b/models/location.h new file mode 100644 index 0000000..98e3772 --- /dev/null +++ b/models/location.h @@ -0,0 +1,24 @@ +#ifndef LOCATION_H +#define LOCATION_H + +#include + +#include "baseentity.h" + +class Location : public BaseEntity +{ +public: + Location(); + virtual ~Location(); + + QString name() const; + void setName(const QString &newName); + + void fromJson(const QJsonObject &json) override; + QJsonObject toJson() const override; + +private: + QString _name = ""; +}; + +#endif // LOCATION_H diff --git a/models/manufacturer.cpp b/models/manufacturer.cpp new file mode 100644 index 0000000..6d9df58 --- /dev/null +++ b/models/manufacturer.cpp @@ -0,0 +1,31 @@ +#include "manufacturer.h" + +Manufacturer::Manufacturer() +{} + +Manufacturer::~Manufacturer() +{} + +QString Manufacturer::name() const +{ + return _name; +} + +void Manufacturer::setName(const QString &newName) +{ + _name = newName; +} + +void Manufacturer::fromJson(const QJsonObject &json) +{ + setId(json["id"].toInt()); + setName(json["name"].toString()); +} + +QJsonObject Manufacturer::toJson() const +{ + QJsonObject obj; + obj["id"] = id(); + obj["name"] = name(); + return obj; +} diff --git a/models/manufacturer.h b/models/manufacturer.h new file mode 100644 index 0000000..6106671 --- /dev/null +++ b/models/manufacturer.h @@ -0,0 +1,24 @@ +#ifndef MANUFACTURER_H +#define MANUFACTURER_H + +#include + +#include "baseentity.h" + +class Manufacturer : public BaseEntity +{ +public: + Manufacturer(); + virtual ~Manufacturer(); + + QString name() const; + void setName(const QString &newName); + + void fromJson(const QJsonObject &json) override; + QJsonObject toJson() const override; + +private: + QString _name = ""; +}; + +#endif // MANUFACTURER_H diff --git a/models/types.h b/models/types.h new file mode 100644 index 0000000..669460b --- /dev/null +++ b/models/types.h @@ -0,0 +1,12 @@ +#ifndef TYPES_H +#define TYPES_H + +#include "location.h" // IWYU pragma: keep +#include "department.h" // IWYU pragma: keep +#include "manufacturer.h" // IWYU pragma: keep +#include "devicetype.h" // IWYU pragma: keep +#include "devicestructureelement.h" // IWYU pragma: keep +#include "devicemodel.h" // IWYU pragma: keep +#include "device.h" // IWYU pragma: keep + +#endif // TYPES_H diff --git a/presenter.cpp b/presenter.cpp new file mode 100644 index 0000000..6e02cd9 --- /dev/null +++ b/presenter.cpp @@ -0,0 +1,86 @@ +#include "presenter.h" + +Presenter::Presenter(QObject *parent) : QObject(parent) +{ + client = new ApiClient(); + window = new MainWindow(); + + connect(client, &ApiClient::devicesReceived, this, &Presenter::onDevicesReceived); + connect(client, &ApiClient::departmentsReceived, this, &Presenter::onDepartmentsReceived); + connect(client, &ApiClient::deviceModelsReceived, this, &Presenter::onDeviceModelsReceived); + connect(client, &ApiClient::deviceTypesReceived, this, &Presenter::onDeviceTypesReceived); + connect(client, &ApiClient::locationsReceived, this, &Presenter::onLocationsReceived); + connect(client, &ApiClient::manufacturersReceived, this, &Presenter::onManufacturersReceived); + + window->setClient(client); + + client->getEntities("/api/locations"); + client->getEntities("/api/departments"); + client->getEntities("/api/manufacturers"); + client->getEntities("/api/devicetypes"); + client->getEntities("/api/devicemodels"); +} + +Presenter::~Presenter() +{ + client->deleteLater(); + window->deleteLater(); +} + +void Presenter::onLocationsReceived(const QMap &locations) +{ + window->setMapLocations(locations); +} + +void Presenter::onDepartmentsReceived(const QMap &departments) +{ + window->setMapDepartments(departments); +} + +void Presenter::onManufacturersReceived(const QMap &manufacturers) +{ + window->setMapManufacturers(manufacturers); +} + +void Presenter::onDeviceTypesReceived(const QMap &deviceTypes) +{ + window->setMapDeviceTypes(deviceTypes); +} + +void Presenter::onDeviceModelsReceived(const QMap &deviceModels) +{ + window->setMapDeviceModels(deviceModels); + client->getFilteredDevices( + false, + 0.00, + std::numeric_limits::max(), + false, + false, + -1, + -1, + "", + "Сначала новые" + ); +} + +void Presenter::onDevicesReceived(const QList &devices) +{ + disconnect(client, &ApiClient::devicesReceived, this, &Presenter::onDevicesReceived); + + QMap devicesMap; + QMap deviceModels = window->getMapDeviceModels(); + + for (const Device &device : devices) { + int deviceModelId = device.deviceModel().id(); + + if (deviceModels.contains(deviceModelId)) { + Device updatedDevice = device; + updatedDevice.setDeviceModel(deviceModels[deviceModelId]); + devicesMap.insert(updatedDevice.id(), updatedDevice); + } else { + devicesMap.insert(device.id(), device); + } + } + window->setMapDevices(devicesMap); + window->show(); +} diff --git a/presenter.h b/presenter.h new file mode 100644 index 0000000..8cd6771 --- /dev/null +++ b/presenter.h @@ -0,0 +1,29 @@ +#ifndef PRESENTER_H +#define PRESENTER_H + +#include + +#include "apiclient.h" +#include "mainwindow.h" + +class Presenter : public QObject +{ + Q_OBJECT +public: + Presenter(QObject *parent = nullptr); + ~Presenter(); + +private slots: + void onDevicesReceived(const QList &devices); + void onDepartmentsReceived(const QMap &departments); + void onDeviceModelsReceived(const QMap &deviceModels); + void onDeviceTypesReceived(const QMap &deviceTypes); + void onManufacturersReceived(const QMap &manufacturers); + void onLocationsReceived(const QMap &locations); + +private: + ApiClient *client; + MainWindow *window; +}; + +#endif // PRESENTER_H diff --git a/resources/images/device-type-1.png b/resources/images/device-type-1.png new file mode 100644 index 0000000..f554bca Binary files /dev/null and b/resources/images/device-type-1.png differ diff --git a/resources/images/device-type-2.png b/resources/images/device-type-2.png new file mode 100644 index 0000000..8cb6fa0 Binary files /dev/null and b/resources/images/device-type-2.png differ diff --git a/resources/images/device-type-3.png b/resources/images/device-type-3.png new file mode 100644 index 0000000..bf6115b Binary files /dev/null and b/resources/images/device-type-3.png differ diff --git a/resources/images/device-type-4.png b/resources/images/device-type-4.png new file mode 100644 index 0000000..1bb18a2 Binary files /dev/null and b/resources/images/device-type-4.png differ diff --git a/resources/images/device-type-5.png b/resources/images/device-type-5.png new file mode 100644 index 0000000..34ac3e6 Binary files /dev/null and b/resources/images/device-type-5.png differ diff --git a/resources/images/device-type-6.png b/resources/images/device-type-6.png new file mode 100644 index 0000000..c4fef45 Binary files /dev/null and b/resources/images/device-type-6.png differ diff --git a/resources/images/device-type-7.png b/resources/images/device-type-7.png new file mode 100644 index 0000000..e4e41ef Binary files /dev/null and b/resources/images/device-type-7.png differ diff --git a/resources/images/device-type-8.png b/resources/images/device-type-8.png new file mode 100644 index 0000000..2ebf3e7 Binary files /dev/null and b/resources/images/device-type-8.png differ diff --git a/resources/images/down-arrow.png b/resources/images/down-arrow.png new file mode 100644 index 0000000..e0d0bba Binary files /dev/null and b/resources/images/down-arrow.png differ diff --git a/resources/images/mw-icon.png b/resources/images/mw-icon.png new file mode 100644 index 0000000..1ddd10d Binary files /dev/null and b/resources/images/mw-icon.png differ diff --git a/resources/images/question.png b/resources/images/question.png new file mode 100644 index 0000000..4efea09 Binary files /dev/null and b/resources/images/question.png differ diff --git a/resources/images/search-hover.png b/resources/images/search-hover.png new file mode 100644 index 0000000..119c8c3 Binary files /dev/null and b/resources/images/search-hover.png differ diff --git a/resources/images/search.png b/resources/images/search.png new file mode 100644 index 0000000..0ec3061 Binary files /dev/null and b/resources/images/search.png differ diff --git a/resources/resources.qrc b/resources/resources.qrc new file mode 100644 index 0000000..b47921c --- /dev/null +++ b/resources/resources.qrc @@ -0,0 +1,45 @@ + + + + images/mw-icon.png + + + images/search.png + + + images/search-hover.png + + + images/question.png + + + images/down-arrow.png + + + images/device-type-1.png + + + images/device-type-2.png + + + images/device-type-3.png + + + images/device-type-4.png + + + images/device-type-5.png + + + images/device-type-6.png + + + images/device-type-7.png + + + images/device-type-8.png + + + styles.qss + + \ No newline at end of file diff --git a/resources/styles.qss b/resources/styles.qss new file mode 100644 index 0000000..8596cec --- /dev/null +++ b/resources/styles.qss @@ -0,0 +1,47 @@ +QMainWindow { + background-color: rgb(246, 246, 246); +} + +QComboBox, QPushButton, QLineEdit, QTextEdit, QListWidget, QTableWidget, QGroupBox, QStackedWidget { + border: 1px solid black; + border-radius: 2px; +} + +QGroupBox#groupBoxFilters, QStackedWidget#stackedWidget { + background-color: white; +} + +QLineEdit { + border-radius: 5px; +} + +QComboBox { + background-color: white; +} + +QComboBox::drop-down { + border: 0px; +} + +QComboBox::down-arrow { + width: 10px; + height: 10px; + image: url(:/images/down-arrow.png); +} + +QPushButton { + background-color: white; + padding: 5px; +} + +QPushButton:hover { + background-color: green; + color: white; +} + +QPushButton:pressed { + background-color: green; + border-radius: 4px; + border-width: 2px; + color: white; +} \ No newline at end of file diff --git a/utils/buttonhoverwatcher.cpp b/utils/buttonhoverwatcher.cpp new file mode 100644 index 0000000..d08a508 --- /dev/null +++ b/utils/buttonhoverwatcher.cpp @@ -0,0 +1,24 @@ +#include "buttonhoverwatcher.h" + +ButtonHoverWatcher::ButtonHoverWatcher(QObject *parent) : QObject(parent) +{} + +bool ButtonHoverWatcher::eventFilter(QObject *watched, QEvent *event) +{ + QPushButton * button = qobject_cast(watched); + if (!button) { + return false; + } + + if (event->type() == QEvent::Enter) { + button->setIcon(QIcon(":/images/search-hover.png")); + return true; + } + + if (event->type() == QEvent::Leave){ + button->setIcon(QIcon(":/images/search.png")); + return true; + } + + return false; +} diff --git a/utils/buttonhoverwatcher.h b/utils/buttonhoverwatcher.h new file mode 100644 index 0000000..659e8a6 --- /dev/null +++ b/utils/buttonhoverwatcher.h @@ -0,0 +1,16 @@ +#ifndef BUTTONHOVERWATCHER_H +#define BUTTONHOVERWATCHER_H + +#include +#include +#include + +class ButtonHoverWatcher : public QObject +{ + Q_OBJECT +public: + explicit ButtonHoverWatcher(QObject *parent = nullptr); + virtual bool eventFilter(QObject * watched, QEvent * event) Q_DECL_OVERRIDE; +}; + +#endif // BUTTONHOVERWATCHER_H