rajout de la majorité des fonctions

This commit is contained in:
florian 2025-08-19 10:49:26 +02:00
parent 1a76d817d6
commit 2bbae40800
33 changed files with 3191 additions and 210 deletions

2
.gitignore vendored
View File

@ -25,3 +25,5 @@ CMakeUserPresets.json
build build
data data
.vscode
build.sh

View File

@ -1,20 +1,51 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.14)
project(stock_manager) project(stock_manager)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOMOC ON)
find_package(Qt5 REQUIRED COMPONENTS Widgets) find_package(Qt5 REQUIRED COMPONENTS Widgets)
find_package(nlohmann_json REQUIRED)
include_directories(include src) set(SOURCES
src/main.cpp
add_executable(stock_manager src/view/abstractView.cpp
main.cpp src/controller/stockController.cpp
src/stockmanager.cpp src/view/terminalView.cpp
src/view/qtView.cpp
src/view/virtualKeyboard.cpp
src/controller/command.cpp
src/model/model.cpp
src/model/stock.cpp
src/model/itemType.cpp
src/errors/stockFull.cpp
src/errors/stockEmpty.cpp
src/errors/invaldiItemType.cpp
) )
target_link_libraries(stock_manager set(HEADERS
Qt5::Widgets src/view/abstractView.hpp
nlohmann_json::nlohmann_json src/controller/stockController.hpp
src/controller/command.hpp
src/view/terminalView.hpp
src/view/qtView.hpp
src/view/virtualKeyboard.hpp
src/model/model.hpp
src/model/stock.hpp
src/model/itemType.hpp
src/errors/stockFull.hpp
src/errors/stockEmpty.hpp
src/errors/invalidItemType.hpp
) )
# Inclure les dossiers pour les headers
include_directories(
src
src/model
src/controller
src/view
)
# Pour que les fichiers avec Q_OBJECT soient mocifiés
qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
add_executable(stock_manager ${SOURCES} ${MOC_SOURCES})
target_link_libraries(stock_manager Qt5::Widgets)

View File

@ -1,18 +0,0 @@
#ifndef MODELS_HPP
#define MODELS_HPP
#include <QString>
#include <vector>
struct Item {
QString name;
int quantity;
int limit;
};
struct Category {
QString name;
std::vector<Item> items;
};
#endif // MODELS_HPP

View File

@ -1,14 +0,0 @@
#include <QApplication>
#include "stockmanager.h"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
StockManager w;
w.setGeometry(0, 0, 1280, 720); // position en haut à gauche, taille 1024x600
w.setWindowFlags(Qt::FramelessWindowHint); // pas de barre de fenêtre
w.setFixedSize(1024, 600); // taille non redimensionnable
w.show();
return app.exec();
}

BIN
qtView.o Normal file

Binary file not shown.

View File

@ -0,0 +1,11 @@
enum Command
{
None,
Stop,
Refresh,
CreateStock,
ShowStocks,
CreateItemType,
ShowItemTypes,
AddItemToStock
};

View File

@ -0,0 +1,16 @@
#ifndef COMMAND_HPP
#define COMMAND_HPP
enum Command
{
None,
Stop,
Refresh,
CreateStock,
ShowStocks,
CreateItemType,
ShowItemTypes,
AddItemToStock
};
#endif // COMMAND_HPP

View File

@ -0,0 +1,189 @@
#include "stockController.hpp"
#include "../view/abstractView.hpp"
#include <string>
#include <sstream>
#include <vector>
#include <thread>
#include <chrono>
#include "../errors/stockFull.hpp"
#include "../errors/stockEmpty.hpp"
#include "../errors/invalidItemType.hpp"
StockController::StockController(AbstractView* view, Model* model) : view(view), model(model)
{
}
StockController::~StockController()
{
stop();
}
void StockController::start()
{
view->setController(this);
view->start();
// Don't call process() here - it blocks the main GUI thread
// Commands will be processed when sendCommand is called
}
void StockController::startProcessing()
{
process();
}
void StockController::stop()
{
processCondition = false;
view->stop();
}
void StockController::process()
{
// Process all pending commands immediately (non-blocking)
while (!commands.empty() && !arguments.empty() && commands.size() == arguments.size())
{
Command command = commands.back();
commands.pop_back();
std::string joinedArguments = arguments.back();
arguments.pop_back();
// Diviser les arguments en utilisant le caractère spécial
std::vector<std::string> commandArgs = splitArguments(joinedArguments);
// Process the command
try {
switch (command)
{
case Command::Stop:
stop();
break;
case Command::CreateStock:
// Handle stock creation logic here
// Maintenant vous avez accès à commandArgs[0], commandArgs[1], etc.
if (commandArgs.size() >= 2) {
model->createStock(
commandArgs[0],
std::stoi(commandArgs[1]),
commandArgs.size() > 2 ? commandArgs[2] : ""
);
// Afficher les stocks après création
view->displayStockCreate(model->getStocks().back());
}
break;
case Command::ShowStocks:
// Afficher tous les stocks
view->displayStocks(model->getStocks());
break;
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
);
view->displayItemTypeCreate(model->getItemTypes().back());
}
break;
case Command::ShowItemTypes:
// Afficher tous les types d'items
view->displayItemTypes(model->getItemTypes());
break;
case Command::AddItemToStock:
// Handle adding items to stock: stockName, itemTypeName, quantity
if (commandArgs.size() >= 3) {
std::string stockName = commandArgs[0];
std::string itemTypeName = commandArgs[1];
int quantity = std::stoi(commandArgs[2]);
bool success = model->addItemToStock(stockName, itemTypeName, quantity);
view->displayAddItemResult(stockName, itemTypeName, quantity, success);
}
break;
case Command::Refresh:
// Handle refresh logic here
break;
default:
break;
}
}
catch (const StockFull& e) {
// Gérer les exceptions et afficher un message d'erreur
view->displayError("The Stock is full");
}
catch (const StockEmpty& e) {
// Gérer les exceptions et afficher un message d'erreur
view->displayError("The Stock is empty");
}
catch (const InvalidItemType& e) {
// Gérer les exceptions et afficher un message d'erreur
view->displayError("Invalid Item Type: " + std::string(e.what()));
}
catch (...)
{
// Gérer les exceptions inconnues
view->displayError("An unknown error occurred while processing the command.");
}
}
}
void StockController::sendCommand(Command command)
{
commands.push_back(command);
arguments.push_back(joinArguments({})); // Arguments vides mais traités de manière cohérente
process(); // Process commands immediately
}
void StockController::sendCommand(Command command, const std::string& argument)
{
commands.push_back(command);
std::vector<std::string> args = {argument};
arguments.push_back(joinArguments(args)); // Un seul argument mais joint de manière cohérente
process(); // Process commands immediately
}
void StockController::sendCommand(Command command, const std::vector<std::string>& args)
{
commands.push_back(command);
arguments.push_back(joinArguments(args)); // Joindre les arguments avec le caractère spécial
process(); // Process commands immediately
}
// Méthode pour joindre plusieurs arguments avec le caractère spécial
std::string StockController::joinArguments(const std::vector<std::string>& args)
{
if (args.empty()) {
return "";
}
std::ostringstream oss;
for (size_t i = 0; i < args.size(); ++i) {
if (i > 0) {
oss << ARGUMENT_SEPARATOR;
}
oss << args[i];
}
return oss.str();
}
// Méthode pour diviser les arguments en utilisant le caractère spécial
std::vector<std::string> StockController::splitArguments(const std::string& joinedArgs)
{
std::vector<std::string> result;
if (joinedArgs.empty()) {
return result;
}
std::istringstream iss(joinedArgs);
std::string arg;
while (std::getline(iss, arg, ARGUMENT_SEPARATOR)) {
result.push_back(arg);
}
return result;
}

