From 611f444d86e0405a3e2f000a885e29beb5ea3df5 Mon Sep 17 00:00:00 2001 From: florian Date: Mon, 25 Aug 2025 12:44:01 +0200 Subject: [PATCH] changement d'interface --- src/controller/command.hpp | 9 +- src/controller/stockController.cpp | 113 +- src/model/model.cpp | 167 +++ src/model/model.hpp | 10 + src/model/stock.cpp | 29 +- src/model/stock.hpp | 1 + src/view/qtView.cpp | 2186 +++++++++++++++------------- src/view/qtView.hpp | 180 ++- src/view/virtualKeyboard.cpp | 1 + 9 files changed, 1642 insertions(+), 1054 deletions(-) diff --git a/src/controller/command.hpp b/src/controller/command.hpp index 230d4d5..03f36dc 100644 --- a/src/controller/command.hpp +++ b/src/controller/command.hpp @@ -10,7 +10,14 @@ enum Command ShowStocks, CreateItemType, ShowItemTypes, - AddItemToStock + AddItemToStock, + MoveItemBetweenStocks, + RemoveItemFromStock, + DeleteStock, + DeleteItemType, + ShowStockContent, + ShowCapacities, + ShowStatistics }; #endif // COMMAND_HPP diff --git a/src/controller/stockController.cpp b/src/controller/stockController.cpp index 58c8d70..3ecedb7 100644 --- a/src/controller/stockController.cpp +++ b/src/controller/stockController.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../errors/stockFull.hpp" #include "../errors/stockEmpty.hpp" @@ -81,11 +82,22 @@ void StockController::process() case Command::CreateItemType: // Handle item type creation logic if (commandArgs.size() >= 1) { - model->createItemType( - commandArgs[0], - commandArgs.size() > 1 ? commandArgs[1] : "", - commandArgs.size() > 2 ? std::stoi(commandArgs[2]) : 1 - ); + if (commandArgs.size() >= 4) { + // Arguments complets: name, id, comment, size + model->createItemType( + commandArgs[0], + std::stoi(commandArgs[1]), + commandArgs[2], + std::stoi(commandArgs[3]) + ); + } else { + // Arguments partiels: utiliser l'ID auto-généré + model->createItemType( + commandArgs[0], + commandArgs.size() > 1 ? commandArgs[1] : "", + commandArgs.size() > 2 ? std::stoi(commandArgs[2]) : 1 + ); + } view->displayItemTypeCreate(model->getItemTypes().back()); } break; @@ -107,6 +119,85 @@ void StockController::process() case Command::Refresh: // Handle refresh logic here break; + case Command::MoveItemBetweenStocks: + // Handle moving items between stocks: sourceStock, targetStock, itemType, quantity + if (commandArgs.size() >= 4) { + std::string sourceStock = commandArgs[0]; + std::string targetStock = commandArgs[1]; + std::string itemTypeName = commandArgs[2]; + int quantity = std::stoi(commandArgs[3]); + + bool success = model->moveItemBetweenStocks(sourceStock, targetStock, itemTypeName, quantity); + if (success) { + view->displayMessage("✅ Déplacement réussi: " + std::to_string(quantity) + " articles de type '" + itemTypeName + "' du stock '" + sourceStock + "' vers '" + targetStock + "'"); + } else { + view->displayError("❌ Échec du déplacement des articles"); + } + } + break; + case Command::RemoveItemFromStock: + // Handle removing items from stock: stockName, itemType, quantity + if (commandArgs.size() >= 3) { + std::string stockName = commandArgs[0]; + std::string itemTypeName = commandArgs[1]; + int quantity = std::stoi(commandArgs[2]); + + bool success = model->removeItemFromStock(stockName, itemTypeName, quantity); + if (success) { + view->displayMessage("✅ Retrait réussi: " + std::to_string(quantity) + " articles de type '" + itemTypeName + "' du stock '" + stockName + "'"); + } else { + view->displayError("❌ Échec du retrait des articles"); + } + } + break; + case Command::DeleteStock: + // Handle stock deletion: stockName + if (commandArgs.size() >= 1) { + std::string stockName = commandArgs[0]; + + bool success = model->deleteStock(stockName); + if (success) { + view->displayMessage("✅ Stock '" + stockName + "' supprimé avec succès"); + } else { + view->displayError("❌ Échec de la suppression du stock '" + stockName + "'"); + } + } + break; + case Command::DeleteItemType: + // Handle item type deletion: typeName + if (commandArgs.size() >= 1) { + std::string typeName = commandArgs[0]; + + bool success = model->deleteItemType(typeName); + if (success) { + view->displayMessage("✅ Type d'article '" + typeName + "' supprimé avec succès"); + } else { + view->displayError("❌ Échec de la suppression du type '" + typeName + "'"); + } + } + break; + case Command::ShowStockContent: + // Handle showing specific stock content: stockName + if (commandArgs.size() >= 1) { + std::string stockName = commandArgs[0]; + std::string content = model->getStockContentDetails(stockName); + view->displayMessage(content); + } + break; + case Command::ShowCapacities: + // Handle showing all stock capacities + { + std::string capacities = model->getCapacitiesReport(); + view->displayMessage(capacities); + } + break; + case Command::ShowStatistics: + // Handle showing statistics + { + std::string statistics = model->getStatisticsReport(); + view->displayMessage(statistics); + } + break; default: break; } @@ -123,6 +214,18 @@ void StockController::process() // Gérer les exceptions et afficher un message d'erreur view->displayError("Invalid Item Type: " + std::string(e.what())); } + catch (const std::invalid_argument& e) { + // Gérer les erreurs de conversion de chaînes en nombres + view->displayError("Invalid argument: " + std::string(e.what())); + } + catch (const std::out_of_range& e) { + // Gérer les erreurs de débordement numérique + view->displayError("Number out of range: " + std::string(e.what())); + } + catch (const std::exception& e) { + // Gérer les autres exceptions standard + view->displayError("Error: " + std::string(e.what())); + } catch (...) { // Gérer les exceptions inconnues diff --git a/src/model/model.cpp b/src/model/model.cpp index 3478aa2..843144c 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -1,5 +1,6 @@ #include "model.hpp" #include "../errors/stockFull.hpp" +#include Model::Model() { @@ -34,6 +35,31 @@ void Model::createItemType(const std::string &name, const std::string &comment, itemTypes.push_back(newItemType); } +void Model::createItemType(const std::string &name, int id, const std::string &comment, int size) +{ + // Vérifier si l'ID existe déjà + for (const auto& existingType : itemTypes) { + if (existingType.getId() == id) { + throw std::invalid_argument("ID " + std::to_string(id) + " already exists for item type"); + } + } + + // Vérifier si le nom existe déjà + for (const auto& existingType : itemTypes) { + if (existingType.getName() == name) { + throw std::invalid_argument("Item type name '" + name + "' already exists"); + } + } + + ItemType newItemType(name, id, comment, size); + itemTypes.push_back(newItemType); + + // Mettre à jour nextItemTypeId si nécessaire + if (id >= nextItemTypeId) { + nextItemTypeId = id + 1; + } +} + std::vector Model::getItemTypes() const { return itemTypes; @@ -93,4 +119,145 @@ Stock* Model::findStockByName(const std::string &name) } } return nullptr; +} + +// Nouvelles méthodes pour la gestion avancée + +bool Model::removeItemFromStock(const std::string &stockName, const std::string &itemTypeName, int quantity) +{ + Stock* stock = findStockByName(stockName); + if (!stock) + { + return false; // Stock not found + } + + ItemType* itemType = findItemTypeByName(itemTypeName); + if (!itemType) + { + return false; // ItemType not found + } + + // Retirer la quantité spécifiée d'articles du stock + for (int i = 0; i < quantity; ++i) + { + if (!stock->removeItem(*itemType)) + { + return false; // Impossible de retirer plus d'articles + } + } + + return true; +} + +bool Model::moveItemBetweenStocks(const std::string &sourceStock, const std::string &targetStock, const std::string &itemTypeName, int quantity) +{ + // Retirer du stock source + if (!removeItemFromStock(sourceStock, itemTypeName, quantity)) + { + return false; + } + + // Ajouter au stock cible + if (!addItemToStock(targetStock, itemTypeName, quantity)) + { + // Si l'ajout échoue, remettre les articles dans le stock source + addItemToStock(sourceStock, itemTypeName, quantity); + return false; + } + + return true; +} + +bool Model::deleteStock(const std::string &stockName) +{ + for (auto it = stocks.begin(); it != stocks.end(); ++it) + { + if (it->getName() == stockName) + { + stocks.erase(it); + return true; + } + } + return false; // Stock not found +} + +bool Model::deleteItemType(const std::string &typeName) +{ + for (auto it = itemTypes.begin(); it != itemTypes.end(); ++it) + { + if (it->getName() == typeName) + { + itemTypes.erase(it); + return true; + } + } + return false; // ItemType not found +} + +std::string Model::getStockContentDetails(const std::string &stockName) +{ + Stock* stock = findStockByName(stockName); + if (!stock) + { + return "Stock '" + stockName + "' non trouvé."; + } + + std::string result = "=== CONTENU DU STOCK: " + stockName + " ===\n"; + result += "Capacité: " + std::to_string(stock->getCapacity()) + "\n"; + result += "Occupation actuelle: " + std::to_string(stock->getCurrentSize()) + "\n"; + result += "Espace libre: " + std::to_string(stock->getCapacity() - stock->getCurrentSize()) + "\n"; + + // Note: Il faudrait ajouter une méthode pour lister les articles dans Stock + result += "Articles: [Détails à implémenter dans la classe Stock]\n"; + + return result; +} + +std::string Model::getCapacitiesReport() +{ + std::string result = "=== RAPPORT DES CAPACITÉS ===\n"; + + if (stocks.empty()) + { + result += "Aucun stock disponible.\n"; + return result; + } + + for (const auto& stock : stocks) + { + result += "📦 " + stock.getName() + ":\n"; + result += " Capacité: " + std::to_string(stock.getCapacity()) + "\n"; + result += " Occupé: " + std::to_string(stock.getCurrentSize()) + "\n"; + result += " Libre: " + std::to_string(stock.getCapacity() - stock.getCurrentSize()) + "\n"; + result += " Utilisation: " + std::to_string((stock.getCurrentSize() * 100) / stock.getCapacity()) + "%\n\n"; + } + + return result; +} + +std::string Model::getStatisticsReport() +{ + std::string result = "=== STATISTIQUES GÉNÉRALES ===\n"; + + result += "📊 Nombre total de stocks: " + std::to_string(stocks.size()) + "\n"; + result += "🏷️ Nombre total de types d'articles: " + std::to_string(itemTypes.size()) + "\n"; + + if (!stocks.empty()) + { + int totalCapacity = 0; + int totalOccupied = 0; + + for (const auto& stock : stocks) + { + totalCapacity += stock.getCapacity(); + totalOccupied += stock.getCurrentSize(); + } + + result += "📦 Capacité totale: " + std::to_string(totalCapacity) + "\n"; + result += "📋 Espace occupé: " + std::to_string(totalOccupied) + "\n"; + result += "💾 Espace libre: " + std::to_string(totalCapacity - totalOccupied) + "\n"; + result += "📈 Taux d'occupation global: " + std::to_string((totalOccupied * 100) / totalCapacity) + "%\n"; + } + + return result; } \ No newline at end of file diff --git a/src/model/model.hpp b/src/model/model.hpp index d171a4a..07ced3d 100644 --- a/src/model/model.hpp +++ b/src/model/model.hpp @@ -20,12 +20,22 @@ public: // Méthodes pour gérer les ItemType void createItemType(const std::string &name, const std::string &comment = "", int size = 1); + void createItemType(const std::string &name, int id, const std::string &comment = "", int size = 1); std::vector getItemTypes() const; ItemType* findItemTypeByName(const std::string &name); // Méthodes pour ajouter des items aux stocks bool addItemToStock(const std::string &stockName, const std::string &itemTypeName, int quantity); Stock* findStockByName(const std::string &name); + + // Nouvelles méthodes pour la gestion avancée + bool removeItemFromStock(const std::string &stockName, const std::string &itemTypeName, int quantity); + bool moveItemBetweenStocks(const std::string &sourceStock, const std::string &targetStock, const std::string &itemTypeName, int quantity); + bool deleteStock(const std::string &stockName); + bool deleteItemType(const std::string &typeName); + std::string getStockContentDetails(const std::string &stockName); + std::string getCapacitiesReport(); + std::string getStatisticsReport(); private: std::vector stocks; // Assuming Stock is a class defined elsewhere std::vector itemTypes; // Assuming ItemType is a class defined elsewhere diff --git a/src/model/stock.cpp b/src/model/stock.cpp index c0a0a61..ab178b7 100644 --- a/src/model/stock.cpp +++ b/src/model/stock.cpp @@ -3,9 +3,9 @@ #include #include -#include "errors/stockFull.hpp" -#include "errors/stockEmpty.hpp" -#include "errors/invalidItemType.hpp" +#include "../errors/stockFull.hpp" +#include "../errors/stockEmpty.hpp" +#include "../errors/invalidItemType.hpp" Stock::Stock(const std::string &name, int capacity, const std::string &comment, int id) : name(name), capacity(capacity), comment(comment), id(id) @@ -44,6 +44,29 @@ void Stock::removeItem(int id) [id](const ItemType &item) { return item.getId() == id; }), items.end()); } +bool Stock::removeItem(const ItemType &item) +{ + if (items.empty()) + { + return false; // No items to remove + } + + // Trouver le premier article du même type + auto it = std::find_if(items.begin(), items.end(), + [&item](const ItemType &stockItem) { + return stockItem.getName() == item.getName(); + }); + + if (it != items.end()) + { + currentSize -= it->getSize(); + items.erase(it); + return true; + } + + return false; // Item type not found in stock +} + ItemType Stock::getItem(int id) const { for (const auto &item : items) diff --git a/src/model/stock.hpp b/src/model/stock.hpp index 9c28fb1..115b925 100644 --- a/src/model/stock.hpp +++ b/src/model/stock.hpp @@ -13,6 +13,7 @@ public: void addItem(const ItemType &item); void removeItem(int id); + bool removeItem(const ItemType &item); // Nouvelle méthode ItemType getItem(int id) const; // Getters diff --git a/src/view/qtView.cpp b/src/view/qtView.cpp index b0c984a..550164a 100644 --- a/src/view/qtView.cpp +++ b/src/view/qtView.cpp @@ -2,1077 +2,1309 @@ #include "virtualKeyboard.hpp" #include "../controller/stockController.hpp" #include "../controller/command.hpp" -#include "../model/stock.hpp" -#include "../model/itemType.hpp" -#include "../model/model.hpp" - +#include #include -#include -#include -#include -#include -#include +#include +#include QtView::QtView(QWidget* parent) - : QWidget(parent) - , AbstractView() - , m_controller(nullptr) - , m_mainLayout(nullptr) - , m_tabWidget(nullptr) - , m_outputDisplay(nullptr) - , m_exitButton(nullptr) - , m_refreshButton(nullptr) - , m_stockTab(nullptr) - , m_stockNameEdit(nullptr) - , m_stockCapacitySpinBox(nullptr) - , m_stockCommentEdit(nullptr) - , m_stockDeleteCombo(nullptr) - , m_createStockButton(nullptr) - , m_showStocksButton(nullptr) - , m_deleteStockButton(nullptr) - , m_itemTypeTab(nullptr) - , m_itemTypeNameEdit(nullptr) - , m_itemTypeCommentEdit(nullptr) - , m_itemTypeSizeSpinBox(nullptr) - , m_itemTypeDeleteCombo(nullptr) - , m_createItemTypeButton(nullptr) - , m_showItemTypesButton(nullptr) - , m_deleteItemTypeButton(nullptr) - , m_itemTab(nullptr) - , m_addItemStockCombo(nullptr) - , m_addItemTypeCombo(nullptr) - , m_addItemQuantitySpinBox(nullptr) - , m_moveFromStockCombo(nullptr) - , m_moveToStockCombo(nullptr) - , m_moveItemTypeCombo(nullptr) - , m_moveQuantitySpinBox(nullptr) - , m_addItemButton(nullptr) - , m_moveItemButton(nullptr) - , m_displayTab(nullptr) - , m_displayStockCombo(nullptr) - , m_showContentButton(nullptr) - , m_showCapacitiesButton(nullptr) - , m_virtualKeyboard(nullptr) + : QWidget(parent), m_controller(nullptr), m_virtualKeyboard(nullptr), m_stockSelectionLayout(nullptr) { - setupUI(); - setupVirtualKeyboard(); - setWindowTitle("Gestionnaire de Stock - Interface Moderne"); - showFullScreen(); } QtView::QtView(StockController* controller, QWidget* parent) - : QtView(parent) + : QWidget(parent), m_controller(controller), m_virtualKeyboard(nullptr), m_stockSelectionLayout(nullptr) { - m_controller = controller; - updateComboBoxes(); + setupUI(); } QtView::~QtView() { - // Cleanup virtual keyboard - if (m_virtualKeyboard) { - m_virtualKeyboard->hide(); - delete m_virtualKeyboard; - m_virtualKeyboard = nullptr; - } - // Qt handles cleanup automatically + delete m_virtualKeyboard; } -void QtView::setupUI() -{ - m_mainLayout = new QVBoxLayout(this); - m_mainLayout->setSpacing(25); - m_mainLayout->setContentsMargins(30, 30, 30, 30); - - // Header with title and control buttons - QHBoxLayout* headerLayout = new QHBoxLayout(); - - QLabel* titleLabel = new QLabel("GESTIONNAIRE DE STOCK"); - titleLabel->setObjectName("titleLabel"); - - QHBoxLayout* controlLayout = new QHBoxLayout(); - m_refreshButton = new QPushButton("⟳ Actualiser"); - m_refreshButton->setObjectName("refreshButton"); - m_exitButton = new QPushButton("✕ Quitter"); - m_exitButton->setObjectName("exitButton"); - - controlLayout->addWidget(m_refreshButton); - controlLayout->addWidget(m_exitButton); - - headerLayout->addWidget(titleLabel); - headerLayout->addStretch(); - headerLayout->addLayout(controlLayout); - - m_mainLayout->addLayout(headerLayout); - - // Main content splitter - QSplitter* mainSplitter = new QSplitter(Qt::Vertical); - - // Tab widget for different functionalities - m_tabWidget = new QTabWidget(); - m_tabWidget->setObjectName("mainTabWidget"); - - setupStockManagementTab(); - setupItemTypeManagementTab(); - setupItemManagementTab(); - setupDisplayTab(); - - mainSplitter->addWidget(m_tabWidget); - - // Output display area - QGroupBox* outputGroup = new QGroupBox("Résultats et Messages"); - outputGroup->setObjectName("outputGroup"); - QVBoxLayout* outputLayout = new QVBoxLayout(outputGroup); - - m_outputDisplay = new QTextEdit(); - m_outputDisplay->setObjectName("outputDisplay"); - m_outputDisplay->setReadOnly(true); - m_outputDisplay->setMaximumHeight(200); - m_outputDisplay->setPlainText("Bienvenue dans le gestionnaire de stock.\nUtilisez les onglets ci-dessus pour gérer vos stocks et articles."); - - outputLayout->addWidget(m_outputDisplay); - mainSplitter->addWidget(outputGroup); - - // Set splitter proportions - mainSplitter->setSizes({600, 200}); - m_mainLayout->addWidget(mainSplitter); - - // Connect signals - connect(m_refreshButton, &QPushButton::clicked, this, &QtView::onRefresh); - connect(m_exitButton, &QPushButton::clicked, this, &QtView::onExit); - - // Connect text field events for virtual keyboard - connectTextFieldEvents(); - - // Apply modern styling - applyModernStyling(); -} - -void QtView::setupStockManagementTab() -{ - m_stockTab = new QWidget(); - QVBoxLayout* stockLayout = new QVBoxLayout(m_stockTab); - stockLayout->setSpacing(20); - - // Create Stock Section - QGroupBox* createStockGroup = new QGroupBox("Créer un Nouveau Stock"); - createStockGroup->setObjectName("createGroup"); - QGridLayout* createLayout = new QGridLayout(createStockGroup); - createLayout->setSpacing(15); - - createLayout->addWidget(new QLabel("Nom du stock:"), 0, 0); - m_stockNameEdit = new QLineEdit(); - m_stockNameEdit->setPlaceholderText("Entrez le nom du stock..."); - createLayout->addWidget(m_stockNameEdit, 0, 1); - - createLayout->addWidget(new QLabel("Capacité:"), 1, 0); - m_stockCapacitySpinBox = new QSpinBox(); - m_stockCapacitySpinBox->setRange(1, 999999); - m_stockCapacitySpinBox->setValue(100); - createLayout->addWidget(m_stockCapacitySpinBox, 1, 1); - - createLayout->addWidget(new QLabel("Commentaire:"), 2, 0); - m_stockCommentEdit = new QLineEdit(); - m_stockCommentEdit->setPlaceholderText("Commentaire optionnel..."); - createLayout->addWidget(m_stockCommentEdit, 2, 1); - - m_createStockButton = new QPushButton("➕ Créer le Stock"); - m_createStockButton->setObjectName("createButton"); - createLayout->addWidget(m_createStockButton, 3, 0, 1, 2); - - stockLayout->addWidget(createStockGroup); - - // Manage Stocks Section - QGroupBox* manageStockGroup = new QGroupBox("Gestion des Stocks"); - manageStockGroup->setObjectName("manageGroup"); - QGridLayout* manageLayout = new QGridLayout(manageStockGroup); - manageLayout->setSpacing(15); - - m_showStocksButton = new QPushButton("📋 Afficher tous les Stocks"); - m_showStocksButton->setObjectName("showButton"); - manageLayout->addWidget(m_showStocksButton, 0, 0, 1, 2); - - manageLayout->addWidget(new QLabel("Supprimer le stock:"), 1, 0); - m_stockDeleteCombo = new QComboBox(); - m_stockDeleteCombo->setPlaceholderText("Sélectionner un stock..."); - manageLayout->addWidget(m_stockDeleteCombo, 1, 1); - - m_deleteStockButton = new QPushButton("🗑️ Supprimer le Stock"); - m_deleteStockButton->setObjectName("deleteButton"); - manageLayout->addWidget(m_deleteStockButton, 2, 0, 1, 2); - - stockLayout->addWidget(manageStockGroup); - stockLayout->addStretch(); - - // Connect signals - connect(m_createStockButton, &QPushButton::clicked, this, &QtView::onCreateStock); - connect(m_showStocksButton, &QPushButton::clicked, this, &QtView::onShowStocks); - connect(m_deleteStockButton, &QPushButton::clicked, this, &QtView::onDeleteStock); - - m_tabWidget->addTab(m_stockTab, "🏪 Stocks"); -} - -void QtView::setupItemTypeManagementTab() -{ - m_itemTypeTab = new QWidget(); - QVBoxLayout* itemTypeLayout = new QVBoxLayout(m_itemTypeTab); - itemTypeLayout->setSpacing(20); - - // Create ItemType Section - QGroupBox* createItemTypeGroup = new QGroupBox("Créer un Nouveau Type d'Article"); - createItemTypeGroup->setObjectName("createGroup"); - QGridLayout* createLayout = new QGridLayout(createItemTypeGroup); - createLayout->setSpacing(15); - - createLayout->addWidget(new QLabel("Nom du type:"), 0, 0); - m_itemTypeNameEdit = new QLineEdit(); - m_itemTypeNameEdit->setPlaceholderText("Entrez le nom du type..."); - createLayout->addWidget(m_itemTypeNameEdit, 0, 1); - - createLayout->addWidget(new QLabel("Taille:"), 1, 0); - m_itemTypeSizeSpinBox = new QSpinBox(); - m_itemTypeSizeSpinBox->setRange(1, 999); - m_itemTypeSizeSpinBox->setValue(1); - createLayout->addWidget(m_itemTypeSizeSpinBox, 1, 1); - - createLayout->addWidget(new QLabel("Commentaire:"), 2, 0); - m_itemTypeCommentEdit = new QLineEdit(); - m_itemTypeCommentEdit->setPlaceholderText("Description optionnelle..."); - createLayout->addWidget(m_itemTypeCommentEdit, 2, 1); - - m_createItemTypeButton = new QPushButton("➕ Créer le Type"); - m_createItemTypeButton->setObjectName("createButton"); - createLayout->addWidget(m_createItemTypeButton, 3, 0, 1, 2); - - itemTypeLayout->addWidget(createItemTypeGroup); - - // Manage ItemTypes Section - QGroupBox* manageItemTypeGroup = new QGroupBox("Gestion des Types d'Articles"); - manageItemTypeGroup->setObjectName("manageGroup"); - QGridLayout* manageLayout = new QGridLayout(manageItemTypeGroup); - manageLayout->setSpacing(15); - - m_showItemTypesButton = new QPushButton("📋 Afficher tous les Types"); - m_showItemTypesButton->setObjectName("showButton"); - manageLayout->addWidget(m_showItemTypesButton, 0, 0, 1, 2); - - manageLayout->addWidget(new QLabel("Supprimer le type:"), 1, 0); - m_itemTypeDeleteCombo = new QComboBox(); - m_itemTypeDeleteCombo->setPlaceholderText("Sélectionner un type..."); - manageLayout->addWidget(m_itemTypeDeleteCombo, 1, 1); - - m_deleteItemTypeButton = new QPushButton("🗑️ Supprimer le Type"); - m_deleteItemTypeButton->setObjectName("deleteButton"); - manageLayout->addWidget(m_deleteItemTypeButton, 2, 0, 1, 2); - - itemTypeLayout->addWidget(manageItemTypeGroup); - itemTypeLayout->addStretch(); - - // Connect signals - connect(m_createItemTypeButton, &QPushButton::clicked, this, &QtView::onCreateItemType); - connect(m_showItemTypesButton, &QPushButton::clicked, this, &QtView::onShowItemTypes); - connect(m_deleteItemTypeButton, &QPushButton::clicked, this, &QtView::onDeleteItemType); - - m_tabWidget->addTab(m_itemTypeTab, "📦 Types d'Articles"); -} - -void QtView::setupItemManagementTab() -{ - m_itemTab = new QWidget(); - QVBoxLayout* itemLayout = new QVBoxLayout(m_itemTab); - itemLayout->setSpacing(20); - - // Add Items Section - QGroupBox* addItemGroup = new QGroupBox("Ajouter des Articles"); - addItemGroup->setObjectName("createGroup"); - QGridLayout* addLayout = new QGridLayout(addItemGroup); - addLayout->setSpacing(15); - - addLayout->addWidget(new QLabel("Stock de destination:"), 0, 0); - m_addItemStockCombo = new QComboBox(); - m_addItemStockCombo->setPlaceholderText("Choisir un stock..."); - addLayout->addWidget(m_addItemStockCombo, 0, 1); - - addLayout->addWidget(new QLabel("Type d'article:"), 1, 0); - m_addItemTypeCombo = new QComboBox(); - m_addItemTypeCombo->setPlaceholderText("Choisir un type..."); - addLayout->addWidget(m_addItemTypeCombo, 1, 1); - - addLayout->addWidget(new QLabel("Quantité:"), 2, 0); - m_addItemQuantitySpinBox = new QSpinBox(); - m_addItemQuantitySpinBox->setRange(1, 99999); - m_addItemQuantitySpinBox->setValue(1); - addLayout->addWidget(m_addItemQuantitySpinBox, 2, 1); - - m_addItemButton = new QPushButton("➕ Ajouter les Articles"); - m_addItemButton->setObjectName("createButton"); - addLayout->addWidget(m_addItemButton, 3, 0, 1, 2); - - itemLayout->addWidget(addItemGroup); - - // Move Items Section - QGroupBox* moveItemGroup = new QGroupBox("Déplacer des Articles"); - moveItemGroup->setObjectName("manageGroup"); - QGridLayout* moveLayout = new QGridLayout(moveItemGroup); - moveLayout->setSpacing(15); - - moveLayout->addWidget(new QLabel("Stock source:"), 0, 0); - m_moveFromStockCombo = new QComboBox(); - m_moveFromStockCombo->setPlaceholderText("Stock d'origine..."); - moveLayout->addWidget(m_moveFromStockCombo, 0, 1); - - moveLayout->addWidget(new QLabel("Stock destination:"), 1, 0); - m_moveToStockCombo = new QComboBox(); - m_moveToStockCombo->setPlaceholderText("Stock de destination..."); - moveLayout->addWidget(m_moveToStockCombo, 1, 1); - - moveLayout->addWidget(new QLabel("Type d'article:"), 2, 0); - m_moveItemTypeCombo = new QComboBox(); - m_moveItemTypeCombo->setPlaceholderText("Type à déplacer..."); - moveLayout->addWidget(m_moveItemTypeCombo, 2, 1); - - moveLayout->addWidget(new QLabel("Quantité:"), 3, 0); - m_moveQuantitySpinBox = new QSpinBox(); - m_moveQuantitySpinBox->setRange(1, 99999); - m_moveQuantitySpinBox->setValue(1); - moveLayout->addWidget(m_moveQuantitySpinBox, 3, 1); - - m_moveItemButton = new QPushButton("🔄 Déplacer les Articles"); - m_moveItemButton->setObjectName("moveButton"); - moveLayout->addWidget(m_moveItemButton, 4, 0, 1, 2); - - itemLayout->addWidget(moveItemGroup); - itemLayout->addStretch(); - - // Connect signals - connect(m_addItemButton, &QPushButton::clicked, this, &QtView::onAddItem); - connect(m_moveItemButton, &QPushButton::clicked, this, &QtView::onMoveItem); - - m_tabWidget->addTab(m_itemTab, "📋 Gestion d'Articles"); -} - -void QtView::setupDisplayTab() -{ - m_displayTab = new QWidget(); - QVBoxLayout* displayLayout = new QVBoxLayout(m_displayTab); - displayLayout->setSpacing(20); - - // Stock Content Display Section - QGroupBox* contentGroup = new QGroupBox("Affichage du Contenu"); - contentGroup->setObjectName("displayGroup"); - QGridLayout* contentLayout = new QGridLayout(contentGroup); - contentLayout->setSpacing(15); - - contentLayout->addWidget(new QLabel("Stock à afficher:"), 0, 0); - m_displayStockCombo = new QComboBox(); - m_displayStockCombo->setPlaceholderText("Choisir un stock..."); - contentLayout->addWidget(m_displayStockCombo, 0, 1); - - m_showContentButton = new QPushButton("📊 Afficher le Contenu"); - m_showContentButton->setObjectName("showButton"); - contentLayout->addWidget(m_showContentButton, 1, 0, 1, 2); - - displayLayout->addWidget(contentGroup); - - // Capacity Display Section - QGroupBox* capacityGroup = new QGroupBox("Informations sur les Capacités"); - capacityGroup->setObjectName("displayGroup"); - QVBoxLayout* capacityLayout = new QVBoxLayout(capacityGroup); - - m_showCapacitiesButton = new QPushButton("📈 Afficher les Capacités"); - m_showCapacitiesButton->setObjectName("showButton"); - capacityLayout->addWidget(m_showCapacitiesButton); - - displayLayout->addWidget(capacityGroup); - displayLayout->addStretch(); - - // Connect signals - connect(m_showContentButton, &QPushButton::clicked, this, &QtView::onShowStockContent); - connect(m_showCapacitiesButton, &QPushButton::clicked, this, &QtView::onShowCapacities); - - m_tabWidget->addTab(m_displayTab, "📊 Affichage"); -} - -void QtView::applyModernStyling() -{ - setStyleSheet(R"( - QWidget { - font-family: 'Segoe UI', Arial, sans-serif; - font-size: 16px; - } - - #titleLabel { - font-size: 32px; - font-weight: bold; - color: #2c3e50; - padding: 15px; - } - - #mainTabWidget::pane { - border: 2px solid #bdc3c7; - background-color: #ffffff; - border-radius: 8px; - } - - #mainTabWidget::tab-bar { - alignment: center; - } - - QTabBar::tab { - background-color: #ecf0f1; - color: #2c3e50; - padding: 18px 30px; - margin-right: 3px; - font-size: 18px; - font-weight: bold; - border-top-left-radius: 8px; - border-top-right-radius: 8px; - min-width: 180px; - } - - QTabBar::tab:selected { - background-color: #3498db; - color: white; - } - - QTabBar::tab:hover:!selected { - background-color: #d5dbdb; - } - - QGroupBox { - font-size: 18px; - font-weight: bold; - color: #2c3e50; - border: 2px solid #bdc3c7; - border-radius: 8px; - margin-top: 20px; - padding-top: 20px; - } - - QGroupBox::title { - subcontrol-origin: margin; - left: 20px; - padding: 0 10px 0 10px; - background-color: white; - } - - #createGroup { - border-color: #27ae60; - } - - #manageGroup { - border-color: #f39c12; - } - - #displayGroup { - border-color: #9b59b6; - } - - #outputGroup { - border-color: #34495e; - } - - QLineEdit, QSpinBox, QComboBox { - padding: 12px 18px; - border: 2px solid #bdc3c7; - border-radius: 6px; - font-size: 16px; - min-height: 30px; - } - - QLineEdit:focus, QSpinBox:focus, QComboBox:focus { - border-color: #3498db; - outline: none; - } - - #createButton { - background-color: #27ae60; - color: white; - border: none; - padding: 18px 30px; - border-radius: 8px; - font-size: 18px; - font-weight: bold; - min-height: 50px; - } - - #createButton:hover { - background-color: #229954; - } - - #createButton:pressed { - background-color: #1e8449; - } - - #deleteButton { - background-color: #e74c3c; - color: white; - border: none; - padding: 18px 30px; - border-radius: 8px; - font-size: 18px; - font-weight: bold; - min-height: 50px; - } - - #deleteButton:hover { - background-color: #c0392b; - } - - #deleteButton:pressed { - background-color: #a93226; - } - - #showButton { - background-color: #3498db; - color: white; - border: none; - padding: 18px 30px; - border-radius: 8px; - font-size: 18px; - font-weight: bold; - min-height: 50px; - } - - #showButton:hover { - background-color: #2980b9; - } - - #showButton:pressed { - background-color: #2471a3; - } - - #moveButton { - background-color: #f39c12; - color: white; - border: none; - padding: 18px 30px; - border-radius: 8px; - font-size: 18px; - font-weight: bold; - min-height: 50px; - } - - #moveButton:hover { - background-color: #e67e22; - } - - #moveButton:pressed { - background-color: #d68910; - } - - #refreshButton { - background-color: #17a2b8; - color: white; - border: none; - padding: 15px 25px; - border-radius: 8px; - font-size: 16px; - font-weight: bold; - min-height: 45px; - } - - #refreshButton:hover { - background-color: #138496; - } - - #exitButton { - background-color: #6c757d; - color: white; - border: none; - padding: 15px 25px; - border-radius: 8px; - font-size: 16px; - font-weight: bold; - min-height: 45px; - } - - #exitButton:hover { - background-color: #5a6268; - } - - #outputDisplay { - font-family: 'Consolas', 'Monaco', monospace; - font-size: 14px; - background-color: #f8f9fa; - border: 2px solid #dee2e6; - border-radius: 6px; - padding: 15px; - line-height: 1.6; - } - - QLabel { - font-size: 12px; - color: #2c3e50; - font-weight: 500; - } - )"); -} - -// AbstractView implementation void QtView::start() { + // Initialize the virtual keyboard + m_virtualKeyboard = new VirtualKeyboard(this); + m_virtualKeyboard->hide(); + + // Set up the UI components + setupUI(); + + // Connect signals and slots for the refresh button + connect(m_refreshButton, &QPushButton::clicked, this, &QtView::onRefresh); + + // full-screen mode + setWindowState(windowState() | Qt::WindowFullScreen); + + // Show the window show(); - updateComboBoxes(); } void QtView::stop() { - hide(); + // Clean up the virtual keyboard + delete m_virtualKeyboard; + m_virtualKeyboard = nullptr; +} + +void QtView::setupUI() +{ + // Layout principal vertical + m_mainLayout = new QVBoxLayout(this); + m_mainLayout->setSpacing(0); + m_mainLayout->setContentsMargins(0, 0, 0, 0); + + // Widget conteneur principal horizontal (menu gauche + contenu droite) + m_menuDisplayWidget = new QWidget(this); + m_menuDisplayLayout = new QHBoxLayout(m_menuDisplayWidget); + m_menuDisplayLayout->setSpacing(0); + m_menuDisplayLayout->setContentsMargins(0, 0, 0, 0); + + // Configuration des layouts + setupLeftMenu(); + setupStackedWidget(); + setupMainMenuScreens(); + setupActionScreens(); + + // Zone de sortie en bas (plus petite) + m_outputDisplay = new QTextEdit(this); + m_outputDisplay->setReadOnly(true); + m_outputDisplay->setPlaceholderText("Messages et résultats..."); + m_outputDisplay->setMinimumHeight(80); + m_outputDisplay->setMaximumHeight(120); + + // Bouton refresh + m_refreshButton = new QPushButton("🔄 Actualiser", this); + m_refreshButton->setMinimumHeight(50); + + // Ajout des éléments au layout principal + m_mainLayout->addWidget(m_menuDisplayWidget, 1); // Prend la majorité de l'espace + m_mainLayout->addWidget(m_outputDisplay, 0); // Taille fixe + m_mainLayout->addWidget(m_refreshButton, 0); // Taille fixe + + // Configuration du clavier virtuel + setupVirtualKeyboard(); + + // Connecter les événements des champs de texte après avoir créé tous les écrans + connectTextFieldEvents(); + + // Application des styles tactiles + applyTouchFriendlyStyling(); + + // Connexions des signaux + connect(m_refreshButton, &QPushButton::clicked, this, &QtView::onRefresh); + + // Afficher le menu Stock par défaut + showMainMenu(0); + + setLayout(m_mainLayout); +} + +void QtView::onRefresh() +{ + if (!m_controller) { + showMessage("Aucun contrôleur disponible", true); + return; + } + + // Envoyer la commande Refresh au contrôleur + m_controller->sendCommand(Refresh); + + // Afficher un message de rafraîchissement + m_outputDisplay->append("🔄 Rafraîchissement en cours..."); + showMessage("Données actualisées"); } void QtView::setController(StockController* controller) { m_controller = controller; - updateComboBoxes(); } void QtView::displayStocks(const std::vector& stocks) { - QString output = "=== LISTE DES STOCKS ===\n\n"; + QString output = "=== LISTE DES STOCKS ===\n"; if (stocks.empty()) { - output += "Aucun stock trouvé.\n"; + output += "Aucun stock disponible.\n"; } else { for (const auto& stock : stocks) { - output += QString("📦 %1\n").arg(QString::fromStdString(stock.getName())); - output += QString(" Capacité: %1\n").arg(stock.getCapacity()); - output += QString(" Utilisé: %1\n").arg(stock.getCurrentSize()); - output += QString(" Libre: %1\n").arg(stock.getCapacity() - stock.getCurrentSize()); - output += QString(" Commentaire: %1\n").arg(QString::fromStdString(stock.getComment())); - output += " ────────────────────\n"; + output += QString("📦 %1 (Capacité: %2)\n") + .arg(QString::fromStdString(stock.getName())) + .arg(stock.getCapacity()); } } - m_outputDisplay->setPlainText(output); - m_tabWidget->setCurrentIndex(3); // Switch to display tab - updateComboBoxes(); + m_outputDisplay->clear(); + m_outputDisplay->append(output); } void QtView::displayStockCreate(const Stock& stock) { - QString message = QString("✅ Stock créé avec succès!\n\n" - "📦 Nom: %1\n" - "📏 Capacité: %2\n" - "💬 Commentaire: %3") - .arg(QString::fromStdString(stock.getName())) - .arg(stock.getCapacity()) - .arg(QString::fromStdString(stock.getComment())); + QString message = QString("✅ Stock '%1' créé avec succès ! (Capacité: %2)") + .arg(QString::fromStdString(stock.getName())) + .arg(stock.getCapacity()); - showSuccessMessage(message); - clearInputFields(); - updateComboBoxes(); + m_outputDisplay->append(message); + showMessage("Stock créé avec succès !"); } void QtView::displayItemTypes(const std::vector& itemTypes) { - QString output = "=== LISTE DES TYPES D'ARTICLES ===\n\n"; + QString output = "=== LISTE DES TYPES D'ARTICLES ===\n"; if (itemTypes.empty()) { - output += "Aucun type d'article trouvé.\n"; + output += "Aucun type d'article disponible.\n"; } else { for (const auto& itemType : itemTypes) { - output += QString("📋 %1 (ID: %2)\n").arg(QString::fromStdString(itemType.getName())).arg(itemType.getId()); - output += QString(" Taille: %1\n").arg(itemType.getSize()); - output += QString(" Commentaire: %1\n").arg(QString::fromStdString(itemType.getComment())); - output += " ────────────────────\n"; + output += QString("🏷️ %1 (ID: %2) - %3 (Taille: %4)\n") + .arg(QString::fromStdString(itemType.getName())) + .arg(itemType.getId()) + .arg(QString::fromStdString(itemType.getComment())) + .arg(itemType.getSize()); } } - m_outputDisplay->setPlainText(output); - m_tabWidget->setCurrentIndex(3); // Switch to display tab - updateComboBoxes(); + m_outputDisplay->clear(); + m_outputDisplay->append(output); } void QtView::displayItemTypeCreate(const ItemType& itemType) { - QString message = QString("✅ Type d'article créé avec succès!\n\n" - "📋 Nom: %1\n" - "🔢 ID: %2\n" - "📏 Taille: %3\n" - "💬 Commentaire: %4") - .arg(QString::fromStdString(itemType.getName())) - .arg(itemType.getId()) - .arg(itemType.getSize()) - .arg(QString::fromStdString(itemType.getComment())); + QString message = QString("✅ Type d'article '%1' créé avec succès !") + .arg(QString::fromStdString(itemType.getName())); - showSuccessMessage(message); - clearInputFields(); - updateComboBoxes(); + m_outputDisplay->append(message); + showMessage("Type d'article créé avec succès !"); } void QtView::displayAddItemResult(const std::string& stockName, const std::string& itemTypeName, int quantity, bool success) { QString message; if (success) { - message = QString("✅ Articles ajoutés avec succès!\n\n" - "📦 Stock: %1\n" - "📋 Type: %2\n" - "🔢 Quantité: %3") - .arg(QString::fromStdString(stockName)) - .arg(QString::fromStdString(itemTypeName)) - .arg(quantity); - showSuccessMessage(message); + message = QString("✅ %1 article(s) de type '%2' ajouté(s) au stock '%3' avec succès !") + .arg(quantity) + .arg(QString::fromStdString(itemTypeName)) + .arg(QString::fromStdString(stockName)); + showMessage("Articles ajoutés avec succès !"); } else { - message = QString("❌ Échec de l'ajout d'articles!\n\n" - "📦 Stock: %1\n" - "📋 Type: %2\n" - "🔢 Quantité: %3\n\n" - "Vérifiez que le stock a suffisamment de capacité.") - .arg(QString::fromStdString(stockName)) - .arg(QString::fromStdString(itemTypeName)) - .arg(quantity); - showErrorMessage(message); + message = QString("❌ Échec lors de l'ajout de %1 article(s) de type '%2' au stock '%3'") + .arg(quantity) + .arg(QString::fromStdString(itemTypeName)) + .arg(QString::fromStdString(stockName)); + showMessage("Erreur lors de l'ajout des articles", true); } + + m_outputDisplay->append(message); } void QtView::displayError(const std::string& message) { - showErrorMessage(QString("❌ ERREUR: %1").arg(QString::fromStdString(message))); + QString errorMsg = QString("❌ ERREUR: %1").arg(QString::fromStdString(message)); + m_outputDisplay->append(errorMsg); + showMessage(QString::fromStdString(message), true); } void QtView::displayMessage(const std::string& message) { - m_outputDisplay->setPlainText(QString::fromStdString(message)); - m_tabWidget->setCurrentIndex(3); // Switch to display tab -} - -// Private helper methods -void QtView::updateComboBoxes() -{ - if (!m_controller) return; - - // Get current model state - const auto& stocks = m_controller->getModel()->getStocks(); - const auto& itemTypes = m_controller->getModel()->getItemTypes(); - - // Update stock combo boxes - QStringList stockNames; - for (const auto& stock : stocks) { - stockNames << QString::fromStdString(stock.getName()); - } - - m_stockDeleteCombo->clear(); - m_stockDeleteCombo->addItems(stockNames); - - m_addItemStockCombo->clear(); - m_addItemStockCombo->addItems(stockNames); - - m_moveFromStockCombo->clear(); - m_moveFromStockCombo->addItems(stockNames); - - m_moveToStockCombo->clear(); - m_moveToStockCombo->addItems(stockNames); - - m_displayStockCombo->clear(); - m_displayStockCombo->addItems(stockNames); - - // Update item type combo boxes - QStringList itemTypeNames; - for (const auto& itemType : itemTypes) { - itemTypeNames << QString::fromStdString(itemType.getName()); - } - - m_itemTypeDeleteCombo->clear(); - m_itemTypeDeleteCombo->addItems(itemTypeNames); - - m_addItemTypeCombo->clear(); - m_addItemTypeCombo->addItems(itemTypeNames); - - m_moveItemTypeCombo->clear(); - m_moveItemTypeCombo->addItems(itemTypeNames); -} - -void QtView::clearInputFields() -{ - // Clear stock input fields - if (m_stockNameEdit) m_stockNameEdit->clear(); - if (m_stockCapacitySpinBox) m_stockCapacitySpinBox->setValue(100); - if (m_stockCommentEdit) m_stockCommentEdit->clear(); - - // Clear item type input fields - if (m_itemTypeNameEdit) m_itemTypeNameEdit->clear(); - if (m_itemTypeSizeSpinBox) m_itemTypeSizeSpinBox->setValue(1); - if (m_itemTypeCommentEdit) m_itemTypeCommentEdit->clear(); - - // Clear item input fields - if (m_addItemQuantitySpinBox) m_addItemQuantitySpinBox->setValue(1); - if (m_moveQuantitySpinBox) m_moveQuantitySpinBox->setValue(1); -} - -void QtView::showSuccessMessage(const QString& message) -{ - m_outputDisplay->setPlainText(message); - m_tabWidget->setCurrentIndex(3); // Switch to display tab -} - -void QtView::showErrorMessage(const QString& message) -{ - m_outputDisplay->setPlainText(message); - m_tabWidget->setCurrentIndex(3); // Switch to display tab -} - -// Slot implementations -void QtView::onCreateStock() -{ - if (!m_controller) return; - - QString name = m_stockNameEdit->text().trimmed(); - if (name.isEmpty()) { - showErrorMessage("❌ Veuillez entrer un nom de stock."); - return; - } - - int capacity = m_stockCapacitySpinBox->value(); - QString comment = m_stockCommentEdit->text(); - - m_controller->sendCommand(Command::CreateStock, {name.toStdString(), - std::to_string(capacity), - comment.toStdString()}); -} - -void QtView::onShowStocks() -{ - if (!m_controller) return; - m_controller->sendCommand(Command::ShowStocks); -} - -void QtView::onDeleteStock() -{ - if (!m_controller) return; - - QString stockName = m_stockDeleteCombo->currentText(); - if (stockName.isEmpty()) { - showErrorMessage("❌ Veuillez sélectionner un stock à supprimer."); - return; - } - - // Note: DeleteStock command is not defined in the enum, - // you may need to add it or handle deletion differently - showErrorMessage("❌ Fonctionnalité de suppression pas encore implémentée."); -} - -void QtView::onCreateItemType() -{ - if (!m_controller) return; - - QString name = m_itemTypeNameEdit->text().trimmed(); - if (name.isEmpty()) { - showErrorMessage("❌ Veuillez entrer un nom de type d'article."); - return; - } - - int size = m_itemTypeSizeSpinBox->value(); - QString comment = m_itemTypeCommentEdit->text(); - - m_controller->sendCommand(Command::CreateItemType, {name.toStdString(), - comment.toStdString(), - std::to_string(size)}); -} - -void QtView::onShowItemTypes() -{ - if (!m_controller) return; - m_controller->sendCommand(Command::ShowItemTypes); -} - -void QtView::onDeleteItemType() -{ - if (!m_controller) return; - - QString itemTypeName = m_itemTypeDeleteCombo->currentText(); - if (itemTypeName.isEmpty()) { - showErrorMessage("❌ Veuillez sélectionner un type d'article à supprimer."); - return; - } - - // Note: DeleteItemType command is not defined in the enum, - // you may need to add it or handle deletion differently - showErrorMessage("❌ Fonctionnalité de suppression pas encore implémentée."); -} - -void QtView::onAddItem() -{ - if (!m_controller) return; - - QString stockName = m_addItemStockCombo->currentText(); - QString itemTypeName = m_addItemTypeCombo->currentText(); - int quantity = m_addItemQuantitySpinBox->value(); - - if (stockName.isEmpty() || itemTypeName.isEmpty()) { - showErrorMessage("❌ Veuillez sélectionner un stock et un type d'article."); - return; - } - - m_controller->sendCommand(Command::AddItemToStock, {stockName.toStdString(), - itemTypeName.toStdString(), - std::to_string(quantity)}); -} - -void QtView::onMoveItem() -{ - if (!m_controller) return; - - QString fromStock = m_moveFromStockCombo->currentText(); - QString toStock = m_moveToStockCombo->currentText(); - QString itemTypeName = m_moveItemTypeCombo->currentText(); - int quantity = m_moveQuantitySpinBox->value(); - - if (fromStock.isEmpty() || toStock.isEmpty() || itemTypeName.isEmpty()) { - showErrorMessage("❌ Veuillez sélectionner les stocks source/destination et le type d'article."); - return; - } - - if (fromStock == toStock) { - showErrorMessage("❌ Le stock source et destination doivent être différents."); - return; - } - - // Note: MoveItem command is not defined in the enum, - // you may need to add it or handle moving differently - showErrorMessage("❌ Fonctionnalité de déplacement pas encore implémentée."); -} - -void QtView::onShowStockContent() -{ - if (!m_controller) return; - - QString stockName = m_displayStockCombo->currentText(); - if (stockName.isEmpty()) { - showErrorMessage("❌ Veuillez sélectionner un stock à afficher."); - return; - } - - // Note: ShowStockContent command is not defined in the enum, - // you may need to add it or handle display differently - showErrorMessage("❌ Fonctionnalité d'affichage de contenu pas encore implémentée."); -} - -void QtView::onShowCapacities() -{ - if (!m_controller) return; - - // Show capacity information for all stocks - const auto& stocks = m_controller->getModel()->getStocks(); - QString output = "=== CAPACITÉS DES STOCKS ===\n\n"; - - if (stocks.empty()) { - output += "Aucun stock trouvé.\n"; - } else { - for (const auto& stock : stocks) { - int used = stock.getCurrentSize(); - int capacity = stock.getCapacity(); - int free = capacity - used; - double percentage = (capacity > 0) ? (double(used) / capacity * 100.0) : 0.0; - - output += QString("📦 %1\n").arg(QString::fromStdString(stock.getName())); - output += QString(" Capacité totale: %1\n").arg(capacity); - output += QString(" Utilisé: %1 (%.1f%)\n").arg(used).arg(percentage); - output += QString(" Libre: %1\n").arg(free); - - // Visual progress bar - QString progressBar = " ["; - int barLength = 20; - int filledLength = static_cast(percentage / 100.0 * barLength); - for (int i = 0; i < barLength; ++i) { - if (i < filledLength) { - progressBar += "█"; - } else { - progressBar += "░"; - } - } - progressBar += "]\n"; - output += progressBar; - output += " ────────────────────\n"; - } - } - - m_outputDisplay->setPlainText(output); - m_tabWidget->setCurrentIndex(3); // Switch to display tab -} - -void QtView::onRefresh() -{ - updateComboBoxes(); - showSuccessMessage("✅ Interface actualisée."); -} - -void QtView::onExit() -{ - if (m_controller) { - m_controller->sendCommand(Command::Stop); - } - QApplication::quit(); -} - -void QtView::setupVirtualKeyboard() -{ - m_virtualKeyboard = new VirtualKeyboard(this); // Passer 'this' comme parent - m_virtualKeyboard->hide(); // Le cacher initialement -} - -void QtView::connectTextFieldEvents() -{ - // Connect all line edit widgets to show virtual keyboard on focus - if (m_stockNameEdit) { - connect(m_stockNameEdit, &QLineEdit::editingFinished, [this]() { - if (m_virtualKeyboard) m_virtualKeyboard->hideKeyboard(); - }); - - // Install event filter to detect mouse clicks - m_stockNameEdit->installEventFilter(this); - } - - if (m_stockCommentEdit) { - connect(m_stockCommentEdit, &QLineEdit::editingFinished, [this]() { - if (m_virtualKeyboard) m_virtualKeyboard->hideKeyboard(); - }); - m_stockCommentEdit->installEventFilter(this); - } - - if (m_itemTypeNameEdit) { - connect(m_itemTypeNameEdit, &QLineEdit::editingFinished, [this]() { - if (m_virtualKeyboard) m_virtualKeyboard->hideKeyboard(); - }); - m_itemTypeNameEdit->installEventFilter(this); - } - - if (m_itemTypeCommentEdit) { - connect(m_itemTypeCommentEdit, &QLineEdit::editingFinished, [this]() { - if (m_virtualKeyboard) m_virtualKeyboard->hideKeyboard(); - }); - m_itemTypeCommentEdit->installEventFilter(this); - } + QString infoMsg = QString("ℹ️ %1").arg(QString::fromStdString(message)); + m_outputDisplay->append(infoMsg); } bool QtView::eventFilter(QObject* obj, QEvent* event) { + // Détecter les clics sur les champs de texte pour afficher le clavier virtuel if (event->type() == QEvent::MouseButtonPress) { QLineEdit* lineEdit = qobject_cast(obj); QTextEdit* textEdit = qobject_cast(obj); if (lineEdit || textEdit) { - onTextFieldClicked(); - if (m_virtualKeyboard) { - m_virtualKeyboard->showForWidget(qobject_cast(obj)); + // Un champ de texte a été cliqué, afficher le clavier virtuel + QWidget* targetWidget = qobject_cast(obj); + if (targetWidget && m_virtualKeyboard) { + m_virtualKeyboard->showForWidget(targetWidget); } } } + // Laisser l'événement se propager normalement return QWidget::eventFilter(obj, event); } -void QtView::onTextFieldFocused() +void QtView::setupLeftMenu() { - QWidget* sender = qobject_cast(this->sender()); - if (sender && m_virtualKeyboard) { - m_virtualKeyboard->showForWidget(sender); + // Widget conteneur pour le menu gauche + m_leftMenuWidget = new QWidget(); + m_leftMenuWidget->setFixedWidth(200); // Largeur fixe pour le menu + m_leftMenuWidget->setStyleSheet("background-color: #2c3e50; border-right: 2px solid #34495e;"); + + // Scroll area pour le menu gauche + m_leftMenuScrollArea = new QScrollArea(); + m_leftMenuScrollArea->setWidget(m_leftMenuWidget); + m_leftMenuScrollArea->setWidgetResizable(true); + m_leftMenuScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_leftMenuScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + + // Layout vertical pour les boutons du menu + m_leftMenuLayout = new QVBoxLayout(m_leftMenuWidget); + m_leftMenuLayout->setSpacing(5); + m_leftMenuLayout->setContentsMargins(10, 10, 10, 10); + + // Bouton retour (masqué par défaut) + m_backButton = new QPushButton("⬅️ Retour", m_leftMenuWidget); + m_backButton->setMinimumHeight(50); + m_backButton->setStyleSheet( + "QPushButton {" + " background-color: #e67e22;" + " color: white;" + " border: none;" + " border-radius: 8px;" + " font-size: 14px;" + " font-weight: bold;" + " text-align: left;" + " padding-left: 15px;" + "}" + "QPushButton:pressed {" + " background-color: #d35400;" + "}" + ); + m_backButton->hide(); // Masqué par défaut + connect(m_backButton, &QPushButton::clicked, this, &QtView::goBack); + + // Création des boutons de menu + m_stockMenuButton = new QPushButton("📦 Stocks", m_leftMenuWidget); + m_itemTypeMenuButton = new QPushButton("🏷️ Types d'articles", m_leftMenuWidget); + m_itemMenuButton = new QPushButton("📋 Articles", m_leftMenuWidget); + m_displayMenuButton = new QPushButton("📊 Affichage", m_leftMenuWidget); + + // Configuration des boutons pour le tactile + QList menuButtons = {m_stockMenuButton, m_itemTypeMenuButton, m_itemMenuButton, m_displayMenuButton}; + for (QPushButton* button : menuButtons) { + button->setMinimumHeight(60); + button->setMaximumHeight(80); + button->setCheckable(true); + button->setStyleSheet( + "QPushButton {" + " background-color: #34495e;" + " color: white;" + " border: none;" + " border-radius: 8px;" + " font-size: 14px;" + " font-weight: bold;" + " text-align: left;" + " padding-left: 15px;" + "}" + "QPushButton:checked {" + " background-color: #3498db;" + "}" + "QPushButton:pressed {" + " background-color: #2980b9;" + "}" + "QPushButton:hover {" + " background-color: #4a6741;" + "}" + ); + } + + // Ajout des boutons au layout + m_leftMenuLayout->addWidget(m_backButton); + m_leftMenuLayout->addWidget(m_stockMenuButton); + m_leftMenuLayout->addWidget(m_itemTypeMenuButton); + m_leftMenuLayout->addWidget(m_itemMenuButton); + m_leftMenuLayout->addWidget(m_displayMenuButton); + m_leftMenuLayout->addStretch(); // Pousse les boutons vers le haut + + // Connexions des signaux pour navigation vers les menus principaux + connect(m_stockMenuButton, &QPushButton::clicked, [this]() { showMainMenu(0); }); + connect(m_itemTypeMenuButton, &QPushButton::clicked, [this]() { showMainMenu(1); }); + connect(m_itemMenuButton, &QPushButton::clicked, [this]() { showMainMenu(2); }); + connect(m_displayMenuButton, &QPushButton::clicked, [this]() { showMainMenu(3); }); + + // Ajout au layout principal + m_menuDisplayLayout->addWidget(m_leftMenuScrollArea, 0); +} + +void QtView::setupVirtualKeyboard() +{ + // Le clavier virtuel sera initialisé dans start() + // et affiché/masqué selon les besoins +} + +void QtView::connectTextFieldEvents() +{ + // Connecter tous les QLineEdit existants au clavier virtuel + QList lineEdits = findChildren(); + for (QLineEdit* lineEdit : lineEdits) { + // Installer un filtre d'événements pour détecter les clics (pas les changements de texte) + lineEdit->installEventFilter(this); + } + + // Connecter aussi les QTextEdit s'il y en a + QList textEdits = findChildren(); + for (QTextEdit* textEdit : textEdits) { + textEdit->installEventFilter(this); } } -void QtView::onTextFieldClicked() +void QtView::updateMenuButtonStyles() { - // This method can be used for additional logic when text fields are clicked - // Currently, the main logic is handled in eventFilter + // Réinitialiser tous les boutons + QList buttons = {m_stockMenuButton, m_itemTypeMenuButton, m_itemMenuButton, m_displayMenuButton}; + for (QPushButton* btn : buttons) { + btn->setChecked(false); + } } +// Slots pour le clavier virtuel +void QtView::onTextFieldFocused() +{ + // Cette méthode peut être appelée manuellement si nécessaire + // Trouver le widget qui a le focus et afficher le clavier pour lui + QWidget* focusedWidget = QApplication::focusWidget(); + if (focusedWidget && m_virtualKeyboard) { + if (qobject_cast(focusedWidget) || qobject_cast(focusedWidget)) { + m_virtualKeyboard->showForWidget(focusedWidget); + } + } +} + +void QtView::showVirtualKeyboard() +{ + if (m_virtualKeyboard) { + m_virtualKeyboard->show(); + m_virtualKeyboard->raise(); + } +} + +void QtView::hideVirtualKeyboard() +{ + if (m_virtualKeyboard) { + m_virtualKeyboard->hide(); + } +} + +// ============================================================================= +// NOUVELLE ARCHITECTURE AVEC ÉCRANS DÉDIÉS +// ============================================================================= + +void QtView::setupStackedWidget() +{ + // Créer le widget empilé pour la zone de contenu + m_stackedWidget = new QStackedWidget(); + m_stackedWidget->setStyleSheet("background-color: white;"); + + // Ajout au layout principal + m_menuDisplayLayout->addWidget(m_stackedWidget, 1); +} + +void QtView::setupMainMenuScreens() +{ + // Créer les écrans de menu principal pour chaque catégorie + + // Menu principal des stocks + QStringList stockActions = {"➕ Créer un nouveau stock", "👁️ Afficher tous les stocks", "🗑️ Supprimer un stock"}; + std::vector> stockCallbacks = { + [this]() { showActionScreen(m_createStockScreen); }, + [this]() { showActionScreen(m_showStocksScreen); }, + [this]() { + // Créer l'écran de suppression si nécessaire + if (!m_deleteStockScreen) { + m_deleteStockScreen = createStockSelectionScreen(); + m_stackedWidget->addWidget(m_deleteStockScreen); + } + showActionScreen(m_deleteStockScreen); + } + }; + m_stockMainScreen = createTitleAndButtonScreen("Gestion des Stocks", stockActions, stockCallbacks); + + // Menu principal des types d'articles + QStringList itemTypeActions = {"➕ Créer un nouveau type", "👁️ Afficher tous les types", "🗑️ Supprimer un type"}; + std::vector> itemTypeCallbacks = { + [this]() { showActionScreen(m_createItemTypeScreen); }, + [this]() { showActionScreen(m_showItemTypesScreen); }, + [this]() { showActionScreen(m_deleteItemTypeScreen); } + }; + m_itemTypeMainScreen = createTitleAndButtonScreen("Gestion des Types d'Articles", itemTypeActions, itemTypeCallbacks); + + // Menu principal des articles + QStringList itemActions = {"➕ Ajouter un article", "🔄 Déplacer un article", "➖ Retirer un article"}; + std::vector> itemCallbacks = { + [this]() { showActionScreen(m_addItemScreen); }, + [this]() { showActionScreen(m_moveItemScreen); }, + [this]() { showActionScreen(m_removeItemScreen); } + }; + m_itemMainScreen = createTitleAndButtonScreen("Gestion des Articles", itemActions, itemCallbacks); + + // Menu principal de l'affichage + QStringList displayActions = {"📋 Contenu des stocks", "📊 Capacités des stocks", "📈 Statistiques"}; + std::vector> displayCallbacks = { + [this]() { showActionScreen(m_showStockContentScreen); }, + [this]() { showActionScreen(m_showCapacitiesScreen); }, + [this]() { showActionScreen(m_showStatisticsScreen); } + }; + m_displayMainScreen = createTitleAndButtonScreen("Affichage et Rapports", displayActions, displayCallbacks); + + // Ajouter tous les écrans au widget empilé + m_stackedWidget->addWidget(m_stockMainScreen); // Index 0 + m_stackedWidget->addWidget(m_itemTypeMainScreen); // Index 1 + m_stackedWidget->addWidget(m_itemMainScreen); // Index 2 + m_stackedWidget->addWidget(m_displayMainScreen); // Index 3 +} + +void QtView::setupActionScreens() +{ + setupStockActionScreens(); + setupItemTypeActionScreens(); + setupItemActionScreens(); + setupDisplayActionScreens(); +} + +void QtView::setupStockActionScreens() +{ + // Écran de création de stock + QStringList createStockLabels = {"Nom du stock:", "Capacité:", "Commentaire (optionnel):"}; + QStringList createStockPlaceholders = {"Entrez le nom", "100", "Description du stock"}; + m_createStockScreen = createFormScreen("Créer un Nouveau Stock", createStockLabels, createStockPlaceholders); + m_stackedWidget->addWidget(m_createStockScreen); + + // Écran d'affichage des stocks + m_showStocksScreen = createTitleAndButtonScreen("Afficher les Stocks", {"🔄 Actualiser la liste"}, {[this]() { onShowStocks(); }}); + m_stackedWidget->addWidget(m_showStocksScreen); + + // Écran de suppression de stock - Sera créé à la demande + m_deleteStockScreen = nullptr; +} + +void QtView::setupItemTypeActionScreens() +{ + // Écran de création de type d'article + QStringList createTypeLabels = {"Nom du type:", "ID:", "Commentaire:", "Taille:"}; + QStringList createTypePlaceholders = {"Type d'article", "1", "Description", "1"}; + m_createItemTypeScreen = createFormScreen("Créer un Type d'Article", createTypeLabels, createTypePlaceholders); + m_stackedWidget->addWidget(m_createItemTypeScreen); + + // Écran d'affichage des types + m_showItemTypesScreen = createTitleAndButtonScreen("Afficher les Types", {"🔄 Actualiser la liste"}, {[this]() { onShowItemTypes(); }}); + m_stackedWidget->addWidget(m_showItemTypesScreen); + + // Écran de suppression de type + QStringList deleteTypeLabels = {"Type à supprimer:"}; + m_deleteItemTypeScreen = createFormScreen("Supprimer un Type", deleteTypeLabels); + m_stackedWidget->addWidget(m_deleteItemTypeScreen); +} + +void QtView::setupItemActionScreens() +{ + // Écran d'ajout d'article + QStringList addItemLabels = {"Stock:", "Type d'article:", "Quantité:"}; + QStringList addItemPlaceholders = {"Sélectionner un stock", "Sélectionner un type", "1"}; + m_addItemScreen = createFormScreen("Ajouter un Article", addItemLabels, addItemPlaceholders); + m_stackedWidget->addWidget(m_addItemScreen); + + // Écran de déplacement d'article + QStringList moveItemLabels = {"Stock source:", "Stock destination:", "Type d'article:", "Quantité:"}; + QStringList moveItemPlaceholders = {"Stock source", "Stock destination", "Type d'article", "1"}; + m_moveItemScreen = createFormScreen("Déplacer un Article", moveItemLabels, moveItemPlaceholders); + m_stackedWidget->addWidget(m_moveItemScreen); + + // Écran de retrait d'article + QStringList removeItemLabels = {"Stock:", "Type d'article:", "Quantité:"}; + QStringList removeItemPlaceholders = {"Sélectionner un stock", "Type d'article", "1"}; + m_removeItemScreen = createFormScreen("Retirer un Article", removeItemLabels, removeItemPlaceholders); + m_stackedWidget->addWidget(m_removeItemScreen); +} + +void QtView::setupDisplayActionScreens() +{ + // Écran de contenu des stocks + QStringList stockContentLabels = {"Stock (optionnel):"}; + QStringList stockContentPlaceholders = {"Laisser vide pour tous"}; + m_showStockContentScreen = createFormScreen("Contenu des Stocks", stockContentLabels, stockContentPlaceholders); + m_stackedWidget->addWidget(m_showStockContentScreen); + + // Écran des capacités + m_showCapacitiesScreen = createTitleAndButtonScreen("Capacités des Stocks", {"📊 Afficher les capacités"}, {[this]() { onShowCapacities(); }}); + m_stackedWidget->addWidget(m_showCapacitiesScreen); + + // Écran des statistiques + m_showStatisticsScreen = createTitleAndButtonScreen("Statistiques", {"📈 Afficher les statistiques"}, {[this]() { onShowStatistics(); }}); + m_stackedWidget->addWidget(m_showStatisticsScreen); +} + +QWidget* QtView::createTitleAndButtonScreen(const QString& title, const QStringList& buttonTexts, const std::vector>& callbacks) +{ + QWidget* screen = new QWidget(); + QVBoxLayout* layout = new QVBoxLayout(screen); + layout->setSpacing(20); + layout->setContentsMargins(30, 30, 30, 30); + + // Titre + QLabel* titleLabel = new QLabel(title); + titleLabel->setStyleSheet("font-size: 28px; font-weight: bold; color: #2c3e50; margin-bottom: 30px;"); + titleLabel->setAlignment(Qt::AlignCenter); + layout->addWidget(titleLabel); + + // Boutons d'action + for (int i = 0; i < buttonTexts.size() && i < callbacks.size(); ++i) { + QPushButton* button = new QPushButton(buttonTexts[i]); + button->setMinimumHeight(80); + button->setStyleSheet( + "QPushButton {" + " background-color: #3498db;" + " color: white;" + " border: none;" + " border-radius: 12px;" + " font-size: 18px;" + " font-weight: bold;" + " padding: 15px;" + "}" + "QPushButton:pressed {" + " background-color: #2980b9;" + "}" + "QPushButton:hover {" + " background-color: #5dade2;" + "}" + ); + + // Connecter le callback + connect(button, &QPushButton::clicked, callbacks[i]); + + layout->addWidget(button); + } + + layout->addStretch(); + return screen; +} + +QWidget* QtView::createFormScreen(const QString& title, const QStringList& labels, const QStringList& placeholders) +{ + QWidget* screen = new QWidget(); + QVBoxLayout* layout = new QVBoxLayout(screen); + layout->setSpacing(20); + layout->setContentsMargins(30, 30, 30, 30); + + // Titre + QLabel* titleLabel = new QLabel(title); + titleLabel->setStyleSheet("font-size: 28px; font-weight: bold; color: #2c3e50; margin-bottom: 30px;"); + titleLabel->setAlignment(Qt::AlignCenter); + layout->addWidget(titleLabel); + + // Formulaire + QWidget* formWidget = new QWidget(); + QVBoxLayout* formLayout = new QVBoxLayout(formWidget); + formLayout->setSpacing(15); + + for (int i = 0; i < labels.size(); ++i) { + // Label + QLabel* label = new QLabel(labels[i]); + label->setStyleSheet("font-size: 16px; font-weight: bold; color: #34495e;"); + formLayout->addWidget(label); + + // Champ de saisie + QLineEdit* field = new QLineEdit(); + field->setMinimumHeight(50); + field->setStyleSheet( + "QLineEdit {" + " border: 2px solid #bdc3c7;" + " border-radius: 8px;" + " padding: 10px;" + " font-size: 16px;" + " background-color: white;" + "}" + "QLineEdit:focus {" + " border-color: #3498db;" + "}" + ); + + if (i < placeholders.size()) { + field->setPlaceholderText(placeholders[i]); + } + + // Objectname pour pouvoir retrouver les champs + field->setObjectName(QString("field_%1").arg(i)); + + // Connecter le champ au clavier virtuel + field->installEventFilter(this); + + formLayout->addWidget(field); + } + + layout->addWidget(formWidget); + + // Boutons d'action + QWidget* buttonWidget = new QWidget(); + QHBoxLayout* buttonLayout = new QHBoxLayout(buttonWidget); + + QPushButton* executeButton = new QPushButton("✓ Exécuter"); + QPushButton* cancelButton = new QPushButton("✕ Annuler"); + + QString buttonStyle = + "QPushButton {" + " border: none;" + " border-radius: 8px;" + " font-size: 16px;" + " font-weight: bold;" + " padding: 12px 20px;" + " min-height: 40px;" + "}" + "QPushButton:pressed {" + " transform: translateY(1px);" + "}"; + + executeButton->setStyleSheet(buttonStyle + + "QPushButton { background-color: #27ae60; color: white; }" + "QPushButton:hover { background-color: #229954; }"); + + cancelButton->setStyleSheet(buttonStyle + + "QPushButton { background-color: #e74c3c; color: white; }" + "QPushButton:hover { background-color: #c0392b; }"); + + // Connecter les boutons + connect(executeButton, &QPushButton::clicked, [this, screen, title]() { + executeFormAction(screen, title); + }); + connect(cancelButton, &QPushButton::clicked, this, &QtView::goBack); + + buttonLayout->addWidget(executeButton); + buttonLayout->addWidget(cancelButton); + layout->addWidget(buttonWidget); + + layout->addStretch(); + return screen; +} + +QWidget* QtView::createStockSelectionScreen() +{ + QWidget* screen = new QWidget(); + QVBoxLayout* layout = new QVBoxLayout(screen); + layout->setSpacing(20); + layout->setContentsMargins(30, 30, 30, 30); + + // Titre + QLabel* titleLabel = new QLabel("Sélectionner un Stock à Supprimer"); + titleLabel->setStyleSheet("font-size: 28px; font-weight: bold; color: #2c3e50; margin-bottom: 30px;"); + titleLabel->setAlignment(Qt::AlignCenter); + layout->addWidget(titleLabel); + + // Scroll area pour la liste des stocks + QScrollArea* scrollArea = new QScrollArea(); + scrollArea->setWidgetResizable(true); + scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + scrollArea->setStyleSheet( + "QScrollArea {" + " border: 2px solid #bdc3c7;" + " border-radius: 8px;" + " background-color: white;" + "}" + ); + + // Widget conteneur pour les boutons de stock + QWidget* stockListWidget = new QWidget(); + m_stockSelectionLayout = new QVBoxLayout(stockListWidget); + m_stockSelectionLayout->setSpacing(10); + m_stockSelectionLayout->setContentsMargins(10, 10, 10, 10); + + scrollArea->setWidget(stockListWidget); + layout->addWidget(scrollArea); + + // Bouton retour + QPushButton* backButton = new QPushButton("← Retour"); + backButton->setStyleSheet( + "QPushButton {" + " background-color: #95a5a6;" + " color: white;" + " border: none;" + " border-radius: 8px;" + " font-size: 16px;" + " font-weight: bold;" + " padding: 12px 20px;" + " min-height: 40px;" + "}" + "QPushButton:hover { background-color: #7f8c8d; }" + "QPushButton:pressed { transform: translateY(1px); }" + ); + connect(backButton, &QPushButton::clicked, this, &QtView::goBack); + layout->addWidget(backButton); + + // Charger la liste des stocks + refreshStockSelectionScreen(); + + return screen; +} + +void QtView::refreshStockSelectionScreen() +{ + if (!m_stockSelectionLayout) return; + if (!m_controller) return; + + // Supprimer tous les boutons existants + QLayoutItem *child; + while ((child = m_stockSelectionLayout->takeAt(0)) != nullptr) { + delete child->widget(); + delete child; + } + + // Vérifier que le modèle existe + auto model = m_controller->getModel(); + if (!model) { + QLabel* errorLabel = new QLabel("Erreur: Modèle non disponible"); + errorLabel->setStyleSheet( + "QLabel {" + " font-size: 18px;" + " color: #e74c3c;" + " padding: 20px;" + " text-align: center;" + "}" + ); + errorLabel->setAlignment(Qt::AlignCenter); + m_stockSelectionLayout->addWidget(errorLabel); + m_stockSelectionLayout->addStretch(); + return; + } + + // Obtenir la liste des stocks depuis le modèle + auto stocks = model->getStocks(); + + if (stocks.empty()) { + QLabel* noStockLabel = new QLabel("Aucun stock disponible"); + noStockLabel->setStyleSheet( + "QLabel {" + " font-size: 18px;" + " color: #7f8c8d;" + " padding: 20px;" + " text-align: center;" + "}" + ); + noStockLabel->setAlignment(Qt::AlignCenter); + m_stockSelectionLayout->addWidget(noStockLabel); + } else { + // Créer un bouton pour chaque stock + for (const auto& stock : stocks) { + QString stockName = QString::fromStdString(stock.getName()); + QPushButton* stockButton = new QPushButton(stockName); + stockButton->setMinimumHeight(60); + stockButton->setStyleSheet( + "QPushButton {" + " background-color: #e74c3c;" + " color: white;" + " border: none;" + " border-radius: 8px;" + " font-size: 18px;" + " font-weight: bold;" + " padding: 15px;" + " text-align: left;" + "}" + "QPushButton:hover {" + " background-color: #c0392b;" + "}" + "QPushButton:pressed {" + " transform: translateY(1px);" + "}" + ); + + // Connecter le bouton à la confirmation de suppression + connect(stockButton, &QPushButton::clicked, [this, stockName]() { + confirmStockDeletion(stockName); + }); + + m_stockSelectionLayout->addWidget(stockButton); + } + } + + // Ajouter un stretch à la fin + m_stockSelectionLayout->addStretch(); +} + +void QtView::confirmStockDeletion(const QString& stockName) +{ + if (!m_controller) { + showMessage("Erreur: Contrôleur non disponible"); + return; + } + + // Afficher une notification de confirmation + QString confirmationMessage = QString( + "
" + "

