CS4820-Winter2020 student project to create a COUNTER SUSHI R5 harvester and related functionality app for Windows and Mac
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

213 lines
11 KiB

"""This module handles all operations involving the user's settings."""
import json
from os import path
from PyQt5.QtWidgets import QWidget
from PyQt5.QtCore import QObject, pyqtSignal
from ui import SettingsTab
import ManageDB
from Constants import *
import GeneralUtils
from GeneralUtils import JsonModel
class Setting(Enum):
"""An enum of all settings"""
YEARLY_DIR = 0
OTHER_DIR = 1
REQUEST_INTERVAL = 2
REQUEST_TIMEOUT = 3
CONCURRENT_VENDORS = 4
CONCURRENT_REPORTS = 5
USER_AGENT = 6
class SettingsModel(JsonModel):
"""This holds the user's settings.
:param yearly_directory: The directory where yearly reports are saved. Yearly reports are reports that include all
the available data for a year.
:param other_directory: The default directory where non-yearly reports are saved.
:param request_interval: The time to wait between each report request, per vendor.
:param request_timeout: The time to wait before timing out a connection (seconds).
:param concurrent_vendors: The max number of vendors to work on at a time.
:param concurrent_reports: The max number of reports to work on at a time, per vendor.
:param user_agent: The user-agent that's included in the header when making requests.
"""
def __init__(self, show_debug_messages: bool, yearly_directory: str, other_directory: str, request_interval: int,
request_timeout: int, concurrent_vendors: int, concurrent_reports: int, user_agent: str,
default_currency: str):
self.show_debug_messages = show_debug_messages
self.yearly_directory = path.abspath(yearly_directory) + path.sep
self.other_directory = path.abspath(other_directory) + path.sep
self.request_interval = request_interval
self.request_timeout = request_timeout
self.concurrent_vendors = concurrent_vendors
self.concurrent_reports = concurrent_reports
self.user_agent = user_agent
self.default_currency = default_currency
@classmethod
def from_json(cls, json_dict: dict):
show_debug_messages = json_dict["show_debug_messages"]\
if "show_debug_messages" in json_dict else SHOW_DEBUG_MESSAGES
yearly_directory = json_dict["yearly_directory"]\
if "yearly_directory" in json_dict else YEARLY_DIR
other_directory = json_dict["other_directory"]\
if "other_directory" in json_dict else OTHER_DIR
request_interval = int(json_dict["request_interval"])\
if "request_interval" in json_dict else REQUEST_INTERVAL
request_timeout = int(json_dict["request_timeout"])\
if "request_timeout" in json_dict else REQUEST_TIMEOUT
concurrent_vendors = int(json_dict["concurrent_vendors"])\
if "concurrent_vendors" in json_dict else CONCURRENT_VENDORS
concurrent_reports = int(json_dict["concurrent_reports"])\
if "concurrent_reports" in json_dict else CONCURRENT_REPORTS
user_agent = json_dict["user_agent"]\
if "user_agent" in json_dict else USER_AGENT
default_currency = json_dict["default_currency"]\
if "default_currency" in json_dict else DEFAULT_CURRENCY
return cls(show_debug_messages, yearly_directory, other_directory, request_interval, request_timeout,
concurrent_vendors, concurrent_reports, user_agent, default_currency)
class SettingsController(QObject):
"""Controls the Settings tab
:param settings_widget: The settings widget.
:param settings_ui: The UI for settings_widget.
"""
settings_changed_signal = pyqtSignal(SettingsModel)
def __init__(self, settings_widget: QWidget, settings_ui: SettingsTab.Ui_settings_tab):
# region General
super().__init__()
self.settings_widget = settings_widget
json_string = GeneralUtils.read_json_file(SETTINGS_FILE_DIR + SETTINGS_FILE_NAME)
json_dict = json.loads(json_string)
self.settings = SettingsModel.from_json(json_dict)
self.show_debug_checkbox = settings_ui.show_debug_check_box
self.show_debug_checkbox.setChecked(self.settings.show_debug_messages)
# endregion
# region Reports
self.yearly_dir_edit = settings_ui.yearly_directory_edit
self.other_dir_edit = settings_ui.other_directory_edit
self.request_interval_spin_box = settings_ui.request_interval_spin_box
self.request_timeout_spin_box = settings_ui.request_timeout_spin_box
self.concurrent_vendors_spin_box = settings_ui.concurrent_vendors_spin_box
self.concurrent_reports_spin_box = settings_ui.concurrent_reports_spin_box
self.user_agent_edit = settings_ui.user_agent_edit
self.yearly_dir_edit.setText(self.settings.yearly_directory)
self.other_dir_edit.setText(self.settings.other_directory)
self.request_interval_spin_box.setValue(self.settings.request_interval)
self.request_timeout_spin_box.setValue(self.settings.request_timeout)
self.concurrent_vendors_spin_box.setValue(self.settings.concurrent_vendors)
self.concurrent_reports_spin_box.setValue(self.settings.concurrent_reports)
self.user_agent_edit.setText(self.settings.user_agent)
settings_ui.yearly_directory_button.clicked.connect(
lambda: self.on_directory_setting_clicked(Setting.YEARLY_DIR))
settings_ui.other_directory_button.clicked.connect(
lambda: self.on_directory_setting_clicked(Setting.OTHER_DIR))
# Reports Help Messages
settings_ui.yearly_directory_help_button.clicked.connect(
lambda: GeneralUtils.show_message("This is where the calendar-year reports will be saved"))
settings_ui.other_directory_help_button.clicked.connect(
lambda: GeneralUtils.show_message("This is where the special and non-calendar-year date range reports will "
"be saved by default"))
settings_ui.request_interval_help_button.clicked.connect(
lambda: GeneralUtils.show_message("The number of seconds the program will wait between sending each report "
"request to a given vendor"))
settings_ui.request_timeout_help_button.clicked.connect(
lambda: GeneralUtils.show_message("The number of seconds the program will allow a vendor to respond to "
"each report request before canceling it"))
settings_ui.concurrent_vendors_help_button.clicked.connect(
lambda: GeneralUtils.show_message("The maximum number of vendors to work on at the same time. "
"If set too high, the UI might freeze while fetching reports but the "
"fetch process will continue"))
settings_ui.concurrent_reports_help_button.clicked.connect(
lambda: GeneralUtils.show_message("The maximum number of reports to work on at the same time (per vendor). "
"If set too high, the UI might freeze while fetching reports but the "
"fetch process will continue"))
settings_ui.user_agent_help_button.clicked.connect(
lambda: GeneralUtils.show_message("How program identifies itself to the SUSHI servers. Some vendors will "
"reject some particular user agents. Only change this if there is a "
"known problem as it will affect all requests to all vendors. "
"See Help for more information."))
settings_ui.default_currency_help_button.clicked.connect(
lambda: GeneralUtils.show_message("The currency shown first in the Costs pulldown and also by Visual to "
"label the local currency in the spreadsheets generated with the Cost "
"Ratio option. Note: This doesn't have to be one of the pre-loaded "
"currencies."))
# endregion
# region Costs
self.default_currency_combobox = settings_ui.settings_costs_default_currency_combobox
self.default_currency_combobox.addItems(CURRENCY_LIST)
self.default_currency_combobox.setCurrentText(self.settings.default_currency)
# endregion
# region Search
# set up restore database button
self.is_rebuilding_database = False
self.update_database_dialog = ManageDB.UpdateDatabaseProgressDialogController(self.settings_widget)
self.rebuild_database_button = settings_ui.settings_rebuild_database_button
self.rebuild_database_button.clicked.connect(self.on_rebuild_database_clicked)
# endregion
settings_ui.save_button.clicked.connect(self.on_save_button_clicked)
def on_directory_setting_clicked(self, setting: Setting):
"""Handles the signal emitted when a choose folder button is clicked
:param setting: The setting to be changed
"""
dir_path = GeneralUtils.choose_directory()
if dir_path:
if setting == Setting.YEARLY_DIR:
self.yearly_dir_edit.setText(dir_path)
elif setting == Setting.OTHER_DIR:
self.other_dir_edit.setText(dir_path)
def on_save_button_clicked(self):
"""Handles the signal emitted when the save button is clicked"""
self.update_settings()
self.save_settings_to_disk()
self.settings_changed_signal.emit(self.settings)
GeneralUtils.show_message("Changes saved!")
def on_rebuild_database_clicked(self):
"""Restores the database when the restore database button is clicked"""
if not self.is_rebuilding_database: # check if already running
if GeneralUtils.ask_confirmation('Are you sure you want to rebuild the database?'):
self.is_rebuilding_database = True
self.update_database_dialog.update_database(ManageDB.get_all_report_files() +
ManageDB.get_all_cost_files(),
True)
self.is_rebuilding_database = False
else:
if self.settings.show_debug_messages: print('Database is already being rebuilt')
def update_settings(self):
"""Updates the app's settings using the values entered on the UI"""
self.settings.show_debug_messages = self.show_debug_checkbox.isChecked()
self.settings.yearly_directory = self.yearly_dir_edit.text()
self.settings.other_directory = self.other_dir_edit.text()
self.settings.request_interval = self.request_interval_spin_box.value()
self.settings.request_timeout = self.request_timeout_spin_box.value()
self.settings.concurrent_vendors = self.concurrent_vendors_spin_box.value()
self.settings.concurrent_reports = self.concurrent_reports_spin_box.value()
self.settings.user_agent = self.user_agent_edit.text()
self.settings.default_currency = self.default_currency_combobox.currentText()
def save_settings_to_disk(self):
"""Saves all settings to disk"""
json_string = json.dumps(self.settings, default=lambda o: o.__dict__)
GeneralUtils.save_json_file(SETTINGS_FILE_DIR, SETTINGS_FILE_NAME, json_string)