rajout de la majorité des fonctions
This commit is contained in:
parent
1a76d817d6
commit
2bbae40800
4
.gitignore
vendored
4
.gitignore
vendored
@ -24,4 +24,6 @@ CMakeUserPresets.json
|
|||||||
|
|
||||||
build
|
build
|
||||||
|
|
||||||
data
|
data
|
||||||
|
.vscode
|
||||||
|
build.sh
|
@ -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)
|
||||||
|
@ -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