Source code for pyDEA.core.gui_modules.text_for_weights_gui

''' This module contains TextForWeights class which is a text widget
    used for displaying and editing weight restrictions.

    Attributes:
        TEXT_WIDTH_VAL (int): width of Text widget.
        TEXT_HEIGHT_VAL (int): heigth of Text widget.
'''


from tkinter import Text, NONE, N, W, E, S, HORIZONTAL, END, TclError
from tkinter import StringVar, LEFT
from tkinter.ttk import Frame, Label, Scrollbar

from pyDEA.core.utils.dea_utils import create_bounds, contraint_is_price_ratio_type

TEXT_WIDTH_VAL = 50
TEXT_HEIGHT_VAL = 10


[docs]class TextForWeights(Frame): ''' Implements text widget used for displaying and editing weight restrictions. Attributes: parent (Tk object): parent of this widget. weight_name (str): text describing type of weight restrictions, e.g. absolute, virtual, etc. examples (str): string with an example of usage of this type of weight restrictions, e.g. I1 <= 2. current_categories (list of str): list of current categories. params (Parameters): parameters. param_name (str): parameter name that corresponds to this type of weight restrictions, e.g. ABS_WEIGHT_RESTRICTIONS. text (Text): text widget used for displaying weight restrictions. error_tag_exists (bool): if set to True, means that there are invalid weight restrictions, False otherwise. errors_strvar (StringVar): is used for storing and displaying error messages for invalid weight restrictions. is_price_ratio (bool): if True price ratio constraints are expected to be entered, if False other constraint types are expected to be entered. Defaults to False. Args: parent (Tk object): parent of this widget. weight_name (str): text describing type of weight restrictions, e.g. absolute, virtual, etc. examples (str): string with an example of usage of this type of weight restrictions, e.g. I1 <= 2. current_categories (list of str): list of current categories. params (Parameters): parameters. param_name (str): parameter name that corresponds to this type of weight restrictions, e.g. ABS_WEIGHT_RESTRICTIONS. is_price_ratio (bool): if True price ratio constraints are expected to be entered, if False other constraint types are expected to be entered. Defaults to False. ''' def __init__(self, parent, weight_name, examples, current_categories, params, param_name, is_price_ratio_constraint = False, *args, **kw): Frame.__init__(self, parent, *args, **kw) self.parent = parent self.examples = examples self.current_categories = current_categories self.params = params self.param_name = param_name self.text = None self.error_tag_exists = False self.errors_strvar = StringVar() self.weight_name = weight_name self.is_price_ratio_constraint = is_price_ratio_constraint self.create_widgets(weight_name)
[docs] def create_widgets(self, weight_name): ''' Creates all widgets. ''' constraints_lbl = Label( self, text='Enter {0} weight restrictions:'.format( weight_name)) constraints_lbl.grid(padx=10, pady=2, sticky=N+W) examples_lbl = Label(self, text='e.g. {0}'.format(self.examples)) examples_lbl.grid(row=1, column=0, padx=10, pady=5, sticky=N+W) errors_lbl = Label(self, textvariable=self.errors_strvar, foreground='red', anchor=W, justify=LEFT, wraplength=80) errors_lbl.grid(row=2, column=2, sticky=N+W, padx=5, pady=5) self.grid_rowconfigure(2, weight=1) self.grid_columnconfigure(0, weight=1) xscrollbar = Scrollbar(self, orient=HORIZONTAL) xscrollbar.grid(row=3, column=0, sticky=E+W) yscrollbar = Scrollbar(self) yscrollbar.grid(row=2, column=1, sticky=N+S) self.text = Text(self, wrap=NONE, width=TEXT_WIDTH_VAL, height=TEXT_HEIGHT_VAL, xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set) self.text.grid(row=2, column=0, sticky=N+S+E+W) xscrollbar.config(command=self.text.xview) yscrollbar.config(command=self.text.yview)
[docs] def delete_weights(self): ''' Removes all weight restrictions. ''' self.text.delete(1.0, END) self.error_tag_exists = False
[docs] def insert_weight(self, weight): ''' Add a given weight restriction in the end of the text widget. Args: weight (str): string that describes a given weight restriction. ''' # we assume that inserted weight is always correct self.text.insert(END, weight + '\n')
[docs] def validate_weights(self): ''' Checks if all weight restrictions are valid. Returns: bool: True if all weight restrictions are valid, False otherwise. ''' self.text.config(foreground='black') if self.error_tag_exists: try: self.text.tag_remove('error', 'error.first', 'error.last') except TclError: # there is no error tag pass self.error_tag_exists = False self.errors_strvar.set('') errors = [] all_constraints = [] for count, line in enumerate(self.text.get('1.0', 'end-1c').splitlines()): # Iterate lines if line: weight_as_list = [] weight_as_list.append(line) try: bounds = create_bounds(weight_as_list, self.current_categories) assert len(bounds) == 1 key, value = bounds.popitem() is_price_ratio = contraint_is_price_ratio_type(key) if self.is_price_ratio_constraint and not is_price_ratio: raise ValueError('Constraint {0} is not a price ratio constraint'. format(line)) if not self.is_price_ratio_constraint and is_price_ratio: raise ValueError('Constraint {0} is a price ratio constraint.' ' Use {1} weight restriction type constraint instead.'. format(line, self.weight_name)) except ValueError as err: self.text.tag_add('error', '%d.0' % (count + 1), '%d.end' % (count + 1)) self.error_tag_exists = True errors.append('* ' + str(err) + '\n') else: # combine correct lines for parameters all_constraints.append(line) errors.append('\n') if self.error_tag_exists: self.text.tag_config('error', foreground='red') constraints = '; '.join(all_constraints) self.params.update_parameter(self.param_name, constraints) if self.error_tag_exists: self.errors_strvar.set(self.get_all_errors(errors)) if constraints: return True return False
[docs] def get_all_errors(self, error_list): ''' Returns given list of errors as one string. Args: error_list (list of str): list of strings to concatenate. Returns: str: concatenated string. ''' if len(error_list) == 0: return '' return ''.join(error_list)