⚠️ Confirmation de suppression

" + "

Êtes-vous sûr de vouloir supprimer le stock :

" + "

%1

" + "

Cette action est irréversible.

" + "
" + ).arg(stockName); + + // Créer un écran de confirmation temporaire + QWidget* confirmationScreen = new QWidget(); + QVBoxLayout* layout = new QVBoxLayout(confirmationScreen); + layout->setSpacing(30); + layout->setContentsMargins(50, 50, 50, 50); + + // Message de confirmation + QLabel* messageLabel = new QLabel(confirmationMessage); + messageLabel->setWordWrap(true); + messageLabel->setAlignment(Qt::AlignCenter); + messageLabel->setStyleSheet( + "QLabel {" + " background-color: white;" + " border: 2px solid #e74c3c;" + " border-radius: 10px;" + " padding: 20px;" + "}" + ); + layout->addWidget(messageLabel); + + // Boutons d'action + QWidget* buttonWidget = new QWidget(); + QHBoxLayout* buttonLayout = new QHBoxLayout(buttonWidget); + buttonLayout->setSpacing(20); + + QPushButton* confirmButton = new QPushButton("✓ Confirmer la suppression"); + QPushButton* cancelButton = new QPushButton("✕ Annuler"); + + QString buttonStyle = + "QPushButton {" + " border: none;" + " border-radius: 8px;" + " font-size: 18px;" + " font-weight: bold;" + " padding: 15px 25px;" + " min-height: 50px;" + "}" + "QPushButton:pressed {" + " transform: translateY(1px);" + "}"; + + confirmButton->setStyleSheet(buttonStyle + + "QPushButton { background-color: #e74c3c; color: white; }" + "QPushButton:hover { background-color: #c0392b; }"); + + cancelButton->setStyleSheet(buttonStyle + + "QPushButton { background-color: #95a5a6; color: white; }" + "QPushButton:hover { background-color: #7f8c8d; }"); + + // Connecter les boutons + connect(confirmButton, &QPushButton::clicked, [this, stockName, confirmationScreen]() { + // Effectuer la suppression + std::vector args = {stockName.toStdString()}; + m_controller->sendCommand(Command::DeleteStock, args); + + // Afficher un message de confirmation + showMessage(QString("Stock '%1' supprimé avec succès").arg(stockName)); + + // Retourner à l'écran de sélection et actualiser + refreshStockSelectionScreen(); + m_stackedWidget->removeWidget(confirmationScreen); + delete confirmationScreen; + m_stackedWidget->setCurrentWidget(m_deleteStockScreen); + }); + + connect(cancelButton, &QPushButton::clicked, [this, confirmationScreen]() { + // Retourner à l'écran de sélection sans suppression + m_stackedWidget->removeWidget(confirmationScreen); + delete confirmationScreen; + m_stackedWidget->setCurrentWidget(m_deleteStockScreen); + }); + + buttonLayout->addWidget(confirmButton); + buttonLayout->addWidget(cancelButton); + layout->addWidget(buttonWidget); + + layout->addStretch(); + + // Ajouter l'écran de confirmation et l'afficher + m_stackedWidget->addWidget(confirmationScreen); + m_stackedWidget->setCurrentWidget(confirmationScreen); +} + +// ============================================================================= +// MÉTHODES DE NAVIGATION +// ============================================================================= + +void QtView::showMainMenu(int menuIndex) +{ + updateMenuButtonStyles(); + + // Marquer le bouton correspondant comme sélectionné + QList buttons = {m_stockMenuButton, m_itemTypeMenuButton, m_itemMenuButton, m_displayMenuButton}; + if (menuIndex >= 0 && menuIndex < buttons.size()) { + buttons[menuIndex]->setChecked(true); + } + + // Afficher l'écran correspondant + m_stackedWidget->setCurrentIndex(menuIndex); + + // Masquer le bouton retour sur les menus principaux + m_backButton->hide(); +} + +void QtView::showActionScreen(QWidget* screen) +{ + int index = m_stackedWidget->indexOf(screen); + if (index != -1) { + // Si c'est l'écran de suppression de stock, actualiser la liste + if (screen == m_deleteStockScreen) { + refreshStockSelectionScreen(); + } + + m_stackedWidget->setCurrentIndex(index); + + // Afficher le bouton retour + m_backButton->show(); + + // Décocher tous les boutons de menu + updateMenuButtonStyles(); + } +} + +void QtView::goBack() +{ + // Retourner au menu principal correspondant au bouton actuellement sélectionné + if (m_stockMenuButton->isChecked()) { + showMainMenu(0); + } else if (m_itemTypeMenuButton->isChecked()) { + showMainMenu(1); + } else if (m_itemMenuButton->isChecked()) { + showMainMenu(2); + } else if (m_displayMenuButton->isChecked()) { + showMainMenu(3); + } else { + // Par défaut, retourner au menu des stocks + showMainMenu(0); + } +} + +void QtView::executeFormAction(QWidget* screen, const QString& title) +{ + // Cette méthode sera appelée pour traiter les formulaires + // Récupérer les valeurs des champs et exécuter l'action correspondante + + QList fields = screen->findChildren(); + QStringList values; + + for (QLineEdit* field : fields) { + values.append(field->text()); + } + + // Exécuter l'action en fonction du titre + if (title.contains("Créer un Nouveau Stock")) { + executeCreateStock(values); + } else if (title.contains("Créer un Type d'Article")) { + executeCreateItemType(values); + } else if (title.contains("Supprimer un Type")) { + executeDeleteItemType(values); + } else if (title.contains("Ajouter un Article")) { + executeAddItem(values); + } else if (title.contains("Déplacer un Article")) { + executeMoveItem(values); + } else if (title.contains("Retirer un Article")) { + executeRemoveItem(values); + } else if (title.contains("Contenu des Stocks")) { + executeShowStockContent(values); + } +} + +// ============================================================================= +// MÉTHODES D'EXÉCUTION DES ACTIONS +// ============================================================================= + +void QtView::executeCreateStock(const QStringList& values) +{ + if (values.size() >= 2 && !values[0].trimmed().isEmpty() && !values[1].trimmed().isEmpty()) { + QString stockName = values[0].trimmed(); + bool ok; + int capacity = values[1].trimmed().toInt(&ok); + + if (ok && capacity > 0) { + QString comment = values.size() > 2 ? values[2].trimmed() : ""; + + // Construire les arguments pour la commande + std::vector args = {stockName.toStdString(), std::to_string(capacity)}; + if (!comment.isEmpty()) { + args.push_back(comment.toStdString()); + } + + m_controller->sendCommand(CreateStock, args); + showMessage(QString("Stock '%1' créé avec succès (capacité: %2)").arg(stockName).arg(capacity), false); + goBack(); + } else { + displayResult("❌ ERREUR: La capacité doit être un nombre entier positif."); + } + } else { + displayResult("❌ ERREUR: Veuillez remplir le nom et la capacité du stock."); + } +} + +void QtView::executeDeleteStock(const QStringList& values) +{ + if (values.size() >= 1 && !values[0].trimmed().isEmpty()) { + QString stockName = values[0].trimmed(); + + m_controller->sendCommand(DeleteStock, stockName.toStdString()); + showMessage(QString("Stock '%1' supprimé avec succès").arg(stockName), false); + goBack(); + } else { + displayResult("❌ ERREUR: Veuillez spécifier le nom du stock à supprimer."); + } +} + +void QtView::executeCreateItemType(const QStringList& values) +{ + if (values.size() >= 4 && !values[0].trimmed().isEmpty() && !values[1].trimmed().isEmpty()) { + QString typeName = values[0].trimmed(); + bool idOk, sizeOk; + int id = values[1].trimmed().toInt(&idOk); + QString comment = values[2].trimmed(); + int size = values[3].trimmed().toInt(&sizeOk); + + if (idOk && sizeOk && id >= 0 && size > 0) { + std::vector args = {typeName.toStdString(), std::to_string(id), comment.toStdString(), std::to_string(size)}; + + m_controller->sendCommand(CreateItemType, args); + showMessage(QString("Type d'article '%1' créé avec succès (ID: %2)").arg(typeName).arg(id), false); + goBack(); + } else { + displayResult("❌ ERREUR: L'ID et la taille doivent être des nombres entiers valides."); + } + } else { + displayResult("❌ ERREUR: Veuillez remplir tous les champs obligatoires."); + } +} + +void QtView::executeDeleteItemType(const QStringList& values) +{ + if (values.size() >= 1 && !values[0].trimmed().isEmpty()) { + QString typeName = values[0].trimmed(); + + m_controller->sendCommand(DeleteItemType, typeName.toStdString()); + showMessage(QString("Type d'article '%1' supprimé avec succès").arg(typeName), false); + goBack(); + } else { + displayResult("❌ ERREUR: Veuillez spécifier le nom du type à supprimer."); + } +} + +void QtView::executeAddItem(const QStringList& values) +{ + if (values.size() >= 3 && !values[0].trimmed().isEmpty() && !values[1].trimmed().isEmpty()) { + QString stockName = values[0].trimmed(); + QString itemTypeName = values[1].trimmed(); + bool ok; + int quantity = values[2].trimmed().toInt(&ok); + + if (ok && quantity > 0) { + std::vector args = {stockName.toStdString(), itemTypeName.toStdString(), std::to_string(quantity)}; + + m_controller->sendCommand(AddItemToStock, args); + showMessage(QString("%1 article(s) de type '%2' ajouté(s) au stock '%3'").arg(quantity).arg(itemTypeName).arg(stockName), false); + goBack(); + } else { + displayResult("❌ ERREUR: La quantité doit être un nombre entier positif."); + } + } else { + displayResult("❌ ERREUR: Veuillez remplir tous les champs."); + } +} + +void QtView::executeMoveItem(const QStringList& values) +{ + if (values.size() >= 4 && !values[0].trimmed().isEmpty() && !values[1].trimmed().isEmpty() && !values[2].trimmed().isEmpty()) { + QString sourceStock = values[0].trimmed(); + QString destStock = values[1].trimmed(); + QString itemTypeName = values[2].trimmed(); + bool ok; + int quantity = values[3].trimmed().toInt(&ok); + + if (ok && quantity > 0) { + std::vector args = {sourceStock.toStdString(), destStock.toStdString(), itemTypeName.toStdString(), std::to_string(quantity)}; + + m_controller->sendCommand(MoveItemBetweenStocks, args); + showMessage(QString("%1 article(s) de type '%2' déplacé(s) de '%3' vers '%4'").arg(quantity).arg(itemTypeName).arg(sourceStock).arg(destStock), false); + goBack(); + } else { + displayResult("❌ ERREUR: La quantité doit être un nombre entier positif."); + } + } else { + displayResult("❌ ERREUR: Veuillez remplir tous les champs."); + } +} + +void QtView::executeRemoveItem(const QStringList& values) +{ + if (values.size() >= 3 && !values[0].trimmed().isEmpty() && !values[1].trimmed().isEmpty()) { + QString stockName = values[0].trimmed(); + QString itemTypeName = values[1].trimmed(); + bool ok; + int quantity = values[2].trimmed().toInt(&ok); + + if (ok && quantity > 0) { + std::vector args = {stockName.toStdString(), itemTypeName.toStdString(), std::to_string(quantity)}; + + m_controller->sendCommand(RemoveItemFromStock, args); + showMessage(QString("%1 article(s) de type '%2' retiré(s) du stock '%3'").arg(quantity).arg(itemTypeName).arg(stockName), false); + goBack(); + } else { + displayResult("❌ ERREUR: La quantité doit être un nombre entier positif."); + } + } else { + displayResult("❌ ERREUR: Veuillez remplir tous les champs."); + } +} + +void QtView::executeShowStockContent(const QStringList& values) +{ + QString stockName = values.size() > 0 ? values[0].trimmed() : ""; + + if (stockName.isEmpty()) { + m_controller->sendCommand(ShowStockContent); + } else { + m_controller->sendCommand(ShowStockContent, stockName.toStdString()); + } + goBack(); +} + +// ============================================================================= +// MÉTHODES POUR LES ACTIONS DIRECTES (sans formulaire) +// ============================================================================= + +void QtView::onShowStocks() +{ + m_controller->sendCommand(ShowStocks); +} + +void QtView::onShowItemTypes() +{ + m_controller->sendCommand(ShowItemTypes); +} + +void QtView::onShowCapacities() +{ + m_controller->sendCommand(ShowCapacities); +} + +void QtView::onShowStatistics() +{ + m_controller->sendCommand(ShowStatistics); +} + +// ============================================================================= +// MÉTHODES UTILITAIRES POUR LES DIALOGUES +// ============================================================================= + +void QtView::showMessage(const QString& message, bool isError) +{ + // Afficher seulement dans la zone de sortie avec du style + QString prefix = isError ? "❌ ERREUR" : "✅ INFO"; + QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss"); + QString styledMessage = QString("[%2 - %3] %4") + .arg(isError ? "#e74c3c" : "#27ae60") + .arg(timestamp) + .arg(prefix) + .arg(message); + + m_outputDisplay->append(styledMessage); + + // Faire défiler vers le bas pour voir le nouveau message + QScrollBar* scrollBar = m_outputDisplay->verticalScrollBar(); + scrollBar->setValue(scrollBar->maximum()); +} + +QStringList QtView::getAvailableStocks() +{ + QStringList stockNames; + + if (m_controller && m_controller->getModel()) { + auto stocks = m_controller->getModel()->getStocks(); + for (const auto& stock : stocks) { + stockNames.append(QString::fromStdString(stock.getName())); + } + } + + return stockNames; +} + +QStringList QtView::getAvailableItemTypes() +{ + QStringList typeNames; + + if (m_controller && m_controller->getModel()) { + auto itemTypes = m_controller->getModel()->getItemTypes(); + for (const auto& itemType : itemTypes) { + typeNames.append(QString::fromStdString(itemType.getName())); + } + } + + return typeNames; +} + +// ============================================================================= +// MÉTHODES UTILITAIRES POUR L'AFFICHAGE +// ============================================================================= + +void QtView::displayResult(const QString& message) +{ + // Afficher le message avec un style spécial pour les résultats + QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss"); + QString styledMessage = QString("[%1 - 📋 RÉSULTAT] %2") + .arg(timestamp) + .arg(message); + + m_outputDisplay->append(styledMessage); + + // Faire défiler vers le bas pour voir le dernier message + QScrollBar* scrollBar = m_outputDisplay->verticalScrollBar(); + scrollBar->setValue(scrollBar->maximum()); +} + +// ============================================================================= +// MÉTHODES MANQUANTES +// ============================================================================= + +void QtView::applyTouchFriendlyStyling() +{ + // Style général pour l'interface tactile + setStyleSheet( + "QScrollBar:vertical {" + " border: none;" + " background: #f1f1f1;" + " width: 20px;" + " border-radius: 10px;" + "}" + "QScrollBar::handle:vertical {" + " background: #c1c1c1;" + " border-radius: 10px;" + " min-height: 30px;" + "}" + "QScrollBar::handle:vertical:hover {" + " background: #a8a8a8;" + "}" + "QTextEdit {" + " border: 2px solid #bdc3c7;" + " border-radius: 8px;" + " padding: 10px;" + " font-size: 14px;" + " background-color: #ecf0f1;" + "}" + ); +} + +// Slots pour la sélection des menus (utilisés par l'ancien système de signaux Qt) +void QtView::onStockMenuSelected() +{ + showMainMenu(0); +} + +void QtView::onItemTypeMenuSelected() +{ + showMainMenu(1); +} + +void QtView::onItemMenuSelected() +{ + showMainMenu(2); +} + +void QtView::onDisplayMenuSelected() +{ + showMainMenu(3); +} diff --git a/src/view/qtView.hpp b/src/view/qtView.hpp index d233b9b..3227531 100644 --- a/src/view/qtView.hpp +++ b/src/view/qtView.hpp @@ -15,6 +15,21 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Forward declarations class StockController; @@ -47,94 +62,123 @@ protected: bool eventFilter(QObject* obj, QEvent* event) override; private slots: - // Stock management slots - void onCreateStock(); - void onShowStocks(); - void onDeleteStock(); - - // ItemType management slots - void onCreateItemType(); - void onShowItemTypes(); - void onDeleteItemType(); - - // Item management slots - void onAddItem(); - void onMoveItem(); - - // Display slots - void onShowStockContent(); - void onShowCapacities(); + // Menu selection slots + void onStockMenuSelected(); + void onItemTypeMenuSelected(); + void onItemMenuSelected(); + void onDisplayMenuSelected(); // Application control - void onExit(); void onRefresh(); // Virtual keyboard slots void onTextFieldFocused(); - void onTextFieldClicked(); + void showVirtualKeyboard(); + void hideVirtualKeyboard(); private: void setupUI(); - void setupStockManagementTab(); - void setupItemTypeManagementTab(); - void setupItemManagementTab(); - void setupDisplayTab(); - void applyModernStyling(); - void updateComboBoxes(); - void clearInputFields(); - void showSuccessMessage(const QString& message); - void showErrorMessage(const QString& message); + void setupLeftMenu(); + void setupStackedWidget(); + void setupMainMenuScreens(); + void setupActionScreens(); + void setupStockActionScreens(); + void setupItemTypeActionScreens(); + void setupItemActionScreens(); + void setupDisplayActionScreens(); + void applyTouchFriendlyStyling(); void setupVirtualKeyboard(); void connectTextFieldEvents(); + void updateMenuButtonStyles(); + + // Navigation methods + void showMainMenu(int menuIndex); + void showActionScreen(QWidget* screen); + void goBack(); + + // Screen creation helpers + QWidget* createTitleAndButtonScreen(const QString& title, const QStringList& buttonTexts, const std::vector>& callbacks); + QWidget* createFormScreen(const QString& title, const QStringList& labels, const QStringList& placeholders = QStringList()); + QWidget* createStockSelectionScreen(); + void refreshStockSelectionScreen(); + void confirmStockDeletion(const QString& stockName); + + // Form execution methods + void executeFormAction(QWidget* screen, const QString& title); + void executeCreateStock(const QStringList& values); + void executeDeleteStock(const QStringList& values); + void executeCreateItemType(const QStringList& values); + void executeDeleteItemType(const QStringList& values); + void executeAddItem(const QStringList& values); + void executeMoveItem(const QStringList& values); + void executeRemoveItem(const QStringList& values); + void executeShowStockContent(const QStringList& values); + + // Direct action methods (without forms) + void onShowStocks(); + void onShowItemTypes(); + void onShowCapacities(); + void onShowStatistics(); + + // Méthodes pour les notifications (plus de popups) + void showMessage(const QString& message, bool isError = false); + void displayResult(const QString& message); // Méthode pour afficher les résultats + + // Méthodes utilitaires pour obtenir les données du modèle + QStringList getAvailableStocks(); + QStringList getAvailableItemTypes(); // Controller StockController* m_controller; // Main layout and widgets QVBoxLayout* m_mainLayout; - QTabWidget* m_tabWidget; + QWidget* m_menuDisplayWidget; // Widget conteneur pour le layout horizontal + QHBoxLayout* m_menuDisplayLayout; + + // Left side menu (vertical selection) + QWidget* m_leftMenuWidget; + QVBoxLayout* m_leftMenuLayout; + QScrollArea* m_leftMenuScrollArea; + + // Right side content area - using stacked widget for screens + QStackedWidget* m_stackedWidget; + + // Menu buttons (left side) + QPushButton* m_stockMenuButton; + QPushButton* m_itemTypeMenuButton; + QPushButton* m_itemMenuButton; + QPushButton* m_displayMenuButton; + QPushButton* m_backButton; // Pour retourner au menu principal + + // Main menu screens + QWidget* m_stockMainScreen; + QWidget* m_itemTypeMainScreen; + QWidget* m_itemMainScreen; + QWidget* m_displayMainScreen; + + // Individual action screens + QWidget* m_createStockScreen; + QWidget* m_showStocksScreen; + QWidget* m_deleteStockScreen; + QVBoxLayout* m_stockSelectionLayout; // Layout pour les boutons de stock + + QWidget* m_createItemTypeScreen; + QWidget* m_showItemTypesScreen; + QWidget* m_deleteItemTypeScreen; + + QWidget* m_addItemScreen; + QWidget* m_moveItemScreen; + QWidget* m_removeItemScreen; + + QWidget* m_showStockContentScreen; + QWidget* m_showCapacitiesScreen; + QWidget* m_showStatisticsScreen; + + // Bottom area QTextEdit* m_outputDisplay; - QPushButton* m_exitButton; QPushButton* m_refreshButton; - // Stock management widgets - QWidget* m_stockTab; - QLineEdit* m_stockNameEdit; - QSpinBox* m_stockCapacitySpinBox; - QLineEdit* m_stockCommentEdit; - QComboBox* m_stockDeleteCombo; - QPushButton* m_createStockButton; - QPushButton* m_showStocksButton; - QPushButton* m_deleteStockButton; - - // ItemType management widgets - QWidget* m_itemTypeTab; - QLineEdit* m_itemTypeNameEdit; - QLineEdit* m_itemTypeCommentEdit; - QSpinBox* m_itemTypeSizeSpinBox; - QComboBox* m_itemTypeDeleteCombo; - QPushButton* m_createItemTypeButton; - QPushButton* m_showItemTypesButton; - QPushButton* m_deleteItemTypeButton; - - // Item management widgets - QWidget* m_itemTab; - QComboBox* m_addItemStockCombo; - QComboBox* m_addItemTypeCombo; - QSpinBox* m_addItemQuantitySpinBox; - QComboBox* m_moveFromStockCombo; - QComboBox* m_moveToStockCombo; - QComboBox* m_moveItemTypeCombo; - QSpinBox* m_moveQuantitySpinBox; - QPushButton* m_addItemButton; - QPushButton* m_moveItemButton; - - // Display widgets - QWidget* m_displayTab; - QComboBox* m_displayStockCombo; - QPushButton* m_showContentButton; - QPushButton* m_showCapacitiesButton; - // Virtual keyboard VirtualKeyboard* m_virtualKeyboard; }; diff --git a/src/view/virtualKeyboard.cpp b/src/view/virtualKeyboard.cpp index 931f45a..5cbea5a 100644 --- a/src/view/virtualKeyboard.cpp +++ b/src/view/virtualKeyboard.cpp @@ -337,6 +337,7 @@ void VirtualKeyboard::applyKeyboardStyling() #functionKey:hover { background-color: #f39c12; + } #functionKey:pressed, #functionKey:checked { background-color: #d35400;