View File

@ -0,0 +1,51 @@
#if !defined(STOCKCONTROLLER_H)
#define STOCKCONTROLLER_H
#include <vector>
#include "command.hpp"
#include "../view/abstractView.hpp"
#include "../model/model.hpp"
class StockController
{
public:
StockController(AbstractView* view, Model* model);
~StockController();
void start();
void startProcessing();
void stop();
void sendCommand(Command command);
void sendCommand(Command command, const std::string& argument);
void sendCommand(Command command, const std::vector<std::string>& arguments);
// Getter for the model
Model* getModel() const { return model; }
private:
AbstractView* view;
Model* model; // Pointer to the model
std::vector<Command> commands; // Assuming commands is a vector of some command type
std::vector<std::string> arguments; // Assuming arguments is a vector of strings for command arguments
bool processCondition = true; // Condition to control the processing loop
// Caractère spécial pour séparer les arguments (Unit Separator ASCII 0x1F)
static constexpr char ARGUMENT_SEPARATOR = '\x1F';
// Méthodes utilitaires pour gérer les arguments
std::string joinArguments(const std::vector<std::string>& args);
std::vector<std::string> splitArguments(const std::string& joinedArgs);
void process();
};
#endif // STOCKCONTROLLER_H

View File

@ -0,0 +1,3 @@
#include "invalidItemType.hpp"
// Le constructeur est défini inline dans le header

View File

@ -0,0 +1,13 @@
#ifndef INVALIDITEMTYPE_HPP
#define INVALIDITEMTYPE_HPP
#include <stdexcept>
class InvalidItemType : public std::runtime_error
{
public:
InvalidItemType(const std::string &message)
: std::runtime_error(message) {}
};
#endif // INVALIDITEMTYPE_HPP

View File

@ -0,0 +1,3 @@
#include "stockEmpty.hpp"
// Le constructeur est défini inline dans le header

13
src/errors/stockEmpty.hpp Normal file
View File

@ -0,0 +1,13 @@
#ifndef STOCKEMPTY_HPP
#define STOCKEMPTY_HPP
#include <stdexcept>
class StockEmpty : public std::runtime_error
{
public:
StockEmpty(const std::string &message)
: std::runtime_error(message) {}
};
#endif // STOCKEMPTY_HPP

3
src/errors/stockFull.cpp Normal file
View File

@ -0,0 +1,3 @@
#include "stockFull.hpp"
// Le constructeur est défini inline dans le header

13
src/errors/stockFull.hpp Normal file
View File

@ -0,0 +1,13 @@
#ifndef STOCKFULL_HPP
#define STOCKFULL_HPP
#include <stdexcept>
class StockFull : public std::runtime_error
{
public:
StockFull(const std::string &message)
: std::runtime_error(message) {}
};
#endif // STOCKFULL_HPP

57
src/main.cpp Normal file
View File

@ -0,0 +1,57 @@
#include <QApplication>
#include <thread>
#include <chrono>
#include <iostream>
#include "view/terminalView.hpp"
#include "view/qtView.hpp"
#include "controller/stockController.hpp"
#include "model/model.hpp"
int main(int argc, char *argv[])
{
// Vérifier les arguments de ligne de commande pour choisir l'interface
bool useTerminal = false;
for (int i = 1; i < argc; ++i) {
std::string arg = argv[i];
if (arg == "--terminal" || arg == "-t") {
useTerminal = true;
break;
}
}
if (useTerminal) {
// Interface Terminal
Model model;
TerminalView view;
StockController controller(&view, &model);
controller.start();
return 0;
} else {
// Interface Qt (par défaut)
QApplication app(argc, argv);
Model model;
QtView view;
StockController controller(&view, &model);
// Configuration dans le thread principal
view.setController(&controller);
view.start(); // Affiche la fenêtre Qt
// Démarrer seulement le traitement dans un thread séparé
std::thread controllerThread([&controller]() {
controller.startProcessing();
});
// La boucle d'événements Qt reste sur le thread principal
int result = app.exec();
// Arrêter le contrôleur avant de quitter
controller.stop();
controllerThread.join();
return result;
}
}

24
src/mainQt.cpp Normal file
View File

@ -0,0 +1,24 @@
#include <QApplication>
#include <thread>
#include <chrono>
#include "view/qtView.hpp"
#include "controller/stockController.hpp"
#include "model/model.hpp"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Créer le modèle et la vue
Model model;
QtView view;
// Créer le contrôleur
StockController controller(&view, &model);
// Démarrer l'application
controller.start();
return app.exec();
}

15
src/model/itemType.cpp Normal file
View File

@ -0,0 +1,15 @@
#include "itemType.hpp"
ItemType::ItemType(const std::string &name, int id, const std::string &comment, int size)
: name(name), id(id), comment(comment), size(size)
{}
ItemType::ItemType(const ItemType &other)
: name(other.getName()), id(other.getId()), comment(other.getComment()), size(other.getSize())
{}
ItemType::~ItemType()
{
// Destructor does not need to do anything special for std::string
// as it will automatically clean up the resources.
}

24
src/model/itemType.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef ITEMTYPE_HPP
#define ITEMTYPE_HPP
#include <string>
class ItemType
{
public:
ItemType(const std::string &name, int id, const std::string &comment = "", int size = 1);
ItemType(const ItemType &other);
~ItemType();
std::string getName() const { return name; }
int getId() const { return id; }
std::string getComment() const { return comment; }
int getSize() const { return size; }
private:
std::string name; // Name of the item type
int id; // Unique identifier for the item type
std::string comment; // Additional comment or description for the item type
int size; // Size of the item type (space it takes in stock)
};
#endif // ITEMTYPE_HPP

96
src/model/model.cpp Normal file
View File

@ -0,0 +1,96 @@
#include "model.hpp"
#include "../errors/stockFull.hpp"
Model::Model()
{
// Initialize your model data here
}
Model::~Model()
{
// Clean up any resources used by the model
}
void Model::addData(const std::string &data)
{
}
void Model::createStock(const std::string &name, int capacity, const std::string &comment)
{
Stock newStock(name, capacity, comment, nextStockId++);
stocks.push_back(newStock);
}
std::vector<Stock> Model::getStocks() const
{
return stocks;
}
// Méthodes pour gérer les ItemType
void Model::createItemType(const std::string &name, const std::string &comment, int size)
{
ItemType newItemType(name, nextItemTypeId++, comment, size);
itemTypes.push_back(newItemType);
}
std::vector<ItemType> Model::getItemTypes() const
{
return itemTypes;
}
ItemType* Model::findItemTypeByName(const std::string &name)
{
for (auto &itemType : itemTypes)
{
if (itemType.getName() == name)
{
return &itemType;
}
}
return nullptr;
}
// Méthodes pour ajouter des items aux stocks
bool Model::addItemToStock(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)
{
// Create the ItemType if it doesn't exist (with default size of 1)
createItemType(itemTypeName, "Auto-created item type", 1);
itemType = findItemTypeByName(itemTypeName);
}
// Add the specified quantity of items to the stock
if (itemType->getSize() * quantity + stock->getCurrentSize() > stock->getCapacity())
{
throw StockFull("Cannot add items, stock is full");
}
for (int i = 0; i < quantity; ++i)
{
stock->addItem(*itemType);
}
return true;
}
Stock* Model::findStockByName(const std::string &name)
{
for (auto &stock : stocks)
{
if (stock.getName() == name)
{
return &stock;
}
}
return nullptr;
}

