start working on input validation

This commit is contained in:
Huy Pham 2019-12-09 16:33:32 -08:00
parent 27131ef367
commit 0b3f3a5166
4 changed files with 200 additions and 7 deletions

View file

@ -4,6 +4,7 @@ size and scale
import tkinter as tk import tkinter as tk
from tkinter import font, ttk from tkinter import font, ttk
from coretk import validation
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
PAD = 5 PAD = 5
@ -37,6 +38,12 @@ class SizeAndScaleDialog(Dialog):
self.meters_width = tk.IntVar(value=width / PIXEL_SCALE * location.scale) self.meters_width = tk.IntVar(value=width / PIXEL_SCALE * location.scale)
self.meters_height = tk.IntVar(value=height / PIXEL_SCALE * location.scale) self.meters_height = tk.IntVar(value=height / PIXEL_SCALE * location.scale)
self.save_default = tk.BooleanVar(value=False) self.save_default = tk.BooleanVar(value=False)
self.vcmd_canvas_int = validation.validate_command(
app.master, validation.check_canvas_int
)
self.vcmd_canvas_float = validation.validate_command(
app.master, validation.check_canvas_float
)
self.draw() self.draw()
def draw(self): def draw(self):
@ -47,6 +54,11 @@ class SizeAndScaleDialog(Dialog):
self.draw_save_as_default() self.draw_save_as_default()
self.draw_buttons() self.draw_buttons()
def focus_out(self, event):
value = event.widget.get()
if value == "":
event.widget.insert(tk.END, 0)
def draw_size(self): def draw_size(self):
label_frame = ttk.Labelframe(self.top, text="Size", padding=PAD) label_frame = ttk.Labelframe(self.top, text="Size", padding=PAD)
label_frame.grid(sticky="ew") label_frame.grid(sticky="ew")
@ -59,11 +71,22 @@ class SizeAndScaleDialog(Dialog):
frame.columnconfigure(3, weight=1) frame.columnconfigure(3, weight=1)
label = ttk.Label(frame, text="Width") label = ttk.Label(frame, text="Width")
label.grid(row=0, column=0, sticky="w", padx=PAD) label.grid(row=0, column=0, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.pixel_width) entry = ttk.Entry(
frame,
textvariable=self.pixel_width,
validate="key",
validatecommand=(self.vcmd_canvas_int, "%P"),
)
entry.grid(row=0, column=1, sticky="ew", padx=PAD) entry.grid(row=0, column=1, sticky="ew", padx=PAD)
entry.bind("<FocusOut>", self.focus_out)
label = ttk.Label(frame, text="x Height") label = ttk.Label(frame, text="x Height")
label.grid(row=0, column=2, sticky="w", padx=PAD) label.grid(row=0, column=2, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.pixel_height) entry = ttk.Entry(
frame,
textvariable=self.pixel_height,
validate="key",
validatecommand=(self.vcmd_canvas_int, "%P"),
)
entry.grid(row=0, column=3, sticky="ew", padx=PAD) entry.grid(row=0, column=3, sticky="ew", padx=PAD)
label = ttk.Label(frame, text="Pixels") label = ttk.Label(frame, text="Pixels")
label.grid(row=0, column=4, sticky="w") label.grid(row=0, column=4, sticky="w")
@ -94,7 +117,12 @@ class SizeAndScaleDialog(Dialog):
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
label = ttk.Label(frame, text=f"{PIXEL_SCALE} Pixels =") label = ttk.Label(frame, text=f"{PIXEL_SCALE} Pixels =")
label.grid(row=0, column=0, sticky="w", padx=PAD) label.grid(row=0, column=0, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.scale) entry = ttk.Entry(
frame,
textvariable=self.scale,
validate="key",
validatecommand=(self.vcmd_canvas_float, "%P"),
)
entry.grid(row=0, column=1, sticky="ew", padx=PAD) entry.grid(row=0, column=1, sticky="ew", padx=PAD)
label = ttk.Label(frame, text="Meters") label = ttk.Label(frame, text="Meters")
label.grid(row=0, column=2, sticky="w") label.grid(row=0, column=2, sticky="w")

View file

@ -3,6 +3,7 @@ import tkinter as tk
from functools import partial from functools import partial
from tkinter import ttk from tkinter import ttk
import coretk.validation as validation
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.dialogs.icondialog import IconDialog from coretk.dialogs.icondialog import IconDialog
from coretk.dialogs.nodeservice import NodeService from coretk.dialogs.nodeservice import NodeService
@ -69,7 +70,10 @@ class NodeConfigDialog(Dialog):
# name field # name field
label = ttk.Label(frame, text="Name") label = ttk.Label(frame, text="Name")
label.grid(row=row, column=0, sticky="ew", padx=PAD, pady=PAD) label.grid(row=row, column=0, sticky="ew", padx=PAD, pady=PAD)
entry = ttk.Entry(frame, textvariable=self.name) vcmd = self.app.master.register(validation.check_node_name)
entry = ttk.Entry(
frame, textvariable=self.name, validate="key", validatecommand=(vcmd, "%P")
)
entry.grid(row=row, column=1, sticky="ew") entry.grid(row=row, column=1, sticky="ew")
row += 1 row += 1
@ -206,5 +210,4 @@ class NodeConfigDialog(Dialog):
# redraw # redraw
self.canvas_node.redraw() self.canvas_node.redraw()
self.destroy() self.destroy()

View file

