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
from tkinter import font, ttk
from coretk import validation
from coretk.dialogs.dialog import Dialog
PAD = 5
@ -37,6 +38,12 @@ class SizeAndScaleDialog(Dialog):
self.meters_width = tk.IntVar(value=width / PIXEL_SCALE * location.scale)
self.meters_height = tk.IntVar(value=height / PIXEL_SCALE * location.scale)
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()
def draw(self):
@ -47,6 +54,11 @@ class SizeAndScaleDialog(Dialog):
self.draw_save_as_default()
self.draw_buttons()
def focus_out(self, event):
value = event.widget.get()
if value == "":
event.widget.insert(tk.END, 0)
def draw_size(self):
label_frame = ttk.Labelframe(self.top, text="Size", padding=PAD)
label_frame.grid(sticky="ew")
@ -59,11 +71,22 @@ class SizeAndScaleDialog(Dialog):
frame.columnconfigure(3, weight=1)
label = ttk.Label(frame, text="Width")
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.bind("<FocusOut>", self.focus_out)
label = ttk.Label(frame, text="x Height")
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)
label = ttk.Label(frame, text="Pixels")
label.grid(row=0, column=4, sticky="w")
@ -94,7 +117,12 @@ class SizeAndScaleDialog(Dialog):
frame.columnconfigure(1, weight=1)
label = ttk.Label(frame, text=f"{PIXEL_SCALE} Pixels =")
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)
label = ttk.Label(frame, text="Meters")
label.grid(row=0, column=2, sticky="w")

View file

@ -3,6 +3,7 @@ import tkinter as tk
from functools import partial
from tkinter import ttk
import coretk.validation as validation
from coretk.dialogs.dialog import Dialog
from coretk.dialogs.icondialog import IconDialog
from coretk.dialogs.nodeservice import NodeService
@ -69,7 +70,10 @@ class NodeConfigDialog(Dialog):
# name field
label = ttk.Label(frame, text="Name")
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")
row += 1
@ -206,5 +210,4 @@ class NodeConfigDialog(Dialog):
# redraw
self.canvas_node.redraw()
self.destroy()

View file

@ -1,3 +1,151 @@
"""
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 core.api.grpc import core_pb2
from coretk import validation
INT_TYPES = {
core_pb2.ConfigOptionType.UINT8,
@ -60,6 +61,7 @@ class FrameScroll(ttk.LabelFrame):
class ConfigFrame(FrameScroll):
def __init__(self, master, app, config, **kw):
super().__init__(master, app, ttk.Notebook, **kw)
self.app = app
self.config = config
self.values = {}
@ -67,6 +69,8 @@ class ConfigFrame(FrameScroll):
padx = 2
pady = 2
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:
option = self.config[key]
group = group_mapping.setdefault(option.group, [])
@ -104,11 +108,21 @@ class ConfigFrame(FrameScroll):
entry.grid(row=index, column=1, sticky="ew", pady=pady)
elif option.type in INT_TYPES:
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)
elif option.type == core_pb2.ConfigOptionType.FLOAT:
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)
else:
logging.error("unhandled config option type: %s", option.type)