Source code for UI.AddTradeDialogWindow

import os
import sys
import inspect
import tkinter as tk
from tkinter import ttk
import datetime

currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)

from Utils.Utils import Actions, Markets
from Utils.Trade import Trade
from .WarningWindow import WarningWindow
from .Widgets import DatePicker


[docs]class AddTradeDialogWindow(tk.Toplevel): def __init__(self, master, confirmCallback): tk.Toplevel.__init__(self) self.master = master self.confirmCallback = confirmCallback self.transient(self.master) self.title("Add Trade") self.geometry( "+{}+{}".format( self.master.winfo_rootx() + 400, self.master.winfo_rooty() + 100 ) ) self.protocol("WM_DELETE_WINDOW", self.destroy) self.grab_set() self.focus_set() self.create_UI() def create_UI(self): # Define the labels on the left hand column ttk.Label(self, text="Date:").grid(row=0, sticky="w", padx=5, pady=5) ttk.Label(self, text="Action:").grid(row=1, sticky="w", padx=5, pady=5) ttk.Label(self, text="Market:").grid(row=2, sticky="w", padx=5, pady=5) ttk.Label(self, text="Symbol:").grid(row=3, sticky="w", padx=5, pady=5) ttk.Label(self, text="Quantity:").grid(row=4, sticky="w", padx=5, pady=5) ttk.Label(self, text="Price [p] :").grid(row=5, sticky="w", padx=5, pady=5) ttk.Label(self, text="Fee [£] :").grid(row=6, sticky="w", padx=5, pady=5) ttk.Label(self, text="Stamp Duty [%] :").grid(row=7, sticky="w", padx=5, pady=5) ttk.Label(self, text="Notes:").grid(row=8, sticky="w", padx=5, pady=5) # Define the date entry widget self.dateSelected = tk.StringVar() self.dateSelected.trace_add("write", self.check_data_validity) datePicker = DatePicker(self, self.dateSelected) datePicker.grid(row=0, column=1, sticky="w", padx=5, pady=5) datePicker.focus_set() # Define an option menu for the action self.actionSelected = tk.StringVar() menuList = [a.name for a in Actions] eAction = ttk.OptionMenu( self, self.actionSelected, menuList[0], *menuList, command=self.on_action_selected ) eAction.grid(row=1, column=1, sticky="w", padx=5, pady=5) # Define an option menu for the market exchange self.marketSelected = tk.StringVar() marketList = [a.name for a in Markets] self.eMarket = ttk.OptionMenu( self, self.marketSelected, marketList[0], *marketList, command=self.on_market_selected ) self.eMarket.grid(row=2, column=1, sticky="w", padx=5, pady=5) self.symbolSelected = tk.StringVar() self.symbolSelected.trace_add("write", self.check_data_validity) self.eSymbol = ttk.Entry(self, textvariable=self.symbolSelected) self.eSymbol.grid(row=3, column=1, sticky="w", padx=5, pady=5) self.quantity_selected = tk.StringVar() self.quantity_selected.trace_add("write", self.check_data_validity) self.e_quantity = ttk.Entry(self, textvariable=self.quantity_selected) self.e_quantity.grid(row=4, column=1, sticky="w", padx=5, pady=5) self.priceSelected = tk.StringVar() self.priceSelected.trace_add("write", self.check_data_validity) self.ePrice = ttk.Entry(self, textvariable=self.priceSelected) self.ePrice.grid(row=5, column=1, sticky="w", padx=5, pady=5) self.feeSelected = tk.StringVar() self.feeSelected.trace_add("write", self.check_data_validity) self.eFee = ttk.Entry(self, textvariable=self.feeSelected) self.eFee.grid(row=6, column=1, sticky="w", padx=5, pady=5) self.stampDutySelected = tk.StringVar() self.stampDutySelected.trace_add("write", self.check_data_validity) self.eStampDuty = ttk.Entry(self, textvariable=self.stampDutySelected) self.eStampDuty.grid(row=7, column=1, sticky="w", padx=5, pady=5) self.notesSelected = tk.StringVar() self.notesSelected.trace_add("write", self.check_data_validity) self.eNotes = ttk.Entry(self, textvariable=self.notesSelected) self.eNotes.grid(row=8, column=1, sticky="w", padx=5, pady=5) cancelButton = ttk.Button(self, text="Cancel", command=self.destroy) cancelButton.grid(row=9, column=0, sticky="e", padx=5, pady=5) self.addButton = ttk.Button(self, text="Add", command=self.add_new_trade) self.addButton.grid(row=9, column=1, sticky="e", padx=5, pady=5) self.addButton.config(state="disabled") # Make the mas ter thread block execution until this window is closed self.master.wait_window(self) def on_market_selected(self, selection): pass def on_action_selected(self, selection): # Clear data entry self.symbolSelected.set("") self.quantity_selected.set("") self.priceSelected.set("") self.feeSelected.set("") self.stampDutySelected.set("") self.notesSelected.set("") # Change layout if selection == Actions.BUY.name: self.eMarket.config(state="enabled") self.eSymbol.config(state="enabled") self.e_quantity.config(state="enabled") self.ePrice.config(state="enabled") self.eFee.config(state="enabled") self.eStampDuty.config(state="enabled") self.eNotes.config(state="enabled") elif selection == Actions.SELL.name: self.eMarket.config(state="enabled") self.eSymbol.config(state="enabled") self.e_quantity.config(state="enabled") self.ePrice.config(state="enabled") self.eFee.config(state="enabled") self.eStampDuty.config(state="disabled") self.eNotes.config(state="enabled") elif selection == Actions.DEPOSIT.name: self.eMarket.config(state="disabled") self.eSymbol.config(state="disabled") self.e_quantity.config(state="enabled") self.ePrice.config(state="disabled") self.eFee.config(state="disabled") self.eStampDuty.config(state="disabled") self.eNotes.config(state="enabled") elif selection == Actions.DIVIDEND.name: self.eMarket.config(state="enabled") self.eSymbol.config(state="enabled") self.e_quantity.config(state="enabled") self.ePrice.config(state="disabled") self.eFee.config(state="disabled") self.eStampDuty.config(state="disabled") self.eNotes.config(state="enabled") elif selection == Actions.WITHDRAW.name: self.eMarket.config(state="disabled") self.eSymbol.config(state="disabled") self.e_quantity.config(state="enabled") self.ePrice.config(state="disabled") self.eFee.config(state="disabled") self.eStampDuty.config(state="disabled") self.eNotes.config(state="enabled") elif selection == Actions.FEE.name: self.eMarket.config(state="disabled") self.eSymbol.config(state="disabled") self.e_quantity.config(state="enabled") self.ePrice.config(state="disabled") self.eFee.config(state="disabled") self.eStampDuty.config(state="disabled") self.eNotes.config(state="enabled") def add_new_trade(self): # Get selected data and call callback item = {} item["date"] = self.dateSelected.get() item["action"] = self.actionSelected.get() market = Markets[self.marketSelected.get()] item["symbol"] = ( (market.name + ":" + self.symbolSelected.get()) if self.symbolSelected.get() is not "" else "" ) item["quantity"] = ( float(self.quantity_selected.get()) if self.quantity_selected.get() is not "" else 0 ) item["price"] = ( float(self.priceSelected.get()) if self.priceSelected.get() is not "" else 0 ) item["fee"] = ( float(self.feeSelected.get()) if self.feeSelected.get() is not "" else 0 ) item["stamp_duty"] = ( float(self.stampDutySelected.get()) if self.stampDutySelected.get() is not "" else 0 ) item["notes"] = str(self.notesSelected.get()) newTrade = Trade.from_dict(item) result = self.confirmCallback(newTrade) if result["success"]: self.destroy() else: WarningWindow(self, "Warning", result["message"]) def check_data_validity(self, *args): # Check the validity of the Entry widgets data to enable the Add button valid = ( self.is_date_valid() and self.is_symbol_valid() and self.is_quantity_valid() and self.is_price_valid() and self.is_fee_valid() and self.is_sd_valid() and self.is_notes_valid() ) self.addButton.config(state="normal" if valid else "disabled") def is_date_valid(self): value = self.dateSelected.get() try: datetime.datetime.strptime(value, "%d/%m/%Y") except ValueError: return False return True def is_symbol_valid(self): # If widget is disabled it should not affect the overall validity if str(self.eSymbol.cget("state")) == tk.DISABLED: return True if len(self.symbolSelected.get()) < 1: return False # Force uppercase self.symbolSelected.set(self.symbolSelected.get().upper()) return True def is_quantity_valid(self): # If widget is disabled it should not affect the overall validity if str(self.e_quantity.cget("state")) == tk.DISABLED: return True try: value = float(self.quantity_selected.get()) if value > 0: return True return False except Exception: return False def is_price_valid(self): # If widget is disabled it should not affect the overall validity if str(self.ePrice.cget("state")) == tk.DISABLED: return True try: value = float(self.priceSelected.get()) if value >= 0.0: return True return False except Exception: return False def is_fee_valid(self): # If widget is disabled it should not affect the overall validity if str(self.eFee.cget("state")) == tk.DISABLED: return True try: value = float(self.feeSelected.get()) if value >= 0.0: return True return False except Exception: return False def is_sd_valid(self): # If widget is disabled it should not affect the overall validity if str(self.eStampDuty.cget("state")) == tk.DISABLED: return True try: value = float(self.stampDutySelected.get()) if value >= 0.0: return True return False except Exception: return False def is_notes_valid(self): # If widget is disabled it should not affect the overall validity if str(self.eNotes.cget("state")) == tk.DISABLED: return True try: test = str(self.notesSelected.get()) except Exception as e: return False return True