37
src/model/model.hpp Normal file
View File

@ -0,0 +1,37 @@
#ifndef MODEL_HPP
#define MODEL_HPP
#include <string>
#include <vector>
#include "stock.hpp"
#include "itemType.hpp"
class Model
{
public:
Model();
~Model();
void addData(const std::string &data);
void createStock(const std::string &name, int capacity, const std::string &comment = "");
std::vector<Stock> getStocks() const;
// Méthodes pour gérer les ItemType
void createItemType(const std::string &name, const std::string &comment = "", int size = 1);
std::vector<ItemType> 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);
private:
std::vector<Stock> stocks; // Assuming Stock is a class defined elsewhere
std::vector<ItemType> itemTypes; // Assuming ItemType is a class defined elsewhere
int nextStockId = 0; // To generate unique IDs for stocks
int nextItemTypeId = 0; // To generate unique IDs for item types
};
#endif // MODEL_HPP

83
src/model/stock.cpp Normal file
View File

@ -0,0 +1,83 @@
#include "stock.hpp"
#include <algorithm>
#include <stdexcept>
#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)
{}
Stock::~Stock()
{
// Destructor logic (if needed)
}
void Stock::addItem(const ItemType &item)
{
if (currentSize + item.getSize() > capacity)
{
throw StockFull("Cannot add item: Stock is full");
}
items.push_back(item);
currentSize += item.getSize();
}
void Stock::removeItem(int id)
{
if (items.empty())
{
throw StockEmpty("No items to remove");
}
else if (std::none_of(items.begin(), items.end(),
[id](const ItemType &item) { return item.getId() == id; }))
{
throw InvalidItemType("Item with given ID not found");
}
currentSize -= items[id].getSize();
// Remove the item with the specified ID
items.erase(std::remove_if(items.begin(), items.end(),
[id](const ItemType &item) { return item.getId() == id; }), items.end());
}
ItemType Stock::getItem(int id) const
{
for (const auto &item : items)
{
if (item.getId() == id)
{
return item;
}
}
throw std::runtime_error("Item not found");
}
// Getters implementation
std::string Stock::getName() const
{
return name;
}
int Stock::getCapacity() const
{
return capacity;
}
int Stock::getCurrentSize() const
{
return currentSize;
}
std::string Stock::getComment() const
{
return comment;
}
int Stock::getId() const
{
return id;
}

36
src/model/stock.hpp Normal file
View File

@ -0,0 +1,36 @@
#ifndef STOCK_HPP
#define STOCK_HPP
#include <vector>
#include <string>
#include "itemType.hpp"
class Stock
{
public:
Stock(const std::string &name, int capacity, const std::string &comment, int id);
~Stock();
void addItem(const ItemType &item);
void removeItem(int id);
ItemType getItem(int id) const;
// Getters
std::string getName() const;
int getCapacity() const;
int getCurrentSize() const;
std::string getComment() const;
int getId() const;
private:
std::vector<ItemType> items;
std::string name; // Name of the stock
int capacity; // Maximum capacity of the stock
std::string comment; // Additional comment or description for the stock
int id; // Unique identifier for the stock
int currentSize = 0; // Current size of the stock (number of items)
};
#endif // STOCK_HPP

View File

@ -1,131 +0,0 @@
#include "stockmanager.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QMessageBox>
#include <QFileDialog>
#include <fstream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
StockManager::StockManager() {
setWindowTitle("Gestionnaire de Stock");
QWidget* central = new QWidget;
QVBoxLayout* mainLayout = new QVBoxLayout;
QHBoxLayout* topLayout = new QHBoxLayout;
categoryList = new QListWidget;
itemList = new QListWidget;
topLayout->addWidget(categoryList);
topLayout->addWidget(itemList);
QHBoxLayout* addCatLayout = new QHBoxLayout;
catNameInput = new QLineEdit;
QPushButton* addCatButton = new QPushButton("Ajouter Categorie");
addCatLayout->addWidget(catNameInput);
addCatLayout->addWidget(addCatButton);
QHBoxLayout* addItemLayout = new QHBoxLayout;
itemNameInput = new QLineEdit;
itemQtyInput = new QSpinBox;
itemLimitInput = new QSpinBox;
itemQtyInput->setMaximum(10000);
itemLimitInput->setMaximum(10000);
QPushButton* addItemButton = new QPushButton("Ajouter Objet");
addItemLayout->addWidget(itemNameInput);
addItemLayout->addWidget(itemQtyInput);
addItemLayout->addWidget(itemLimitInput);
addItemLayout->addWidget(addItemButton);
QPushButton* saveButton = new QPushButton("Sauvegarder");
QPushButton* loadButton = new QPushButton("Charger");
mainLayout->addLayout(topLayout);
mainLayout->addLayout(addCatLayout);
mainLayout->addLayout(addItemLayout);
mainLayout->addWidget(saveButton);
mainLayout->addWidget(loadButton);
central->setLayout(mainLayout);
setCentralWidget(central);
connect(addCatButton, &QPushButton::clicked, this, &StockManager::addCategory);
connect(addItemButton, &QPushButton::clicked, this, &StockManager::addItem);
connect(saveButton, &QPushButton::clicked, this, &StockManager::saveToFile);
connect(loadButton, &QPushButton::clicked, this, &StockManager::loadFromFile);
connect(categoryList, &QListWidget::currentTextChanged, this, &StockManager::updateItemList);
}
void StockManager::addCategory() {
QString name = catNameInput->text();
if (name.isEmpty() || categories.count(name)) return;
categories[name] = Category{name};
categoryList->addItem(name);
catNameInput->clear();
}
void StockManager::addItem() {
QString catName = categoryList->currentItem() ? categoryList->currentItem()->text() : "";
if (catName.isEmpty()) return;
QString name = itemNameInput->text();
int qty = itemQtyInput->value();
int lim = itemLimitInput->value();
if (name.isEmpty()) return;
auto& items = categories[catName].items;
for (const auto& i : items)
if (i.name == name) return;
items.push_back(Item{name, qty, lim});
updateItemList(catName);
itemNameInput->clear();
}
void StockManager::updateItemList(const QString& catName) {
itemList->clear();
for (const auto& item : categories[catName].items) {
itemList->addItem(item.name + " | Stock: " + QString::number(item.quantity) + " / Limite: " + QString::number(item.limit));
}
}
void StockManager::saveToFile() {
QString filename = QFileDialog::getSaveFileName(this, "Sauvegarder sous", "stock.json");
if (filename.isEmpty()) return;
json j;
for (const auto& [catName, cat] : categories) {
for (const auto& item : cat.items) {
j[catName.toStdString()].push_back({{"name", item.name.toStdString()}, {"quantity", item.quantity}, {"limit", item.limit}});
}
}
std::ofstream file(filename.toStdString());
file << j.dump(4);
}
void StockManager::loadFromFile() {
QString filename = QFileDialog::getOpenFileName(this, "Charger depuis", "stock.json");
if (filename.isEmpty()) return;
std::ifstream file(filename.toStdString());
if (!file) return;
json j;
file >> j;
categories.clear();
categoryList->clear();
itemList->clear();
for (auto& [catName, items] : j.items()) {
Category cat{QString::fromStdString(catName)};
for (auto& it : items) {
cat.items.push_back(Item{
QString::fromStdString(it["name"]),
it["quantity"],
it["limit"]
});
}
categories[QString::fromStdString(catName)] = cat;
categoryList->addItem(QString::fromStdString(catName));
}
}

