diff --git a/.gitignore b/.gitignore
index 687c4d1d..9777fe96 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,6 @@
#Ignoring Intellij workspace specific folders and files
/**/.idea/workspace.xml
/**/tasks.xml
-/**/*.iml
/**/.idea/libraries
diff --git a/Workspace/client/client.iml b/Workspace/client/client.iml
new file mode 100644
index 00000000..b561a70c
--- /dev/null
+++ b/Workspace/client/client.iml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Workspace/client/src/main/java/com/pqt/client/Main.java b/Workspace/client/src/main/java/com/pqt/client/Main.java
new file mode 100644
index 00000000..c7240576
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/Main.java
@@ -0,0 +1,50 @@
+package com.pqt.client;
+
+import com.pqt.client.gui.main_frame.MainFrame;
+import com.pqt.client.gui.modules.account_screen.AccountScreen;
+import com.pqt.client.gui.modules.sale_screen.SaleScreen;
+import com.pqt.client.gui.modules.stat_screen.StatScreen;
+import com.pqt.client.gui.modules.stock_screen.StockScreen;
+import com.pqt.client.gui.ressources.components.generics.others.SideBar;
+import com.pqt.client.gui.ressources.components.generics.others.listeners.ISideBarListener;
+import com.pqt.client.gui.ressources.components.generics.toast.ToastFactory;
+import com.pqt.client.gui.ressources.css.GUICssTool;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.client.module.account.AccountService;
+import com.pqt.client.module.sale.SaleService;
+import com.pqt.client.module.stat.StatService;
+import com.pqt.client.module.stock.StockService;
+import javafx.application.Application;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+
+public class Main extends Application{
+
+ public static void main(String[] args){
+ launch(args);
+ }
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ SaleService saleService = new SaleService();
+ StockService stockService = new StockService();
+ AccountService accountService = new AccountService();
+ StatService statService = new StatService();
+
+ MainFrame mainFrame = new MainFrame(accountService);
+ mainFrame.addModule(new SaleScreen(accountService, stockService, saleService), true);
+ mainFrame.addModule(new StockScreen(stockService, accountService));
+ mainFrame.addModule(new StatScreen(statService));
+ mainFrame.addModule(new AccountScreen(accountService));
+
+
+ Scene scene = new Scene(mainFrame.getPane(), 800, 600);
+ scene.getStylesheets().clear();
+ scene.getStylesheets().addAll(getClass().getResource(GUICssTool.getCssFilePath()).toExternalForm());
+
+ ToastFactory.init(primaryStage);
+ primaryStage.setTitle(GUIStringTool.getAppTitle());
+ primaryStage.setScene(scene);
+ primaryStage.show();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrame.java b/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrame.java
new file mode 100644
index 00000000..4ded52f6
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrame.java
@@ -0,0 +1,35 @@
+package com.pqt.client.gui.main_frame;
+
+import com.pqt.client.gui.modules.IGuiModule;
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.client.module.account.AccountService;
+import javafx.scene.layout.Pane;
+
+public class MainFrame implements IFXComponent {
+
+ private MainFrameView view;
+ private MainFrameController ctrl;
+
+ public MainFrame(AccountService accountService) {
+ MainFrameModel model = new MainFrameModel(accountService);
+ ctrl = new MainFrameController(model);
+ model.addListener(ctrl);
+
+ view = new MainFrameView(ctrl);
+ ctrl.setView(view);
+ ctrl.updateView();
+ }
+
+ public void addModule(IGuiModule module, boolean setActive){
+ ctrl.addModule(module, setActive);
+ }
+
+ public void addModule(IGuiModule module){
+ ctrl.addModule(module, false);
+ }
+
+ @Override
+ public Pane getPane() {
+ return view.getPane();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrameController.java b/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrameController.java
new file mode 100644
index 00000000..180f7802
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrameController.java
@@ -0,0 +1,94 @@
+package com.pqt.client.gui.main_frame;
+
+import com.pqt.client.gui.main_frame.listeners.IMainFrameModelListener;
+import com.pqt.client.gui.modules.IGuiModule;
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener;
+import com.pqt.client.gui.ressources.components.specifics.account.listeners.IAccountComponentListener;
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.event.Event;
+
+class MainFrameController implements IMainFrameModelListener {
+
+ private MainFrameModel model;
+ private MainFrameView view;
+ private IValidatorComponentListener accountManagerAccountListener;
+
+ MainFrameController(MainFrameModel model) {
+ this.model = model;
+ }
+
+ void setView(MainFrameView view) {
+ this.view = view;
+ }
+
+ void updateView(){
+ view.feedAccountCollectionToManager(model.getAccounts());
+ view.setCurrentAccount(model.getCurrentAccount());
+ if(model.getCurrentAccount()!=null)
+ view.updateModuleButtonLock(model.getCurrentAccount().getPermissionLevel());
+ else
+ view.updateModuleButtonLock(AccountLevel.getLowest());
+ }
+
+ void addModule(IGuiModule module, boolean activationRequired) {
+ boolean activate = activationRequired
+ && model.getCurrentAccount()!=null
+ && model.getCurrentAccount().getPermissionLevel().compareTo(module.getLowestRequiredAccountLevel())>=0;
+ this.view.addGuiModule(module.getModuleName(),module.getPane(), module.getLowestRequiredAccountLevel(), activate);
+ }
+
+ IValidatorComponentListener getAccountManagerValidatorListener() {
+ return new IValidatorComponentListener() {
+ @Override
+ public void onValidationEvent() {
+ if(view.isAccountCreationPossible())
+ model.connectAccount(view.create());
+ }
+
+ @Override
+ public void onCancelEvent() {
+ model.disconnectCurrentAccount();
+ }
+ };
+ }
+
+ IAccountComponentListener getAccountManagerAccountListener() {
+ return new IAccountComponentListener() {
+ @Override
+ public void onRefreshContentRequestEvent() {
+
+ }
+
+ @Override
+ public void onContentClickEvent(Event event, Account eventTarget) {
+
+ }
+
+ @Override
+ public void onAddContentRequestEvent() {
+
+ }
+
+ @Override
+ public void onRemoveContentRequestEvent(Account content) {
+
+ }
+
+ @Override
+ public void onDetailContentRequestEvent(Account content) {
+
+ }
+ };
+ }
+
+ @Override
+ public void onAccountStatusChangedEvent(boolean status) {
+ updateView();
+ }
+
+ @Override
+ public void onAccountCollectionChangedEvent() {
+ updateView();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrameModel.java b/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrameModel.java
new file mode 100644
index 00000000..c8cb5fc7
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrameModel.java
@@ -0,0 +1,65 @@
+package com.pqt.client.gui.main_frame;
+
+import com.pqt.client.gui.main_frame.listeners.IMainFrameModelListener;
+import com.pqt.client.module.account.AccountService;
+import com.pqt.client.module.account.listeners.IAccountListener;
+import com.pqt.core.entities.user_account.Account;
+
+import javax.swing.event.EventListenerList;
+import java.util.Arrays;
+import java.util.Collection;
+
+class MainFrameModel {
+
+ private EventListenerList listenerList;
+ private AccountService accountService;
+
+ MainFrameModel(AccountService accountService) {
+ listenerList = new EventListenerList();
+ this.accountService = accountService;
+ this.accountService.addListener(new IAccountListener() {
+ @Override
+ public void onAccountStatusChangedEvent(boolean status) {
+ MainFrameModel.this.fireAccountStatusChangedEvent(status);
+ }
+
+ @Override
+ public void onAccountListChangedEvent() {
+ MainFrameModel.this.fireAccountCollectionChangedEvent();
+ }
+ });
+ }
+
+ private void fireAccountCollectionChangedEvent() {
+ Arrays.stream(listenerList.getListeners(IMainFrameModelListener.class)).forEach(IMainFrameModelListener::onAccountCollectionChangedEvent);
+ }
+
+ private void fireAccountStatusChangedEvent(boolean status) {
+ Arrays.stream(listenerList.getListeners(IMainFrameModelListener.class)).forEach(l->l.onAccountStatusChangedEvent(status));
+ }
+
+ void connectAccount(Account account) {
+ accountService.setCurrentAccount(account);
+ accountService.logInCurrentAccount(account.getPassword());
+ }
+
+ void disconnectCurrentAccount() {
+ accountService.logOutCurrentAccount();
+ }
+
+ Collection getAccounts(){
+ return accountService.getAllAccounts();
+ }
+
+ void addListener(IMainFrameModelListener listener){
+ listenerList.add(IMainFrameModelListener.class, listener);
+ }
+
+ void removeListener(IMainFrameModelListener listener){
+ listenerList.remove(IMainFrameModelListener.class, listener);
+ }
+
+ Account getCurrentAccount() {
+ return accountService.getCurrentAccount();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrameView.java b/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrameView.java
new file mode 100644
index 00000000..7b951581
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/MainFrameView.java
@@ -0,0 +1,142 @@
+package com.pqt.client.gui.main_frame;
+
+import com.pqt.client.gui.ressources.components.AccountManager;
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.client.gui.ressources.components.generics.others.SideBar;
+import com.pqt.client.gui.ressources.components.generics.others.listeners.ISideBarListener;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.application.Platform;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.value.ObservableValue;
+import javafx.geometry.Orientation;
+import javafx.scene.Node;
+import javafx.scene.control.Button;
+import javafx.scene.control.ToolBar;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.MouseButton;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.VBox;
+
+import java.util.Collection;
+
+class MainFrameView implements IFXComponent{
+
+ private final MainFrameController ctrl;
+
+ private BorderPane mainPane;
+ private AccountManager accountManager;
+ private VBox buttonHolder;
+ private ObjectProperty currentAccountLevel;
+
+ MainFrameView(MainFrameController ctrl) {
+ this.ctrl = ctrl;
+ currentAccountLevel = new SimpleObjectProperty<>(AccountLevel.getLowest());
+ initGui();
+ }
+
+ private void initGui(){
+ mainPane = new BorderPane();
+ mainPane.getStyleClass().addAll("main-module-pane", "main-frame");
+
+ buttonHolder = new VBox();
+
+ SideBar sidebar = new SideBar();
+ sidebar.setFillWidth(true);
+ SideBar.setVgrow(buttonHolder, Priority.ALWAYS);
+ buttonHolder.prefWidthProperty().bind(sidebar.widthProperty());
+ sidebar.getChildren().add(buttonHolder);
+
+ accountManager = new AccountManager();
+ accountManager.addListener(ctrl.getAccountManagerValidatorListener());
+ accountManager.addListener(ctrl.getAccountManagerAccountListener());
+ accountManager.getPane().prefWidthProperty().bind(sidebar.widthProperty());
+ sidebar.getChildren().add(accountManager.getPane());
+
+ mainPane.setLeft(sidebar);
+
+ Button sidebarCtrl = new Button();
+ if(sidebar.isExpanded())
+ sidebarCtrl.setText(GUIStringTool.getSideBarCollapseButtonLabel());
+ else
+ sidebarCtrl.setText(GUIStringTool.getSideBarExpandButtonLabel());
+ sidebarCtrl.setOnMouseClicked(event -> {
+ if(sidebar.isExpanded())
+ sidebar.collapse();
+ else if(sidebar.isCollapsed())
+ sidebar.expand();
+ });
+ sidebar.addListener(new ISideBarListener() {
+ @Override
+ public void onCollapsedFinished() {
+ sidebarCtrl.setText(GUIStringTool.getSideBarExpandButtonLabel());
+ }
+
+ @Override
+ public void onExpandFinished() {
+ sidebarCtrl.setText(GUIStringTool.getSideBarCollapseButtonLabel());
+ }
+ });
+ mainPane.setTop(sidebarCtrl);
+ }
+
+ @Override
+ public Pane getPane() {
+ return mainPane;
+ }
+
+ void addGuiModule(String moduleName, Pane moduleContent, AccountLevel requiredLevel, boolean setActive){
+ Button button = new Button(moduleName);
+ button.getStyleClass().add("menu-button");
+
+ Runnable buttonActivationCode = ()->{
+ buttonHolder.getChildren()
+ .stream()
+ .filter(Button.class::isInstance)
+ .map(Button.class::cast)
+ .forEach(b-> b.getStyleClass().remove("menu-button-selected"));
+ button.getStyleClass().add("menu-button-selected");
+ Platform.runLater(()->{
+ buttonHolder.getChildren().forEach(Node::applyCss);
+ mainPane.setCenter(moduleContent);
+ });
+ };
+ button.setOnMouseClicked(event-> {
+ if(event.getButton().equals(MouseButton.PRIMARY))
+ buttonActivationCode.run();
+ });
+ button.setOnKeyTyped(event->{
+ if (event.getCode().equals(KeyCode.ENTER))
+ buttonActivationCode.run();
+ });
+ currentAccountLevel.addListener((obs, oldVal, newVal)->button.setDisable(requiredLevel.compareTo(newVal)>0));
+ button.setDisable(requiredLevel.compareTo(currentAccountLevel.get())>0);
+ if(setActive)
+ buttonActivationCode.run();
+ buttonHolder.getChildren().add(button);
+ }
+
+ boolean isAccountCreationPossible(){
+ return accountManager.isCreationPossible();
+ }
+
+ Account create(){
+ return accountManager.create();
+ }
+
+ void setCurrentAccount(Account account){
+ accountManager.setCurrentAccount(account);
+ }
+
+ void feedAccountCollectionToManager(Collection accounts){
+ accountManager.display(accounts);
+ }
+
+ void updateModuleButtonLock(AccountLevel level) {
+ currentAccountLevel.setValue(level);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/listeners/IMainFrameModelListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/listeners/IMainFrameModelListener.java
new file mode 100644
index 00000000..5c876e26
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/main_frame/listeners/IMainFrameModelListener.java
@@ -0,0 +1,8 @@
+package com.pqt.client.gui.main_frame.listeners;
+
+import java.util.EventListener;
+
+public interface IMainFrameModelListener extends EventListener{
+ void onAccountStatusChangedEvent(boolean status);
+ void onAccountCollectionChangedEvent();
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/IGuiModule.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/IGuiModule.java
new file mode 100644
index 00000000..e4dfa3d2
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/IGuiModule.java
@@ -0,0 +1,9 @@
+package com.pqt.client.gui.modules;
+
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.core.entities.user_account.AccountLevel;
+
+public interface IGuiModule extends IFXComponent{
+ String getModuleName();
+ AccountLevel getLowestRequiredAccountLevel();
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreen.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreen.java
new file mode 100644
index 00000000..ceee3d9e
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreen.java
@@ -0,0 +1,36 @@
+package com.pqt.client.gui.modules.account_screen;
+
+import com.pqt.client.gui.modules.IGuiModule;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.client.module.account.AccountService;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.scene.layout.Pane;
+
+public class AccountScreen implements IGuiModule {
+
+ private AccountScreenView view;
+
+ public AccountScreen(AccountService accountService) {
+ AccountScreenModel model = new AccountScreenModel(accountService);
+ AccountScreenController ctrl = new AccountScreenController(model);
+ view = new AccountScreenView(ctrl);
+
+ ctrl.setView(view);
+ ctrl.updateView();
+ }
+
+ @Override
+ public String getModuleName() {
+ return GUIStringTool.getAccountGuiModuleName();
+ }
+
+ @Override
+ public AccountLevel getLowestRequiredAccountLevel() {
+ return AccountLevel.WAITER;
+ }
+
+ @Override
+ public Pane getPane() {
+ return view.getPane();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreenController.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreenController.java
new file mode 100644
index 00000000..4cb8f15f
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreenController.java
@@ -0,0 +1,83 @@
+package com.pqt.client.gui.modules.account_screen;
+
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener;
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+
+class AccountScreenController {
+
+ private AccountScreenModel model;
+ private AccountScreenView view;
+
+ AccountScreenController(AccountScreenModel model) {
+ this.model = model;
+ }
+
+ void setView(AccountScreenView view) {
+ this.view = view;
+ }
+
+ void updateView() {
+ updateViewAccountCollection();
+ updateViewActionLock();
+ }
+
+ private void updateViewAccountCollection(){
+ view.setAccountCollection(model.getAccountCollection());
+ }
+
+ private void updateViewActionLock() {
+ if (model.getCurrentAccount() != null) {
+ view.setAddAccountActionLocked(AccountLevel.MASTER.compareTo(model.getCurrentAccount().getPermissionLevel()) > 0);
+ view.setDetailAccountActionLocked(!view.isItemSelected() || AccountLevel.MASTER.compareTo(model.getCurrentAccount().getPermissionLevel()) > 0);
+ view.setRemoveAccountActionLocked(!view.isItemSelected() || AccountLevel.MASTER.compareTo(model.getCurrentAccount().getPermissionLevel()) > 0);
+ }else{
+ view.setAddAccountActionLocked(true);
+ view.setDetailAccountActionLocked(true);
+ view.setRemoveAccountActionLocked(true);
+ }
+ }
+
+ IValidatorComponentListener getDetailScreenValidationListener(){
+ return new IValidatorComponentListener() {
+ @Override
+ public void onValidationEvent() {
+ if(view.isDetailCreationPossible()){
+ if(view.getDetailScreenInitialValue()!=null){
+ model.modifyAccount(view.getDetailScreenInitialValue(), view.getDetailScreenCreatedValue());
+ }else{
+ model.addAccount(view.getDetailScreenCreatedValue());
+ }
+ view.hideDetailScreen();
+ }
+ }
+
+ @Override
+ public void onCancelEvent() {
+ view.hideDetailScreen();
+ }
+ };
+ }
+
+ void onAddAccountRequested() {
+ view.showDetailScreen(null, model.getLevels());
+ }
+
+ void onDetailAccountRequested() {
+ if(view.isItemSelected())
+ view.showDetailScreen(view.getSelectedItem(), model.getLevels());
+ }
+
+ void onRemoveAccountRequested() {
+ if(view.isItemSelected())
+ model.removeAccount(view.getSelectedItem());
+ }
+
+ void onRefreshAccountRequested() {
+ this.updateView();
+ }
+
+ void onSelectedAccountChanged(Account oldVal, Account newVal) {
+ updateViewActionLock();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreenModel.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreenModel.java
new file mode 100644
index 00000000..a1a129a0
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreenModel.java
@@ -0,0 +1,44 @@
+package com.pqt.client.gui.modules.account_screen;
+
+import com.pqt.client.module.account.AccountService;
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+
+import java.util.Collection;
+import java.util.EnumSet;
+
+//TODO MAJ les méthds modif, add et remove une fois que l'accountService prend en compte les modifs
+class AccountScreenModel {
+
+ private AccountService accountService;
+
+ AccountScreenModel(AccountService accountService) {
+ this.accountService = accountService;
+ }
+
+ void modifyAccount(Account oldVal, Account newVal) {
+ //accountService.submitAccountUpdate(oldVal, newVal);
+ }
+
+ void addAccount(Account newVal) {
+ //accountService.submitAccountUpdate(null, newVal);
+ }
+
+ void removeAccount(Account oldVal) {
+ //accountService.submitAccountUpdate(oldVal, null);
+ }
+
+ Collection getAccountCollection() {
+ return accountService.getAllAccounts();
+ }
+
+ Account getCurrentAccount() {
+ return accountService.getCurrentAccount();
+ }
+
+ Collection getLevels() {
+ //TODO régler ça aussi
+ //return accountService.getAvailableLevels();
+ return EnumSet.allOf(AccountLevel.class);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreenView.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreenView.java
new file mode 100644
index 00000000..71a067fc
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/AccountScreenView.java
@@ -0,0 +1,178 @@
+package com.pqt.client.gui.modules.account_screen;
+
+import com.pqt.client.gui.modules.account_screen.account_manager_screen.AccountManagerScreen;
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.client.gui.ressources.css.GUICssTool;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.application.Platform;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.scene.Node;
+import javafx.scene.control.*;
+import javafx.scene.input.MouseButton;
+import javafx.scene.layout.*;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+class AccountScreenView implements IFXComponent{
+
+ private AccountScreenController ctrl;
+ private StackPane mainPane;
+ private BorderPane mainPaneContent;
+ private TableView tableView;
+ private AccountManagerScreen accountManagerScreen;
+
+ private Button addAccountButton, detailAccountButton, removeAccountButton;
+
+
+ AccountScreenView(AccountScreenController ctrl) {
+ this.ctrl = ctrl;
+ initGui();
+ }
+
+ private void initGui() {
+ mainPane = new StackPane();
+ mainPane.getStyleClass().add(GUICssTool.getMainModulePaneCssClass());
+
+ mainPaneContent = new BorderPane();
+
+ tableView = new TableView<>();
+
+ tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
+ tableView.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal)-> ctrl.onSelectedAccountChanged(oldVal, newVal));
+ TableColumn nameColumn = new TableColumn<>(GUIStringTool.getAccountNameColumnHeaderLabel());
+ nameColumn.setCellValueFactory(param -> new SimpleStringProperty(param.getValue().getUsername()));
+ tableView.getColumns().add(nameColumn);
+
+ TableColumn levelColumn = new TableColumn<>(GUIStringTool.getAccountLevelColumnHeaderLabel());
+ levelColumn.setCellValueFactory(param -> new SimpleStringProperty(
+ GUIStringTool.getAccountLevelStringRenderer().render(param.getValue().getPermissionLevel())
+ ));
+ tableView.getColumns().add(levelColumn);
+ mainPaneContent.setCenter(tableView);
+
+ HBox mainPaneTopContent = new HBox();
+ mainPaneTopContent.setFillHeight(true);
+
+ Label label = new Label(GUIStringTool.getAccountListTitleLabel());
+ label.getStyleClass().add(GUICssTool.getTitleTextStyleClass());
+ mainPaneTopContent.getChildren().add(label);
+
+ HBox separator = new HBox();
+ ToolBar buttonToolbar = new ToolBar();
+ addAccountButton = new Button(GUIStringTool.getAddButtonLabel());
+ addAccountButton.setOnMouseClicked(event->{
+ if (event.getButton().equals(MouseButton.PRIMARY))
+ ctrl.onAddAccountRequested();
+ });
+ buttonToolbar.getItems().add(addAccountButton);
+ detailAccountButton = new Button(GUIStringTool.getDetailButtonLabel());
+ detailAccountButton.setOnMouseClicked(event->{
+ if (event.getButton().equals(MouseButton.PRIMARY))
+ ctrl.onDetailAccountRequested();
+ });
+ buttonToolbar.getItems().add(detailAccountButton);
+ removeAccountButton = new Button(GUIStringTool.getRemoveButtonLabel());
+ removeAccountButton.setOnMouseClicked(event->{
+ if (event.getButton().equals(MouseButton.PRIMARY))
+ ctrl.onRemoveAccountRequested();
+ });
+ buttonToolbar.getItems().add(removeAccountButton);
+ Button refreshAccountButton = new Button(GUIStringTool.getRefreshButtonLabel());
+ refreshAccountButton.setOnMouseClicked(event->{
+ if (event.getButton().equals(MouseButton.PRIMARY))
+ ctrl.onRefreshAccountRequested();
+ });
+ buttonToolbar.getItems().add(refreshAccountButton);
+
+ mainPaneTopContent.getChildren().addAll(separator, buttonToolbar);
+ HBox.setHgrow(separator, Priority.ALWAYS);
+
+ mainPaneContent.setTop(mainPaneTopContent);
+ mainPane.getChildren().add(mainPaneContent);
+ }
+
+ boolean isItemSelected(){
+ return tableView.getSelectionModel().getSelectedItem()!=null;
+ }
+
+ Account getSelectedItem(){
+ return tableView.getSelectionModel().getSelectedItem();
+ }
+
+ @Override
+ public Pane getPane() {
+ return mainPane;
+ }
+
+ boolean isDetailCreationPossible() {
+ return accountManagerScreen!=null && accountManagerScreen.isCreationPossible();
+ }
+
+ Account getDetailScreenInitialValue() {
+ if(accountManagerScreen!=null)
+ return accountManagerScreen.getInitialValue();
+ return null;
+ }
+
+ Account getDetailScreenCreatedValue() {
+ if(accountManagerScreen!=null)
+ return accountManagerScreen.create();
+ return null;
+ }
+
+ boolean isDetailScreenShown(){
+ return accountManagerScreen!=null;
+ }
+
+ void showDetailScreen(Account initialValue, Collection availableLevels){
+ if(!isDetailScreenShown()){
+ Pane separator = new Pane();
+ separator.getStyleClass().add(GUICssTool.getIntermediaryPaneStyleClass());
+ accountManagerScreen = new AccountManagerScreen(initialValue, availableLevels);
+ accountManagerScreen.addListener(ctrl.getDetailScreenValidationListener());
+
+ Platform.runLater(()->{
+ mainPane.getChildren().addAll(separator, accountManagerScreen.getPane());
+ });
+ }
+ }
+
+ void hideDetailScreen(){
+ if(isDetailScreenShown()){
+ List toRemove = mainPane.getChildren()
+ .stream()
+ .filter(node->!node.equals(mainPaneContent))
+ .collect(Collectors.toList());
+
+ Platform.runLater(()->{
+ mainPane.getChildren().removeAll(toRemove);
+ accountManagerScreen = null;
+ });
+
+ }
+ }
+
+ void setAccountCollection(Collection accountCollection) {
+ Platform.runLater(()->{
+ tableView.getItems().clear();
+ if(accountCollection!=null)
+ tableView.getItems().addAll(accountCollection);
+ });
+ }
+
+ void setAddAccountActionLocked(boolean locked) {
+ addAccountButton.setDisable(locked);
+ }
+
+ void setDetailAccountActionLocked(boolean locked) {
+ detailAccountButton.setDisable(locked);
+ }
+
+ void setRemoveAccountActionLocked(boolean locked) {
+ removeAccountButton.setDisable(locked);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreen.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreen.java
new file mode 100644
index 00000000..26cd33e2
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreen.java
@@ -0,0 +1,56 @@
+package com.pqt.client.gui.modules.account_screen.account_manager_screen;
+
+import com.pqt.client.gui.ressources.components.generics.creators.IFXCreatorComponent;
+import com.pqt.client.gui.ressources.components.generics.validators.IFXValidatorComponent;
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener;
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.scene.layout.Pane;
+
+import java.util.Collection;
+
+//TODO à faire
+public class AccountManagerScreen implements IFXValidatorComponent, IFXCreatorComponent{
+
+ private AccountManagerScreenModel model;
+ private AccountManagerScreenView view;
+ private AccountManagerScreenController ctrl;
+
+ public AccountManagerScreen(Account initialValue, Collection availableLevels) {
+ model = new AccountManagerScreenModel(initialValue, availableLevels);
+ ctrl = new AccountManagerScreenController(model);
+ view = new AccountManagerScreenView(ctrl);
+
+ ctrl.setView(view);
+ ctrl.updateView();
+ }
+
+ public Account getInitialValue(){
+ return model.getInitialValue();
+ }
+
+ @Override
+ public Account create() {
+ return model.getCurrentValue();
+ }
+
+ @Override
+ public boolean isCreationPossible() {
+ return model.isCurrentValueValid();
+ }
+
+ @Override
+ public void addListener(IValidatorComponentListener l) {
+ ctrl.addListener(l);
+ }
+
+ @Override
+ public void removeListener(IValidatorComponentListener l) {
+ ctrl.removeListener(l);
+ }
+
+ @Override
+ public Pane getPane() {
+ return view.getPane();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreenController.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreenController.java
new file mode 100644
index 00000000..e3b6e000
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreenController.java
@@ -0,0 +1,58 @@
+package com.pqt.client.gui.modules.account_screen.account_manager_screen;
+
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener;
+import com.pqt.core.entities.user_account.AccountLevel;
+
+import javax.swing.event.EventListenerList;
+import java.util.Arrays;
+
+class AccountManagerScreenController {
+
+ private EventListenerList listenerList;
+ private AccountManagerScreenView view;
+ private AccountManagerScreenModel model;
+
+ AccountManagerScreenController(AccountManagerScreenModel model) {
+ listenerList = new EventListenerList();
+ this.model = model;
+ }
+
+ void setView(AccountManagerScreenView view) {
+ this.view = view;
+ }
+
+ void updateView() {
+ view.setLevelCollection(model.getAccountLevelCollection());
+ view.setData(model.getCurrentValue());
+ }
+
+ void addListener(IValidatorComponentListener l) {
+ listenerList.add(IValidatorComponentListener.class, l);
+ }
+
+ void removeListener(IValidatorComponentListener l) {
+ listenerList.remove(IValidatorComponentListener.class, l);
+ }
+
+ void onNameChanged(String oldVal, String newVal) {
+ model.changeName(newVal);
+ }
+
+ void onPasswordChanged(String oldVal, String newVal) {
+ model.changePassword(newVal);
+ }
+
+ void onLevelChanged(AccountLevel oldVal, AccountLevel newVal) {
+ model.changeLevel(newVal);
+ }
+
+ void onValidationEvent() {
+ Arrays.stream(listenerList.getListeners(IValidatorComponentListener.class))
+ .forEach(IValidatorComponentListener::onValidationEvent);
+ }
+
+ void onCancelEvent() {
+ Arrays.stream(listenerList.getListeners(IValidatorComponentListener.class))
+ .forEach(IValidatorComponentListener::onCancelEvent);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreenModel.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreenModel.java
new file mode 100644
index 00000000..e0dd15d0
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreenModel.java
@@ -0,0 +1,61 @@
+package com.pqt.client.gui.modules.account_screen.account_manager_screen;
+
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+class AccountManagerScreenModel {
+ private Account currentValue;
+ private Account initialValue;
+ private Set levels;
+
+ AccountManagerScreenModel(Account initialValue, Collection availableLevels) {
+ levels = new HashSet<>();
+ if(availableLevels!=null)
+ levels.addAll(availableLevels);
+ this.initialValue = initialValue;
+ this.currentValue = (initialValue!=null?new Account(initialValue):getNewAccount());
+ }
+
+ Account getCurrentValue() {
+ return currentValue;
+ }
+
+ Account getInitialValue() {
+ return initialValue;
+ }
+
+ boolean isCurrentValueValid() {
+ return !currentValue.equals(initialValue)
+ && currentValue.getUsername()!=null
+ && !currentValue.getUsername().isEmpty()
+ && currentValue.getPermissionLevel()!=null;
+ }
+
+ Collection getAccountLevelCollection(){
+ return levels;
+ }
+
+ void changeName(String username) {
+ currentValue.setUsername(username);
+ }
+
+ void changePassword(String password) {
+ currentValue.setPassword(password);
+ }
+
+ void changeLevel(AccountLevel level) {
+ currentValue.setPermissionLevel(level);
+ }
+
+ private Account getNewAccount() {
+ Account account = new Account();
+ account.setUsername("");
+ account.setPassword("");
+ account.setPermissionLevel(levels.stream().min(Enum::compareTo).orElse(AccountLevel.getLowest()));
+ return account;
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreenView.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreenView.java
new file mode 100644
index 00000000..3d9d6410
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/account_screen/account_manager_screen/AccountManagerScreenView.java
@@ -0,0 +1,107 @@
+package com.pqt.client.gui.modules.account_screen.account_manager_screen;
+
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.application.Platform;
+import javafx.geometry.Pos;
+import javafx.scene.control.*;
+import javafx.scene.input.MouseButton;
+import javafx.scene.layout.*;
+
+import java.util.Collection;
+
+
+class AccountManagerScreenView implements IFXComponent{
+
+ private StackPane mainPane;
+ private AccountManagerScreenController ctrl;
+
+ private ChoiceBox levelChoiceBox;
+ private TextField nameTextField;
+ private PasswordField passwordField;
+
+ AccountManagerScreenView(AccountManagerScreenController ctrl) {
+ this.ctrl = ctrl;
+ initGui();
+ }
+
+ private void initGui() {
+ mainPane = new StackPane();
+
+ BorderPane mainPaneContent = new BorderPane();
+
+
+ GridPane mainPaneCenterContent = new GridPane();
+ mainPaneCenterContent.setAlignment(Pos.CENTER);
+ Label nameLabel = new Label(GUIStringTool.getUsernameLabel());
+ nameTextField = new TextField();
+ nameTextField.textProperty().addListener((obs, oldVal, newVal)->ctrl.onNameChanged(oldVal, newVal));
+ mainPaneCenterContent.add(nameLabel, 0, 0);
+ mainPaneCenterContent.add(nameTextField, 1,0);
+
+ Label passwordLabel = new Label(GUIStringTool.getPasswordLabel());
+ passwordField = new PasswordField();
+ passwordField.textProperty().addListener((obs, oldVal, newVal)->ctrl.onPasswordChanged(oldVal, newVal));
+ mainPaneCenterContent.add(passwordLabel, 0, 1);
+ mainPaneCenterContent.add(passwordField, 1,1);
+
+ Label levelLabel = new Label(GUIStringTool.getUserLevelLabel());
+ levelChoiceBox = new ChoiceBox<>();
+ levelChoiceBox.valueProperty().addListener((obs, oldVal, newVal)->ctrl.onLevelChanged(oldVal, newVal));
+ mainPaneCenterContent.add(levelLabel, 0, 2);
+ mainPaneCenterContent.add(levelChoiceBox, 1,2);
+
+ mainPaneContent.setCenter(mainPaneCenterContent);
+
+ HBox mainPaneBottomContent = new HBox();
+ mainPaneBottomContent.setFillHeight(true);
+ Button validationButton = new Button(GUIStringTool.getValidationButtonLabel());
+ validationButton.setOnMouseClicked(event -> {
+ if (event.getButton().equals(MouseButton.PRIMARY))
+ ctrl.onValidationEvent();
+ });
+ Button cancelButton = new Button(GUIStringTool.getCancelButtonLabel());
+ cancelButton.setOnMouseClicked(event -> {
+ if (event.getButton().equals(MouseButton.PRIMARY))
+ ctrl.onCancelEvent();
+ });
+ HBox separator = new HBox();
+
+ mainPaneBottomContent.getChildren().addAll(separator, validationButton, cancelButton);
+ HBox.setHgrow(separator, Priority.ALWAYS);
+
+ mainPaneContent.setBottom(mainPaneBottomContent);
+ mainPane.getChildren().add(mainPaneContent);
+ }
+
+ @Override
+ public Pane getPane() {
+ return mainPane;
+ }
+
+ void setLevelCollection(Collection levelCollection) {
+ Platform.runLater(()->{
+ levelChoiceBox.getItems().clear();
+ levelChoiceBox.getItems().addAll(levelCollection);
+ });
+ }
+
+ void setData(Account data) {
+ Platform.runLater(()->{
+ if(data!=null){
+ nameTextField.setText(data.getUsername());
+ passwordField.setText(data.getPassword());
+ levelChoiceBox.setValue(data.getPermissionLevel());
+ }else{
+ nameTextField.setText("");
+ passwordField.setText("");
+ levelChoiceBox.setValue(levelChoiceBox.getItems()
+ .stream()
+ .min(Enum::compareTo)
+ .orElse(AccountLevel.getLowest()));
+ }
+ });
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreen.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreen.java
new file mode 100644
index 00000000..c1e72268
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreen.java
@@ -0,0 +1,39 @@
+package com.pqt.client.gui.modules.sale_screen;
+
+import com.pqt.client.gui.modules.IGuiModule;
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.client.module.account.AccountService;
+import com.pqt.client.module.sale.SaleService;
+import com.pqt.client.module.stock.StockService;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.scene.layout.Pane;
+
+public class SaleScreen implements IGuiModule {
+
+ private SaleScreenView view;
+
+ public SaleScreen(AccountService accountService, StockService stockService, SaleService saleService) {
+ SaleScreenModel model = new SaleScreenModel(accountService, stockService, saleService);
+ SaleScreenController ctrl = new SaleScreenController(model);
+ view = new SaleScreenView(ctrl);
+
+ ctrl.setView(view);
+ ctrl.updateView();
+ }
+
+ @Override
+ public Pane getPane() {
+ return view.getPane();
+ }
+
+ @Override
+ public String getModuleName() {
+ return GUIStringTool.getSaleGuiModuleName();
+ }
+
+ @Override
+ public AccountLevel getLowestRequiredAccountLevel() {
+ return AccountLevel.WAITER;
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreenController.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreenController.java
new file mode 100644
index 00000000..6640d324
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreenController.java
@@ -0,0 +1,191 @@
+package com.pqt.client.gui.modules.sale_screen;
+
+import com.pqt.client.gui.modules.sale_screen.listeners.ISaleScreenModelListener;
+import com.pqt.client.gui.modules.sale_screen.sale_validation_screen.listeners.ISaleValidationScreenListener;
+import com.pqt.client.gui.ressources.components.specifics.products.listeners.IStockComponentListener;
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener;
+import com.pqt.client.gui.ressources.components.specifics.sale.listeners.ISaleComponentListener;
+import com.pqt.core.entities.product.Product;
+import com.pqt.core.entities.sale.Sale;
+import com.pqt.core.entities.sale.SaleStatus;
+import com.pqt.core.entities.sale.SaleType;
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.event.Event;
+
+import java.util.List;
+
+class SaleScreenController {
+
+ private SaleScreenModel model;
+ private SaleScreenView view;
+
+ SaleScreenController(SaleScreenModel model) {
+ this.model = model;
+ this.model.addListener(new ISaleScreenModelListener() {
+ @Override
+ public void onSaleValidatedEvent() {
+ SaleScreenController.this.onSaleValidationSuccess();
+ }
+
+ @Override
+ public void onSaleNotValidatedEvent(SaleStatus status, Throwable cause) {
+ onSaleValidationError(status, cause);
+ }
+
+ @Override
+ public void onStockUpdatedEvent() {
+ view.setProducts(model.getProductList());
+ }
+
+ @Override
+ public void onAccountConnectedStateUpdatedEvent() {
+ updateActionLock();
+ }
+
+ @Override
+ public void onAccountListUpdatedEvent() {
+ view.setAccounts(model.getAccountList());
+ }
+
+
+ });
+ }
+
+ private void onSaleValidationSuccess() {
+ view.setSaleStatus(SaleStatus.ACCEPTED);
+ }
+
+ private void onSaleValidationError(SaleStatus status, Throwable cause) {
+ view.setSaleStatus(status);
+ }
+
+ void setView(SaleScreenView view) {
+ this.view = view;
+ }
+
+ void onAccountSelectedAsBeneficiary(Account account){
+ model.setSaleBeneficiary(account);
+ }
+
+ private Sale getCurrentSale(){
+ return model.getCurrentSale();
+ }
+
+ private void updateSale(){
+ view.setSale(getCurrentSale());
+ updateActionLock();
+ }
+
+ private void updateActionLock() {
+ boolean validationButtonEnabled = model.checkValidity(getCurrentSale())
+ && model.isCurrentAccountConnected()
+ && model.getCurrentAccountLevel().compareTo(AccountLevel.WAITER)>=0;
+ view.setValidationButtonEnabled(validationButtonEnabled);
+ }
+
+ private void updateData(){
+ view.setProducts(fetchProductList());
+ view.setSaleTypes(fetchSaleTypeList());
+ view.setAccounts(fetchAccountList());
+ }
+
+ void updateView(){
+ updateData();
+ updateSale();
+ }
+
+ private List fetchProductList(){
+ return model.getProductList();
+ }
+ private List fetchAccountList(){
+ return model.getAccountList();
+ }
+ private List fetchSaleTypeList(){
+ return model.getSaleTypeList();
+ }
+
+ ISaleComponentListener getSaleDisplayerListener() {
+ return new ISaleComponentListener() {
+ @Override
+ public void onComponentClickEvent(Event event, Product product) {
+ model.removeProductFromSale(product);
+ SaleScreenController.this.updateSale();
+ }
+
+ @Override
+ public void onRefreshContentRequestEvent() {}
+
+ @Override
+ public void onContentClickEvent(Event event, Sale eventTarget) {}
+
+ @Override
+ public void onAddContentRequestEvent() {}
+
+ @Override
+ public void onRemoveContentRequestEvent(Sale content) {}
+
+ @Override
+ public void onDetailContentRequestEvent(Sale content) {}
+ };
+ }
+
+ IStockComponentListener getStockDisplayerListener() {
+ return new IStockComponentListener() {
+ @Override
+ public void onRefreshContentRequestEvent() {}
+
+ @Override
+ public void onContentClickEvent(Event event, Product eventTarget) {
+ if(eventTarget!=null) {
+ model.addProductToSale(eventTarget);
+ SaleScreenController.this.updateSale();
+ }
+ }
+
+ @Override
+ public void onAddContentRequestEvent() {}
+
+ @Override
+ public void onRemoveContentRequestEvent(Product content) {}
+
+ @Override
+ public void onDetailContentRequestEvent(Product content) {}
+ };
+ }
+
+ Account getDefaultAccount() {
+ return new Account(null, null, AccountLevel.getLowest());
+ }
+
+ IValidatorComponentListener getValidatorListener() {
+ return new IValidatorComponentListener() {
+ @Override
+ public void onValidationEvent() {
+ if(model.commitSale())
+ view.switchToSaleValidationWaitingMode(model.getTempSaleId(), model.getCurrentSale());
+ }
+
+ @Override
+ public void onCancelEvent() {
+ model.clearSale();
+ SaleScreenController.this.updateView();
+ }
+ };
+ }
+
+ void onSaleTypeSelected(SaleType saleType) {
+ model.setSaleType(saleType);
+ }
+
+ ISaleValidationScreenListener getSaleValidationScreenListener() {
+ return saleValidatedSuccessfully -> {
+ view.switchToSaleCompositionMode();
+ if(saleValidatedSuccessfully){
+ model.clearSale();
+ }
+
+ updateView();
+ };
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreenModel.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreenModel.java
new file mode 100644
index 00000000..4cfc6d54
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreenModel.java
@@ -0,0 +1,225 @@
+package com.pqt.client.gui.modules.sale_screen;
+
+import com.pqt.client.gui.modules.sale_screen.listeners.ISaleScreenModelListener;
+import com.pqt.client.module.account.AccountService;
+import com.pqt.client.module.account.listeners.IAccountListener;
+import com.pqt.client.module.sale.SaleBuilder;
+import com.pqt.client.module.sale.SaleService;
+import com.pqt.client.module.sale.listeners.ISaleListener;
+import com.pqt.client.module.stock.Listeners.IStockListener;
+import com.pqt.client.module.stock.StockService;
+import com.pqt.core.entities.product.Product;
+import com.pqt.core.entities.sale.Sale;
+import com.pqt.core.entities.sale.SaleStatus;
+import com.pqt.core.entities.sale.SaleType;
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+
+import javax.swing.event.EventListenerList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+class SaleScreenModel {
+
+ private EventListenerList listeners;
+
+ private AccountService accountService;
+ private StockService stockService;
+ private SaleService saleService;
+
+ private SaleBuilder currentSaleBuilder;
+ private long tempSaleId;
+
+ SaleScreenModel(AccountService accountService, StockService stockService, SaleService saleService) {
+ if(accountService==null || stockService==null || saleService==null)
+ throw new NullPointerException("At least one of the following services is null : account, stock, sale");
+
+ listeners = new EventListenerList();
+ this.accountService = accountService;
+ this.stockService = stockService;
+ this.saleService = saleService;
+
+ saleService.addListener(new ISaleListener() {
+ @Override
+ public void onSaleValidationSuccess(long saleId) {
+ if(saleId == SaleScreenModel.this.tempSaleId){
+ SaleScreenModel.this.fireSaleValidatedEvent();
+ }
+ }
+
+ @Override
+ public void onSaleValidationError(long saleId, Throwable cause) {
+ if(saleId == SaleScreenModel.this.tempSaleId){
+ SaleScreenModel.this.fireSaleNotValidatedEvent(SaleStatus.ABORTED, cause);
+ }
+ }
+
+ @Override
+ public void onSaleValidationRefused(long saleId, Throwable cause) {
+ if(saleId == SaleScreenModel.this.tempSaleId){
+ SaleScreenModel.this.fireSaleNotValidatedEvent(SaleStatus.REFUSED, cause);
+ }
+ }
+ });
+ stockService.addListener(new IStockListener() {
+ @Override
+ public void onGetProductListSuccessEvent() {
+
+ }
+
+ @Override
+ public void onGetProductListErrorEvent(Throwable cause) {
+
+ }
+
+ @Override
+ public void onGetProductListRefusedEvent(Throwable cause) {
+
+ }
+
+ @Override
+ public void onProductListUpdateSuccessEvent(long id) {
+
+ }
+
+ @Override
+ public void onProductListUpdateErrorEvent(long id, Throwable cause) {
+
+ }
+
+ @Override
+ public void onProductListUpdateRefusedEvent(long id, Throwable cause) {
+
+ }
+
+ @Override
+ public void onProductListChangedEvent() {
+ fireStockUpdatedEvent();
+ }
+ });
+ accountService.addListener(new IAccountListener() {
+ @Override
+ public void onAccountStatusChangedEvent(boolean status) {
+ fireAccountConnectedStatusUpdateEvent();
+ }
+
+ @Override
+ public void onAccountListChangedEvent() {
+ fireAccountListUpdatedEvent();
+ }
+ });
+
+ clearSale();
+ }
+
+ private void fireSaleValidatedEvent() {
+ Arrays.stream(listeners.getListeners(ISaleScreenModelListener.class))
+ .forEach(ISaleScreenModelListener::onSaleValidatedEvent);
+ }
+
+ private void fireSaleNotValidatedEvent(SaleStatus status, Throwable cause) {
+ Arrays.stream(listeners.getListeners(ISaleScreenModelListener.class))
+ .forEach(l->l.onSaleNotValidatedEvent(status, cause));
+ }
+
+ private void fireStockUpdatedEvent(){
+ Arrays.stream(listeners.getListeners(ISaleScreenModelListener.class))
+ .forEach(ISaleScreenModelListener::onStockUpdatedEvent);
+ }
+
+ private void fireAccountListUpdatedEvent(){
+ Arrays.stream(listeners.getListeners(ISaleScreenModelListener.class))
+ .forEach(ISaleScreenModelListener::onAccountListUpdatedEvent);
+ }
+
+ private void fireAccountConnectedStatusUpdateEvent() {
+ Arrays.stream(listeners.getListeners(ISaleScreenModelListener.class))
+ .forEach(ISaleScreenModelListener::onAccountConnectedStateUpdatedEvent);
+ }
+
+ List getAccountList() {
+ return accountService.getAllAccounts();
+ }
+
+ List getSaleTypeList() {
+ return saleService.getSaleTypes();
+ }
+
+ Sale getCurrentSale() {
+ return currentSaleBuilder!=null?currentSaleBuilder.build():null;
+ }
+
+ List getProductList() {
+ return stockService.getProducts().stream().filter(Product::isSellable).collect(Collectors.toList());
+ }
+
+ void clearSale() {
+ currentSaleBuilder = getNewSaleBuilder();
+ tempSaleId = -1;
+ }
+
+ private SaleBuilder getNewSaleBuilder(){
+ SaleBuilder saleBuilder = saleService.getNewSaleBuilder();
+ saleBuilder.orderedBy(accountService.getCurrentAccount());
+ saleBuilder.saleType(SaleType.CASH);
+ return saleBuilder;
+ }
+
+ boolean commitSale() {
+ if(!checkValidity(currentSaleBuilder.build()))
+ return false;
+
+ tempSaleId = saleService.commitSale(currentSaleBuilder);
+ return tempSaleId!=-1;
+ }
+
+ boolean checkValidity(Sale sale) {
+ return sale.getProducts().size()>0
+ && sale.getOrderedBy()!=null
+ && sale.getType()!=null;
+ }
+
+ long getTempSaleId(){
+ return tempSaleId;
+ }
+
+ void addProductToSale(Product product) {
+ if(currentSaleBuilder!=null)
+ currentSaleBuilder.addProduct(product);
+ }
+
+ void removeProductFromSale(Product product) {
+ if(currentSaleBuilder!=null)
+ currentSaleBuilder.removeProduct(product);
+ }
+
+ void setSaleType(SaleType saleType) {
+ if(currentSaleBuilder!=null)
+ currentSaleBuilder.saleType(saleType);
+ }
+
+ void setSaleBeneficiary(Account saleBeneficiary) {
+ if(currentSaleBuilder!=null)
+ currentSaleBuilder.orderedFor(saleBeneficiary);
+ }
+
+ void addListener(ISaleScreenModelListener listener){
+ listeners.add(ISaleScreenModelListener.class, listener);
+ }
+
+ void removeListener(ISaleScreenModelListener listener){
+ listeners.remove(ISaleScreenModelListener.class, listener);
+ }
+
+ boolean isCurrentAccountConnected() {
+ return accountService.isCurrentAccountLoggedIn();
+ }
+
+ AccountLevel getCurrentAccountLevel() {
+ if(accountService.getCurrentAccount()!=null)
+ return accountService.getCurrentAccount().getPermissionLevel();
+ else
+ return AccountLevel.getLowest();
+ }
+}
\ No newline at end of file
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreenView.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreenView.java
new file mode 100644
index 00000000..f3595839
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/SaleScreenView.java
@@ -0,0 +1,224 @@
+package com.pqt.client.gui.modules.sale_screen;
+
+import com.pqt.client.gui.modules.sale_screen.sale_validation_screen.SaleValidationScreen;
+import com.pqt.client.gui.ressources.components.CommandComposerSaleDisplayer;
+import com.pqt.client.gui.ressources.components.SimpleValidator;
+import com.pqt.client.gui.ressources.components.generics.javafx_override.CssEnabledGridPane;
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.client.gui.ressources.css.GUICssTool;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.client.gui.ressources.components.CategoryTabStockDisplayer;
+import com.pqt.core.entities.product.Product;
+import com.pqt.core.entities.sale.Sale;
+import com.pqt.core.entities.sale.SaleStatus;
+import com.pqt.core.entities.sale.SaleType;
+import com.pqt.core.entities.user_account.Account;
+import javafx.application.Platform;
+
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.*;
+import javafx.scene.layout.*;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+class SaleScreenView implements IFXComponent {
+
+ private SaleScreenController ctrl;
+
+ private SaleValidationScreen saleValidationScreen;
+ private StackPane mainPane;
+ private BorderPane mainPaneContent;
+
+ private CategoryTabStockDisplayer stockDisplayer;
+ private CommandComposerSaleDisplayer saleDisplayer;
+ private TextField saleMakerAccountDisplayer;
+ private ChoiceBox saleBeneficiaryAccountDisplayer;
+ private ChoiceBox saleTypeDisplayer;
+ private TextField salePriceDisplayer;
+ private SimpleValidator validator;
+
+ SaleScreenView(SaleScreenController ctrl) {
+ this.ctrl = ctrl;
+ initGui();
+ }
+
+ private void initGui() {
+ mainPane = new StackPane();
+ mainPane.getStyleClass().add(GUICssTool.getMainModulePaneCssClass());
+
+ mainPaneContent = new BorderPane();
+
+ /*
+ -----------------------CENTER PANE-----------------------
+ */
+ {
+ mainPaneContent.prefWidthProperty().bind(mainPane.widthProperty());
+ mainPaneContent.prefHeightProperty().bind(mainPane.heightProperty());
+
+ stockDisplayer = new CategoryTabStockDisplayer();
+ stockDisplayer.addListener(ctrl.getStockDisplayerListener());
+
+ saleDisplayer = new CommandComposerSaleDisplayer();
+ saleDisplayer.addListener(ctrl.getSaleDisplayerListener());
+
+ HBox mainContentCenterPane = new HBox();
+ mainContentCenterPane.getChildren().addAll(stockDisplayer.getPane(), saleDisplayer.getPane());
+ mainContentCenterPane.setFillHeight(true);
+ stockDisplayer.getPane().prefWidthProperty().bind(mainContentCenterPane.widthProperty().divide(2));
+ saleDisplayer.getPane().prefWidthProperty().bind(mainContentCenterPane.widthProperty().divide(2));
+
+ mainPaneContent.setCenter(mainContentCenterPane);
+ }
+ /*
+ -----------------------BOTTOM PANE-----------------------
+ */
+ {
+ HBox mainContentBottomPane = new HBox();
+ mainContentBottomPane.setFillHeight(true);
+ mainContentBottomPane.setAlignment(Pos.CENTER);
+ // Sale secondary data configuration (author, beneficiary, payment type, etc...
+ {
+ saleMakerAccountDisplayer = new TextField();
+ saleMakerAccountDisplayer.setEditable(false);
+ saleMakerAccountDisplayer.setPromptText(GUIStringTool.getSaleMakerTextFieldPromptText());
+
+ saleBeneficiaryAccountDisplayer = new ChoiceBox<>();
+ saleBeneficiaryAccountDisplayer.setConverter(GUIStringTool.getAccountStringConverter());
+ saleBeneficiaryAccountDisplayer.getSelectionModel()
+ .selectedItemProperty()
+ .addListener((observable, oldElem, newElem) -> ctrl.onAccountSelectedAsBeneficiary(newElem));
+
+ saleTypeDisplayer = new ChoiceBox<>();
+ saleTypeDisplayer.setConverter(GUIStringTool.getSaleTypeStringConverter());
+ saleTypeDisplayer.getSelectionModel()
+ .selectedItemProperty()
+ .addListener((observable, oldElem, newElem) -> ctrl.onSaleTypeSelected(newElem));
+
+ salePriceDisplayer = new TextField();
+ salePriceDisplayer.setEditable(false);
+ salePriceDisplayer.setPromptText(GUIStringTool.getSalePriceTextFieldPromptText());
+
+
+ GridPane mainContentBottomCenterPane = new CssEnabledGridPane();
+ mainContentBottomCenterPane.add(new Label(GUIStringTool.getSaleMakerTextFieldLabel()), 0, 0);
+ mainContentBottomCenterPane.add(saleMakerAccountDisplayer, 1, 0);
+ mainContentBottomCenterPane.add(new Label(GUIStringTool.getSaleBeneficiaryTextFieldLabel()), 0, 1);
+ mainContentBottomCenterPane.add(saleBeneficiaryAccountDisplayer, 1, 1);
+ mainContentBottomCenterPane.add(new Label(GUIStringTool.getSaleTypeTextFieldLabel()), 0, 2);
+ mainContentBottomCenterPane.add(saleTypeDisplayer, 1, 2);
+ mainContentBottomCenterPane.add(new Label(GUIStringTool.getSalePriceTextFieldLabel()), 0, 3);
+ mainContentBottomCenterPane.add(salePriceDisplayer, 1, 3);
+
+ mainContentBottomPane.getChildren().add(mainContentBottomCenterPane);
+ }
+ //Sale Validator
+ {
+ AnchorPane anchorPane = new AnchorPane();
+ validator = new SimpleValidator(true);
+ validator.addListener(ctrl.getValidatorListener());
+ anchorPane.getChildren().add(validator.getPane());
+ AnchorPane.setRightAnchor(validator.getPane(), 0d);
+ AnchorPane.setBottomAnchor(validator.getPane(), 0d);
+
+ mainContentBottomPane.getChildren().add(anchorPane);
+ HBox.setHgrow(anchorPane, Priority.ALWAYS);
+ }
+ mainPaneContent.setBottom(mainContentBottomPane);
+ }
+ /*
+ ------------------------MAIN PANE------------------------
+ */
+ mainPane.getChildren().add(mainPaneContent);
+ }
+
+ @Override
+ public Pane getPane() {
+ return mainPane;
+ }
+
+ void switchToSaleValidationWaitingMode(long saleId, Sale sale){
+ boolean clearChildren = mainPane.getChildren().size()>1;
+
+ Pane greyIntermediaryPane = new Pane();
+ greyIntermediaryPane.getStyleClass().clear();
+ greyIntermediaryPane.getStyleClass().add(GUICssTool.getIntermediaryPaneStyleClass());
+
+ saleValidationScreen = new SaleValidationScreen(saleId, sale);
+ saleValidationScreen.addListener(ctrl.getSaleValidationScreenListener());
+ Platform.runLater(()->{
+ if(clearChildren){
+ mainPane.getChildren().clear();
+ mainPane.getChildren().add(mainPaneContent);
+ }
+
+ StackPane.setAlignment(saleValidationScreen.getPane(), Pos.CENTER);
+ mainPane.getChildren().addAll(greyIntermediaryPane, saleValidationScreen.getPane());
+ });
+ }
+
+ void switchToSaleCompositionMode(){
+ Node[] childrenToRemove = mainPane.getChildren()
+ .stream()
+ .filter(child->!child.equals(mainPaneContent))
+ .collect(Collectors.toList())
+ .toArray(new Node[]{});
+ Platform.runLater(()->mainPane.getChildren().removeAll(childrenToRemove));
+ }
+
+ void setProducts(List products) {
+ stockDisplayer.display(products);
+ }
+
+ void setSaleTypes(List saleTypes) {
+ Platform.runLater(()->{
+ saleTypeDisplayer.getItems().clear();
+ if(saleTypes!=null)
+ saleTypeDisplayer.getItems().addAll(saleTypes);
+ });
+ }
+
+ void setAccounts(List accounts) {
+ Platform.runLater(()->{
+ saleBeneficiaryAccountDisplayer.getItems().clear();
+ saleBeneficiaryAccountDisplayer.getItems().add(ctrl.getDefaultAccount());
+ if(accounts!=null)
+ saleBeneficiaryAccountDisplayer.getItems().addAll(accounts);
+ });
+ }
+
+ void setSale(Sale sale) {
+ if(sale!=null) {
+ saleDisplayer.display(sale);
+
+ String price = GUIStringTool.getPriceRenderer().render(sale.getTotalPrice());
+ String currentAccount = GUIStringTool.getAccountStringConverter().toString(sale.getOrderedBy());
+
+ Platform.runLater(() -> {
+ salePriceDisplayer.setText(price);
+ saleMakerAccountDisplayer.setText(currentAccount);
+
+ selectElement(saleTypeDisplayer, sale.getType());
+ selectElement(saleBeneficiaryAccountDisplayer, sale.getOrderedFor());
+ });
+ }
+ }
+
+ private void selectElement(ChoiceBox choiceBox, T element){
+ if(element!=null){
+ if(!choiceBox.getItems().contains(element))
+ choiceBox.getItems().add(element);
+ choiceBox.getSelectionModel().select(element);
+ }else
+ choiceBox.getSelectionModel().clearSelection();
+ }
+
+ void setSaleStatus(SaleStatus status){
+ this.saleValidationScreen.setSaleStatus(status);
+ }
+
+ void setValidationButtonEnabled(boolean validationButtonEnabled) {
+ validator.setValidationButtonEnable(validationButtonEnabled);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/listeners/ISaleScreenModelListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/listeners/ISaleScreenModelListener.java
new file mode 100644
index 00000000..02996c3e
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/listeners/ISaleScreenModelListener.java
@@ -0,0 +1,13 @@
+package com.pqt.client.gui.modules.sale_screen.listeners;
+
+import com.pqt.core.entities.sale.SaleStatus;
+
+import java.util.EventListener;
+
+public interface ISaleScreenModelListener extends EventListener {
+ void onSaleValidatedEvent();
+ void onSaleNotValidatedEvent(SaleStatus status, Throwable cause);
+ void onStockUpdatedEvent();
+ void onAccountConnectedStateUpdatedEvent();
+ void onAccountListUpdatedEvent();
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/sale_validation_screen/SaleValidationScreen.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/sale_validation_screen/SaleValidationScreen.java
new file mode 100644
index 00000000..93a4b7c8
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/sale_validation_screen/SaleValidationScreen.java
@@ -0,0 +1,97 @@
+package com.pqt.client.gui.modules.sale_screen.sale_validation_screen;
+
+import com.pqt.client.gui.modules.sale_screen.sale_validation_screen.listeners.ISaleValidationScreenListener;
+import com.pqt.client.gui.ressources.components.generics.javafx_override.CssEnabledGridPane;
+import com.pqt.client.gui.ressources.css.GUICssTool;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.core.entities.sale.Sale;
+import com.pqt.core.entities.sale.SaleStatus;
+import javafx.application.Platform;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ProgressIndicator;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.Pane;
+
+import javax.swing.event.EventListenerList;
+import java.util.Arrays;
+
+public class SaleValidationScreen {
+
+ private Pane mainPane;
+
+ private TextField saleStatusTextField;
+ private SaleStatus saleStatus;
+ private ProgressIndicator progressIndicator;
+ private Button validationButton;
+
+ private EventListenerList listeners;
+
+ public SaleValidationScreen(long saleId, Sale sale) {
+ listeners = new EventListenerList();
+ mainPane = new Pane();
+ mainPane.getStyleClass().add(GUICssTool.getMainModulePaneCssClass());
+
+ saleStatus = sale.getStatus();
+
+ BorderPane mainPaneContent = new BorderPane();
+
+ GridPane centerPane = new CssEnabledGridPane();
+ centerPane.setAlignment(Pos.CENTER);
+
+ Label saleIdLabel = new Label(GUIStringTool.getSaleIdLabel());
+ centerPane.add(saleIdLabel, 0, 0);
+
+ TextField saleIdTextField = new TextField(Long.toString(saleId));
+ saleIdTextField.setEditable(false);
+ centerPane.add(saleIdTextField, 1, 0);
+
+ Label saleStatusLabel = new Label(GUIStringTool.getSaleStatusLabel());
+ centerPane.add(saleStatusLabel, 0, 1);
+
+ saleStatusTextField = new TextField(GUIStringTool.getSaleStatusRenderer().render(saleStatus));
+ saleStatusTextField.setEditable(false);
+ centerPane.add(saleStatusTextField, 1, 1);
+
+ validationButton = new Button(GUIStringTool.getOkButtonLabel());
+ validationButton.setDisable(saleStatus.equals(SaleStatus.PENDING));
+ validationButton.setOnMouseClicked(event->fireScreenClose(saleStatus.equals(SaleStatus.ACCEPTED)));
+ centerPane.add(validationButton, 1,2);
+
+ mainPaneContent.setCenter(centerPane);
+
+ progressIndicator = new ProgressIndicator();
+ mainPaneContent.setLeft(progressIndicator);
+
+ mainPaneContent.prefHeightProperty().bind(mainPane.heightProperty());
+ mainPaneContent.prefWidthProperty().bind(mainPane.widthProperty());
+ mainPane.getChildren().add(mainPaneContent);
+ }
+
+ private void fireScreenClose(boolean saleValidatedSuccessFully) {
+ if(!validationButton.isDisable()){
+ Arrays.stream(listeners.getListeners(ISaleValidationScreenListener.class))
+ .forEach(listener->listener.onScreenClose(saleValidatedSuccessFully));
+ }
+ }
+
+ public void addListener(ISaleValidationScreenListener listener){
+ listeners.add(ISaleValidationScreenListener.class, listener);
+ }
+
+ public void setSaleStatus(SaleStatus status){
+ saleStatus = status;
+ Platform.runLater(()->{
+ validationButton.setDisable(saleStatus.equals(SaleStatus.PENDING));
+ saleStatusTextField.setText(GUIStringTool.getSaleStatusRenderer().render(status));
+ progressIndicator.setProgress((status.equals(SaleStatus.PENDING)?ProgressIndicator.INDETERMINATE_PROGRESS:1F));
+ });
+ }
+
+ public Pane getPane(){
+ return mainPane;
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/sale_validation_screen/listeners/ISaleValidationScreenListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/sale_validation_screen/listeners/ISaleValidationScreenListener.java
new file mode 100644
index 00000000..e2011357
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/sale_screen/sale_validation_screen/listeners/ISaleValidationScreenListener.java
@@ -0,0 +1,7 @@
+package com.pqt.client.gui.modules.sale_screen.sale_validation_screen.listeners;
+
+import java.util.EventListener;
+
+public interface ISaleValidationScreenListener extends EventListener {
+ void onScreenClose(boolean saleValidatedSuccessfully);
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreen.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreen.java
new file mode 100644
index 00000000..6ef1f98b
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreen.java
@@ -0,0 +1,35 @@
+package com.pqt.client.gui.modules.stat_screen;
+
+import com.pqt.client.gui.modules.IGuiModule;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.client.module.stat.StatService;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.scene.layout.Pane;
+
+public class StatScreen implements IGuiModule {
+
+ private StatScreenView view;
+
+ public StatScreen(StatService statService) {
+ StatScreenModel model = new StatScreenModel(statService);
+ StatScreenController ctrl = new StatScreenController(model);
+ view = new StatScreenView();
+
+ ctrl.setView(view);
+ }
+
+ @Override
+ public String getModuleName() {
+ return GUIStringTool.getStatGuiModuleName();
+ }
+
+ @Override
+ public AccountLevel getLowestRequiredAccountLevel() {
+ return AccountLevel.STAFF;
+ }
+
+ @Override
+ public Pane getPane() {
+ return view.getPane();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreenController.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreenController.java
new file mode 100644
index 00000000..5f2510e3
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreenController.java
@@ -0,0 +1,22 @@
+package com.pqt.client.gui.modules.stat_screen;
+
+import com.pqt.client.gui.modules.stat_screen.listeners.IStatScreenModelListener;
+
+class StatScreenController implements IStatScreenModelListener{
+
+ private StatScreenModel model;
+ private StatScreenView view;
+
+ StatScreenController(StatScreenModel model) {
+ this.model = model;
+ }
+
+ void setView(StatScreenView view) {
+ this.view = view;
+ }
+
+ @Override
+ public void onStatisticsChangedEvent() {
+ view.display(model.getStatistics());
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreenModel.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreenModel.java
new file mode 100644
index 00000000..2add8f38
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreenModel.java
@@ -0,0 +1,38 @@
+package com.pqt.client.gui.modules.stat_screen;
+
+import com.pqt.client.gui.modules.stat_screen.listeners.IStatScreenModelListener;
+import com.pqt.client.module.stat.StatService;
+import com.pqt.client.module.stat.listeners.IStatListener;
+import com.pqt.client.module.stat.listeners.StatListenerAdapter;
+
+import javax.swing.event.EventListenerList;
+import java.util.Arrays;
+import java.util.Map;
+
+class StatScreenModel {
+ private EventListenerList listenerList;
+ private StatService statService;
+
+ StatScreenModel(StatService statService) {
+ this.statService = statService;
+ listenerList = new EventListenerList();
+ this.statService.addListener(new StatListenerAdapter() {
+ @Override
+ public void onGetStatSuccess() {
+ Arrays.stream(listenerList.getListeners(IStatScreenModelListener.class)).forEach(IStatScreenModelListener::onStatisticsChangedEvent);
+ }
+ });
+ }
+
+ Map getStatistics() {
+ return statService.getStats();
+ }
+
+ void addListener(IStatScreenModelListener l){
+ listenerList.add(IStatScreenModelListener.class, l);
+ }
+
+ void removeListener(IStatScreenModelListener l){
+ listenerList.remove(IStatScreenModelListener.class, l);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreenView.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreenView.java
new file mode 100644
index 00000000..a9a79644
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/StatScreenView.java
@@ -0,0 +1,52 @@
+package com.pqt.client.gui.modules.stat_screen;
+
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.client.gui.ressources.css.GUICssTool;
+import javafx.application.Platform;
+import javafx.scene.control.TextArea;
+import javafx.scene.layout.Pane;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+class StatScreenView implements IFXComponent {
+
+ private TextArea statTextArea;
+ private Pane mainPane;
+
+ StatScreenView() {
+ initGui();
+ }
+
+ private void initGui() {
+ mainPane = new Pane();
+ mainPane.getStyleClass().add(GUICssTool.getMainModulePaneCssClass());
+
+ statTextArea = new TextArea();
+ mainPane.getChildren().add(statTextArea);
+ statTextArea.setId("stat-screen-text-area");
+ statTextArea.setWrapText(true);
+ statTextArea.setEditable(false);
+ statTextArea.prefWidthProperty().bind(mainPane.widthProperty());
+ statTextArea.prefHeightProperty().bind(mainPane.heightProperty());
+ }
+
+ void display(Map statistics){
+ List lines = new ArrayList<>();
+
+ if(statistics!=null)
+ lines.addAll(statistics.keySet()
+ .stream()
+ .map(key->String.format(" * %s : %s", key, statistics.get(key)))
+ .collect(Collectors.toList()));
+
+ Platform.runLater(()->lines.forEach(line -> statTextArea.appendText(line+"\n")));
+ }
+
+ @Override
+ public Pane getPane() {
+ return mainPane;
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/listeners/IStatScreenModelListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/listeners/IStatScreenModelListener.java
new file mode 100644
index 00000000..c02c49f8
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stat_screen/listeners/IStatScreenModelListener.java
@@ -0,0 +1,7 @@
+package com.pqt.client.gui.modules.stat_screen.listeners;
+
+import java.util.EventListener;
+
+public interface IStatScreenModelListener extends EventListener {
+ void onStatisticsChangedEvent();
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreen.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreen.java
new file mode 100644
index 00000000..4deb2d97
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreen.java
@@ -0,0 +1,39 @@
+package com.pqt.client.gui.modules.stock_screen;
+
+import com.pqt.client.gui.modules.IGuiModule;
+import com.pqt.client.gui.modules.stock_screen.product_manager_screen.ProductManagerScreen;
+import com.pqt.client.gui.modules.stock_screen.product_manager_screen.ProductManagerScreenFactory;
+import com.pqt.client.module.account.AccountService;
+import com.pqt.client.module.stock.StockService;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.scene.layout.Pane;
+
+public class StockScreen implements IGuiModule {
+
+ private StockScreenView view;
+
+ public StockScreen(StockService stockService, AccountService accountService) {
+ StockScreenModel model = new StockScreenModel(stockService, accountService);
+ StockScreenController ctrl = new StockScreenController(model);
+ view = new StockScreenView(ctrl, new ProductManagerScreenFactory(stockService));
+
+ model.addListener(ctrl);
+ ctrl.setView(view);
+ ctrl.refreshView();
+ }
+
+ @Override
+ public String getModuleName() {
+ return "Stock";
+ }
+
+ @Override
+ public AccountLevel getLowestRequiredAccountLevel() {
+ return AccountLevel.WAITER;
+ }
+
+ @Override
+ public Pane getPane() {
+ return view.getPane();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenController.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenController.java
new file mode 100644
index 00000000..7418e94f
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenController.java
@@ -0,0 +1,112 @@
+package com.pqt.client.gui.modules.stock_screen;
+
+
+import com.pqt.client.gui.modules.stock_screen.listeners.IStockItemEventListener;
+import com.pqt.client.gui.modules.stock_screen.listeners.IStockScreenModelListener;
+import com.pqt.client.gui.modules.stock_screen.product_manager_screen.ProductManagerScreen;
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.core.entities.product.Product;
+import com.pqt.core.entities.user_account.AccountLevel;
+
+class StockScreenController implements IStockScreenModelListener{
+
+ private StockScreenModel model;
+ private StockScreenView view;
+
+ StockScreenController(StockScreenModel model) {
+ this.model = model;
+ }
+
+ void setView(StockScreenView view) {
+ this.view = view;
+ }
+
+ void onAddProductRequest() {
+ detailProduct(null);
+ }
+
+ void onDetailProductRequest() {
+ if(view.getSelectedProduct()!=null)
+ detailProduct(view.getSelectedProduct());
+ }
+
+ private void detailProduct(Product product){
+ view.switchToDetailMode(product);
+ }
+
+ IValidatorComponentListener getDetailScreenValidationListener(){
+ return new IValidatorComponentListener() {
+ @Override
+ public void onValidationEvent() {
+ if(view.isDetailScreenCreationPossible()) {
+ if (view.hasDetailScreenInitialValue()){
+ modifyProduct(view.getDetailScreenInitialValue(), view.getDetailScreenCreation());
+ }else{
+ addProduct(view.getDetailScreenCreation());
+ }
+ view.switchToGeneralMode();
+ }
+ }
+
+ @Override
+ public void onCancelEvent() {
+ view.switchToGeneralMode();
+ }
+ };
+ }
+
+ void onDeleteProductRequest() {
+ deleteProduct(view.getSelectedProduct());
+ }
+
+ private void addProduct(Product product){
+ model.commitProductAddition(product);
+ }
+
+ private void modifyProduct(Product oldProduct, Product newProduct){
+ model.commitProductModification(oldProduct, newProduct);
+ }
+
+ private void deleteProduct(Product product){
+ model.commitProductDeletion(product);;
+ }
+
+ void onRefreshProductsRequest() {
+ refreshView();
+ }
+
+ IStockItemEventListener getProductActivationListener() {
+ return this::detailProduct;
+ }
+
+ void refreshView(){
+ view.display(model.getProductCollection());
+ }
+
+ @Override
+ public void onStockUpdatedEvent() {
+ refreshView();
+ }
+
+ @Override
+ public void onAcccountConnectedStatusUpdatedEvent() {
+ updateViewActionLock();
+ }
+
+ void updateViewActionLock(){
+ if(model.isAccountConnected() && model.getConnectedAccountLevel().compareTo(AccountLevel.MASTER)>=0){
+ view.setAddProductActionLocked(false);
+ view.setEditProductActionLocked(view.getSelectedProduct()==null);
+ view.setRemoveProductActionLocked(view.getSelectedProduct()==null);
+ }else{
+ view.setAddProductActionLocked(true);
+ view.setEditProductActionLocked(true);
+ view.setRemoveProductActionLocked(true);
+ }
+ }
+
+ void onProductSelectedChange(){
+ updateViewActionLock();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenModel.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenModel.java
new file mode 100644
index 00000000..365c0648
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenModel.java
@@ -0,0 +1,88 @@
+package com.pqt.client.gui.modules.stock_screen;
+
+import com.pqt.client.gui.modules.stock_screen.listeners.IStockScreenModelListener;
+import com.pqt.client.module.account.AccountService;
+import com.pqt.client.module.account.listeners.IAccountListener;
+import com.pqt.client.module.stock.Listeners.StockListenerAdapter;
+import com.pqt.client.module.stock.StockService;
+import com.pqt.core.entities.product.Product;
+import com.pqt.core.entities.user_account.AccountLevel;
+
+import javax.swing.event.EventListenerList;
+import java.util.Arrays;
+import java.util.Collection;
+
+class StockScreenModel {
+
+ private StockService stockService;
+ private AccountService accountService;
+ private EventListenerList listenerList;
+
+ StockScreenModel(StockService stockService, AccountService accountService) {
+ listenerList = new EventListenerList();
+ this.stockService = stockService;
+ this.stockService.addListener(new StockListenerAdapter(){
+ @Override
+ public void onProductListChangedEvent() {
+ StockScreenModel.this.fireProductCollectionChanged();
+ }
+ });
+ this.accountService = accountService;
+ this.accountService.addListener(new IAccountListener() {
+ @Override
+ public void onAccountStatusChangedEvent(boolean status) {
+ StockScreenModel.this.fireConnectedStatusChanged();
+ }
+
+ @Override
+ public void onAccountListChangedEvent() {
+
+ }
+ });
+ }
+
+ private void fireConnectedStatusChanged() {
+ Arrays.stream(listenerList.getListeners(IStockScreenModelListener.class))
+ .forEach(IStockScreenModelListener::onAcccountConnectedStatusUpdatedEvent);
+ }
+
+ private void fireProductCollectionChanged() {
+ Arrays.stream(listenerList.getListeners(IStockScreenModelListener.class))
+ .forEach(IStockScreenModelListener::onStockUpdatedEvent);
+ }
+
+ Collection getProductCollection() {
+ return stockService.getProducts();
+ }
+
+ void commitProductDeletion(Product product) {
+ stockService.commitUpdate(stockService.getNewUpdateBuilder().removeProduct(product));
+ }
+
+ void commitProductModification(Product oldProduct, Product newProduct) {
+ stockService.commitUpdate(stockService.getNewUpdateBuilder().modifyProduct(oldProduct, newProduct));
+ }
+
+ void commitProductAddition(Product product) {
+ stockService.commitUpdate(stockService.getNewUpdateBuilder().addProduct(product));
+ }
+
+ void addListener(IStockScreenModelListener l){
+ listenerList.add(IStockScreenModelListener.class, l);
+ }
+
+ void removeListener(IStockScreenModelListener l){
+ listenerList.remove(IStockScreenModelListener.class, l);
+ }
+
+ boolean isAccountConnected() {
+ return accountService.isCurrentAccountLoggedIn();
+ }
+
+ AccountLevel getConnectedAccountLevel() {
+ if(accountService.getCurrentAccount()!=null)
+ return accountService.getCurrentAccount().getPermissionLevel();
+ else
+ return AccountLevel.getLowest();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenView.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenView.java
new file mode 100644
index 00000000..83034d8d
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenView.java
@@ -0,0 +1,242 @@
+package com.pqt.client.gui.modules.stock_screen;
+
+import com.pqt.client.gui.modules.stock_screen.product_manager_screen.ProductManagerScreen;
+import com.pqt.client.gui.modules.stock_screen.product_manager_screen.ProductManagerScreenFactory;
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.client.gui.ressources.css.GUICssTool;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.client.gui.ressources.strings.IObjectStringRenderer;
+import com.pqt.core.entities.product.Product;
+import javafx.application.Platform;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleDoubleProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.value.ObservableValue;
+import javafx.css.PseudoClass;
+import javafx.scene.Node;
+import javafx.scene.control.*;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.MouseButton;
+import javafx.scene.layout.*;
+import javafx.util.Callback;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+class StockScreenView implements IFXComponent {
+
+ private StockScreenController ctrl;
+ private StackPane mainPane;
+ private BorderPane mainPaneContent;
+ private TableView stockTableView;
+ private ProductManagerScreenFactory productManagerScreenFactory;
+ private ProductManagerScreen currentDetailScreen;
+ private Button addProductButton;
+ private Button detailProductButton;
+ private Button removeProductButton;
+
+ StockScreenView(StockScreenController ctrl, ProductManagerScreenFactory productManagerScreenFactory) {
+ this.ctrl = ctrl;
+ this.productManagerScreenFactory = productManagerScreenFactory;
+ initGui();
+ }
+
+ private void initGui() {
+ mainPane = new StackPane();
+ mainPane.getStyleClass().add(GUICssTool.getMainModulePaneCssClass());
+ mainPaneContent = new BorderPane();
+ mainPane.getChildren().add(mainPaneContent);
+ mainPaneContent.prefWidthProperty().bind(mainPane.widthProperty());
+ mainPaneContent.prefHeightProperty().bind(mainPane.heightProperty());
+
+ addProductButton = new Button(GUIStringTool.getAddButtonLabel());
+ addProductButton.setOnMouseClicked(event -> ctrl.onAddProductRequest());
+ detailProductButton = new Button(GUIStringTool.getDetailButtonLabel());
+ detailProductButton.setOnMouseClicked(event -> ctrl.onDetailProductRequest());
+ detailProductButton.setDisable(true);
+ removeProductButton = new Button(GUIStringTool.getRemoveButtonLabel());
+ removeProductButton.setDisable(true);
+ removeProductButton.setOnMouseClicked(event -> ctrl.onDeleteProductRequest());
+ Button refreshProductButton = new Button(GUIStringTool.getRefreshButtonLabel());
+ refreshProductButton.setOnMouseClicked(event -> ctrl.onRefreshProductsRequest());
+
+ ToolBar actionToolbar = new ToolBar();
+ actionToolbar.getItems().addAll(addProductButton, detailProductButton, removeProductButton, refreshProductButton);
+
+ HBox mainPaneTopContent = new HBox();
+ HBox separator = new HBox();
+ mainPaneTopContent.getChildren().addAll(separator, actionToolbar);
+ HBox.setHgrow(separator, Priority.ALWAYS);
+ mainPaneContent.setTop(mainPaneTopContent);
+
+ PseudoClass outOfStockPseudoClass = PseudoClass.getPseudoClass("stock-out");
+ PseudoClass lowStockPseudoClass = PseudoClass.getPseudoClass("stock-low");
+ PseudoClass highStockPseudoClass = PseudoClass.getPseudoClass("stock-high");
+ stockTableView = new TableView<>();
+ stockTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
+ stockTableView.setRowFactory(tableView->{
+ TableRow row = new TableRow<>();
+ row.itemProperty().addListener((obs, oldVal, newVal)->{
+ if(newVal!=null){
+ row.pseudoClassStateChanged(outOfStockPseudoClass, newVal.getAmountRemaining()<=0);
+ row.pseudoClassStateChanged(lowStockPseudoClass, newVal.getAmountRemaining()>0 && newVal.getAmountRemaining()<30);
+ row.pseudoClassStateChanged(highStockPseudoClass, newVal.getAmountRemaining()>=30);
+ }else{
+ row.pseudoClassStateChanged(outOfStockPseudoClass, false);
+ row.pseudoClassStateChanged(lowStockPseudoClass, false);
+ row.pseudoClassStateChanged(highStockPseudoClass, false);
+ }
+ });
+ row.setOnMouseClicked(event -> {
+ if (event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2)
+ ctrl.getProductActivationListener().onProductActivated(row.getItem());
+ });
+ row.setOnKeyTyped(event -> {
+ if (event.getCode().equals(KeyCode.ENTER))
+ ctrl.getProductActivationListener().onProductActivated(row.getItem());
+ });
+ return row;
+ });
+ stockTableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
+ stockTableView.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal)->ctrl.onProductSelectedChange());
+ List> columns = new ArrayList<>();
+
+ columns.add(createNewTableColumn(String.class,
+ GUIStringTool.getProductNameColumnHeader(),
+ param -> new SimpleStringProperty(param.getValue().getName()),
+ null
+ ));
+ columns.add(createNewTableColumn(String.class,
+ GUIStringTool.getProductCategoryColumnHeader(),
+ param -> new SimpleStringProperty(param.getValue().getCategory().getName()),
+ null
+ ));
+ columns.add(createNewTableColumn(Integer.class,
+ GUIStringTool.getProductAmountRemainingColumnHeader(),
+ param -> new SimpleIntegerProperty(param.getValue().getAmountRemaining()).asObject(),
+ null
+ ));
+ columns.add(createNewTableColumn(Integer.class,
+ GUIStringTool.getProductAmountSoldColumnHeader(),
+ param -> new SimpleIntegerProperty(param.getValue().getAmountSold()).asObject(),
+ null
+ ));
+ columns.add(createNewTableColumn(Double.class,
+ GUIStringTool.getProductPriceColumnHeader(),
+ param -> new SimpleDoubleProperty(param.getValue().getPrice()).asObject(),
+ GUIStringTool.getPriceRenderer()
+ ));
+ columns.add(createNewTableColumn(Boolean.class,
+ GUIStringTool.getProductIsSellableColumnHeader(),
+ param -> new SimpleBooleanProperty(param.getValue().isSellable()),
+ GUIStringTool.getBooleanRenderer()
+ ));
+
+ stockTableView.getColumns().addAll(columns);
+ mainPaneContent.setCenter(stockTableView);
+ }
+
+ private TableColumn createNewTableColumn(Class clazz,
+ String header,
+ Callback, ObservableValue> cellValueFactory,
+ IObjectStringRenderer renderer){
+ TableColumn column = new TableColumn<>();
+ if(header!=null)
+ column.setText(header);
+ if(cellValueFactory!=null)
+ column.setCellValueFactory(cellValueFactory);
+ if(renderer!=null)
+ column.setCellFactory(table -> new TableCell() {
+ @Override
+ protected void updateItem(T item, boolean empty) {
+ super.updateItem(item, empty);
+ if (item == null || empty) {
+ setText(null);
+ setStyle("");
+ } else {
+ setText(renderer.render(item));
+ }
+ }
+ }
+ );
+
+ return column;
+ }
+
+ void display(Collection productCollection){
+ Platform.runLater(()->{
+ this.stockTableView.getItems().clear();
+ this.stockTableView.getItems().addAll(productCollection);
+ });
+ }
+
+ @Override
+ public Pane getPane() {
+ return mainPane;
+ }
+
+ Product getSelectedProduct() {
+ return stockTableView.getSelectionModel().getSelectedItem();
+ }
+
+ void switchToDetailMode(Product product) {
+ if(currentDetailScreen==null){
+ currentDetailScreen = productManagerScreenFactory.create(product);
+ currentDetailScreen.addListener(ctrl.getDetailScreenValidationListener());
+ Pane separator = new Pane();
+ separator.getStyleClass().add(GUICssTool.getIntermediaryPaneStyleClass());
+ Platform.runLater(()->mainPane.getChildren().addAll(separator, currentDetailScreen.getPane()));
+ }
+ }
+
+ void switchToGeneralMode() {
+ if(currentDetailScreen!=null){
+ List toRemove = mainPane.getChildren()
+ .stream()
+ .filter(node->!node.equals(mainPaneContent))
+ .collect(Collectors.toList());
+ Platform.runLater(()->{
+ mainPane.getChildren().removeAll(toRemove);
+ currentDetailScreen = null;
+ });
+ }
+ }
+
+ boolean isDetailScreenCreationPossible() {
+ System.out.println("test creation possible : ");
+ return currentDetailScreen!=null && currentDetailScreen.isCreationPossible();
+ }
+
+ boolean hasDetailScreenInitialValue() {
+ return currentDetailScreen!=null && currentDetailScreen.hasInitialValue();
+ }
+
+ Product getDetailScreenInitialValue() {
+ if(currentDetailScreen!=null)
+ return currentDetailScreen.getInitialValueSnapshot();
+ else
+ return null;
+ }
+
+ Product getDetailScreenCreation() {
+ if(currentDetailScreen!=null)
+ return currentDetailScreen.create();
+ else
+ return null;
+ }
+
+ void setAddProductActionLocked(boolean locked){
+ addProductButton.setDisable(locked);
+ }
+
+ void setRemoveProductActionLocked(boolean locked){
+ removeProductButton.setDisable(locked);
+ }
+
+ void setEditProductActionLocked(boolean locked){
+ detailProductButton.setDisable(locked);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/listeners/IStockItemEventListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/listeners/IStockItemEventListener.java
new file mode 100644
index 00000000..08e002eb
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/listeners/IStockItemEventListener.java
@@ -0,0 +1,7 @@
+package com.pqt.client.gui.modules.stock_screen.listeners;
+
+import com.pqt.core.entities.product.Product;
+
+public interface IStockItemEventListener {
+ void onProductActivated(Product product);
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/listeners/IStockScreenModelListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/listeners/IStockScreenModelListener.java
new file mode 100644
index 00000000..54604eec
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/listeners/IStockScreenModelListener.java
@@ -0,0 +1,8 @@
+package com.pqt.client.gui.modules.stock_screen.listeners;
+
+import java.util.EventListener;
+
+public interface IStockScreenModelListener extends EventListener {
+ void onStockUpdatedEvent();
+ void onAcccountConnectedStatusUpdatedEvent();
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreen.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreen.java
new file mode 100644
index 00000000..d5aee803
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreen.java
@@ -0,0 +1,56 @@
+package com.pqt.client.gui.modules.stock_screen.product_manager_screen;
+
+import com.pqt.client.gui.ressources.components.generics.creators.IFXCreatorComponent;
+import com.pqt.client.gui.ressources.components.generics.validators.IFXValidatorComponent;
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener;
+import com.pqt.client.module.stock.StockService;
+import com.pqt.core.entities.product.Product;
+import javafx.scene.layout.Pane;
+
+public class ProductManagerScreen implements IFXCreatorComponent, IFXValidatorComponent {
+
+ private ProductManagerScreenView view;
+ private ProductManagerScreenModel model;
+ private ProductManagerScreenController ctrl;
+
+ public ProductManagerScreen(Product initialData, StockService stockService){
+ model = new ProductManagerScreenModel(initialData, stockService);
+ ctrl = new ProductManagerScreenController(model);
+ view = new ProductManagerScreenView(ctrl);
+ ctrl.setView(view);
+ ctrl.updateView();
+ }
+
+ @Override
+ public Product create() {
+ return model.create();
+ }
+
+ @Override
+ public boolean isCreationPossible() {
+ return model.isProductCreationPossible();
+ }
+
+ @Override
+ public Pane getPane() {
+ return view.getPane();
+ }
+
+ @Override
+ public void addListener(IValidatorComponentListener l) {
+ ctrl.addListener(l);
+ }
+
+ @Override
+ public void removeListener(IValidatorComponentListener l) {
+ ctrl.removeListener(l);
+ }
+
+ public boolean hasInitialValue(){
+ return model.hasInitialData();
+ }
+
+ public Product getInitialValueSnapshot(){
+ return new Product(model.getInitialData());
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenController.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenController.java
new file mode 100644
index 00000000..b948bf82
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenController.java
@@ -0,0 +1,93 @@
+package com.pqt.client.gui.modules.stock_screen.product_manager_screen;
+
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener;
+import com.pqt.core.entities.product.Category;
+import com.pqt.core.entities.product.Product;
+import javafx.beans.value.ChangeListener;
+
+import javax.swing.event.EventListenerList;
+import java.util.Arrays;
+
+class ProductManagerScreenController {
+
+ private EventListenerList listenerList;
+ private ProductManagerScreenModel model;
+ private ProductManagerScreenView view;
+
+ ProductManagerScreenController(ProductManagerScreenModel model) {
+ listenerList = new EventListenerList();
+ this.model = model;
+ }
+
+ void setView(ProductManagerScreenView view){
+ this.view = view;
+ }
+
+ ChangeListener super Product> getProductComponentSelectionListener() {
+ return (obs, oldValue, newValue)->{
+ if(newValue!=null) {
+ if (model.isComponent(newValue))
+ model.removeComponent(newValue);
+ else
+ model.addComponent(newValue);
+ updateView();
+ }
+ };
+ }
+
+ void updateView() {
+ view.setProduct(model.getActualProductState());
+ view.setCategoryCollection(model.getCategoryCollection());
+ view.setProductCollection(model.getEligibleComponentList());
+ }
+
+ IValidatorComponentListener getValidatorListener() {
+ return new IValidatorComponentListener() {
+ @Override
+ public void onValidationEvent() {
+ Arrays.stream(listenerList.getListeners(IValidatorComponentListener.class)).forEach(IValidatorComponentListener::onValidationEvent);
+ }
+
+ @Override
+ public void onCancelEvent() {
+ Arrays.stream(listenerList.getListeners(IValidatorComponentListener.class)).forEach(IValidatorComponentListener::onCancelEvent);
+ }
+ };
+ }
+
+ public void addListener(IValidatorComponentListener l) {
+ listenerList.add(IValidatorComponentListener.class, l);
+ }
+
+ public void removeListener(IValidatorComponentListener l) {
+ listenerList.remove(IValidatorComponentListener.class, l);
+ }
+
+ boolean isProductHighlighted(Product product) {
+ return model.getActualProductState().getComponents().contains(product);
+ }
+
+ void onNameChanged(String oldVal, String newVal) {
+ model.changeName(newVal);
+ }
+
+ void onPriceChanged(double oldVal, double newVal) {
+ model.changePrice(newVal);
+ }
+
+ void onCategoryChanged(Category oldVal, Category newVal) {
+ model.changeCategory(newVal);
+ }
+
+ void onAmountRemainingChanged(int oldVal, int newVal) {
+ model.changeAmountRemaining(newVal);
+ }
+
+ void onAmountSoldChanged(int oldVal, int newVal) {
+ model.changeAmountSold(newVal);
+ }
+
+ void onSellableStateChanged(boolean oldVal, boolean newVal) {
+ model.setSellable(newVal);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenFactory.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenFactory.java
new file mode 100644
index 00000000..c583115c
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenFactory.java
@@ -0,0 +1,17 @@
+package com.pqt.client.gui.modules.stock_screen.product_manager_screen;
+
+import com.pqt.client.module.stock.StockService;
+import com.pqt.core.entities.product.Product;
+
+public final class ProductManagerScreenFactory {
+
+ private StockService stockService;
+
+ public ProductManagerScreenFactory(StockService stockService) {
+ this.stockService = stockService;
+ }
+
+ public ProductManagerScreen create(Product product){
+ return new ProductManagerScreen(product, stockService);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenModel.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenModel.java
new file mode 100644
index 00000000..962390fb
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenModel.java
@@ -0,0 +1,100 @@
+package com.pqt.client.gui.modules.stock_screen.product_manager_screen;
+
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.client.module.stock.StockService;
+import com.pqt.core.entities.product.Category;
+import com.pqt.core.entities.product.LightweightProduct;
+import com.pqt.core.entities.product.Product;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+class ProductManagerScreenModel {
+
+ private StockService stockService;
+ private Product initialData;
+ private Product currentData;
+
+ ProductManagerScreenModel(Product initialData, StockService stockService) {
+ this.stockService = stockService;
+ this.initialData = initialData;
+ if(initialData==null)
+ currentData = new Product();
+ else
+ currentData = new Product(initialData);
+ }
+
+ List getEligibleComponentList() {
+ return stockService.getProductsExcluding(currentData);
+ }
+
+ Product getActualProductState(){
+ return currentData;
+ }
+
+ Product create() {
+ if(isProductCreationPossible())
+ return currentData;
+ else
+ return null;
+ }
+
+ boolean isProductCreationPossible() {
+ return (initialData!=null && !currentData.equals(initialData))
+ && !currentData.getName().isEmpty()
+ && currentData.getCategory()!=null
+ && currentData.getPrice()>=0;
+ }
+
+ void addComponent(Product product) {
+ currentData.getComponents().add(product);
+ }
+
+ void removeComponent(Product product) {
+ currentData.getComponents().remove(product);
+ }
+
+ void changeCategory(Category category){
+ this.currentData.setCategory(category);
+ }
+
+ void changePrice(double price){
+ this.currentData.setPrice(price);
+ }
+
+ void changeName(String name){
+ this.currentData.setName(name);
+ }
+
+ void changeAmountRemaining(int amount){
+ this.currentData.setAmountRemaining(amount);
+ }
+
+ void changeAmountSold(int amount){
+ this.currentData.setAmountSold(amount);
+ }
+
+ void setSellable(boolean sellable){
+ this.currentData.setSellable(sellable);
+ }
+
+ Collection getCategoryCollection() {
+ return stockService.getProducts()
+ .stream()
+ .map(Product::getCategory)
+ .distinct()
+ .collect(Collectors.toList());
+ }
+
+ boolean isComponent(Product product) {
+ return currentData.getComponents().contains(product);
+ }
+
+ boolean hasInitialData(){
+ return initialData!=null;
+ }
+
+ Product getInitialData(){
+ return initialData;
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenView.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenView.java
new file mode 100644
index 00000000..d9118917
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenView.java
@@ -0,0 +1,212 @@
+package com.pqt.client.gui.modules.stock_screen.product_manager_screen;
+
+import com.pqt.client.gui.ressources.components.SimpleValidator;
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.client.gui.ressources.components.generics.javafx_override.CssEnabledGridPane;
+import com.pqt.client.gui.ressources.components.generics.javafx_override.HighlightListCell;
+import com.pqt.client.gui.ressources.css.GUICssTool;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.core.entities.product.Category;
+import com.pqt.core.entities.product.Product;
+import javafx.application.Platform;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.*;
+import javafx.scene.layout.*;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.Collection;
+
+class ProductManagerScreenView implements IFXComponent {
+
+ private ProductManagerScreenController ctrl;
+
+ private int gridLines;
+ private StackPane mainPane;
+ private BorderPane mainPaneContent;
+ private TextField productNameTextField,
+ productAmountRemainingTextField,
+ productAmountSoldTextField,
+ productPriceTextField;
+ private ComboBox productCategoryComboBox;
+ private CheckBox productSellableCheckBox;
+ private ListView productComponentsListView;
+
+ ProductManagerScreenView(ProductManagerScreenController ctrl) {
+ this.ctrl = ctrl;
+ initGui();
+ }
+
+ private void initGui() {
+ mainPane = new StackPane();
+ mainPane.getStyleClass().add(GUICssTool.getMainModulePaneCssClass());
+
+ mainPaneContent = new BorderPane();
+
+ GridPane mainPaneCenterContent = new CssEnabledGridPane();
+ mainPaneCenterContent.setAlignment(Pos.CENTER);
+ gridLines = 0;
+ NumberFormat priceFormat = NumberFormat.getNumberInstance();
+ NumberFormat intFormat = NumberFormat.getIntegerInstance();
+
+ Label productNameLabel = new Label(GUIStringTool.getProductNameLabel());
+ productNameTextField = new TextField();
+ productNameTextField.textProperty().addListener((obs, oldVal, newVal)->ctrl.onNameChanged(oldVal,newVal));
+ addLineToGrid(mainPaneCenterContent, productNameLabel, productNameTextField);
+
+ Label productCategoryLabel = new Label(GUIStringTool.getProductCategoryLabel());
+ productCategoryComboBox = new ComboBox<>();
+ productCategoryComboBox.setEditable(true);
+ productCategoryComboBox.setConverter(GUIStringTool.getCategoryStringConverter());
+ productCategoryComboBox.valueProperty().addListener((obs, oldVal, newVal)->ctrl.onCategoryChanged(oldVal, newVal));
+ addLineToGrid(mainPaneCenterContent, productCategoryLabel, productCategoryComboBox);
+
+ Label productAmountRemainingLabel = new Label(GUIStringTool.getProductAmountRemainingLabel());
+ productAmountRemainingTextField = getNumberOnlyTextField(intFormat);
+ productAmountRemainingTextField.textProperty().addListener((obs, oldVal, newVal)->{
+ try{
+ int oldInt = oldVal.isEmpty()?0:Integer.parseInt(oldVal);
+ int newInt = newVal.isEmpty()?0:Integer.parseInt(newVal);
+ ctrl.onAmountRemainingChanged(oldInt, newInt);
+ }catch(NumberFormatException e){
+ e.printStackTrace();
+ }
+ });
+ addLineToGrid(mainPaneCenterContent, productAmountRemainingLabel, productAmountRemainingTextField);
+
+ Label productAmountSoldLabel = new Label(GUIStringTool.getProductAmountSoldLabel());
+ productAmountSoldTextField = getNumberOnlyTextField(intFormat);
+ productAmountSoldTextField.textProperty().addListener((obs, oldVal, newVal)->{
+ try{
+ int oldInt = oldVal.isEmpty()?0:Integer.parseInt(oldVal);
+ int newInt = newVal.isEmpty()?0:Integer.parseInt(newVal);
+ ctrl.onAmountSoldChanged(oldInt, newInt);
+ }catch(NumberFormatException e){
+ e.printStackTrace();
+ }
+ });
+ addLineToGrid(mainPaneCenterContent, productAmountSoldLabel, productAmountSoldTextField);
+
+ Label productSellableLabel = new Label(GUIStringTool.getProductSellableLabel());
+ productSellableCheckBox = new CheckBox();
+ productSellableCheckBox.selectedProperty().addListener((obs, oldVal, newVal)->ctrl.onSellableStateChanged(oldVal,newVal));
+ addLineToGrid(mainPaneCenterContent, productSellableLabel, productSellableCheckBox);
+
+ Label productPriceLabel = new Label(GUIStringTool.getProductPriceLabel());
+ productPriceTextField = getNumberOnlyTextField(priceFormat);
+ productPriceTextField.textProperty().addListener((obs, oldVal, newVal)->{
+ try{
+ ctrl.onPriceChanged((oldVal.isEmpty()?-1:Double.parseDouble(oldVal)), (newVal.isEmpty()?-1:Double.parseDouble(newVal)));
+ }catch(NumberFormatException e){
+ e.printStackTrace();
+ }
+ });
+ addLineToGrid(mainPaneCenterContent, productPriceLabel, productPriceTextField);
+
+ mainPaneContent.setCenter(mainPaneCenterContent);
+
+ VBox mainPaneRightContent = new VBox();
+ mainPaneRightContent.setAlignment(Pos.CENTER);
+ Label title = new Label(GUIStringTool.getComponentListTitleLabel());
+ title.setAlignment(Pos.CENTER);
+ title.getStyleClass().add(GUICssTool.getTitleTextStyleClass());
+ productComponentsListView = new ListView<>();
+ productComponentsListView.setCellFactory(listView->new HighlightListCell(){
+ @Override
+ protected void updateItem(Product item, boolean empty) {
+ super.updateItem(item, empty);
+ if(item==null || empty){
+ setText(null);
+ setGraphic(null);
+ }else{
+ setText(GUIStringTool.getSimpleProductStringRenderer().render(item));
+ if(ctrl.isProductHighlighted(item)){
+ if(!isHightlighted()) {
+ setHighLight(true);
+ applyCss();
+ }
+ }else {
+ if (isHightlighted()) {
+ setHighLight(false);
+ applyCss();
+ }
+ }
+ }
+ }
+ });
+ productComponentsListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
+ productComponentsListView.getSelectionModel().selectedItemProperty().addListener((obs, oldValue, newValue)->{
+ this.ctrl.getProductComponentSelectionListener().changed(obs, oldValue, newValue);
+ if(newValue!=null)
+ Platform.runLater(()->productComponentsListView.getSelectionModel().clearSelection(productComponentsListView.getSelectionModel().getSelectedIndex()));
+ });
+
+ mainPaneRightContent.getChildren().addAll(title, productComponentsListView);
+ mainPaneContent.setRight(mainPaneRightContent);
+
+ HBox mainPaneBottomContent = new HBox();
+ HBox separator = new HBox();
+ SimpleValidator validator = new SimpleValidator();
+ validator.addListener(ctrl.getValidatorListener());
+ mainPaneBottomContent.getChildren().addAll(separator, validator.getPane());
+ HBox.setHgrow(separator, Priority.ALWAYS);
+
+ mainPaneContent.setBottom(mainPaneBottomContent);
+ mainPane.getChildren().add(mainPaneContent);
+ }
+
+ private void addLineToGrid(GridPane grid, Node... nodes){
+ gridLines++;
+ int columnIndex = 0;
+ for(Node node : nodes){
+ grid.add(node, columnIndex, gridLines);
+ columnIndex++;
+ }
+ }
+
+ private TextField getNumberOnlyTextField(NumberFormat format){
+ TextField textField = new TextField();
+ textField.textProperty().addListener((obs, oldValue, newValue)->{
+ if(!newValue.matches("^[-+]?[0-9]+[.,]?[0-9]*$"))
+ Platform.runLater(()->textField.setText(oldValue));
+ });
+ return textField;
+ }
+
+ @Override
+ public Pane getPane() {
+ return mainPane;
+ }
+
+ void setProduct(Product product){
+ if(product!=null){
+ Platform.runLater(()->{
+ productNameTextField.setText(product.getName());
+ productCategoryComboBox.setValue(product.getCategory());
+ productAmountRemainingTextField.setText(Integer.toString(product.getAmountRemaining()));
+ productAmountRemainingTextField.setEditable(product.getComponents().isEmpty());
+ productAmountSoldTextField.setText(Integer.toString(product.getAmountSold()));
+ productComponentsListView.getItems().clear();
+ productComponentsListView.getItems().addAll(product.getComponents());
+ productSellableCheckBox.setSelected(product.isSellable());
+ productPriceTextField.setText(Double.toString(product.getPrice()));
+ });
+ }
+
+ }
+
+ void setCategoryCollection(Collection categoryCollection){
+ Platform.runLater(()->{
+ productCategoryComboBox.getItems().clear();
+ productCategoryComboBox.getItems().addAll(categoryCollection);
+ });
+ }
+
+ void setProductCollection(Collection productCollection){
+ Platform.runLater(()->{
+ productComponentsListView.getItems().clear();
+ productComponentsListView.getItems().addAll(productCollection);
+ });
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/AccountManager.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/AccountManager.java
new file mode 100644
index 00000000..a88fb26c
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/AccountManager.java
@@ -0,0 +1,162 @@
+package com.pqt.client.gui.ressources.components;
+
+import com.pqt.client.gui.ressources.components.generics.creators.IFXCreatorComponent;
+import com.pqt.client.gui.ressources.components.generics.validators.IFXValidatorComponent;
+import com.pqt.client.gui.ressources.components.specifics.account.listeners.IAccountComponentListener;
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener;
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.SimpleValidatorComponentFirerer;
+import com.pqt.client.gui.ressources.components.specifics.account.IFXAccountsDisplayerComponent;
+import com.pqt.client.gui.ressources.components.specifics.account.listeners.SimpleAccountComponentFirerer;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.application.Platform;
+import javafx.collections.FXCollections;
+import javafx.scene.control.Button;
+import javafx.scene.control.ChoiceBox;
+import javafx.scene.control.PasswordField;
+import javafx.scene.control.TextField;
+import javafx.scene.input.KeyCode;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.VBox;
+
+import java.util.Collection;
+
+public class AccountManager implements IFXAccountsDisplayerComponent, IFXValidatorComponent, IFXCreatorComponent {
+
+ private Pane mainPane;
+
+ private VBox mainDisconnectedPane, mainConnectedPane;
+ private TextField connectedUsernameField;
+ private ChoiceBox disconnectedUsernameField;
+ private PasswordField passwordField;
+
+ private SimpleAccountComponentFirerer accountEventFirerer;
+ private SimpleValidatorComponentFirerer validatorEventFirerer;
+
+ private Account currentAccount;
+
+ public AccountManager() {
+ accountEventFirerer = new SimpleAccountComponentFirerer();
+ validatorEventFirerer = new SimpleValidatorComponentFirerer();
+
+ currentAccount = null;
+
+ init();
+ }
+
+ private void init() {
+ mainPane = new Pane();
+
+ mainConnectedPane = new VBox();
+ mainDisconnectedPane = new VBox();
+
+ connectedUsernameField = new TextField();
+ connectedUsernameField.setEditable(false);
+
+ Button disconnectButton = new Button(GUIStringTool.getLogoutButtonLabel());
+ disconnectButton.setOnMouseClicked(event->validatorEventFirerer.fireCancelEvent());
+ disconnectButton.setOnKeyTyped(event->{if(event.getCode().equals(KeyCode.ENTER)) validatorEventFirerer.fireCancelEvent();});
+
+ mainConnectedPane.getChildren().addAll(connectedUsernameField, disconnectButton);
+
+
+ disconnectedUsernameField = new ChoiceBox<>();
+ disconnectedUsernameField.setConverter(GUIStringTool.getAccountStringConverter());
+
+ passwordField = new PasswordField();
+ passwordField.setPromptText(GUIStringTool.getPasswordFieldPromptText());
+
+ Button validationButton = new Button(GUIStringTool.getLoginButtonLabel());
+ validationButton.setOnMouseClicked(event-> validatorEventFirerer.fireValidationEvent());
+ validationButton.setOnKeyTyped(event->{if(event.getCode().equals(KeyCode.ENTER)) validatorEventFirerer.fireValidationEvent();});
+
+ mainDisconnectedPane.getChildren().addAll(disconnectedUsernameField, passwordField, validationButton);
+
+ refreshMainPane();
+ display(null);
+ }
+
+ @Override
+ public void display(Collection content) {
+ Platform.runLater(()->{
+ if(content!=null && content.size()>0)
+ disconnectedUsernameField.setItems(FXCollections.observableArrayList(content));
+ else{
+ disconnectedUsernameField.getItems().clear();
+ disconnectedUsernameField.getItems().add(new Account("null", "", AccountLevel.getLowest()));
+ }
+ });
+ }
+
+ public void setCurrentAccount(Account account){
+ currentAccount = account;
+ Platform.runLater(()->connectedUsernameField.setText(GUIStringTool.getAccountStringConverter().toString(currentAccount)));
+ refreshMainPane();
+ }
+
+ private void refreshMainPane() {
+ if(currentAccount!=null)
+ Platform.runLater(
+ ()->{
+ mainPane.getChildren().clear();
+ mainPane.getChildren().add(mainConnectedPane);
+ }
+ );
+ else
+ Platform.runLater(
+ ()->{
+ mainPane.getChildren().clear();
+ mainPane.getChildren().add(mainDisconnectedPane);
+ }
+ );
+ }
+
+ public Account getCurrentAccount() {
+ return currentAccount;
+ }
+
+ @Override
+ public void addListener(IAccountComponentListener l) {
+ accountEventFirerer.addListener(l);
+ }
+
+ @Override
+ public void removeListener(IAccountComponentListener l) {
+ accountEventFirerer.removeListener(l);
+ }
+
+ @Override
+ public Pane getPane() {
+ return mainPane;
+ }
+
+ @Override
+ public void addListener(IValidatorComponentListener l) {
+ validatorEventFirerer.addListener(l);
+ }
+
+ @Override
+ public void removeListener(IValidatorComponentListener l) {
+ validatorEventFirerer.removeListener(l);
+ }
+
+ @Override
+ public Account create() {
+ if(!isCreationPossible())
+ return null;
+
+ return new Account(disconnectedUsernameField.getValue().getUsername(), passwordField.getText(), disconnectedUsernameField.getValue().getPermissionLevel());
+ }
+
+ @Override
+ public boolean isCreationPossible() {
+ return currentAccount==null
+ && disconnectedUsernameField.getAccessibleText()!=null
+ && !disconnectedUsernameField.getAccessibleText().isEmpty()
+ && passwordField.getText()!=null
+ && !passwordField.getText().isEmpty();
+
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/CategoryTabStockDisplayer.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/CategoryTabStockDisplayer.java
new file mode 100644
index 00000000..1e95f923
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/CategoryTabStockDisplayer.java
@@ -0,0 +1,129 @@
+package com.pqt.client.gui.ressources.components;
+
+import com.pqt.client.gui.ressources.components.generics.displayers.IFXDisplayerComponent;
+import com.pqt.client.gui.ressources.components.specifics.products.listeners.IStockComponentListener;
+import com.pqt.client.gui.ressources.components.specifics.products.listeners.SimpleStockComponentFirerer;
+import com.pqt.client.gui.ressources.css.GUICssTool;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.client.gui.ressources.strings.IObjectStringRenderer;
+import com.pqt.core.entities.product.Product;
+import javafx.application.Platform;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.geometry.Pos;
+import javafx.scene.control.*;
+import javafx.scene.input.KeyCode;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class CategoryTabStockDisplayer implements IFXDisplayerComponent, IStockComponentListener> {
+
+ private SimpleStockComponentFirerer firerer;
+ private BorderPane mainPane;
+ private TabPane tabPane;
+
+ public CategoryTabStockDisplayer() {
+ init();
+ firerer = new SimpleStockComponentFirerer();
+ }
+
+ @Override
+ public void display(Collection content) {
+ final ObservableList tabs = FXCollections.observableArrayList();
+ if(content!=null){
+ List categories = content.stream().map(product->product.getCategory().getName()).distinct().collect(Collectors.toList());
+
+ for(String cat : categories){
+ tabs.add(createCategoryTab(cat, content.stream().filter(p->p.getCategory().getName().equals(cat)).collect(Collectors.toList())));
+ }
+
+ }
+
+ Platform.runLater(()->{
+ tabPane.getTabs().clear();
+ tabPane.getTabs().addAll(tabs);
+ });
+ }
+
+ @Override
+ public void addListener(IStockComponentListener l) {
+ firerer.addListener(l);
+ }
+
+ @Override
+ public void removeListener(IStockComponentListener l) {
+ firerer.removeListener(l);
+ }
+
+ @Override
+ public Pane getPane() {
+ return mainPane;
+ }
+
+ private void init(){
+ mainPane = new BorderPane();
+
+ Label title = new Label(GUIStringTool.getCategorytabStockDisplayerTitle());
+ title.setAlignment(Pos.CENTER);
+ title.getStyleClass().add(GUICssTool.getTitleTextStyleClass());
+
+ HBox topPane = new HBox();
+ topPane.setFillHeight(true);
+ topPane.setAlignment(Pos.CENTER);
+ topPane.getChildren().add(title);
+
+ mainPane.setTop(topPane);
+
+ tabPane = new TabPane();
+ mainPane.setCenter(tabPane);
+ }
+
+ private Tab createCategoryTab(String categoryName, Collection products){
+ Tab tab = new Tab(categoryName);
+ tab.closableProperty().setValue(false);
+
+ ListView listView = new ListView<>();
+ listView.setCellFactory(list->new ListCell(){
+
+ @Override
+ protected void updateItem(Product item, boolean empty) {
+ super.updateItem(item, empty);
+
+ if (empty || item == null) {
+ setText(null);
+ setGraphic(null);
+ } else {
+ setText(CategoryTabStockDisplayer.getProductRenderer().render(item));
+ }
+ }
+ });
+
+ listView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
+ listView.setEditable(false);
+ listView.setOnMouseClicked(event->{
+ firerer.fireContentClickEvent(event, listView.getSelectionModel().getSelectedItem());
+ Platform.runLater(()->listView.getSelectionModel().clearSelection(listView.getSelectionModel().getSelectedIndex()));
+ });
+ listView.setOnKeyTyped(event -> {
+ if(event.getCode().equals(KeyCode.ENTER)){
+ firerer.fireContentClickEvent(event, listView.getSelectionModel().getSelectedItem());
+ Platform.runLater(()->listView.getSelectionModel().clearSelection(listView.getSelectionModel().getSelectedIndex()));
+ event.consume();
+ }
+ });
+
+ listView.setItems(FXCollections.observableArrayList(products));
+
+ tab.setContent(listView);
+ return tab;
+ }
+
+ private static IObjectStringRenderer getProductRenderer(){
+ return GUIStringTool.getDetailledProductStringRenderer();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/CommandComposerSaleDisplayer.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/CommandComposerSaleDisplayer.java
new file mode 100644
index 00000000..21460ac3
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/CommandComposerSaleDisplayer.java
@@ -0,0 +1,96 @@
+package com.pqt.client.gui.ressources.components;
+
+import com.pqt.client.gui.ressources.components.specifics.sale.IFXSaleDisplayerComponent;
+import com.pqt.client.gui.ressources.components.specifics.sale.listeners.ISaleComponentListener;
+import com.pqt.client.gui.ressources.components.specifics.sale.listeners.SimpleSaleComponentFirerer;
+import com.pqt.client.gui.ressources.css.GUICssTool;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.core.entities.product.Product;
+import com.pqt.core.entities.sale.Sale;
+import javafx.application.Platform;
+import javafx.geometry.Pos;
+import javafx.scene.control.*;
+import javafx.scene.input.KeyCode;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+
+public class CommandComposerSaleDisplayer implements IFXSaleDisplayerComponent {
+
+ private SimpleSaleComponentFirerer firerer;
+ private BorderPane mainPane;
+ private ListView listView;
+
+ private Sale sale;
+
+ public CommandComposerSaleDisplayer() {
+ firerer = new SimpleSaleComponentFirerer();
+ init();
+ }
+
+ private void init() {
+ mainPane = new BorderPane();
+
+ Label title = new Label(GUIStringTool.getCommandComposerTitleLabel());
+ title.setAlignment(Pos.CENTER);
+ title.getStyleClass().add(GUICssTool.getTitleTextStyleClass());
+
+ HBox topPane = new HBox();
+ topPane.setFillHeight(true);
+ topPane.setAlignment(Pos.CENTER);
+ topPane.getChildren().add(title);
+
+ mainPane.setTop(topPane);
+
+ listView = new ListView<>();
+ listView.setCellFactory(list->new ListCell(){
+ @Override
+ protected void updateItem(Product item, boolean empty) {
+ super.updateItem(item, empty);
+
+ if (empty || item == null) {
+ setText(null);
+ setGraphic(null);
+ } else {
+ setText(GUIStringTool.getSaleItemStringRenderer().render(item, sale.getProducts().get(item)));
+ }
+ }
+ });
+ listView.setEditable(false);
+ listView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
+ listView.setOnMouseClicked(event->firerer.fireComponentClickEvent(event, listView.getSelectionModel().getSelectedItem()));
+ listView.setOnKeyTyped(event -> {
+ if(event.getCode().equals(KeyCode.ENTER)){
+ firerer.fireComponentClickEvent(event, listView.getSelectionModel().getSelectedItem());
+ }
+ });
+ mainPane.setCenter(listView);
+ }
+
+ @Override
+ public void display(Sale content) {
+ if(content ==null)
+ return;
+
+ this.sale = content;
+ Platform.runLater(()->{
+ this.listView.getItems().clear();
+ this.listView.getItems().addAll(this.sale.getProducts().keySet());
+ });
+ }
+
+ @Override
+ public void addListener(ISaleComponentListener l) {
+ firerer.addListener(l);
+ }
+
+ @Override
+ public void removeListener(ISaleComponentListener l) {
+ firerer.removeListener(l);
+ }
+
+ @Override
+ public Pane getPane() {
+ return mainPane;
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/SimpleValidator.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/SimpleValidator.java
new file mode 100644
index 00000000..0d895aa4
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/SimpleValidator.java
@@ -0,0 +1,108 @@
+package com.pqt.client.gui.ressources.components;
+
+import com.pqt.client.gui.ressources.components.generics.validators.IFXValidatorComponent;
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentFirerer;
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener;
+import com.pqt.client.gui.ressources.strings.GUIStringTool;
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.SimpleValidatorComponentFirerer;
+import javafx.application.Platform;
+import javafx.scene.control.Button;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+
+public class SimpleValidator implements IFXValidatorComponent {
+
+ private final IValidatorComponentFirerer firerer;
+ private Pane pane;
+ private boolean askConfirmation;
+ private Button validationButton, cancelButton;
+
+ public SimpleValidator() {
+ this(false);
+ }
+
+ public SimpleValidator(boolean askConfirmation) {
+ firerer = new SimpleValidatorComponentFirerer();
+ this.askConfirmation = askConfirmation;
+ }
+
+ @Override
+ public void addListener(IValidatorComponentListener l) {
+ firerer.addListener(l);
+ }
+
+ @Override
+ public void removeListener(IValidatorComponentListener l) {
+ firerer.removeListener(l);
+ }
+
+ @Override
+ public Pane getPane() {
+ if(pane == null)
+ pane = createPane();
+ return pane;
+ }
+
+ private Pane createPane(){
+ GridPane grid = new GridPane();
+ grid.getStyleClass().add("validator");
+
+ validationButton = new Button(GUIStringTool.getValidationButtonLabel());
+ validationButton.setOnMouseClicked(event->{
+ getValidationButtonProcess().process();
+ });
+ grid.add(validationButton, 0,0);
+
+ cancelButton = new Button(GUIStringTool.getCancelButtonLabel());
+ cancelButton.setOnMouseClicked(event->{
+ getCancelButtonProcess().process();
+ });
+ grid.add(cancelButton, 1, 0);
+
+ return grid;
+ }
+
+ private IButtonProcess getValidationButtonProcess(){
+ return ()->{
+ if(validationButton.getText().equals(GUIStringTool.getValidationButtonLabel())){
+ if(askConfirmation)
+ Platform.runLater(()->validationButton.setText(GUIStringTool.getConfirmationValidationButtonLabel()));
+ else
+ firerer.fireValidationEvent();
+ }else{
+ if(validationButton.getText().equals(GUIStringTool.getConfirmationValidationButtonLabel()))
+ firerer.fireValidationEvent();
+ Platform.runLater(()->validationButton.setText(GUIStringTool.getValidationButtonLabel()));
+ }
+ };
+ }
+
+ private IButtonProcess getCancelButtonProcess(){
+ return ()->{
+ if(cancelButton.getText().equals(GUIStringTool.getCancelButtonLabel())){
+ if(askConfirmation)
+ Platform.runLater(()->cancelButton.setText(GUIStringTool.getConfirmationCancelButtonLabel()));
+ else
+ firerer.fireCancelEvent();
+ }else{
+ Platform.runLater(()->cancelButton.setText(GUIStringTool.getCancelButtonLabel()));
+ firerer.fireCancelEvent();
+ }
+ };
+
+
+ }
+
+ private interface IButtonProcess{
+ void process();
+ }
+
+ public void setValidationButtonEnable(boolean enable){
+ this.validationButton.setDisable(!enable);
+ }
+
+ public void setCancelationButtonEnable(boolean enable){
+ this.cancelButton.setDisable(!enable);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/IFXComponent.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/IFXComponent.java
new file mode 100644
index 00000000..d333e909
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/IFXComponent.java
@@ -0,0 +1,7 @@
+package com.pqt.client.gui.ressources.components.generics;
+
+import javafx.scene.layout.Pane;
+
+public interface IFXComponent {
+ Pane getPane();
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/creators/IFXCreatorComponent.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/creators/IFXCreatorComponent.java
new file mode 100644
index 00000000..4a79f9d1
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/creators/IFXCreatorComponent.java
@@ -0,0 +1,8 @@
+package com.pqt.client.gui.ressources.components.generics.creators;
+
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+
+public interface IFXCreatorComponent extends IFXComponent{
+ T create();
+ boolean isCreationPossible();
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/IFXDisplayerComponent.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/IFXDisplayerComponent.java
new file mode 100644
index 00000000..6d9ea7fb
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/IFXDisplayerComponent.java
@@ -0,0 +1,10 @@
+package com.pqt.client.gui.ressources.components.generics.displayers;
+
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.client.gui.ressources.components.generics.displayers.listeners.IDisplayerComponentListener;
+
+public interface IFXDisplayerComponent extends IFXComponent{
+ void display(T content);
+ void addListener(U l);
+ void removeListener(U l);
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/listeners/IDisplayerComponentFirerer.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/listeners/IDisplayerComponentFirerer.java
new file mode 100644
index 00000000..9824dd5f
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/listeners/IDisplayerComponentFirerer.java
@@ -0,0 +1,13 @@
+package com.pqt.client.gui.ressources.components.generics.displayers.listeners;
+
+import javafx.event.Event;
+
+public interface IDisplayerComponentFirerer {
+ void fireRefreshContentRequestEvent();
+ void fireContentClickEvent(Event event, T eventTarget);
+ void fireAddContentRequestEvent();
+ void fireRemoveContentRequestEvent(T content);
+ void fireDetailContentRequestEvent(T content);
+ void addListener(IDisplayerComponentListener l);
+ void removeListener(IDisplayerComponentListener l);
+}
\ No newline at end of file
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/listeners/IDisplayerComponentListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/listeners/IDisplayerComponentListener.java
new file mode 100644
index 00000000..e2c28d07
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/listeners/IDisplayerComponentListener.java
@@ -0,0 +1,13 @@
+package com.pqt.client.gui.ressources.components.generics.displayers.listeners;
+
+import javafx.event.Event;
+
+import java.util.EventListener;
+
+public interface IDisplayerComponentListener extends EventListener {
+ void onRefreshContentRequestEvent();
+ void onContentClickEvent(Event event, T eventTarget);
+ void onAddContentRequestEvent();
+ void onRemoveContentRequestEvent(T content);
+ void onDetailContentRequestEvent(T content);
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/listeners/SimpleDisplayerComponentFirerer.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/listeners/SimpleDisplayerComponentFirerer.java
new file mode 100644
index 00000000..c1909ad0
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/displayers/listeners/SimpleDisplayerComponentFirerer.java
@@ -0,0 +1,58 @@
+package com.pqt.client.gui.ressources.components.generics.displayers.listeners;
+
+import javafx.event.Event;
+
+import javax.swing.event.EventListenerList;
+import java.util.Arrays;
+
+public class SimpleDisplayerComponentFirerer> implements IDisplayerComponentFirerer {
+
+ protected EventListenerList listenerList;
+ protected Class clazz;
+
+ public SimpleDisplayerComponentFirerer(Class clazz) {
+ listenerList = new EventListenerList();
+ this.clazz = clazz;
+ }
+
+ @Override
+ public void fireRefreshContentRequestEvent() {
+ Arrays.stream(listenerList.getListeners(clazz)).forEach(IDisplayerComponentListener::onRefreshContentRequestEvent);
+ }
+
+ @Override
+ public void fireContentClickEvent(Event event, T eventTarget) {
+ Arrays.stream(listenerList.getListeners(clazz)).forEach(l->l.onContentClickEvent(event, eventTarget));
+ }
+
+ @Override
+ public void fireAddContentRequestEvent() {
+ Arrays.stream(listenerList.getListeners(clazz)).forEach(IDisplayerComponentListener::onAddContentRequestEvent);
+ }
+
+ @Override
+ public void fireRemoveContentRequestEvent(T content) {
+ Arrays.stream(listenerList.getListeners(clazz)).forEach(l->l.onRemoveContentRequestEvent(content));
+ }
+
+ @Override
+ public void fireDetailContentRequestEvent(T content) {
+ Arrays.stream(listenerList.getListeners(clazz)).forEach(l->l.onDetailContentRequestEvent(content));
+ }
+
+ @Override
+ public void addListener(IDisplayerComponentListener l) throws IllegalArgumentException {
+ if(clazz.isInstance(l)){
+ listenerList.add(clazz, clazz.cast(l));
+ }else{
+ throw new IllegalArgumentException("Listener must implement the following interface : "+clazz.getName());
+ }
+ }
+
+ @Override
+ public void removeListener(IDisplayerComponentListener l) {
+ if (clazz.isInstance(l)) {
+ listenerList.remove(clazz, clazz.cast(l));
+ }
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/javafx_override/CssEnabledGridPane.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/javafx_override/CssEnabledGridPane.java
new file mode 100644
index 00000000..3ef68e26
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/javafx_override/CssEnabledGridPane.java
@@ -0,0 +1,11 @@
+package com.pqt.client.gui.ressources.components.generics.javafx_override;
+
+import javafx.scene.layout.GridPane;
+
+public class CssEnabledGridPane extends GridPane {
+
+ public CssEnabledGridPane() {
+ super();
+ this.getStyleClass().add("grid-pane");
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/javafx_override/HighlightListCell.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/javafx_override/HighlightListCell.java
new file mode 100644
index 00000000..985b058c
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/javafx_override/HighlightListCell.java
@@ -0,0 +1,25 @@
+package com.pqt.client.gui.ressources.components.generics.javafx_override;
+
+import javafx.css.PseudoClass;
+import javafx.scene.control.ListCell;
+
+public class HighlightListCell extends ListCell {
+
+ private PseudoClass highlightPC;
+ private boolean highlighted;
+
+ public HighlightListCell() {
+ super();
+ highlighted = false;
+ highlightPC = PseudoClass.getPseudoClass("highlighted");
+ }
+
+ public void setHighLight(boolean highLight){
+ highlighted = highLight;
+ this.pseudoClassStateChanged(highlightPC, highLight);
+ }
+
+ public boolean isHightlighted(){
+ return highlighted;
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/others/SideBar.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/others/SideBar.java
new file mode 100644
index 00000000..d5c5351a
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/others/SideBar.java
@@ -0,0 +1,119 @@
+package com.pqt.client.gui.ressources.components.generics.others;
+
+import com.pqt.client.gui.ressources.components.generics.others.listeners.ISideBarListener;
+import javafx.animation.Animation;
+import javafx.animation.Transition;
+import javafx.beans.value.ObservableValue;
+import javafx.css.*;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.layout.VBox;
+import javafx.util.Duration;
+
+import javax.swing.event.EventListenerList;
+import java.util.Arrays;
+import java.util.List;
+
+public class SideBar extends VBox {
+
+ private static final StyleablePropertyFactory FACTORY = new StyleablePropertyFactory<>(VBox.getClassCssMetaData());
+
+ private static final CssMetaData EXPANDED_WIDTH =
+ FACTORY.createSizeCssMetaData("-pqt-expanded-width",p->p.expandedWidth, 100, false);
+
+ private StyleableProperty expandedWidth;
+ private EventListenerList listenerList;
+ private Animation collapseSideBar, expandSideBar;
+
+ /** creates a sidebar containing a vertical alignment of the given nodes */
+ public SideBar(Node... children) {
+ listenerList = new EventListenerList();
+ getStyleClass().add("sidebar");
+ this.setMinWidth(0);
+ this.expandedWidth = new SimpleStyleableDoubleProperty(EXPANDED_WIDTH, this, "expanded-width");
+ this.setPrefWidth(expandedWidth.getValue().doubleValue());
+
+ setAlignment(Pos.CENTER);
+ getChildren().addAll(children);
+
+ // create an animation to show a sidebar.
+ expandSideBar = new Transition() {
+ {
+ setCycleDuration(Duration.millis(250));
+ }
+ protected void interpolate(double frac) {
+ SideBar.this.setVisible(true);
+ final double curWidth = expandedWidth.getValue().doubleValue() * frac;
+ setPrefWidth(curWidth);
+ setTranslateX(-expandedWidth.getValue().doubleValue() + curWidth);
+ }
+ };
+ expandSideBar.onFinishedProperty().set(actionEvent ->
+ Arrays.stream(listenerList.getListeners(ISideBarListener.class))
+ .forEach(ISideBarListener::onExpandFinished)
+ );
+
+
+ // create an animation to hide sidebar.
+ collapseSideBar = new Transition() {
+ {
+ setCycleDuration(Duration.millis(250));
+ }
+ protected void interpolate(double frac) {
+ final double curWidth = expandedWidth.getValue().doubleValue() * (1.0 - frac);
+ setPrefWidth(curWidth);
+ setTranslateX(-expandedWidth.getValue().doubleValue() + curWidth);
+ }
+ };
+ collapseSideBar.onFinishedProperty().set(actionEvent ->{
+ setVisible(false);
+ Arrays.stream(listenerList.getListeners(ISideBarListener.class))
+ .forEach(ISideBarListener::onCollapsedFinished);
+ });
+ collapse();
+ }
+
+ public void expand(){
+ if (expandSideBar.statusProperty().get() == Animation.Status.STOPPED
+ && collapseSideBar.statusProperty().get() == Animation.Status.STOPPED) {
+ if (!isVisible()) {
+ expandSideBar.play();
+ }
+ }
+ }
+
+ public void collapse(){
+ if (expandSideBar.statusProperty().get() == Animation.Status.STOPPED
+ && collapseSideBar.statusProperty().get() == Animation.Status.STOPPED) {
+ if (isVisible()) {
+ collapseSideBar.play();
+ }
+ }
+ }
+
+ public boolean isExpanded(){
+ return isVisible() && expandSideBar.statusProperty().get().equals(Animation.Status.STOPPED);
+ }
+
+ public boolean isCollapsed() {
+ return !isVisible() && collapseSideBar.statusProperty().get().equals(Animation.Status.STOPPED);
+ }
+
+ public void addListener(ISideBarListener listener){
+ listenerList.add(ISideBarListener.class, listener);
+ }
+
+ public void removeListener(ISideBarListener listener){
+ listenerList.remove(ISideBarListener.class, listener);
+ }
+
+
+ public static List> getClassCssMetaData() {
+ return FACTORY.getCssMetaData();
+ }
+
+ @Override
+ public List> getCssMetaData() {
+ return FACTORY.getCssMetaData();
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/others/listeners/ISideBarListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/others/listeners/ISideBarListener.java
new file mode 100644
index 00000000..2a1314ff
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/others/listeners/ISideBarListener.java
@@ -0,0 +1,9 @@
+package com.pqt.client.gui.ressources.components.generics.others.listeners;
+
+import java.util.EventListener;
+
+public interface ISideBarListener extends EventListener {
+
+ void onCollapsedFinished();
+ void onExpandFinished();
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/toast/Toast.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/toast/Toast.java
new file mode 100644
index 00000000..051cc5ac
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/toast/Toast.java
@@ -0,0 +1,54 @@
+package com.pqt.client.gui.ressources.components.generics.toast;
+
+import com.pqt.client.gui.ressources.css.GUICssTool;
+import javafx.animation.KeyFrame;
+import javafx.animation.KeyValue;
+import javafx.animation.Timeline;
+import javafx.scene.Scene;
+import javafx.scene.layout.StackPane;
+import javafx.scene.paint.Color;
+import javafx.scene.text.Text;
+import javafx.stage.Stage;
+import javafx.stage.StageStyle;
+import javafx.util.Duration;
+
+final class Toast {
+ static void toast(Stage ownerStage, String toastMsg, int toastDelay, int fadeInDelay, int fadeOutDelay) {
+ Stage toastStage = new Stage();
+ toastStage.initOwner(ownerStage);
+ toastStage.setResizable(false);
+ toastStage.initStyle(StageStyle.TRANSPARENT);
+
+ Text text = new Text(toastMsg);
+ text.getStyleClass().add("toast-text");
+
+ StackPane root = new StackPane(text);
+ root.getStyleClass().add("toast-pane");
+ root.setOpacity(0);
+
+ Scene scene = new Scene(root);
+ scene.setFill(Color.TRANSPARENT);
+ scene.getStylesheets().addAll(Toast.class.getResource(GUICssTool.getCssFilePath()).toExternalForm());
+ toastStage.setScene(scene);
+ toastStage.show();
+
+ Timeline fadeInTimeline = new Timeline();
+ KeyFrame fadeInKey1 = new KeyFrame(Duration.millis(fadeInDelay), new KeyValue (toastStage.getScene().getRoot().opacityProperty(), 1));
+ fadeInTimeline.getKeyFrames().add(fadeInKey1);
+ fadeInTimeline.setOnFinished((ae) ->
+ new Thread(() -> {
+ try {
+ Thread.sleep(toastDelay);
+ }
+ catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ Timeline fadeOutTimeline = new Timeline();
+ KeyFrame fadeOutKey1 = new KeyFrame(Duration.millis(fadeOutDelay), new KeyValue (toastStage.getScene().getRoot().opacityProperty(), 0));
+ fadeOutTimeline.getKeyFrames().add(fadeOutKey1);
+ fadeOutTimeline.setOnFinished((aeb) -> toastStage.close());
+ fadeOutTimeline.play();
+ }).start());
+ fadeInTimeline.play();
+ }
+}
\ No newline at end of file
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/toast/ToastFactory.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/toast/ToastFactory.java
new file mode 100644
index 00000000..d174244e
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/toast/ToastFactory.java
@@ -0,0 +1,46 @@
+package com.pqt.client.gui.ressources.components.generics.toast;
+
+import javafx.stage.Stage;
+
+public class ToastFactory {
+
+ private static ToastFactory INSTANCE = null;
+
+ private Stage stage;
+ private int delay, fadeInDelay, fadeOutDelay;
+
+ private ToastFactory(Stage stage){
+ this.stage = stage;
+ delay = 3000;
+ fadeInDelay = 250;
+ fadeOutDelay = 250;
+ }
+
+ public void setToastDelay(int msDelay){
+ this.delay = msDelay;
+ }
+
+ public void setToastFadeInDelay(int msDelay){
+ this.fadeInDelay = msDelay;
+ }
+
+ public void setToastFadeOutDelay(int msDelay){
+ this.fadeOutDelay = msDelay;
+ }
+
+ public void toast(String message){
+ Toast.toast(stage, message, delay, fadeInDelay, fadeOutDelay);
+ }
+
+ public static void init(Stage stage){
+ INSTANCE = new ToastFactory(stage);
+ }
+
+ public static boolean isInitialized(){
+ return INSTANCE!=null;
+ }
+
+ public static ToastFactory getINSTANCE(){
+ return INSTANCE;
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/IFXValidatorComponent.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/IFXValidatorComponent.java
new file mode 100644
index 00000000..01f96276
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/IFXValidatorComponent.java
@@ -0,0 +1,9 @@
+package com.pqt.client.gui.ressources.components.generics.validators;
+
+import com.pqt.client.gui.ressources.components.generics.IFXComponent;
+import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener;
+
+public interface IFXValidatorComponent extends IFXComponent{
+ void addListener(IValidatorComponentListener l);
+ void removeListener(IValidatorComponentListener l);
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/listeners/IValidatorComponentFirerer.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/listeners/IValidatorComponentFirerer.java
new file mode 100644
index 00000000..2e44be06
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/listeners/IValidatorComponentFirerer.java
@@ -0,0 +1,9 @@
+package com.pqt.client.gui.ressources.components.generics.validators.listeners;
+
+public interface IValidatorComponentFirerer {
+ void addListener(IValidatorComponentListener l);
+ void removeListener(IValidatorComponentListener l);
+
+ void fireValidationEvent();
+ void fireCancelEvent();
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/listeners/IValidatorComponentListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/listeners/IValidatorComponentListener.java
new file mode 100644
index 00000000..c4144f91
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/listeners/IValidatorComponentListener.java
@@ -0,0 +1,8 @@
+package com.pqt.client.gui.ressources.components.generics.validators.listeners;
+
+import java.util.EventListener;
+
+public interface IValidatorComponentListener extends EventListener {
+ void onValidationEvent();
+ void onCancelEvent();
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/listeners/SimpleValidatorComponentFirerer.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/listeners/SimpleValidatorComponentFirerer.java
new file mode 100644
index 00000000..cdaa979c
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/generics/validators/listeners/SimpleValidatorComponentFirerer.java
@@ -0,0 +1,33 @@
+package com.pqt.client.gui.ressources.components.generics.validators.listeners;
+
+import javax.swing.event.EventListenerList;
+import java.util.Arrays;
+
+public class SimpleValidatorComponentFirerer implements IValidatorComponentFirerer {
+
+ private EventListenerList listenerList;
+
+ public SimpleValidatorComponentFirerer() {
+ listenerList = new EventListenerList();
+ }
+
+ @Override
+ public void addListener(IValidatorComponentListener l) {
+ listenerList.add(IValidatorComponentListener.class, l);
+ }
+
+ @Override
+ public void removeListener(IValidatorComponentListener l) {
+ listenerList.remove(IValidatorComponentListener.class, l);
+ }
+
+ @Override
+ public void fireValidationEvent() {
+ Arrays.stream(listenerList.getListeners(IValidatorComponentListener.class)).forEach(IValidatorComponentListener::onValidationEvent);
+ }
+
+ @Override
+ public void fireCancelEvent() {
+ Arrays.stream(listenerList.getListeners(IValidatorComponentListener.class)).forEach(IValidatorComponentListener::onCancelEvent);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/account/IFXAccountsDisplayerComponent.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/account/IFXAccountsDisplayerComponent.java
new file mode 100644
index 00000000..1c459115
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/account/IFXAccountsDisplayerComponent.java
@@ -0,0 +1,11 @@
+package com.pqt.client.gui.ressources.components.specifics.account;
+
+import com.pqt.client.gui.ressources.components.generics.displayers.IFXDisplayerComponent;
+import com.pqt.client.gui.ressources.components.specifics.account.listeners.IAccountComponentListener;
+import com.pqt.core.entities.user_account.Account;
+
+import java.util.Collection;
+
+public interface IFXAccountsDisplayerComponent extends IFXDisplayerComponent, IAccountComponentListener> {
+
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/account/listeners/IAccountComponentListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/account/listeners/IAccountComponentListener.java
new file mode 100644
index 00000000..9fe3ff70
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/account/listeners/IAccountComponentListener.java
@@ -0,0 +1,7 @@
+package com.pqt.client.gui.ressources.components.specifics.account.listeners;
+
+import com.pqt.client.gui.ressources.components.generics.displayers.listeners.IDisplayerComponentListener;
+import com.pqt.core.entities.user_account.Account;
+
+public interface IAccountComponentListener extends IDisplayerComponentListener{
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/account/listeners/SimpleAccountComponentFirerer.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/account/listeners/SimpleAccountComponentFirerer.java
new file mode 100644
index 00000000..8f06f6a2
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/account/listeners/SimpleAccountComponentFirerer.java
@@ -0,0 +1,10 @@
+package com.pqt.client.gui.ressources.components.specifics.account.listeners;
+
+import com.pqt.client.gui.ressources.components.generics.displayers.listeners.SimpleDisplayerComponentFirerer;
+import com.pqt.core.entities.user_account.Account;
+
+public class SimpleAccountComponentFirerer extends SimpleDisplayerComponentFirerer {
+ public SimpleAccountComponentFirerer() {
+ super(IAccountComponentListener.class);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/products/IFXProductsDisplayerComponent.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/products/IFXProductsDisplayerComponent.java
new file mode 100644
index 00000000..5411b73d
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/products/IFXProductsDisplayerComponent.java
@@ -0,0 +1,10 @@
+package com.pqt.client.gui.ressources.components.specifics.products;
+
+import com.pqt.client.gui.ressources.components.generics.displayers.IFXDisplayerComponent;
+import com.pqt.client.gui.ressources.components.specifics.products.listeners.IStockComponentListener;
+import com.pqt.core.entities.product.Product;
+
+import java.util.Collection;
+
+public interface IFXProductsDisplayerComponent extends IFXDisplayerComponent, IStockComponentListener> {
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/products/listeners/IStockComponentListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/products/listeners/IStockComponentListener.java
new file mode 100644
index 00000000..0dffba47
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/products/listeners/IStockComponentListener.java
@@ -0,0 +1,7 @@
+package com.pqt.client.gui.ressources.components.specifics.products.listeners;
+
+import com.pqt.client.gui.ressources.components.generics.displayers.listeners.IDisplayerComponentListener;
+import com.pqt.core.entities.product.Product;
+
+public interface IStockComponentListener extends IDisplayerComponentListener {
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/products/listeners/SimpleStockComponentFirerer.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/products/listeners/SimpleStockComponentFirerer.java
new file mode 100644
index 00000000..5832a288
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/products/listeners/SimpleStockComponentFirerer.java
@@ -0,0 +1,11 @@
+package com.pqt.client.gui.ressources.components.specifics.products.listeners;
+
+import com.pqt.client.gui.ressources.components.generics.displayers.listeners.SimpleDisplayerComponentFirerer;
+import com.pqt.core.entities.product.Product;
+
+public class SimpleStockComponentFirerer extends SimpleDisplayerComponentFirerer {
+
+ public SimpleStockComponentFirerer() {
+ super(IStockComponentListener.class);
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/sale/IFXSaleDisplayerComponent.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/sale/IFXSaleDisplayerComponent.java
new file mode 100644
index 00000000..5f0a0fbc
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/sale/IFXSaleDisplayerComponent.java
@@ -0,0 +1,8 @@
+package com.pqt.client.gui.ressources.components.specifics.sale;
+
+import com.pqt.client.gui.ressources.components.generics.displayers.IFXDisplayerComponent;
+import com.pqt.client.gui.ressources.components.specifics.sale.listeners.ISaleComponentListener;
+import com.pqt.core.entities.sale.Sale;
+
+public interface IFXSaleDisplayerComponent extends IFXDisplayerComponent {
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/sale/listeners/ISaleComponentListener.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/sale/listeners/ISaleComponentListener.java
new file mode 100644
index 00000000..f64fbc7f
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/sale/listeners/ISaleComponentListener.java
@@ -0,0 +1,10 @@
+package com.pqt.client.gui.ressources.components.specifics.sale.listeners;
+
+import com.pqt.client.gui.ressources.components.generics.displayers.listeners.IDisplayerComponentListener;
+import com.pqt.core.entities.product.Product;
+import com.pqt.core.entities.sale.Sale;
+import javafx.event.Event;
+
+public interface ISaleComponentListener extends IDisplayerComponentListener {
+ void onComponentClickEvent(Event event, Product product);
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/sale/listeners/SimpleSaleComponentFirerer.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/sale/listeners/SimpleSaleComponentFirerer.java
new file mode 100644
index 00000000..aa83a903
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/components/specifics/sale/listeners/SimpleSaleComponentFirerer.java
@@ -0,0 +1,19 @@
+package com.pqt.client.gui.ressources.components.specifics.sale.listeners;
+
+import com.pqt.client.gui.ressources.components.generics.displayers.listeners.SimpleDisplayerComponentFirerer;
+import com.pqt.core.entities.product.Product;
+import com.pqt.core.entities.sale.Sale;
+import javafx.event.Event;
+
+import java.util.Arrays;
+
+public class SimpleSaleComponentFirerer extends SimpleDisplayerComponentFirerer {
+
+ public SimpleSaleComponentFirerer() {
+ super(ISaleComponentListener.class);
+ }
+
+ public void fireComponentClickEvent(Event event, Product product) {
+ Arrays.stream(listenerList.getListeners(ISaleComponentListener.class)).forEach(l->l.onComponentClickEvent(event, product));
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/css/GUICssTool.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/css/GUICssTool.java
new file mode 100644
index 00000000..a2f283e5
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/css/GUICssTool.java
@@ -0,0 +1,20 @@
+package com.pqt.client.gui.ressources.css;
+
+public class GUICssTool {
+ public static String getCssFilePath(){
+ //return "/daymode-blue.css";
+ return "/nightmode.css";
+ }
+
+ public static String getMainModulePaneCssClass() {
+ return "main-module-pane";
+ }
+
+ public static String getIntermediaryPaneStyleClass() {
+ return "grey-intermediary-pane";
+ }
+
+ public static String getTitleTextStyleClass() {
+ return "label-header";
+ }
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/strings/GUIStringTool.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/strings/GUIStringTool.java
new file mode 100644
index 00000000..af5f1781
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/strings/GUIStringTool.java
@@ -0,0 +1,336 @@
+package com.pqt.client.gui.ressources.strings;
+
+import com.pqt.core.entities.product.Category;
+import com.pqt.core.entities.product.Product;
+import com.pqt.core.entities.sale.SaleStatus;
+import com.pqt.core.entities.sale.SaleType;
+import com.pqt.core.entities.user_account.Account;
+import com.pqt.core.entities.user_account.AccountLevel;
+import javafx.util.StringConverter;
+
+import java.text.NumberFormat;
+import java.util.EnumSet;
+
+//TODO faire ça un peu mieux
+public class GUIStringTool {
+
+ public static String getValidationButtonLabel() {
+ return "Valider";
+ }
+
+ public static String getConfirmationValidationButtonLabel() {
+ return "Confirmer";
+ }
+
+ public static String getCancelButtonLabel() {
+ return "Annuler";
+ }
+
+ public static String getConfirmationCancelButtonLabel() {
+ return "Confirmer";
+ }
+
+ public static String getCategorytabStockDisplayerTitle() {
+ return "Produits";
+ }
+
+ public static IObjectStringRenderer getDetailledProductStringRenderer(){
+ return product->{
+ if(product!=null){
+ String amountStr;
+ if(product.getAmountRemaining()<=0){
+ amountStr = "OUT OF STOCK";
+ }else if(product.getAmountRemaining()>=30){
+ amountStr = "30+";
+ }else{
+ amountStr = Integer.toString(product.getAmountRemaining());
+ }
+ return String.format("%s - %.2f€ (%s)", product.getName(), product.getPrice(), amountStr);
+ }else
+ return "null";
+ };
+ }
+
+ public static IObjectStringRenderer getSimpleProductStringRenderer(){
+ return product->{
+ if(product!=null)
+ return String.format("%s - %.2f€", product.getName(), product.getPrice());
+ else
+ return "null";
+ };
+ }
+
+ public static String getCommandComposerTitleLabel() {
+ return "Commande";
+ }
+
+ public static IObjectWithQuantityStringRenderer getSaleItemStringRenderer(){
+ return (product, qte)->String.format("%dx %s", qte, product.getName());
+ }
+
+ public static String getPasswordFieldPromptText() {
+ return "mot de passe";
+ }
+
+ public static StringConverter getAccountStringConverter() {
+ return new StringConverter() {
+ @Override
+ public String toString(Account object) {
+ if(object!=null)
+ return String.format("%s - (%s)", object.getUsername(), object.getPermissionLevel());
+
+ return "null";
+ }
+
+ @Override
+ public Account fromString(String string) {
+ Account reply = new Account();
+
+ String[] pieces = string.split(" - ");
+ reply.setUsername(pieces[0]);
+ if(pieces.length>1)
+ for(AccountLevel al : EnumSet.allOf(AccountLevel.class)){
+ if(al.name().equals(pieces[1]))
+ reply.setPermissionLevel(al);
+ }
+
+ return reply;
+ }
+ };
+ }
+
+ public static String getLogoutButtonLabel() {
+ return "Déconnexion";
+ }
+
+ public static String getLoginButtonLabel() {
+ return "Connexion";
+ }
+
+ public static IObjectStringRenderer getPriceRenderer() {
+ return price -> NumberFormat.getCurrencyInstance().format(price);
+ }
+
+ public static String getSaleMakerTextFieldPromptText() {
+ return "Auteur";
+ }
+
+ public static String getSaleMakerTextFieldLabel() {
+ return "Fait par : ";
+ }
+
+ public static String getSaleBeneficiaryTextFieldLabel() {
+ return "Fait pour : ";
+ }
+
+ public static String getSaleTypeTextFieldLabel() {
+ return "Type de paiement : ";
+ }
+
+ public static String getSalePriceTextFieldLabel() {
+ return "Prix de la commande : ";
+ }
+
+ public static StringConverter getSaleTypeStringConverter() {
+ return new StringConverter() {
+ @Override
+ public String toString(SaleType object) {
+ return object.name();
+ }
+
+ @Override
+ public SaleType fromString(String string) {
+ return EnumSet.allOf(SaleType.class).stream().filter(type->type.name().equals(string)).findFirst().orElse(null);
+ }
+ };
+ }
+
+ public static String getSalePriceTextFieldPromptText() {
+ return getPriceRenderer().render(0d);
+ }
+
+ public static String getCommandValidationErrorMessage() {
+ return "La commande n'a pas pu être validée";
+ }
+
+ public static String getCommandValidationErrorMessage(Throwable cause) {
+ return "La commande n'a pas pu être validée : "+cause.getMessage();
+ }
+
+ public static String getSaleIdLabel() {
+ return "Numéro de commande : ";
+ }
+
+ public static String getSaleStatusLabel() {
+ return "Etat actuel";
+ }
+
+ public static IObjectStringRenderer getSaleStatusRenderer() {
+ return Enum::name;
+ }
+
+ public static String getOkButtonLabel() {
+ return "OK";
+ }
+
+ public static String getAppTitle() {
+ return "Client PQT - Gargotte";
+ }
+
+ public static String getSideBarCollapseButtonLabel() {
+ return "Réduire";
+ }
+
+ public static String getSideBarExpandButtonLabel() {
+ return "Menu";
+ }
+
+ public static String getSaleGuiModuleName() {
+ return "Vente";
+ }
+
+ public static String getAddButtonLabel() {
+ return "Ajouter";
+ }
+
+ public static String getDetailButtonLabel() {
+ return "Détail";
+ }
+
+ public static String getRemoveButtonLabel() {
+ return "Supprimer";
+ }
+
+ public static String getRefreshButtonLabel() {
+ return "Rafraichir";
+ }
+
+ public static String getProductNameColumnHeader() {
+ return "Nom";
+ }
+
+ public static String getProductCategoryColumnHeader() {
+ return "Catégorie";
+ }
+
+ public static String getProductAmountRemainingColumnHeader() {
+ return "Stock";
+ }
+
+ public static String getProductAmountSoldColumnHeader() {
+ return "Vendu";
+ }
+
+ public static String getProductPriceColumnHeader() {
+ return "Prix";
+ }
+
+ public static String getProductIsSellableColumnHeader() {
+ return "Vendable";
+ }
+
+ public static IObjectStringRenderer getBooleanRenderer() {
+ return bool->bool?"Oui":"Non";
+ }
+
+ public static String getStatGuiModuleName() {
+ return "Statistiques";
+ }
+
+ public static String getProductNameLabel() {
+ return "Nom : ";
+ }
+
+ public static String getProductCategoryLabel() {
+ return "Catégorie : ";
+ }
+
+ public static String getProductAmountRemainingLabel() {
+ return "En stock : ";
+ }
+
+ public static String getProductAmountSoldLabel() {
+ return "Vendu : ";
+ }
+
+ public static String getProductSellableLabel() {
+ return "Vendable : ";
+ }
+
+ public static String getProductPriceLabel() {
+ return "Prix : ";
+ }
+
+ public static StringConverter getCategoryStringConverter() {
+ return new StringConverter() {
+ @Override
+ public String toString(Category object) {
+ if(object!=null)
+ return object.getName();
+ else
+ return "";
+ }
+
+ @Override
+ public Category fromString(String string) {
+ if(string!=null)
+ return new Category(-1, string);
+ else
+ return null;
+ }
+ };
+ }
+
+ public static String getComponentListTitleLabel() {
+ return "Composants";
+ }
+
+ public static String getAccountGuiModuleName() {
+ return "Utilisateurs";
+ }
+
+ public static IObjectStringRenderer getAccountLevelStringRenderer() {
+ return level->{
+ switch (level){
+ case LOWEST:
+ return "autre";
+ case GUEST:
+ return "Invité";
+ case STAFF:
+ return "Staff";
+ case WAITER:
+ return "Caissier";
+ case MASTER:
+ return "Chef";
+ default:
+ return "unknown";
+ }
+ };
+ }
+
+ public static String getAccountListTitleLabel() {
+ return "Utilisateurs";
+ }
+
+ public static String getUsernameLabel() {
+ return "Nom :";
+ }
+
+ public static String getPasswordLabel() {
+ return "Mot de passe : ";
+ }
+
+ public static String getUserLevelLabel() {
+ return "Niveau d'accréditation : ";
+ }
+
+ public static String getAccountNameColumnHeaderLabel() {
+ return "Nom d'utilisateur";
+ }
+
+ public static String getAccountLevelColumnHeaderLabel() {
+ return "Niveau d'accréditation";
+ }
+}
+
+
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/strings/IObjectStringRenderer.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/strings/IObjectStringRenderer.java
new file mode 100644
index 00000000..ebbb8c6a
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/strings/IObjectStringRenderer.java
@@ -0,0 +1,5 @@
+package com.pqt.client.gui.ressources.strings;
+
+public interface IObjectStringRenderer {
+ String render(T obj);
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/ressources/strings/IObjectWithQuantityStringRenderer.java b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/strings/IObjectWithQuantityStringRenderer.java
new file mode 100644
index 00000000..52dbbed2
--- /dev/null
+++ b/Workspace/client/src/main/java/com/pqt/client/gui/ressources/strings/IObjectWithQuantityStringRenderer.java
@@ -0,0 +1,5 @@
+package com.pqt.client.gui.ressources.strings;
+
+public interface IObjectWithQuantityStringRenderer {
+ String render(T obj, int quantity);
+}
diff --git a/Workspace/client/src/main/java/com/pqt/client/module/account/AccountService.java b/Workspace/client/src/main/java/com/pqt/client/module/account/AccountService.java
index c3affffa..9f6c76a0 100644
--- a/Workspace/client/src/main/java/com/pqt/client/module/account/AccountService.java
+++ b/Workspace/client/src/main/java/com/pqt/client/module/account/AccountService.java
@@ -18,7 +18,7 @@ public class AccountService {
}
- public boolean isAccountLoggedIn(Account account) {
+ public boolean isCurrentAccountLoggedIn() {
return false;
}
@@ -26,7 +26,7 @@ public class AccountService {
}
- public void logOutCurrentAccount(String password) {
+ public void logOutCurrentAccount() {
}
@@ -42,4 +42,7 @@ public class AccountService {
}
+ public List getAllAccounts() {
+ return null;
+ }
}
diff --git a/Workspace/client/src/main/java/com/pqt/client/module/account/listeners/AccountListenerAdapter.java b/Workspace/client/src/main/java/com/pqt/client/module/account/listeners/AccountListenerAdapter.java
index 50243c75..6abd0649 100644
--- a/Workspace/client/src/main/java/com/pqt/client/module/account/listeners/AccountListenerAdapter.java
+++ b/Workspace/client/src/main/java/com/pqt/client/module/account/listeners/AccountListenerAdapter.java
@@ -6,9 +6,16 @@ public class AccountListenerAdapter implements IAccountListener {
/**
- * @see com.pqt.client.module.account.listeners.IAccountListener#onAccountStatusChanged(boolean)
+ * @see com.pqt.client.module.account.listeners.IAccountListener#onAccountStatusChangedEvent(boolean)
*/
- public void onAccountStatusChanged(boolean status) {
+ public void onAccountStatusChangedEvent(boolean status) {
+
+ }
+
+ /**
+ * @see com.pqt.client.module.account.listeners.IAccountListener#onAccountListChangedEvent()
+ */
+ public void onAccountListChangedEvent() {
}
diff --git a/Workspace/client/src/main/java/com/pqt/client/module/account/listeners/IAccountListener.java b/Workspace/client/src/main/java/com/pqt/client/module/account/listeners/IAccountListener.java
index 7fa6dfef..0de33085 100644
--- a/Workspace/client/src/main/java/com/pqt/client/module/account/listeners/IAccountListener.java
+++ b/Workspace/client/src/main/java/com/pqt/client/module/account/listeners/IAccountListener.java
@@ -4,6 +4,6 @@ import java.util.EventListener;
public interface IAccountListener extends EventListener {
- public void onAccountStatusChanged(boolean status);
-
+ void onAccountStatusChangedEvent(boolean status);
+ void onAccountListChangedEvent();
}
diff --git a/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleBuilder.java b/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleBuilder.java
index 4c550960..a70bac00 100644
--- a/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleBuilder.java
+++ b/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleBuilder.java
@@ -1,5 +1,6 @@
package com.pqt.client.module.sale;
+import com.pqt.client.module.stock.StockDao;
import com.pqt.core.entities.members.Client;
import com.pqt.core.entities.product.Product;
import com.pqt.core.entities.sale.Sale;
@@ -7,9 +8,7 @@ import com.pqt.core.entities.sale.SaleStatus;
import com.pqt.core.entities.sale.SaleType;
import com.pqt.core.entities.user_account.Account;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
//TODO écrire javadoc
public class SaleBuilder {
@@ -26,18 +25,40 @@ public class SaleBuilder {
}
public SaleBuilder addProduct(Product product) {
- if(products.containsKey(product)){
- //Check for sufficient stock
- if(product.getAmountRemaining() rank0Products = new HashMap<>();
+ collectRank0Products(newProduct, requiredAmount, rank0Products);
+ products.keySet().forEach(oldProduct->collectRank0Products(oldProduct, products.get(oldProduct), rank0Products));
+
+ return rank0Products.keySet()
+ .stream()
+ .filter(rank0Product->rank0Product.getAmountRemaining() collector){
+ if(rootProduct.getComponents().isEmpty()){
+ if(collector.containsKey(rootProduct))
+ collector.replace(rootProduct, collector.get(rootProduct)+rootProductAmount);
+ else
+ collector.put(rootProduct, rootProductAmount);
+ }else{
+ rootProduct.getComponents().forEach(product->collectRank0Products(product, rootProductAmount, collector));
+ }
+ }
+
public SaleBuilder removeProduct(Product product) {
if(products.containsKey(product)) {
if (products.get(product) == 1)
diff --git a/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleService.java b/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleService.java
index cdaf60b9..081df440 100644
--- a/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleService.java
+++ b/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleService.java
@@ -6,6 +6,9 @@ import com.pqt.client.module.query.query_callback.IIdQueryCallback;
import com.pqt.client.module.sale.listeners.ISaleFirerer;
import com.pqt.client.module.sale.listeners.ISaleListener;
import com.pqt.client.module.sale.listeners.SimpleSaleFirerer;
+import com.pqt.core.entities.sale.SaleType;
+
+import java.util.List;
//TODO écrire javadoc
//TODO add log lines
@@ -55,4 +58,8 @@ public class SaleService {
eventFirerer.removeListener(listener);
}
+ public List getSaleTypes() {
+ //TODO
+ return null;
+ }
}
diff --git a/Workspace/client/src/main/java/com/pqt/client/module/sale/listeners/ISaleListener.java b/Workspace/client/src/main/java/com/pqt/client/module/sale/listeners/ISaleListener.java
index ddb44c48..8369a112 100644
--- a/Workspace/client/src/main/java/com/pqt/client/module/sale/listeners/ISaleListener.java
+++ b/Workspace/client/src/main/java/com/pqt/client/module/sale/listeners/ISaleListener.java
@@ -1,15 +1,13 @@
package com.pqt.client.module.sale.listeners;
-import com.pqt.core.entities.sale.Sale;
-
import java.util.EventListener;
public interface ISaleListener extends EventListener {
- public abstract void onSaleValidationSuccess(long saleId);
+ void onSaleValidationSuccess(long saleId);
- public abstract void onSaleValidationError(long saleId, Throwable cause);
+ void onSaleValidationError(long saleId, Throwable cause);
- public abstract void onSaleValidationRefused(long saleId, Throwable cause);
+ void onSaleValidationRefused(long saleId, Throwable cause);
}
diff --git a/Workspace/client/src/main/java/com/pqt/client/module/stock/StockDao.java b/Workspace/client/src/main/java/com/pqt/client/module/stock/StockDao.java
index d682f84f..08439d66 100644
--- a/Workspace/client/src/main/java/com/pqt/client/module/stock/StockDao.java
+++ b/Workspace/client/src/main/java/com/pqt/client/module/stock/StockDao.java
@@ -33,12 +33,8 @@ public class StockDao {
}
public synchronized Product getProduct(final int id) {
- Optional match = products.stream().filter((product->product.getId()==id)).findFirst();
- if(match.isPresent())
- return match.get();
-
- return null;
- }
+ return products.stream().filter((product->product.getId()==id)).findFirst().orElse(null);
+ }
public void refreshProductList() {
QueryExecutor.INSTANCE.execute(QueryFactory.newStockQuery(), new IStockQueryCallback() {
diff --git a/Workspace/client/src/main/java/com/pqt/client/module/stock/StockService.java b/Workspace/client/src/main/java/com/pqt/client/module/stock/StockService.java
index 95644e61..8c2e67aa 100644
--- a/Workspace/client/src/main/java/com/pqt/client/module/stock/StockService.java
+++ b/Workspace/client/src/main/java/com/pqt/client/module/stock/StockService.java
@@ -13,7 +13,7 @@ public class StockService {
private StockDao dao;
- private StockService() {
+ public StockService() {
dao = new StockDao();
}
@@ -39,7 +39,8 @@ public class StockService {
/**
* Accesseur de la liste des produits actuellement en vente.
*
- * La liste peut être obsolète, voir {@link #getLastRefreshTimestamp()} pour la date du dernier refresh et {@link #refreshProductList()} pour la mettre à jour.
+ * La liste peut être obsolète, voir {@link #getLastRefreshTimestamp()} pour la date du dernier refresh et
+ * {@link #refreshProductList()} pour la mettre à jour.
*
* @return Liste des produits en vente.
*/
@@ -47,6 +48,35 @@ public class StockService {
return dao.getProducts();
}
+ /**
+ * Récupère la liste des produits n'étant pas {@code product} et n'étant pas composé de {@code product}.
+ * Les composants sont récursivements vérifiés pour que ces derniers valident aussi ces deux conditions.
+ *
+ * La liste peut être obsolète, voir {@link #getLastRefreshTimestamp()} pour la date du dernier refresh et
+ * {@link #refreshProductList()} pour la mettre à jour.
+ *
+ * @param product produit à exclure des résultats.
+ * @return Liste de produit n'étant pas et ne contenant pas {@code product}.
+ */
+ public List getProductsExcluding(Product product) {
+ return dao.getProducts();
+ }
+
+ private boolean contains(Product container, Product contained){
+ if(container==null || contained==null)
+ return false;
+ if(container.equals(contained))
+ return true;
+
+ if(container.getComponents()!=null)
+ return container.getComponents()
+ .stream()
+ .filter(component->contains(component, contained))
+ .count()>0;
+
+ return false;
+ }
+
/**
* Accesseur récupérant un unique produit présent dans les stocks en se basant sur son id.
*
@@ -100,5 +130,4 @@ public class StockService {
public void removeListener(IStockListener listener) {
dao.removeListener(listener);
}
-
}
diff --git a/Workspace/client/src/main/java/com/pqt/client/module/stock/UpdateBuilder.java b/Workspace/client/src/main/java/com/pqt/client/module/stock/UpdateBuilder.java
index 36826f26..f471916b 100644
--- a/Workspace/client/src/main/java/com/pqt/client/module/stock/UpdateBuilder.java
+++ b/Workspace/client/src/main/java/com/pqt/client/module/stock/UpdateBuilder.java
@@ -16,20 +16,23 @@ public class UpdateBuilder {
toModify = new HashMap<>();
}
- public void addProduct(Product product) {
+ public UpdateBuilder addProduct(Product product) {
if(!toAdd.contains(product)){
toAdd.add(product);
}
+ return this;
}
- public void removeProduct(Product product) {
+ public UpdateBuilder removeProduct(Product product) {
if(toRemove.contains(product)){
toRemove.remove(product);
}
+ return this;
}
- public void modifyProduct(Product oldVersion, Product newVersion) {
+ public UpdateBuilder modifyProduct(Product oldVersion, Product newVersion) {
toModify.put(oldVersion, newVersion);
+ return this;
}
public List build() {
diff --git a/Workspace/client/src/main/resources/nightmode.css b/Workspace/client/src/main/resources/nightmode.css
new file mode 100644
index 00000000..a33217d2
--- /dev/null
+++ b/Workspace/client/src/main/resources/nightmode.css
@@ -0,0 +1,235 @@
+.root {
+ -fx-background-color: #1d1d1d;
+}
+
+.label {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: white;
+ -fx-opacity: 0.8;
+}
+
+.label-bright {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: white;
+ -fx-opacity: 1;
+}
+
+.label-header {
+ -fx-font-size: 25pt;
+ -fx-font-family: "Segoe UI";
+ -fx-text-fill: white;
+ -fx-opacity: 1;
+}
+
+.tab {
+ -fx-background-color: #3a3a3a;
+}
+
+.tab-label {
+ -fx-text-fill: white;
+}
+
+.tab:selected {
+ -fx-background-color: #4d4d4d;
+}
+
+.tab-pane *.tab-header-background {
+ -fx-background-color: #1d1d1d;
+}
+
+.list-view {
+ -fx-control-inner-background: #1d1d1d;
+ -fx-control-inner-background-alt: #333333;
+ -fx-padding: 5;
+ -fx-border-width: 0px;
+}
+
+.list-view .list-cell .label{
+ -fx-font-size: 20pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-alignment: center-left;
+}
+
+.list-view:focused .list-cell:filled:focused:selected {
+ -fx-background-color: -fx-focus-color;
+}
+.list-cell:highlighted{
+ -fx-text-fill: #cc7a00;
+ -fx-border-width: 1px;
+ -fx-border-color: white;
+}
+
+.table-view {
+ -fx-base: #1d1d1d;
+ -fx-control-inner-background: #1d1d1d;
+ -fx-control-inner-background-alt: #333333;
+ -fx-table-cell-border-color: transparent;
+ -fx-table-header-border-color: transparent;
+ -fx-padding: 5;
+}
+
+.table-view .column-header-background {
+ -fx-background-color: transparent;
+}
+
+.table-view .column-header, .table-view .filler {
+ -fx-size: 35px;
+ -fx-border-width: 0 0 1 0;
+ -fx-background-color: transparent;
+ -fx-border-color:
+ transparent
+ transparent
+ derive(-fx-base, 80%)
+ transparent;
+ -fx-border-insets: 0 10 1 0;
+}
+
+.table-view .column-header .label {
+ -fx-font-size: 20pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-alignment: center-left;
+ -fx-opacity: 1;
+}
+
+.table-view .table-row-cell {
+ -fx-control-inner-background: #1d1d1d;
+ -fx-control-inner-background-alt: #333333;
+}
+
+.table-view .table-row-cell:stock-out {
+ -fx-control-inner-background: #4d0000;
+ -fx-control-inner-background-alt: #4d0000;
+}
+
+.table-view .table-row-cell:stock-low {
+ -fx-control-inner-background: #4d2e00;
+ -fx-control-inner-background-alt: #4d2e00;
+}
+
+.table-view .table-row-cell:stock-high {
+ -fx-control-inner-background: #1a3300;
+ -fx-control-inner-background-alt: #1a3300;
+}
+
+.table-view:focused .table-row-cell:filled:focused:selected {
+ -fx-background-color: -fx-focus-color;
+}
+
+.grid-pane {
+ -fx-hgap: 10;
+ -fx-vgap: 10;
+}
+
+.context-menu {
+ -fx-background-color: derive(#1d1d1d,5%);
+}
+.text-field, .password-field, .choice-box, .text-area, .combo-box, .button {
+ -fx-font-size: 12pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-pref-width: 150;
+ -fx-pref-height: 30;
+ -fx-background-color: #1d1d1d;
+ -fx-border-color: #e2e2e2;
+ -fx-border-width: 2;
+ -fx-text-fill: #d8d8d8;
+}
+
+.button:hover {
+ -fx-background-color: #3a3a3a;
+}
+
+.button:pressed, .button:default:hover:pressed {
+ -fx-background-color: white;
+ -fx-text-fill: #1d1d1d;
+}
+
+.button:focused {
+ -fx-border-color: white, white;
+ -fx-border-width: 1, 1;
+ -fx-border-style: solid;
+ -fx-border-radius: 0, 0;
+ -fx-border-insets: 1 1 1 1, 0;
+}
+
+.button:disabled, .button:default:disabled {
+ -fx-opacity: 0.4;
+ -fx-background-color: #1d1d1d;
+ -fx-text-fill: white;
+}
+
+.button:default {
+ -fx-background-color: -fx-focus-color;
+ -fx-text-fill: #ffffff;
+}
+
+.button:default:hover {
+ -fx-background-color: derive(-fx-focus-color,30%);
+}
+
+.text-area .content {
+ -fx-background-color: #1d1d1d;
+ -fx-padding: 15 15 15 15;
+}
+
+#stat-screen-text-area {
+ -fx-border-width: 0;
+}
+
+.progress-indicator {
+ -fx-pref-width: 50;
+ -fx-pref-height: 50;
+}
+
+.grey-intermediary-pane {
+ -fx-background-color: #1d1d1d;
+ -fx-opacity: 85%;
+}
+
+.main-module-pane {
+ -fx-padding: 10 10 10 10;
+}
+
+.validator {
+ -fx-padding: 10 10 10 10;
+ -fx-hgap: 10;
+ -fx-vgap: 10;
+}
+.validator .button{
+ -fx-pref-width: 150;
+ -fx-pref-height: 50;
+}
+
+.sidebar {
+ -fx-background-color: #2e2e2e;
+ -fx-padding: 5 22 5 22;
+ -fx-border-color: whitesmoke;
+ -fx-border-width: 2;
+ -fx-background-radius: 0;
+ -fx-background-insets: 0 0 0 0, 0, 1, 2;
+ -pqt-expanded-width : 195px;
+}
+
+.tool-bar {
+ -fx-background-color: #2e2e2e;
+ -fx-padding: 5 5 5 5;
+ -fx-background-radius: 0;
+ -fx-background-insets: 0 0 0 0, 0, 1, 2;
+}
+
+.toast-text{
+ -fx-font: 50px "Impact";
+ -fx-fill: whitesmoke;
+}
+
+.toast-pane {
+ -fx-background-radius: 10px;
+ -fx-background-color: rgba(0, 0, 0, 0.4);
+ -fx-border-width: 2px;
+ -fx-border-color: whitesmoke;
+ -fx-border-radius: 6px;
+ -fx-padding: 25px;
+}
\ No newline at end of file
diff --git a/Workspace/core/core.iml b/Workspace/core/core.iml
new file mode 100644
index 00000000..192d284a
--- /dev/null
+++ b/Workspace/core/core.iml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Workspace/core/src/main/java/com/pqt/core/communication/GSonMessageToolFactory.java b/Workspace/core/src/main/java/com/pqt/core/communication/GSonMessageToolFactory.java
index 9eac8abd..939c3bda 100644
--- a/Workspace/core/src/main/java/com/pqt/core/communication/GSonMessageToolFactory.java
+++ b/Workspace/core/src/main/java/com/pqt/core/communication/GSonMessageToolFactory.java
@@ -3,13 +3,6 @@ package com.pqt.core.communication;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
-import com.pqt.core.entities.members.PqtMember;
-import com.pqt.core.entities.members.PqtMemberType;
-import com.pqt.core.entities.messages.Message;
-import com.pqt.core.entities.messages.MessageType;
-import com.pqt.core.entities.product.Product;
-import com.pqt.core.entities.product.ProductUpdate;
-import com.pqt.core.entities.sale.Sale;
import java.lang.reflect.Type;
import java.util.ArrayList;
diff --git a/Workspace/core/src/main/java/com/pqt/core/entities/members/Client.java b/Workspace/core/src/main/java/com/pqt/core/entities/members/Client.java
index a4498012..aaa92a4d 100644
--- a/Workspace/core/src/main/java/com/pqt/core/entities/members/Client.java
+++ b/Workspace/core/src/main/java/com/pqt/core/entities/members/Client.java
@@ -27,21 +27,6 @@ public class Client extends PqtMember{
this.address = address;
}
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- Client client = (Client) o;
-
- return address.equals(client.address) && id==client.id && type.equals(client.type);
- }
-
- @Override
- public int hashCode() {
- return address.hashCode() + type.hashCode() + Integer.class.cast(id);
- }
-
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), address);
diff --git a/Workspace/core/src/main/java/com/pqt/core/entities/product/Product.java b/Workspace/core/src/main/java/com/pqt/core/entities/product/Product.java
index ec5d5074..6c40e894 100644
--- a/Workspace/core/src/main/java/com/pqt/core/entities/product/Product.java
+++ b/Workspace/core/src/main/java/com/pqt/core/entities/product/Product.java
@@ -6,7 +6,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-
+//TODO faire en sorte que les composés reprennent les qté dispo des composants
/**
* Created by Notmoo on 18/07/2017.
*/
@@ -123,6 +123,7 @@ public class Product implements ILoggable, Serializable{
return this.id == other.id
&& Objects.equals(this.name, other.name)
&& Objects.equals(this.components, other.components)
- && Objects.equals(this.category, other.category);
+ && Objects.equals(this.category, other.category)
+ && Objects.equals(this.price, other.price);
}
}
diff --git a/Workspace/core/src/main/java/com/pqt/core/entities/user_account/Account.java b/Workspace/core/src/main/java/com/pqt/core/entities/user_account/Account.java
index be090371..f3d7ad34 100644
--- a/Workspace/core/src/main/java/com/pqt/core/entities/user_account/Account.java
+++ b/Workspace/core/src/main/java/com/pqt/core/entities/user_account/Account.java
@@ -23,6 +23,10 @@ public class Account implements ILoggable, Serializable {
this.permissionLevel = permissionLevel;
}
+ public Account(Account account) {
+ this(account.getUsername(), account.getPassword(), account.getPermissionLevel());
+ }
+
public String getUsername() {
return username;
}
@@ -49,7 +53,7 @@ public class Account implements ILoggable, Serializable {
@Override
public int hashCode() {
- return Objects.hash(id, username, passwordHash, permissionLevel);
+ return Objects.hash(username, password, permissionLevel);
}
@Override
@@ -61,9 +65,8 @@ public class Account implements ILoggable, Serializable {
return false;
Account acc = Account.class.cast(obj);
- return this.id == acc.id
- && Objects.equals(this.username, acc.username)
- && Objects.equals(this.passwordHash, acc.passwordHash)
+ return Objects.equals(this.username, acc.username)
+ && Objects.equals(this.password, acc.password)
&& Objects.equals(this.permissionLevel, acc.permissionLevel);
}
}
diff --git a/Workspace/server/server.iml b/Workspace/server/server.iml
new file mode 100644
index 00000000..3284aafa
--- /dev/null
+++ b/Workspace/server/server.iml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file