Ejemplo n.º 1
0
class GroceryProgram:

    def __init__(self, master,
                 email_config: EmailAccessBase = None,
                 wunderpy_config: WunderpyAccessBase = None,
                 inital_grocery_content: str = ''):
        self.inital_menu_content = inital_grocery_content
        self.wunderpy_config = wunderpy_config
        self.email_config = email_config
        self.master = master

        self.master.wm_title('Grocery shopping')
        self.master.geometry('1000x500')

        self.current_menu = None

        # Grid definition:

        tk.Grid.rowconfigure(self.master, 0, weight=1)
        tk.Grid.columnconfigure(self.master, 0, weight=1)

        frame = tk.Frame(self.master)
        frame.grid(row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W)
        grid = tk.Frame(frame)
        grid.grid(sticky=tk.N + tk.S + tk.E + tk.W, column=0, row=0)
        tk.Grid.rowconfigure(frame, 0, weight=1)
        tk.Grid.columnconfigure(frame, 0, weight=1)

        ## Grocery list
        self.grocery_list = ScrolledText(frame, undo=True)
        self.grocery_list.grid(rowspan=2, columnspan=1, row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W, padx=10,
                               pady=10)

        # Set callback on all key presses:
        bindtags = list(self.grocery_list.bindtags())
        bindtags.insert(2, "custom")  # index 1 is where most default bindings live
        self.grocery_list.bindtags(tuple(bindtags))
        self.grocery_list.bind_class("custom", "<Key>", self.callback_any_key_grocery_list)
        self.grocery_list.bind('<Control-Return>', self.callback_controll_return_grocery_list)
        self.grocery_list.bind('<Control-BackSpace>', self.callback_get_recipe_from_parsed)
        # self.grocery_list.bind('<Key>', self.callback_parse_grocery_list)

        # set initial grocery_list:
        self.grocery_list.insert(tk.INSERT,
                                 inital_grocery_content)

        ## Menu list
        self.menu_box = ScrolledText(frame, undo=True)
        self.menu_box.grid(rowspan=2, columnspan=3, row=0, column=1, sticky=tk.N + tk.S + tk.E + tk.W, padx=10, pady=10)

        ## View menu
        self.view_menu_button = tk.Button(frame, text='View menu', command=self.callback_view_menu)
        self.view_menu_button.grid(rowspan=1, columnspan=1, row=2, column=0, sticky=tk.N + tk.S + tk.E + tk.W,
                                   padx=10, pady=10)

        ## View grocery list
        self.view_grocery_list = tk.Button(frame, text='View grocery list',
                                           command=self.callback_view_grocery_list)
        self.view_grocery_list.grid(rowspan=1, columnspan=1, row=3, column=0, sticky=tk.N + tk.S + tk.E + tk.W,
                                    padx=10, pady=10)

        ## View categories
        self.categories_button = tk.Button(frame, text='View categories', command=self.calback_show_categories_list)
        self.categories_button.grid(rowspan=1, columnspan=1, row=2, column=1, sticky=tk.N + tk.S + tk.E + tk.W, padx=10,
                                    pady=10)

        ## Commands
        self.command_text = tk.Label(frame, text='Ctrl+Enter: Reroll recipe suggestion.\nCtrl+Backspace: Lock suggestion.')
        self.command_text.grid(rowspan=1, columnspan=1, row=3, column=1, sticky=tk.N + tk.S + tk.E + tk.W, padx=10,
                               pady=10)

        ## Email recipients
        self.email_target_entry = tk.Entry(frame)
        self.email_target_entry.grid(rowspan=1, columnspan=1, row=2, column=2, sticky=tk.N + tk.S + tk.E + tk.W,
                                     padx=10, pady=10)
        if self.email_config:
            self.email_target_entry.insert(tk.INSERT,
                                           ', '.join(self.email_config.recipients))

        ## Send email_sender button
        self.email_button = tk.Button(frame, text='Send menu to email_sender', command=self.callback_send_menu_to_email)
        self.email_button.grid(rowspan=1, columnspan=1, row=2, column=3, sticky=tk.N + tk.S + tk.E + tk.W, padx=10,
                               pady=10)
        if not self.email_config:
            self.email_button['state'] = tk.DISABLED

        ## Wunderlist target entry
        self.wunderlist_target_entry = tk.Entry(frame)
        self.wunderlist_target_entry.grid(rowspan=1, columnspan=1, row=3, column=2, sticky=tk.N + tk.S + tk.E + tk.W,
                                          padx=10, pady=10)
        if self.wunderpy_config:
            self.wunderlist_target_entry.insert(tk.INSERT, self.wunderpy_config.default_list)

        ## Send to wunderlist button:
        self.send_to_wunderlist_button = tk.Button(frame, text='Send groceries to Wunderlist',
                                                   command=self.callback_send_to_wunderlist_button)
        self.send_to_wunderlist_button.grid(rowspan=1, columnspan=1, row=3, column=3, sticky=tk.N + tk.S + tk.E + tk.W,
                                            padx=10, pady=10)
        if not self.wunderpy_config:
            self.send_to_wunderlist_button['state'] = tk.DISABLED

        rows = range(3)
        columns = []

        for row in rows:
            tk.Grid.rowconfigure(frame, row, weight=1)
        for column in columns:
            tk.Grid.columnconfigure(frame, column, weight=1)

        self.parse_grocery_list()

    def callback_get_recipe_from_parsed(self, event):
        cursor_position = self.grocery_list.index(tk.INSERT)
        row = int(cursor_position.split('.')[0])
        corresponding_line = self.menu_box.get(1.0, tk.END).split('\n')[row - 1]
        all_lines = self.grocery_list.get(1.0, tk.END).split('\n')
        # Swap line:
        all_lines[row - 1] = corresponding_line

        self.grocery_list.delete(1.0, tk.END)
        self.grocery_list.insert(tk.INSERT, '\n'.join(all_lines))
        self.grocery_list.mark_set(tk.INSERT, cursor_position)
        print("I've hit control+backspace at row {0} and column {1}".format(
            *self.grocery_list.index(tk.INSERT).split('.')))
        return 'break'

    def callback_send_menu_to_email(self):
        print('send menu by email_sender button')
        sender = 'GroceryProgram'
        recipients = self.email_target_entry.get().split(', ')
        text = html.escape(self.current_menu.generate_menu_str(), quote=True)
        template = '<html><pre><font face="Courier New, Courier, monospace">%s</font></pre></html>' % text
        template = template.replace('\n', '<br />')

        send_email(self.email_config, 'Week menu', recipients, template)
        print('email_sender ok')

    def callback_send_to_wunderlist_button(self):
        print('send to wunderlist button')
        target_list = self.wunderlist_target_entry.get()

        # Create a list of {item, description} for all groceries
        processed_groceries = []
        for grocery in self.current_menu.groceries.components():
            item = ''
            if grocery['amount']:
                item += grocery['amount'] + ' '
            item += grocery['name']

            descriptions = []
            for source_dict in grocery['components']:
                source = ''
                source_name = ''
                if source_dict['amount']:
                    source_name += source_dict['amount'] + ' '
                source_name += source_dict['name']

                source += source_name

                if source_dict['comments']:
                    comments = '(' + ', '.join(source_dict['comments']) + ')'
                    source += comments + ' '

                if source_dict['recipe']:
                    recipe = ' til %s' % source_dict['recipe']
                    if not source_dict['recipe'] == config.language.no_recipe_name:
                        if source_dict['recipe_multiplier'] == 1:
                            recipe += ' for %d pers' % source_dict['recipe_made_for']
                        else:
                            recipe += ' x%f' % source_dict['recipe_multiplier']
                    source += recipe

                descriptions += [source]

            processed_groceries += [{'item': item, 'description': ', '.join(descriptions)}]

        response = add_groceries_to_wunderlist(self.wunderpy_config, target_list_name=target_list,
                                               groceries=processed_groceries)

        print(response)

    def callback_controll_return_grocery_list(self, event):
        self.parse_grocery_list(smart=False)
        return 'break'

    def callback_any_key_grocery_list(self, event):
        self.parse_grocery_list()

    def callback_button_parse_grocery_list(self):
        self.parse_grocery_list(smart=False)

    def parse_grocery_list(self, smart=True):
        print('callback works')
        text = self.grocery_list.get(1.0, tk.END)

        self.menu_box.delete(1.0, tk.END)

        if text.strip() == 'tags':
            string = '\n'.join([tag for tag in COOKBOOK.available_tags.keys()])
            self.menu_box.insert(tk.INSERT, string)
        if text.strip() == 'recipes':
            string = '\n'.join(COOKBOOK.available_recipes)
            self.menu_box.insert(tk.INSERT, string)
        else:
            # Intelligent update: Only update the lines that have changed.
            if not self.current_menu or not smart:
                self.current_menu = COOKBOOK.parse_menu(self.grocery_list.get(1.0, tk.END))
            else:
                new_menu = COOKBOOK.parse_menu(self.grocery_list.get(1.0, tk.END))

                for index, line in enumerate(new_menu.input_lines):
                    if line in self.current_menu.input_lines:
                        current_index = self.current_menu.input_lines.index(line)
                        new_menu.input_lines[index] = self.current_menu.input_lines[current_index]
                        new_menu.processed_lines[index] = self.current_menu.processed_lines[current_index]

                new_menu.input_plan = '\n'.join(new_menu.input_lines)
                new_menu.processed_plan = new_menu.create_output_lines(new_menu.processed_lines)
                self.current_menu = new_menu

                self.current_menu.process_input()

            self.menu_box.insert(tk.INSERT, self.current_menu.processed_plan)

    def callback_view_menu(self):
        """Callback for the send menu as email_sender button."""
        print('callback_send_menu_email')
        if isinstance(self.current_menu, Menu):
            self.menu_box.delete(1.0, tk.END)
            self.menu_box.insert(tk.INSERT, '\n'+self.current_menu.generate_menu_str())
        else:
            print('No menu to view')

    def callback_view_grocery_list(self):
        """Callback for the send menu as email_sender button."""
        print('callback_view_grocery_list')
        if isinstance(self.current_menu, Menu):
            self.menu_box.delete(1.0, tk.END)
            string = '\n'.join(self.current_menu.groceries.ingredients_formatted(pretty=True, sort='alphabetical'))
            self.menu_box.insert(tk.INSERT, string)
        else:
            print('No menu to view')

    def calback_show_categories_list(self):
        self.menu_box.delete(1.0, tk.END)
        string = '\n'.join(sorted(COOKBOOK.tags))
        self.menu_box.insert(tk.INSERT, string)