View File

@ -1,35 +0,0 @@
#ifndef STOCKMANAGER_H
#define STOCKMANAGER_H
#include <QMainWindow>
#include <QListWidget>
#include <QLineEdit>
#include <QSpinBox>
#include <unordered_map>
#include "models.hpp"
class StockManager : public QMainWindow {
Q_OBJECT
private:
std::unordered_map<QString, Category> categories;
QListWidget* categoryList;
QListWidget* itemList;
QLineEdit* catNameInput;
QLineEdit* itemNameInput;
QSpinBox* itemQtyInput;
QSpinBox* itemLimitInput;
public:
StockManager();
private slots:
void addCategory();
void addItem();
void updateItemList(const QString& catName);
void saveToFile();
void loadFromFile();
};
#endif // STOCKMANAGER_H

View File

@ -0,0 +1,3 @@
#include "abstractView.hpp"
AbstractView::~AbstractView() = default;

32
src/view/abstractView.hpp Normal file
View File

@ -0,0 +1,32 @@
#ifndef ABSTRACTVIEW_HPP
#define ABSTRACTVIEW_HPP
#include <vector>
#include <string>
// Forward declarations to avoid circular dependency
class StockController;
class Stock;
class ItemType;
class AbstractView
{
public:
virtual ~AbstractView();
virtual void start() = 0; // Function to start the view, if needed
virtual void stop() = 0; // Function to stop the view, if needed
virtual void setController(StockController* controller) = 0; // Set the controller for this view
virtual void displayStocks(const std::vector<Stock>& stocks) = 0; // Display stocks in the view
virtual void displayStockCreate(const Stock& stock) = 0; // Display stock creation confirmation
// Méthodes pour les ItemType
virtual void displayItemTypes(const std::vector<ItemType>& itemTypes) = 0; // Display item types
virtual void displayItemTypeCreate(const ItemType& itemType) = 0; // Display item type creation confirmation
virtual void displayAddItemResult(const std::string& stockName, const std::string& itemTypeName, int quantity, bool success) = 0; // Display add item result
virtual void displayError(const std::string& message) = 0; // Display error messages
virtual void displayMessage(const std::string& message) = 0; // Display general
};
#endif // ABSTRACTVIEW_HPP

1071
src/view/qtView.cpp Normal file

File diff suppressed because it is too large Load Diff

142
src/view/qtView.hpp Normal file
View File

@ -0,0 +1,142 @@
#ifndef QTVIEW_HPP
#define QTVIEW_HPP
#include "abstractView.hpp"
#include <QWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QTabWidget>
#include <QPushButton>
#include <QLabel>
#include <QLineEdit>
#include <QSpinBox>
#include <QComboBox>
#include <QTextEdit>
#include <QGroupBox>
#include <QScrollArea>
// Forward declarations
class StockController;
class Stock;
class ItemType;
class VirtualKeyboard;
class QtView : public QWidget, public AbstractView
{
Q_OBJECT
public:
explicit QtView(QWidget* parent = nullptr);
explicit QtView(StockController* controller, QWidget* parent = nullptr);
virtual ~QtView();
// AbstractView interface implementation
void start() override;
void stop() override;
void setController(StockController* controller) override;
void displayStocks(const std::vector<Stock>& stocks) override;
void displayStockCreate(const Stock& stock) override;
void displayItemTypes(const std::vector<ItemType>& itemTypes) override;
void displayItemTypeCreate(const ItemType& itemType) override;
void displayAddItemResult(const std::string& stockName, const std::string& itemTypeName, int quantity, bool success) override;
void displayError(const std::string& message) override;
void displayMessage(const std::string& message) override;
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();
// Application control
void onExit();
void onRefresh();
// Virtual keyboard slots
void onTextFieldFocused();
void onTextFieldClicked();
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 setupVirtualKeyboard();
void connectTextFieldEvents();
// Controller
StockController* m_controller;
// Main layout and widgets
QVBoxLayout* m_mainLayout;
QTabWidget* m_tabWidget;
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;
};
#endif // QTVIEW_HPP

571
src/view/terminalView.cpp Normal file
View File

