rajout de la majorité des fonctions
This commit is contained in:
parent
1a76d817d6
commit
2bbae40800
2
.gitignore
vendored
2
.gitignore
vendored
@ -25,3 +25,5 @@ CMakeUserPresets.json
|
||||
build
|
||||
|
||||
data
|
||||
.vscode
|
||||
build.sh
|
@ -1,20 +1,51 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(stock_manager)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
find_package(Qt5 REQUIRED COMPONENTS Widgets)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
|
||||
include_directories(include src)
|
||||
|
||||
add_executable(stock_manager
|
||||
main.cpp
|
||||
src/stockmanager.cpp
|
||||
set(SOURCES
|
||||
src/main.cpp
|
||||
src/view/abstractView.cpp
|
||||
src/controller/stockController.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
|
||||
Qt5::Widgets
|
||||
nlohmann_json::nlohmann_json
|
||||
set(HEADERS
|
||||
src/view/abstractView.hpp
|
||||
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)
|
||||
|
@ -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
|
14
main.cpp
14
main.cpp
@ -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();
|
||||
}
|
11
src/controller/command.cpp
Normal file
11
src/controller/command.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
enum Command
|
||||
{
|
||||
None,
|
||||
Stop,
|
||||
Refresh,
|
||||
CreateStock,
|
||||
ShowStocks,
|
||||
CreateItemType,
|
||||
ShowItemTypes,
|
||||
AddItemToStock
|
||||
};
|
16
src/controller/command.hpp
Normal file
16
src/controller/command.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef COMMAND_HPP
|
||||
#define COMMAND_HPP
|
||||
|
||||
enum Command
|
||||
{
|
||||
None,
|
||||
Stop,
|
||||
Refresh,
|
||||
CreateStock,
|
||||
ShowStocks,
|
||||
CreateItemType,
|
||||
ShowItemTypes,
|
||||
AddItemToStock
|
||||
};
|
||||
|
||||
#endif // COMMAND_HPP
|
189
src/controller/stockController.cpp
Normal file
189
src/controller/stockController.cpp
Normal 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;
|
||||
}
|
51
src/controller/stockController.hpp
Normal file
51
src/controller/stockController.hpp
Normal 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
|
3
src/errors/invaldiItemType.cpp
Normal file
3
src/errors/invaldiItemType.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include "invalidItemType.hpp"
|
||||
|
||||
// Le constructeur est défini inline dans le header
|
13
src/errors/invalidItemType.hpp
Normal file
13
src/errors/invalidItemType.hpp
Normal 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
|
3
src/errors/stockEmpty.cpp
Normal file
3
src/errors/stockEmpty.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include "stockEmpty.hpp"
|
||||
|
||||
// Le constructeur est défini inline dans le header
|
13
src/errors/stockEmpty.hpp
Normal file
13
src/errors/stockEmpty.hpp
Normal 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
3
src/errors/stockFull.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include "stockFull.hpp"
|
||||
|
||||
// Le constructeur est défini inline dans le header
|
13
src/errors/stockFull.hpp
Normal file
13
src/errors/stockFull.hpp
Normal 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
57
src/main.cpp
Normal 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
24
src/mainQt.cpp
Normal 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
15
src/model/itemType.cpp
Normal 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
24
src/model/itemType.hpp
Normal 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
96
src/model/model.cpp
Normal 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
37
src/model/model.hpp
Normal 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
83
src/model/stock.cpp
Normal 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
36
src/model/stock.hpp
Normal 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
|
@ -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));
|
||||
}
|
||||
}
|
@ -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
|
3
src/view/abstractView.cpp
Normal file
3
src/view/abstractView.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include "abstractView.hpp"
|
||||
|
||||
AbstractView::~AbstractView() = default;
|
32
src/view/abstractView.hpp
Normal file
32
src/view/abstractView.hpp
Normal 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
1071
src/view/qtView.cpp
Normal file
File diff suppressed because it is too large
Load Diff
142
src/view/qtView.hpp
Normal file
142
src/view/qtView.hpp
Normal 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
571
src/view/terminalView.cpp
Normal 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
98
src/view/terminalView.hpp
Normal 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
|
469
src/view/virtualKeyboard.cpp
Normal file
469
src/view/virtualKeyboard.cpp
Normal 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();
|
||||
}
|
73
src/view/virtualKeyboard.hpp
Normal file
73
src/view/virtualKeyboard.hpp
Normal 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
|
Loading…
x
Reference in New Issue
Block a user