@ -1,3 +1,151 @@
""" """
input validation input validation
""" """
import logging
import tkinter as tk
def validate_command(master, func):
return master.register(func)
def check_positive_int(s):
logging.debug("int validation...")
try:
int_value = int(s)
if int_value >= 0:
return True
return False
except ValueError:
return False
def check_positive_float(s):
logging.debug("float validation...")
try:
float_value = float(s)
if float_value >= 0.0:
return True
return False
except ValueError:
return False
def check_node_name(name):
logging.debug("node name validation...")
if len(name) <= 0:
return False
for char in name:
if not char.isalnum() and char != "_":
return False
return True
def check_canvas_int(s):
logging.debug("int validation...")
if len(s) == 0:
return True
try:
int_value = int(s)
if int_value >= 0:
return True
return False
except ValueError:
return False
def check_canvas_float(s):
logging.debug("canvas float validation")
if not s:
return True
try:
float_value = float(s)
if float_value >= 0.0:
return True
return False
except ValueError:
return False
def check_interface(name):
logging.debug("interface name validation...")
if len(name) <= 0:
return False, "Interface name cannot be an empty string"
for char in name:
if not char.isalnum() and char != "_":
return (
False,
"Interface name can only contain alphanumeric letter (a-z) and (0-9) or underscores (_)",
)
return True, ""
def combine_message(key, current_validation, current_message, res, msg):
if not res:
current_validation = res
current_message = current_message + key + ": " + msg + "\n\n"
return current_validation, current_message
def check_wlan_config(config):
result = True
message = ""
checks = ["bandwidth", "delay", "error", "jitter", "range"]
for check in checks:
if check in ["bandwidth", "delay", "jitter"]:
res, msg = check_positive_int(config[check].value)
result, message = combine_message(check, result, message, res, msg)
elif check in ["range", "error"]:
res, msg = check_positive_float(config[check].value)
result, message = combine_message(check, result, message, res, msg)
return result, message
def check_size_and_scale(dialog):
result = True
message = ""
try:
pixel_width = dialog.pixel_width.get()
if pixel_width < 0:
result, message = combine_message(
"pixel width", result, message, False, "cannot be negative"
)
except tk.TclError:
result, message = combine_message(
"pixel width",
result,
message,
False,
"invalid value, input non-negative float",
)
try:
pixel_height = dialog.pixel_height.get()
if pixel_height < 0:
result, message = combine_message(
"pixel height", result, message, False, "cannot be negative"
)
except tk.TclError:
result, message = combine_message(
"pixel height",
result,
message,
False,
"invalid value, input non-negative float",
)
try:
scale = dialog.scale.get()
if scale <= 0:
result, message = combine_message(
"scale", result, message, False, "cannot be negative"
)
except tk.TclError:
result, message = combine_message(
"scale", result, message, False, "invalid value, input non-negative float"
)
# pixel_height = dialog.pixel_height.get()
# print(pixel_width, pixel_height)
# res, msg = check_positive_int(pixel_width)
# result, message = combine_message("pixel width", result, message, res, msg)
# res, msg = check_positive_int(pixel_height)
# result, message = combine_message("pixel height", result, message, res, msg)
return result, message

View file

@ -5,6 +5,7 @@ from tkinter import font, ttk
from tkinter.scrolledtext import ScrolledText from tkinter.scrolledtext import ScrolledText
from core.api.grpc import core_pb2 from core.api.grpc import core_pb2
from coretk import validation
INT_TYPES = { INT_TYPES = {
core_pb2.ConfigOptionType.UINT8, core_pb2.ConfigOptionType.UINT8,
@ -60,6 +61,7 @@ class FrameScroll(ttk.LabelFrame):
class ConfigFrame(FrameScroll): class ConfigFrame(FrameScroll):
def __init__(self, master, app, config, **kw): def __init__(self, master, app, config, **kw):
super().__init__(master, app, ttk.Notebook, **kw) super().__init__(master, app, ttk.Notebook, **kw)
self.app = app
self.config = config self.config = config
self.values = {} self.values = {}
@ -67,6 +69,8 @@ class ConfigFrame(FrameScroll):
padx = 2 padx = 2
pady = 2 pady = 2
group_mapping = {} group_mapping = {}
vcmd_int = self.app.master.register(validation.check_positive_int)
vcmd_float = self.app.master.register(validation.check_positive_float)
for key in self.config: for key in self.config:
option = self.config[key] option = self.config[key]
group = group_mapping.setdefault(option.group, []) group = group_mapping.setdefault(option.group, [])
@ -104,11 +108,21 @@ class ConfigFrame(FrameScroll):
entry.grid(row=index, column=1, sticky="ew", pady=pady) entry.grid(row=index, column=1, sticky="ew", pady=pady)
elif option.type in INT_TYPES: elif option.type in INT_TYPES:
value.set(option.value) value.set(option.value)
entry = ttk.Entry(frame, textvariable=value) entry = ttk.Entry(
frame,
textvariable=value,
validate="key",
validatecommand=(vcmd_int, "%P"),
)
entry.grid(row=index, column=1, sticky="ew", pady=pady) entry.grid(row=index, column=1, sticky="ew", pady=pady)
elif option.type == core_pb2.ConfigOptionType.FLOAT: elif option.type == core_pb2.ConfigOptionType.FLOAT:
value.set(option.value) value.set(option.value)
entry = ttk.Entry(frame, textvariable=value) entry = ttk.Entry(
frame,
textvariable=value,
validate="key",
validatecommand=(vcmd_float, "%P"),
)
entry.grid(row=index, column=1, sticky="ew", pady=pady) entry.grid(row=index, column=1, sticky="ew", pady=pady)
else: else:
logging.error("unhandled config option type: %s", option.type) logging.error("unhandled config option type: %s", option.type)