@ -0,0 +1,571 @@
#include "terminalView.hpp"
#include "../controller/stockController.hpp"
#include "../model/stock.hpp"
#include "../model/itemType.hpp"
#include <iostream>
#include <chrono>
#include <mutex>
#include <limits>
TerminalView::TerminalView() : running(false)
{
}
void TerminalView::start()
{
startThread();
}
void TerminalView::stop()
{
stopThread();
joinThread();
}
TerminalView::~TerminalView()
{
// Arrêter le thread d'abord
if (running.load())
{
running.store(false);
}
// Attendre que le thread se termine
if (viewThread.joinable())
{
viewThread.join();
}
}
void TerminalView::setController(StockController *controller)
{
this->controller = controller;
}
void TerminalView::startThread()
{
if (!running.load())
{
running.store(true);
viewThread = std::thread(&TerminalView::threadFunction, this);
{
std::lock_guard<std::mutex> lock(outputMutex);
std::cout << "Terminal view thread started." << std::endl;
}
}
}
void TerminalView::stopThread()
{
if (running.load())
{
running.store(false);
std::cout << "Terminal view thread stopping..." << std::endl;
}
}
void TerminalView::joinThread()
{
if (viewThread.joinable())
{
viewThread.join();
std::cout << "Terminal view thread joined." << std::endl;
}
}
void TerminalView::print(const std::string &message)
{
std::lock_guard<std::mutex> lock(outputMutex);
std::cout << message;
std::cout.flush();
}
void TerminalView::println(const std::string &message)
{
print(message + "\n");
}
void TerminalView::setCursorPosition(int x, int y)
{
// This is a placeholder for setting cursor position in a terminal.
// Actual implementation would depend on the terminal capabilities.
std::string escapeCode = "\033[";
escapeCode += std::to_string(y) + ";" + std::to_string(x) + "H";
print(escapeCode);
}
void TerminalView::threadFunction()
{
try
{
menu(); // Start the menu in the terminal view
// Ne pas utiliser le mutex dans cette sortie finale pour éviter les race conditions
std::cout << "Terminal view thread function exiting." << std::endl;
}
catch (const std::exception &e)
{
// Gestion des exceptions pour éviter les crashes
std::cout << "Exception in thread: " << e.what() << std::endl;
running.store(false); // Stop the thread if an exception occurs
controller->sendCommand(Command::Stop); // Notify the controller to stop
}
}
void TerminalView::menu()
{
print("\x1B[2J"); // Clear the screen and reset cursor position
setCursorPosition(0, 0); // Move cursor to the top-left corner
println("Terminal view started. Type 'exit' or 'quit' to stop.");
std::string input = "";
while (running.load())
{
setCursorPosition(0, 0); // Move cursor to the top-left corner
println("Terminal view started. Type 'exit' or 'quit' to stop.");
setCursorPosition(0, 2);
print("input: ");
std::getline(std::cin, input); // Wait for user input to continue
UserCommand command = parseUserInput(input);
switch (command)
{
case UserCommand::Exit:
handleExitCommand();
break;
case UserCommand::CreateStock:
handleCreateStockCommand();
break;
case UserCommand::ShowStocks:
handleShowStocksCommand();
break;
case UserCommand::CreateItemType:
handleCreateItemTypeCommand();
break;
case UserCommand::ShowItemTypes:
handleShowItemTypesCommand();
break;
case UserCommand::AddItemToStock:
handleAddItemToStockCommand();
break;
case UserCommand::CreateObjects:
handleCreateObjectsCommand();
break;
case UserCommand::Unknown:
default:
handleUnknownCommand(input);
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Simulate processing delay
}
}
void TerminalView::createStock()
{
println("Creating stock objects...");
std::string stockName = getStockNameFromUser();
int stockCapacity = getStockCapacityFromUser();
std::string stockComment = getStockCommentFromUser();
// Envoyer la commande au contrôleur avec les arguments joints
std::vector<std::string> args = {stockName, std::to_string(stockCapacity), stockComment};
controller->sendCommand(Command::CreateStock, args);
}
std::string TerminalView::getStockNameFromUser()
{
std::string stockName;
bool isValid = false;
do {
print("What is the name of the stock? ");
std::getline(std::cin, stockName);
if (stockName.empty())
{
println("Stock name cannot be empty. Please try again.");
}
else if (stockName.length() > 50)
{
println("Stock name is too long. Please limit it to 50 characters.");
}
else
{
isValid = true;
}
} while (!isValid);
return stockName;
}
int TerminalView::getStockCapacityFromUser()
{
int stockCapacity;
bool isValid = false;
do {
print("What is the capacity of the stock? ");
std::cin >> stockCapacity;
if (std::cin.fail())
{
println("Invalid input. Please enter a number.");
std::cin.clear(); // Clear the error flag
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Ignore invalid input
}
else if (stockCapacity <= 0)
{
println("Stock capacity must be a positive number. Please try again.");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Ignore the rest of the line
}
else
{
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Ignore the rest of the line
isValid = true;
}
} while (!isValid);
return stockCapacity;
}
std::string TerminalView::getStockCommentFromUser()
{
std::string stockComment;
print("What is the comment for the stock? (optional, press Enter to skip) ");
std::getline(std::cin, stockComment);
return stockComment;
}
void TerminalView::displayStockCreate(const Stock& stock){
std::string stockName = stock.getName();
int stockCapacity = stock.getCapacity();
std::string stockComment = stock.getComment();
setCursorPosition(0, 3);
println("Stock '" + stockName + "' with capacity " + std::to_string(stockCapacity) + " created successfully.");
}
void TerminalView::displayStocks(const std::vector<Stock>& stocks)
{
setCursorPosition(60, 0); // Move cursor to a specific position for displaying stocks
println("Displaying stocks:");
for (int i = 0; i < stocks.size(); ++i)
{
const Stock& stock = stocks[i];
setCursorPosition(60, i + 2); // Set cursor position for each stock
print(" - " + stock.getName() + ": " + std::to_string(stock.getCapacity()));
}
lastStocksDisplayed = stocks;
}
void TerminalView::eraseDisplayStock()
{
setCursorPosition(60, 0); // Move cursor to a specific position for displaying stocks
println(" ");
for (int i = 0; i < lastStocksDisplayed.size(); ++i)
{
Stock& stock = lastStocksDisplayed[i];
setCursorPosition(60, i + 2); // Set cursor position for each stock
std::string stringToDisplay = " - " + lastStocksDisplayed[i].getName() + ": " + std::to_string(lastStocksDisplayed[i].getCapacity());
for (int y = 0 ; y < stringToDisplay.length(); ++y)
{
print(" ");
}
}
}
// Méthode pour parser l'entrée utilisateur et retourner la commande correspondante
TerminalView::UserCommand TerminalView::parseUserInput(const std::string& input)
{
if (input == "exit" || input == "quit")
{
return UserCommand::Exit;
}
else if (input == "create stock" || input == "create stocks"
|| input == "create stock objects" || input == "new stock"
|| input == "new stocks" || input == "new stock objects")
{
return UserCommand::CreateStock;
}
else if (input == "show stocks" || input == "list stocks"
|| input == "display stocks" || input == "show stock"
|| input == "list stock" || input == "display stock")
{
return UserCommand::ShowStocks;
}
else if (input == "create itemtype" || input == "create item type"
|| input == "new itemtype" || input == "new item type")
{
return UserCommand::CreateItemType;
}
else if (input == "show itemtypes" || input == "show item types"
|| input == "list itemtypes" || input == "list item types"
|| input == "display itemtypes" || input == "display item types")
{
return UserCommand::ShowItemTypes;
}
else if (input == "add to stock")
{
// Commandes comme "add 20 patate to MonStock" ou "add item to stock"
return UserCommand::AddItemToStock;
}
else if (input == "create objects")
{
return UserCommand::CreateObjects;
}
else
{
return UserCommand::Unknown;
}
}
// Gestionnaire pour la commande de sortie
void TerminalView::handleExitCommand()
{
controller->sendCommand(Command::Stop);
}
// Gestionnaire pour la commande de création de stock
void TerminalView::handleCreateStockCommand()
{
createStock(); // Appeler la fonction existante pour créer un stock
}
// Gestionnaire pour la commande d'affichage des stocks
void TerminalView::handleShowStocksCommand()
{
controller->sendCommand(Command::ShowStocks);
}
// Gestionnaire pour la commande de création d'objets
void TerminalView::handleCreateObjectsCommand()
{
print("\x1B[2J"); // Clear the screen and reset cursor position
setCursorPosition(0, 3);
println("Creating objects is not implemented yet.");
}
// Gestionnaire pour les commandes inconnues
void TerminalView::handleUnknownCommand(const std::string& input)
{
print("\x1B[2J"); // Clear the screen and reset cursor position
setCursorPosition(0, 3);
println("Unknown command: " + input);
println("Available commands:");
println(" - exit, quit: Exit the application");
println(" - create stock, new stock: Create a new stock");
println(" - show stocks, list stocks: Display all stocks");
println(" - create itemtype, new itemtype: Create a new item type");
println(" - show itemtypes, list itemtypes: Display all item types");
println(" - add [quantity] [itemtype] to [stock]: Add items to stock");
}
// Nouveaux gestionnaires de commandes pour ItemType
void TerminalView::handleCreateItemTypeCommand()
{
println("Creating item type...");
std::string itemTypeName = getItemTypeNameFromUser();
std::string itemTypeComment = getItemTypeCommentFromUser();
int itemTypeSize = getItemTypeSizeFromUser();
std::vector<std::string> args = {itemTypeName, itemTypeComment, std::to_string(itemTypeSize)};
controller->sendCommand(Command::CreateItemType, args);
}
void TerminalView::handleShowItemTypesCommand()
{
controller->sendCommand(Command::ShowItemTypes);
}
void TerminalView::handleAddItemToStockCommand()
{
println("Adding items to stock...");
std::string stockName = getStockNameForAddItem();
std::string itemTypeName = getItemTypeNameForAddItem();
int quantity = getQuantityFromUser();
std::vector<std::string> args = {stockName, itemTypeName, std::to_string(quantity)};
controller->sendCommand(Command::AddItemToStock, args);
}
// Méthodes utilitaires pour ItemType
std::string TerminalView::getItemTypeNameFromUser()
{
std::string itemTypeName;
bool isValid = false;
do {
print("What is the name of the item type? ");
std::getline(std::cin, itemTypeName);
if (itemTypeName.empty())
{
println("Item type name cannot be empty. Please try again.");
}
else if (itemTypeName.length() > 50)
{
println("Item type name is too long. Please limit it to 50 characters.");
}
else
{
isValid = true;
}
} while (!isValid);
return itemTypeName;
}
std::string TerminalView::getItemTypeCommentFromUser()
{
std::string itemTypeComment;
print("What is the comment for the item type? (optional, press Enter to skip) ");
std::getline(std::cin, itemTypeComment);
return itemTypeComment;
}
// Méthodes utilitaires pour ajouter des items au stock
std::string TerminalView::getStockNameForAddItem()
{
controller->sendCommand(Command::ShowStocks); // Show available stocks before asking for input
std::string stockName;
print("Which stock do you want to add items to? ");
std::getline(std::cin, stockName);
eraseDisplayStock(); // Clear the display after getting input
return stockName;
}
std::string TerminalView::getItemTypeNameForAddItem()
{
controller->sendCommand(Command::ShowItemTypes); // Show available item types before asking for input
std::string itemTypeName;
print("What type of item do you want to add? ");
std::getline(std::cin, itemTypeName);
return itemTypeName;
}
int TerminalView::getQuantityFromUser()
{
int quantity;
bool isValid = false;
do {
print("How many items do you want to add? ");
std::cin >> quantity;
if (std::cin.fail())
{
println("Invalid input. Please enter a number.");
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
else if (quantity <= 0)
{
println("Quantity must be a positive number. Please try again.");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
else
{
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
isValid = true;
}
} while (!isValid);
return quantity;
}
// Méthodes d'affichage pour ItemType
void TerminalView::displayItemTypes(const std::vector<ItemType>& itemTypes)
{
print("\x1B[2J");
setCursorPosition(0, 0);
println("Displaying item types:");
for (int i = 0; i < itemTypes.size(); ++i)
{
const ItemType& itemType = itemTypes[i];
setCursorPosition(0, i + 2);
print(" - " + itemType.getName() + " (ID: " + std::to_string(itemType.getId()) + ", Size: " + std::to_string(itemType.getSize()) + ")");
if (!itemType.getComment().empty())
{
print(" - " + itemType.getComment());
}
println("");
}
}
void TerminalView::displayItemTypeCreate(const ItemType& itemType)
{
print("\x1B[2J");
setCursorPosition(0, 3);
println("Item type '" + itemType.getName() + "' (ID: " + std::to_string(itemType.getId()) + ", Size: " + std::to_string(itemType.getSize()) + ") created successfully.");
}
void TerminalView::displayAddItemResult(const std::string& stockName, const std::string& itemTypeName, int quantity, bool success)
{
print("\x1B[2J");
setCursorPosition(0, 3);
if (success)
{
println("Successfully added " + std::to_string(quantity) + " " + itemTypeName + "(s) to stock '" + stockName + "'.");
}
else
{
println("Failed to add items. Stock '" + stockName + "' not found.");
}
}
int TerminalView::getItemTypeSizeFromUser()
{
int itemTypeSize;
bool isValid = false;
do {
print("What is the size of the item type? (default is 1) ");
std::cin >> itemTypeSize;
if (std::cin.fail())
{
println("Invalid input. Please enter a number.");
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
else if (itemTypeSize <= 0)
{
println("Item type size must be a positive number. Please try again.");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
else
{
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
isValid = true;
}
} while (!isValid);
return itemTypeSize;
}
void TerminalView::displayError(const std::string& message)
{
print("\x1B[2J"); // Clear the screen
setCursorPosition(0, 0);
println("Error: " + message);
}
void TerminalView::displayMessage(const std::string& message)
{
print("\x1B[2J"); // Clear the screen
setCursorPosition(0, 0);
println("Message: " + message);
}

98
src/view/terminalView.hpp Normal file
View File

@ -0,0 +1,98 @@
#ifndef TERMINALVIEW_HPP
#define TERMINALVIEW_HPP
#include "abstractView.hpp"
#include <thread>
#include <atomic>
#include <mutex>
// Forward declaration to avoid circular dependency
class StockController;
class TerminalView : public AbstractView
{
public:
TerminalView();
~TerminalView();
void start() override;
void stop() override;
void setController(StockController* controller) override;
void displayStocks(const std::vector<Stock>& stocks) override;
void displayStockCreate(const Stock& stock) override;
// Méthodes pour les ItemType
void displayItemTypes(const std::vector<ItemType>& itemTypes) override;
void displayItemTypeCreate(const ItemType& itemType) override;
void displayAddItemResult(const std::string& stockName, const std::string& itemTypeName, int quantity, bool success) override;
void displayError(const std::string& message) override;
void displayMessage(const std::string& message) override;
private:
// Énumération pour les commandes utilisateur
enum class UserCommand {
Exit,
CreateStock,
ShowStocks,
CreateItemType,
ShowItemTypes,
AddItemToStock,
CreateObjects,
Unknown
};
void threadFunction();
void print(const std::string& message);
void println(const std::string& message);
void setCursorPosition(int x, int y);
void menu();
UserCommand parseUserInput(const std::string& input);
// Méthodes pour chaque commande
void handleExitCommand();
void handleCreateStockCommand();
void handleShowStocksCommand();
void handleCreateItemTypeCommand();
void handleShowItemTypesCommand();
void handleAddItemToStockCommand();
void handleCreateObjectsCommand();
void handleUnknownCommand(const std::string& input);
void createStock(); // Function to create stock in the terminal view
// Méthodes utilitaires pour la création de stock
std::string getStockNameFromUser();
int getStockCapacityFromUser();
std::string getStockCommentFromUser();
// Méthodes utilitaires pour la création d'ItemType
std::string getItemTypeNameFromUser();
std::string getItemTypeCommentFromUser();
int getItemTypeSizeFromUser();
// Méthodes utilitaires pour ajouter des items au stock
std::string getStockNameForAddItem();
std::string getItemTypeNameForAddItem();
int getQuantityFromUser();
void startThread();
void stopThread();
void joinThread();
void eraseDisplayStock();
std::vector<Stock> lastStocksDisplayed; // Store the last displayed stocks
StockController* controller;
std::thread viewThread;
std::atomic<bool> running;
std::mutex outputMutex; // Protection pour les sorties console
};
#endif // TERMINALVIEW_HPP

View File

@ -0,0 +1,469 @@
#include "virtualKeyboard.hpp"
#include <QLabel>
#include <QFocusEvent>
#include <QShowEvent>
#include <QHideEvent>
#include <QScreen>
VirtualKeyboard::VirtualKeyboard(QWidget* parent)
: QWidget(parent)
, m_mainLayout(nullptr)
, m_keyboardLayout(nullptr)
, m_functionLayout(nullptr)
, m_targetWidget(nullptr)
, m_capsLock(false)
, m_shift(false)
, m_spaceButton(nullptr)
, m_backspaceButton(nullptr)
, m_enterButton(nullptr)
, m_shiftButton(nullptr)
, m_capsLockButton(nullptr)
, m_hideButton(nullptr)
{
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
setAttribute(Qt::WA_ShowWithoutActivating);
// Initialize key layouts
m_qwertyLayout << "q" << "w" << "e" << "r" << "t" << "y" << "u" << "i" << "o" << "p"
<< "a" << "s" << "d" << "f" << "g" << "h" << "j" << "k" << "l"
<< "z" << "x" << "c" << "v" << "b" << "n" << "m";
m_numericLayout << "1" << "2" << "3" << "4" << "5" << "6" << "7" << "8" << "9" << "0";
setupKeyboard();
applyKeyboardStyling();
updateKeyLabels();
}
VirtualKeyboard::~VirtualKeyboard()
{
// Qt handles cleanup automatically
}
void VirtualKeyboard::setTargetWidget(QWidget* target)
{
m_targetWidget = target;
}
void VirtualKeyboard::showForWidget(QWidget* target)
{
setTargetWidget(target);
positionKeyboard();
show();
raise();
}
void VirtualKeyboard::hideKeyboard()
{
hide();
m_targetWidget = nullptr;
}
void VirtualKeyboard::setupKeyboard()
{
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setSpacing(5);
m_mainLayout->setContentsMargins(10, 10, 10, 10);
// Header with title and hide button
QHBoxLayout* headerLayout = new QHBoxLayout();
QLabel* titleLabel = new QLabel("Clavier Virtuel");
titleLabel->setObjectName("keyboardTitle");
m_hideButton = new QPushButton("");
m_hideButton->setObjectName("hideButton");
m_hideButton->setFixedSize(30, 30);
connect(m_hideButton, &QPushButton::clicked, this, &VirtualKeyboard::hideKeyboard);
headerLayout->addWidget(titleLabel);
headerLayout->addStretch();
headerLayout->addWidget(m_hideButton);
m_mainLayout->addLayout(headerLayout);
// Numeric row
setupNumericKeys();
// Alphabetic rows
setupAlphabeticKeys();
// Function keys row
setupFunctionKeys();
}
void VirtualKeyboard::setupNumericKeys()
{
QHBoxLayout* numericLayout = new QHBoxLayout();
numericLayout->setSpacing(3);
for (const QString& key : m_numericLayout) {
QPushButton* button = new QPushButton(key);
button->setObjectName("numericKey");
button->setFixedSize(45, 45);
connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed);
m_numericKeys.append(button);
numericLayout->addWidget(button);
}
// Add special numeric characters
QStringList specialChars = {"-", "=", "[", "]", "\\"};
for (const QString& key : specialChars) {
QPushButton* button = new QPushButton(key);
button->setObjectName("specialKey");
button->setFixedSize(45, 45);
connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed);
numericLayout->addWidget(button);
}
m_mainLayout->addLayout(numericLayout);
}
void VirtualKeyboard::setupAlphabeticKeys()
{
// First row: QWERTYUIOP
QHBoxLayout* firstRow = new QHBoxLayout();
firstRow->setSpacing(3);
for (int i = 0; i < 10; ++i) {
QPushButton* button = new QPushButton(m_qwertyLayout[i]);
button->setObjectName("alphabeticKey");
button->setFixedSize(45, 45);
connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed);
m_alphabeticKeys.append(button);
firstRow->addWidget(button);
}
m_mainLayout->addLayout(firstRow);
// Second row: ASDFGHJKL
QHBoxLayout* secondRow = new QHBoxLayout();
secondRow->setSpacing(3);
secondRow->addSpacing(20); // Slight offset
for (int i = 10; i < 19; ++i) {
QPushButton* button = new QPushButton(m_qwertyLayout[i]);
button->setObjectName("alphabeticKey");
button->setFixedSize(45, 45);
connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed);
m_alphabeticKeys.append(button);
secondRow->addWidget(button);
}
m_mainLayout->addLayout(secondRow);
// Third row: ZXCVBNM
QHBoxLayout* thirdRow = new QHBoxLayout();
thirdRow->setSpacing(3);
// Shift button
m_shiftButton = new QPushButton("");
m_shiftButton->setObjectName("functionKey");
m_shiftButton->setFixedSize(60, 45);
m_shiftButton->setCheckable(true);
connect(m_shiftButton, &QPushButton::clicked, this, &VirtualKeyboard::onShiftPressed);
thirdRow->addWidget(m_shiftButton);
for (int i = 19; i < 26; ++i) {
QPushButton* button = new QPushButton(m_qwertyLayout[i]);
button->setObjectName("alphabeticKey");
button->setFixedSize(45, 45);
connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed);
m_alphabeticKeys.append(button);
thirdRow->addWidget(button);
}
// Backspace button
m_backspaceButton = new QPushButton("");
m_backspaceButton->setObjectName("functionKey");
m_backspaceButton->setFixedSize(60, 45);
connect(m_backspaceButton, &QPushButton::clicked, this, &VirtualKeyboard::onBackspacePressed);
thirdRow->addWidget(m_backspaceButton);
m_mainLayout->addLayout(thirdRow);
}
void VirtualKeyboard::setupFunctionKeys()
{
m_functionLayout = new QHBoxLayout();
m_functionLayout->setSpacing(5);
// Caps Lock
m_capsLockButton = new QPushButton("Caps");
m_capsLockButton->setObjectName("functionKey");
m_capsLockButton->setFixedSize(60, 45);
m_capsLockButton->setCheckable(true);
connect(m_capsLockButton, &QPushButton::clicked, this, &VirtualKeyboard::onCapsLockPressed);
m_functionLayout->addWidget(m_capsLockButton);
// Space bar
m_spaceButton = new QPushButton("Espace");
m_spaceButton->setObjectName("spaceKey");
m_spaceButton->setFixedHeight(45);
connect(m_spaceButton, &QPushButton::clicked, this, &VirtualKeyboard::onSpacePressed);
m_functionLayout->addWidget(m_spaceButton);
// Enter
m_enterButton = new QPushButton("");
m_enterButton->setObjectName("functionKey");
m_enterButton->setFixedSize(60, 45);
connect(m_enterButton, &QPushButton::clicked, this, &VirtualKeyboard::onEnterPressed);
m_functionLayout->addWidget(m_enterButton);
// Common punctuation
QStringList punctuation = {".", ",", "?", "!", ":", ";"};
for (const QString& key : punctuation) {
QPushButton* button = new QPushButton(key);
button->setObjectName("punctuationKey");
button->setFixedSize(40, 45);
connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed);
m_functionLayout->addWidget(button);
}
m_mainLayout->addLayout(m_functionLayout);
}
void VirtualKeyboard::applyKeyboardStyling()
{
setStyleSheet(R"(
VirtualKeyboard {
background-color: #2c3e50;
border: 2px solid #34495e;
border-radius: 10px;
}
#keyboardTitle {
color: #ecf0f1;
font-size: 14px;
font-weight: bold;
padding: 5px;
}
#hideButton {
background-color: #e74c3c;
color: white;
border: none;
border-radius: 15px;
font-size: 12px;
font-weight: bold;
}
#hideButton:hover {
background-color: #c0392b;
}
#hideButton:pressed {
background-color: #a93226;
}
#alphabeticKey, #numericKey {
background-color: #34495e;
color: #ecf0f1;
border: 1px solid #5d6d7e;
border-radius: 6px;
font-size: 13px;
font-weight: bold;
}
#alphabeticKey:hover, #numericKey:hover {
background-color: #4a5f7a;
}
#alphabeticKey:pressed, #numericKey:pressed {
background-color: #3498db;
}
#functionKey {
background-color: #e67e22;
color: white;
border: 1px solid #d68910;
border-radius: 6px;
font-size: 12px;
font-weight: bold;
}
#functionKey:hover {
background-color: #f39c12;
}
#functionKey:pressed, #functionKey:checked {
background-color: #d35400;
}
#spaceKey {
background-color: #27ae60;
color: white;
border: 1px solid #229954;
border-radius: 6px;
font-size: 12px;
font-weight: bold;
}
#spaceKey:hover {
background-color: #2ecc71;
}
#spaceKey:pressed {
background-color: #1e8449;
}
#specialKey, #punctuationKey {
background-color: #8e44ad;
color: white;
border: 1px solid #7d3c98;
border-radius: 6px;
font-size: 11px;
font-weight: bold;
}
#specialKey:hover, #punctuationKey:hover {
background-color: #a569bd;
}
#specialKey:pressed, #punctuationKey:pressed {
background-color: #6c3483;
}
)");
}
void VirtualKeyboard::updateKeyLabels()
{
bool upperCase = m_capsLock || m_shift;
for (int i = 0; i < m_alphabeticKeys.size(); ++i) {
QString key = m_qwertyLayout[i];
if (upperCase) {
key = key.toUpper();
}
m_alphabeticKeys[i]->setText(key);
}
// Update shift button appearance
m_shiftButton->setChecked(m_shift);
m_capsLockButton->setChecked(m_capsLock);
}
void VirtualKeyboard::insertTextToTarget(const QString& text)
{
if (!m_targetWidget) return;
if (QLineEdit* lineEdit = qobject_cast<QLineEdit*>(m_targetWidget)) {
lineEdit->insert(text);
} else if (QTextEdit* textEdit = qobject_cast<QTextEdit*>(m_targetWidget)) {
textEdit->insertPlainText(text);
}
}
void VirtualKeyboard::positionKeyboard()
{
if (!m_targetWidget) return;
// Get screen geometry
QScreen* screen = QApplication::primaryScreen();
QRect screenGeometry = screen->availableGeometry();
// Get target widget global position
QPoint targetPos = m_targetWidget->mapToGlobal(QPoint(0, 0));
QSize targetSize = m_targetWidget->size();
// Calculate keyboard size
adjustSize();
QSize keyboardSize = size();
// Position keyboard below the target widget
int x = targetPos.x();
int y = targetPos.y() + targetSize.height() + 10;
// Ensure keyboard stays within screen bounds
if (x + keyboardSize.width() > screenGeometry.right()) {
x = screenGeometry.right() - keyboardSize.width();
}
if (x < screenGeometry.left()) {
x = screenGeometry.left();
}
if (y + keyboardSize.height() > screenGeometry.bottom()) {
// If no space below, position above the target widget
y = targetPos.y() - keyboardSize.height() - 10;
}
move(x, y);
}
void VirtualKeyboard::showEvent(QShowEvent* event)
{
QWidget::showEvent(event);
positionKeyboard();
}
void VirtualKeyboard::hideEvent(QHideEvent* event)
{
QWidget::hideEvent(event);
m_targetWidget = nullptr;
}
// Slot implementations
void VirtualKeyboard::onKeyPressed()
{
QPushButton* button = qobject_cast<QPushButton*>(sender());
if (!button) return;
QString text = button->text();
insertTextToTarget(text);
// Reset shift after key press (but not caps lock)
if (m_shift && !m_capsLock) {
m_shift = false;
updateKeyLabels();
}
}
void VirtualKeyboard::onBackspacePressed()
{
if (!m_targetWidget) return;
if (QLineEdit* lineEdit = qobject_cast<QLineEdit*>(m_targetWidget)) {
lineEdit->backspace();
} else if (QTextEdit* textEdit = qobject_cast<QTextEdit*>(m_targetWidget)) {
QTextCursor cursor = textEdit->textCursor();
cursor.deletePreviousChar();
textEdit->setTextCursor(cursor);
}
}
void VirtualKeyboard::onSpacePressed()
{
insertTextToTarget(" ");
// Reset shift after space (but not caps lock)
if (m_shift && !m_capsLock) {
m_shift = false;
updateKeyLabels();
}
}
void VirtualKeyboard::onEnterPressed()
{
insertTextToTarget("\n");
// Reset shift after enter (but not caps lock)
if (m_shift && !m_capsLock) {
m_shift = false;
updateKeyLabels();
}
}
void VirtualKeyboard::onShiftPressed()
{
m_shift = !m_shift;
updateKeyLabels();
}
void VirtualKeyboard::onCapsLockPressed()
{
m_capsLock = !m_capsLock;
// If caps lock is on, turn off shift
if (m_capsLock) {
m_shift = false;
}
updateKeyLabels();
}

