def _do_lookup(self): """ Searches for and displays one or more log entries. Arguments: none. Returns: True if successful; False if the user aborted. ------------------------------------------------------------- """ try: # Clear the screen. wl_resource.print_header(self) # If there are no entries in the log, tell the user and then # return. if len(self.entries) == 0: io_utils.print_status( "Error", "There are no tasks in the log to search!", line_length=self.line_length) return False # end if # Main menu. option_list = [ "By Date/Time", "By Duration", "By Text Search", "By RE Pattern" ] prompt = "Please select a method by which to find entries:" search_opt = io_utils.menu(option_list, keystroke_list="#", prompt=prompt, line_length=self.line_length) # If the user quits, just return. if search_opt == 0: return False # end if # Otherwise call the appropriate lookup function. if search_opt == 1: results = wl_search.search_by_date(self) elif search_opt == 2: results = wl_search.search_by_duration(self) elif search_opt == 3: results = wl_search.search_by_text(self) else: # search_opt == 4 results = wl_search.search_by_re(self) # end if # If the search was unsuccessful, just return. if not results: return True # end if # Call the appropriate browse function, which will call other # functions if needed. if type(results[0]) == datetime.date: wl_search.select_date(self, results) return True else: wl_search.select_entry(self, results) return True # end if except Exception as err: _z_exc("worklog.py/WorkLog/_do_lookup", err)
def _do_settings(self, flag): """ Allows the user to change a setting. The date format, time format, or width of the screen can be changed. Arguments: none. Returns: nothing. ------------------------------------------------------------- """ try: # Loop until the user is done. while True: # Clear screen and print header. wl_resource.print_header(self) # Print instructions. self.help.print_help(self.show_help, "Settings", "_xh_settings", line_length=self.line_length) # Show menu and get a response. response = io_utils.menu( ["Set Date Format", "Set Time Format", "Set Screen Width"], keystroke_list="#", help_toggle=True, line_length=self.line_length) # If the user chose to toggle help, do that and then # loop back. if str(response).lower() == "-h": self.show_help = not self.show_help continue # end if # If the user chose to go back, just return. if response == QUIT: self.total_entries = flag return # Otherwise, to change a setting, call the appropriate # function. elif response == DATE_F: wl_datetime.set_endian(self) elif response == TIME_F: wl_datetime.set_time_format(self) else: # response == 3 wl_resource.set_screen_width(self) # end if # end while except Exception as err: _z_exc("worklog.py/WorkLog/_do_settings", err)
def action_get(self): """ Gets an action from the user. If the log object is unitialized, asks the user to open or create a file. Arguments: none. Returns: False if the user chooses to exit the program, else True. ------------------------------------------------------------- """ try: print() # If the total_entries attribute is -1, the object is not # initialized. Ask the user to open or create a log file. if self.total_entries == -1: keystroke_list = ["O", "N", "X", "M"] action = io_utils.menu([ "Open Log File", "New Log File", "Change Settings", "Read User Manual" ], option_type="actions", keystroke=True, keystroke_list=keystroke_list, lines=True, top_level=True, line_length=self.line_length) # If the user chooses to quit here... if action == 0: # Set the action attribute so _action_take knows to # do nothing. self.action = None # return False to main() so it knows to exit the # program. return False else: # Set the action attribute, skip the other menu code and # immediately return. self.action = keystroke_list[action - 1] return True # end if # end if # If the object has been initialized, skip the above code, # print the header and ask the user what they want to do. wl_resource.print_header(self) keystroke_list = ["A", "F", "S", "C", "X"] action = io_utils.menu([ "Add Entries", "Find/Edit/Delete Entries", "Save Log File", "Close Log File", "Change Settings" ], option_type="actions", lines=True, keystroke=True, keystroke_list=keystroke_list, top_level=True, line_length=self.line_length) # If the user chose to quit... if action == QUIT: # Set the action attribute to None, which will be a flag # for the action_take method. self.action = None # If the log object has changed, prompt to save. if self.changed is True: save = io_utils.yes_no( "The log file has changed. Do you want to save it?", line_length=self.line_length) # If yes, just save the file now (bypass action_take # so that it will still exit). if save: self._do_save() # end if # end if # Return the flag to end the object loop. return False else: # Set the action attribute. self.action = keystroke_list[action - 1] # end if # Always return True unless the user chose to quit. return True except Exception as err: _z_exc("worklog.py/WorkLog/action_get", err)
def browse_entries(wl_obj, entry_list, ndx=0): """ Allows the user to browse entries. Arguments: - wl_obj -- the work log object. - entry_list -- the list of entries to browse. Keyword Arguments: - ndx -- the index of the entry to initially display. Returns: the entry list as modified. ----------------------------------------------------------------- """ try: # Loop. while True: # If the list is empty, automatically return. if len(entry_list) == 0: return entry_list # end if # Clear the screen. wl_resource.print_header(wl_obj) # Print status message. msg = f"Displaying task {(ndx + 1)} of {len(entry_list)}" io_utils.print_status("Status", msg, go=True, line_length=wl_obj.line_length) # Display the current entry. display_entry(wl_obj, entry_list[ndx]) # Beneath the entry, display a menu. options = ["Edit", "Delete"] key_list = ["E", "D"] if ndx > 0: options.append("Previous") key_list.append("P") # end if if ndx < (len(entry_list) - 1): options.append("Next") key_list.append("N") # end if options.append("Back") key_list.append("B") response = io_utils.menu(options, keystroke=True, keystroke_list=key_list, lines=False, quit_=False, prompt=" ", line_length=wl_obj.line_length) # Convert the integer response back into the correct option. response = key_list[response - 1] # Take the appropriate action. if response == "B": # If the user wants to go back, return the entry list # (as it may have been modified). return entry_list elif response == "P": # If the user wants to back up one entry, decrement the # index and loop. ndx -= 1 continue elif response == "N": # If the user wants to go to the next entry, increment # the index and loop. ndx += 1 continue elif response == "E": # If the user wants to edit the current entry, call the # edit function and then loop. _edit_entry(wl_obj, entry_list[ndx], ndx, len(entry_list)) continue else: # If the user wants to delete the entry, confirm, and if # confirmed, call the delete function. and then loop. if io_utils.confirm("delete this entry"): _delete_entry(wl_obj, entry_list, ndx) # Delete the entry from the entry list. # If there are no more entries, return the empty # list. if len(entry_list) == 0: return entry_list # end if # If the index is past the end of the list, reset # it. if ndx <= len(entry_list): ndx = len(entry_list) - 1 # end if # end if continue # end if # end while except Exception as err: _z_exc("wl_viewedit.py/browse_entries", err)
def _edit_entry(wl_obj, edit_entry, ndx, total): """ Allows the user to edit a log entry. Arguments: - wl_obj -- the work log object. - edit_entry -- the entry to edit. - ndx -- the number of the entry being edited. - total -- the total number of entries being displayed. Returns: nothing. ----------------------------------------------------------------- """ try: # This function mainly piggybacks on the add functions to alter # the attributes of the log entry object. All values are # preserved via the info attribute of a working copy until # saved by the user. changed = False # Create a working copy of the entry to be edited. new_entry = _copy_entry(edit_entry) # Store the original values in the info attribute. new_entry.info["title"] = new_entry.title new_entry.info["date"] = new_entry.date new_entry.info["time"] = new_entry.time new_entry.info["duration"] = new_entry.duration new_entry.info["notes"] = new_entry.notes new_entry.info["ndx"] = f"task {ndx + 1} of {total}" resort = False # Loop. while True: # Clear the screen and display program header. wl_resource.print_header(wl_obj) # Print status message. io_utils.print_status("Status", f"Editing {new_entry.info['ndx']}…", go=True, line_length=wl_obj.line_length) # Display the entry. display_entry(wl_obj, new_entry, edit=True) # Print instructions. wl_obj.help.print_help(wl_obj.show_help, "Editing", "_eh_edit", line_length=wl_obj.line_length) options = ["Title", "Date", "Time", "Duration", "Notes"] # User selects the field to edit. response = io_utils.menu( options, keystroke_list="#", prompt="Please select a field to edit. When you are finished," + " go back to save or discard your changes:", line_length=wl_obj.line_length, help_toggle=True) # If the user chose to toggle help, do that and loop back. if str(response).lower() == "-h": wl_obj.show_help = not wl_obj.show_help continue # end if # If the user chose to quit... if response == QUIT: # If the entry has been edited, prompt to save changes. if (changed and io_utils.yes_no( "Do you want to save your changes?", line_length=wl_obj.line_length)): # Recalculate the datetime attribute, in case either # the date or time changed. new_entry.datetime = wl_add.add_datetime(new_entry) # Save the changed values to the original log entry # object. _update_entry(wl_obj, new_entry, resort) # Set the flag that the log object has changed. wl_obj.changed = True # end if return # Edit title. elif response == TITLE: ch = wl_add.add_title(wl_obj, new_entry, edit=True) # If the title was edited, turn on the resort flag. if ch: resort = True # end if # Edit date. elif response == DATE: ch = wl_add.add_date(wl_obj, new_entry, edit=True) # If the date was edited, turn on the resort flag. if ch: resort = True # end if # Edit time. elif response == TIME: ch = wl_add.add_time(wl_obj, new_entry, edit=True) # If the time was edited, turn on the resort flag. if ch: resort = True # end if # Edit duration. elif response == DURATION: ch = wl_add.add_duration(wl_obj, new_entry, edit=True) # Edit notes. else: ch = wl_add.add_note(wl_obj, new_entry, edit=True) # end if # If something was edited, turn on the changed flag. if ch: changed = True # end if # end while except Exception as err: _z_exc("wl_viewedit.py/_edit_entry", err)
def browse_list(wl_obj, browse_list, start=0): """ Presents a list to the user and asks him/her to select one. Arguments: - wl_obj -- the work log object. - browse_list -- the list to present. - start -- the first item to display (default 0). Returns: an integer representing an item to display, 0 if the user quits, or a string representing a navigational command. ----------------------------------------------------------------- """ try: # If the list is empty, automatically return as if the user had # quit. if len(browse_list) == 0: return 0 # end if # Clear the screen and print the matches to be listed. wl_resource.print_header(wl_obj) if len(browse_list) == 1: msg = "Showing match 1 of 1" else: msg = f"Showing matches {start + 1}-" if start + 9 <= len(browse_list): msg += f"{start + 9} of {len(browse_list)}" else: msg += f"{len(browse_list)} of {len(browse_list)}" # end if # end if io_utils.print_status("Status", msg, go=True, line_length=wl_obj.line_length) # Build the options list. options = [] # For dates, just append the date (as a string). if type(browse_list[0]) == datetime.date: for ndx in range(start, start + 9): # Stop if at the end of the list. if ndx == len(browse_list): break # end if options.append(str(browse_list[ndx])) # end for # For entries, append the title, date and time (as strings). else: for ndx in range(start, start + 9): # Stop if at the end of the list. if ndx == len(browse_list): break # end if # Gather the fields. title = browse_list[ndx].title date = wl_resource.format_string(wl_obj, browse_list[ndx].date, short=True) time = wl_resource.format_string(wl_obj, browse_list[ndx].time) # If the time had a leading zero stripped, replace it # with a space. if time[1] == ":": time = f" {time}" # end if max_title_len = wl_obj.line_length - 23 # If the title is too long to fit in the column, # truncate it. if len(title) > max_title_len: title = title[:max_title_len - 1] + "… " else: title += " " # end if rj = wl_obj.line_length - len(title) - 4 option = title + f" {date} {time}".rjust(rj, ".") # Append the assembled string. options.append(option) # end for # end if if start > 0: prev = True else: prev = False # end if if start + 9 < len(browse_list): nxt = True else: nxt = False # end if # Now display the menu and return the user's choice. return io_utils.menu(options, prompt="Select an entry to view:", keystroke_list="#", nav=True, prev=prev, nxt=nxt, line_length=wl_obj.line_length) except Exception as err: _z_exc("wl_viewedit.py/browse_list", err)
def select_entry(wl_obj, entry_list): """ Allows the user to either browse a set of entries, or choose from a list. Arguments: - wl_obj -- the work log object. - entry_list -- the list of entries. Returns: nothing. ----------------------------------------------------------------- """ try: # Clear the screen. wl_resource.print_header(wl_obj) # Print the number of dates found. if len(entry_list) == 1: msg = "Found 1 task." else: msg = f"Found {len(entry_list)} tasks." # end if io_utils.print_status("Status", msg, line_length=wl_obj.line_length) # Ask the user to browse or pick from list. response = io_utils.menu( [ "Browse all matching tasks", "Choose from a list of matching tasks" ], keystroke_list="#", quit_=True, prompt="Please select how you want to see the matching tasks:", line_length=wl_obj.line_length) # If the user chooses to go back, just return. if response == QUIT: return # end if # If the user chooses to browse the matches, call the browse # function, then return. if response == 1: entry_list = wl_viewedit.browse_entries(wl_obj, entry_list) return # If the user chooses to see a list, display it here. else: start = 0 # Run in a loop until the user is done viewing/editing, then # return. while True: # Call list browse. response = wl_viewedit.browse_list(wl_obj, entry_list, start=start) # If the response isn't an integer, it's a command to # move forward or back. Move the start position, but # only if it doesn't go beyond the bounds of the list. if type(response) == str: if (response.lower() == "p") and (start - 9 >= 0): start -= 9 elif ((response.lower() == "n") and (start + 9 < len(entry_list))): start += 9 # end if # Clear the screen before looping back. wl_resource.print_header(wl_obj) continue # end if # If the user quits, return. if response == QUIT: return # end if # If it's a non-zero integer, the user chose an entry. # Get the index number of the chosen entry in the list. ndx = start + response - 1 # Browse entries, starting with the selected one. wl_viewedit.browse_entries(wl_obj, entry_list, ndx=ndx) # Clear the screen before looping back. wl_resource.print_header(wl_obj) # end while # end if except Exception as err: _z_exc("wl_search.py/select_entry", err)
def select_date(wl_obj, date_list): """ Show a list (or part of a list) of dates that contain log entries. Arguments: - wl_obj -- the work log object. - date_list -- the list of dates. Returns: nothing. ----------------------------------------------------------------- """ try: start = 0 # Clear the screen. wl_resource.print_header(wl_obj) # Print the number of dates found. if len(date_list) == 1: msg = "Found 1 date with entries." else: msg = f"Found {len(date_list)} dates with entries." # end if io_utils.print_status("Status", msg, line_length=wl_obj.line_length) # Run in a loop until the user is done viewing/editing, then # return. while True: # Call list browse. response = wl_viewedit.browse_list(wl_obj, date_list, start=start) # If the response isn't an integer, it's a command to move # forward or back. Move the start position, but only if it # doesn't go beyond the bounds of the list. if type(response) == str: if (response.upper() == "P") and (start - 9 >= 0): start -= 9 elif ((response.upper() == "N") and (start + 9 < len(date_list))): start += 9 # end if # Clear the screen before looping back. wl_resource.print_header(wl_obj) continue # end if # If the user quits, return. if response == QUIT: return # end if # If it's a non-zero integer, the user chose a date. Find # all entries on that date. start_date = datetime.datetime.combine( date_list[start + response - 1], datetime.time()) end_date = start_date.replace(hour=23, minute=59) entry_list = _find_entries_date(wl_obj, start_date, end_date) # Let the user browse/edit those entries. (If the user # edited the list, it will come back changed.) entry_list = wl_viewedit.browse_entries(wl_obj, entry_list) # If the user deleted all of the entries for a date, then # that date is no longer valid and must be removed. if len(entry_list) == 0: del date_list[start + response - 1] # end if # Clear the screen before looping back. wl_resource.print_header(wl_obj) # end while except Exception as err: _z_exc("wl_search.py/select_date", err)