View File

@ -0,0 +1,73 @@
#ifndef VIRTUALKEYBOARD_HPP
#define VIRTUALKEYBOARD_HPP
#include <QWidget>
#include <QGridLayout>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QTextEdit>
#include <QApplication>
#include <QDesktopWidget>
class VirtualKeyboard : public QWidget
{
Q_OBJECT
public:
explicit VirtualKeyboard(QWidget* parent = nullptr);
~VirtualKeyboard();
void setTargetWidget(QWidget* target);
void showForWidget(QWidget* target);
void hideKeyboard();
public slots:
void onKeyPressed();
void onBackspacePressed();
void onSpacePressed();
void onEnterPressed();
void onShiftPressed();
void onCapsLockPressed();
protected:
void showEvent(QShowEvent* event) override;
void hideEvent(QHideEvent* event) override;
private:
void setupKeyboard();
void setupAlphabeticKeys();
void setupNumericKeys();
void setupFunctionKeys();
void applyKeyboardStyling();
void updateKeyLabels();
void insertTextToTarget(const QString& text);
void positionKeyboard();
QVBoxLayout* m_mainLayout;
QGridLayout* m_keyboardLayout;
QHBoxLayout* m_functionLayout;
QWidget* m_targetWidget;
// Keyboard state
bool m_capsLock;
bool m_shift;
// Key buttons
QList<QPushButton*> m_alphabeticKeys;
QList<QPushButton*> m_numericKeys;
QPushButton* m_spaceButton;
QPushButton* m_backspaceButton;
QPushButton* m_enterButton;
QPushButton* m_shiftButton;
QPushButton* m_capsLockButton;
QPushButton* m_hideButton;
// Key layouts
QStringList m_qwertyLayout;
QStringList m_numericLayout;
};
#endif // VIRTUALKEYBOARD_HPP