from event_logger import EventLogger from event_receiver_thread import EventReceiverThread from command_thread import CommandThread from command_tester import CommandTester # def signal_handler(signal, frame): # print('You pressed Ctrl+Z!') if __name__ == '__main__': # signal.signal(signal.SIGTSTP, signal_handler) outbound_queue = Queue() inbound_queue = Queue() command_thread = CommandThread(outbound_queue) command_thread.start() event_receiver_thread = EventReceiverThread(inbound_queue) event_receiver_thread.start() event_logger_thread = EventLogger(inbound_queue) event_logger_thread.start() command_tester = CommandTester(outbound_queue) command_tester.start() command_thread.join() event_receiver_thread.close() event_receiver_thread.join() event_logger_thread.join() command_tester.join()
class ConfigSFTPDialog(QDialog, Ui_ConfigSFTPDialog): def __init__(self, window, just_save): QDialog.__init__(self) Ui_ConfigSFTPDialog.__init__(self) self.setupUi(self) self.window = window self.backup = None self.just_save = just_save if self.just_save: self.confirm_password_line_edit.hide() self.label_3.hide() self.browse_button.pressed.connect(self.browse) def browse(self): path, _ = QFileDialog.getOpenFileName() self.private_key_line_edit.setText(path) def command_done(self, res): self.setEnabled(True) ret, message = res if not ret: QMessageBox.warning(self.window, "Invalid details", message) return if self.just_save: Backups.save(self.backup) super().accept() def accept(self): name = self.name_line_edit.text().strip() password = self.password_line_edit.text() if self.just_save: confirm_password = password else: confirm_password = self.confirm_password_line_edit.text() private_key = self.private_key_line_edit.text() username = self.username_line_edit.text().strip() sftp_password = self.sftp_password_line_edit.text().strip() server = self.server_line_edit.text().strip() prefix = self.prefix_line_edit.text().strip() backup = Backup() backup.name = name backup.location = "SFTP" backup.password = password if len(private_key) is not 0: backup.sftp_private_key = private_key backup.sftp_username = username if len(sftp_password) is not 0: backup.sftp_password = sftp_password backup.sftp_server = server backup.cloud_prefix = prefix self.backup = backup fs = [ Validator.validate_plan_name, Validator.validate_confirm_password, Validator.validate_non_empty, Validator.validate_non_empty, Validator.validate_non_empty, Validator.validate_no_space, Validator.validate_no_space, Validator.validate_no_space, Validator.validate_backend, Validator.validate_repo ] args = [(name, ), (password, confirm_password), ("Username", username), ("Server", server), ("Prefix", prefix), ("Server", server), ("Prefix", prefix), ("Username", username), (backup, ), (backup, self.just_save)] self.setEnabled(False) self.thread = CommandThread(config_worker, {"fs": fs, "args": args}) self.thread.result.connect(self.command_done) self.thread.start()
class ConfigAwsDialog(QDialog, Ui_ConfigAwsDialog): def __init__(self, window, just_save=False): QDialog.__init__(self) Ui_ConfigAwsDialog.__init__(self) self.setupUi(self) self.window = window self.backup = None self.just_save = just_save if self.just_save: self.confirm_password_line_edit.hide() self.label_3.hide() def command_done(self, res): self.setEnabled(True) ret, message = res if not ret: QMessageBox.warning(self.window, "Invalid details", message) return if self.just_save: Backups.save(self.backup) super().accept() def accept(self): name = self.name_line_edit.text().strip() password = self.password_line_edit.text() if self.just_save: confirm_password = password else: confirm_password = self.confirm_password_line_edit.text() key_id = self.key_id_line_edit.text().strip() key = self.key_line_edit.text().strip() bucket = self.bucket_line_edit.text().strip() prefix = self.prefix_line_edit.text().strip() backup = Backup() backup.name = name backup.location = "Amazon AWS" backup.password = password backup.aws_key_id = key_id backup.aws_key = key backup.aws_bucket = bucket backup.cloud_prefix = prefix self.backup = backup fs = [ Validator.validate_plan_name, Validator.validate_confirm_password, Validator.validate_non_empty, Validator.validate_non_empty, Validator.validate_non_empty, Validator.validate_non_empty, Validator.validate_no_space, Validator.validate_no_space, Validator.validate_backend, Validator.validate_repo ] args = [(name, ), (password, confirm_password), ("AWS Key Id", key_id), ("AWS Key", key), ("Bucket", bucket), ("Prefix", prefix), ("Bucket", bucket), ("Prefix", prefix), (backup, ), (backup, self.just_save)] self.setEnabled(False) self.thread = CommandThread(config_worker, {"fs": fs, "args": args}) self.thread.result.connect(self.command_done) self.thread.start()
def main(config, thread=False): """ 主函数 config: {'server': {host:, port:, db:} } """ server = config['server'] # 动态注册task for module in server['modules'].split(): try: __import__(module) except ImportError: modules = module.split('.') __import__(modules[0], globals(), locals(), modules[1]) # 连结服务器 redis_host = server['host'] redis_port = int(server['port']) redis_db = int(server['db']) ztq_core.setup_redis('default', host=redis_host, port=redis_port, db=redis_db) # 开启一个命令线程 alias = server.get('alias', '') if not alias: alias = get_ip() server['alias'] = alias command_thread = CommandThread(worker_name=alias) sys.stdout.write('Starting server in PID %s\n' % os.getpid()) worker_state = ztq_core.get_worker_state() active_config = server.get('active_config', 'false') # 计算那些是需要根据线上配置启动的队列 active_queue_config = {} if active_config.lower( ) == 'true' and command_thread.worker_name in worker_state: # 如果服务器有这个机器的配置信息,需要自动启动工作线程 worker_config = ztq_core.get_worker_config() active_queue_config = worker_config.get(command_thread.worker_name, {}) # 根据本地配置,启动的队列 local_queue_config = {} if config['queues']: # 把worker监视队列的情况上报到服务器 queue_config = ztq_core.get_queue_config() # 如果配置有queues,自动启动线程监视 for queue_name, sleeps in config['queues'].items(): # 线上配置稍后再设置 if queue_name in active_queue_config: continue local_queue_config[queue_name] = [{ 'interval': int(sleep) } for sleep in sleeps.split(',')] if not queue_config.get(queue_name, []): queue_config[queue_name] = { 'name': queue_name, 'title': queue_name, 'widget': 5 } # 合并线上和线下的配置 active_queue_config.update(local_queue_config) init_job_threads(active_queue_config) loggers = config['log'] initlog( loggers.get('key', 'ztq_worker'), loggers.get('handler_file'), loggers.get('level', 'ERROR'), ) # 不是以线程启动 if thread: command_thread.setDaemon(True) command_thread.start() else: command_thread.run()
class ConfigGcpDialog(QDialog, Ui_ConfigGcpDialog): def __init__(self, window, just_save): QDialog.__init__(self) Ui_ConfigGcpDialog.__init__(self) self.setupUi(self) self.window = window self.backup = None self.just_save = just_save if self.just_save: self.confirm_password_line_edit.hide() self.label_3.hide() self.browse_button.pressed.connect(self.browse) def browse(self): path, _ = QFileDialog.getOpenFileName() self.cred_file_line_edit.setText(path) def command_done(self, res): self.setEnabled(True) ret, message = res if not ret: QMessageBox.warning(self.window, "Invalid details", message) return if self.just_save: Backups.save(self.backup) super().accept() def accept(self): name = self.name_line_edit.text().strip() password = self.password_line_edit.text() if self.just_save: confirm_password = password else: confirm_password = self.confirm_password_line_edit.text() cred_file = self.cred_file_line_edit.text() project = self.project_line_edit.text().strip() bucket = self.bucket_line_edit.text().strip() prefix = self.prefix_line_edit.text().strip() backup = Backup() backup.name = name backup.location = "Google Cloud" backup.password = password backup.gcp_cred_file = cred_file backup.gcp_project = project backup.gcp_bucket = bucket backup.cloud_prefix = prefix self.backup = backup fs = [Validator.validate_plan_name, Validator.validate_confirm_password, Validator.validate_local_path, Validator.validate_non_empty, Validator.validate_non_empty, Validator.validate_non_empty, Validator.validate_no_space, Validator.validate_no_space, Validator.validate_backend, Validator.validate_repo] args = [(name, ), (password, confirm_password), (cred_file, ), ("Project", project), ("Bucket", bucket), ("Prefix", prefix), ("Bucket", bucket), ("Prefix", prefix), (backup, ), (backup, self.just_save)] self.setEnabled(False) self.thread = CommandThread(config_worker, {"fs": fs, "args": args}) self.thread.result.connect(self.command_done) self.thread.start()
class MainWindow(QMainWindow): """ This is a class that creates a PyQt5 window containing start, stop, and exit buttons as well as gesture icons. The window is the main window for our program. Attributes: commands: KeyboardCommand class object capture: QtCapture class object camera: OpenCV camera object command_thread: CommandThread class object google_earth: GoogleEarth class object popup_window: QMessageBox object popup_title (string) : Pop up window title popup_text (string) : Pop up window body text desktop : Available screen geometry based on current screen resolution screen : Total screen geometry based on current screen resolution qt_window_height (int) : Calculated value for gesture icon window size layout : Instantiate QVBoxLayout or QHBoxLayout classes, used for aligning images and buttons label_dict (dict) : Contains labels that are used to display gesture icon images image_list (list) : Contains names of image files for gesture icon images title_list (list) : Contains names of titles for corresponding gesture images state_machine: Instantiate QStateMachine class, used to control state of program buttons label : Instantiate QLabel class, labels used to hold gesture icon images and text button : Instantiate QPushButton class, buttons used to start, stop, and exit program widget : Insantiate QWidget class, contains and displays labels and buttons Args: earth : GoogleEarth class object desk_geo: Available screen geometry screen_geo: Total screen geometry """ # Signals for updating state of state machine onSignal = pyqtSignal() offSignal = pyqtSignal() def __init__(self, earth, desk_geo, screen_geo, *args, **kwargs): """ Please see help(MainWindow) for more info. """ super(MainWindow, self).__init__(*args, **kwargs) # Instantiate KeyboardCommands class self.commands = KeyboardCommands() # Will hold hand_recognition QtCapture class self.capture = None # Will hold camera object for OpenCV self.camera = None # Will hold thread for issuing GE commands self.command_thread = None # Make Qt gesture icon window frameless self.setWindowFlags(QtCore.Qt.FramelessWindowHint) # Get resolution, window size, and offsets for positioning self.google_earth = earth # Variables for popup windows self.popup_window = None self.popup_title = "" self.popup_text = "" # Available screen geometry self.desktop = desk_geo # Total screen geometry self.screen = screen_geo # Sets gesture icon window to be 1/4 of available screen space self.qt_window_height = int(self.desktop.height() * 1 / 4) # Set geometry of Qt gesture icon window self.setGeometry( QtWidgets.QStyle.alignedRect( QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, QtCore.QSize(self.desktop.width(), self.qt_window_height), self.desktop)) # Create layouts for organizing Qt gesture icon window self.layout = QVBoxLayout() self.layout1 = QHBoxLayout() self.layout2 = QHBoxLayout() self.layout3 = QHBoxLayout() # Dictionary to hold labels once they are created self.label_dict = dict() # Lists hold gesture icon file names and gesture icon titles self.image_list = [ 'images/index_up.png', 'images/v_sign.png', 'images/thumb_left.png', 'images/thumb_right.png', 'images/fist.png', 'images/five_wide.png', 'images/palm.png', 'images/shaka.png' ] self.title_list = [ 'Move Up', 'Move Down', 'Move Left', 'Move Right', 'Zoom In', 'Zoom Out', 'Tilt Up', 'Tilt Down' ] # Create and add 6 labels containing hand gesture image to layout2 and 6 # labels with the gesture descriptions to layout1 for num in range(0, 8): # Each label is created to hold gesture icon image self.label = QLabel(self) # Pixmap is created with the current gesture icon image self.pixmap = QPixmap(self.image_list[num]) # Breakpoints to scale size of gesture icons for different resolutions if self.screen.width() >= 2560: self.pixmap = self.pixmap.scaledToWidth(225) elif self.screen.width() >= 1920: self.pixmap = self.pixmap.scaledToWidth(185) elif self.screen.width() > 1280 and self.screen.height() >= 1200: self.pixmap = self.pixmap.scaledToWidth(175) elif self.screen.width() > 800 and self.screen.height() >= 1024: self.pixmap = self.pixmap.scaledToWidth(125) elif self.screen.width() > 800: self.pixmap = self.pixmap.scaledToWidth(100) else: self.pixmap = self.pixmap.scaledToWidth(50) # Assigns gesture icon image to the current label self.label.setPixmap(self.pixmap) # Create gesture title label for the image self.label_title = QLabel(self.title_list[num]) # Store current icon image label in dictionary self.label_dict[num] = self.label # Place current icon image label in layout self.layout2.addWidget(self.label_dict[num], alignment=QtCore.Qt.AlignCenter) # Place current icon image title label in layout self.layout1.addWidget(self.label_title, alignment=QtCore.Qt.AlignCenter) # Create state machine to reliably handle state changes during threading self.state_machine = QStateMachine() # Create button to handle state changes when pressed self.state_button = QPushButton(self) self.state_button.setStyleSheet("background-color: silver") # Connect button released signal to check_state slot self.state_button.released.connect(self.check_state) # Create on state for state machine self.on = QState() # Create off state for state machine self.off = QState() # Add transition for on state to off state when offSignal is emitted self.on.addTransition(self.offSignal, self.off) # Add transition for on state to on state when state_button clicked signal emitted self.on.addTransition(self.state_button.clicked, self.on) # Add transition for off state to on state when onSignal is emitted self.off.addTransition(self.onSignal, self.on) # Assign text property to state_button in on state self.on.assignProperty(self.state_button, "text", "Start Gesture Navigation") # Assign text property to state_button in off state self.off.assignProperty(self.state_button, "text", "Stop Gesture Navigation") # Add off state to state machine self.state_machine.addState(self.off) # Add on state to state machine self.state_machine.addState(self.on) # Set state machine initial state to on self.state_machine.setInitialState(self.on) # State state machine self.state_machine.start() # Create gesture tips button and connect it to start_gesture_tips slot self.tips_button = QPushButton("Gesture Navigation Tips") self.tips_button.setStyleSheet("background-color: silver") self.tips_button.pressed.connect(self.start_gesture_tips) # Create exit button and connect it to exit slot self.exit_button = QPushButton("Exit Program") self.exit_button.setStyleSheet("background-color: silver") self.exit_button.pressed.connect(self.exit) # Add tips, state, and exit button to layout 3 self.layout3.addWidget(self.tips_button) self.layout3.addWidget(self.state_button) self.layout3.addWidget(self.exit_button) # Add layout 1, 2, and 3 to layout self.layout.addLayout(self.layout1) self.layout.addLayout(self.layout2) self.layout.addLayout(self.layout3) # Create widget to hold layout, add layout to widget self.widget = QWidget() self.widget.setLayout(self.layout) # Set widget with layouts as central widget self.setCentralWidget(self.widget) # Function to display pop up windows and block GUI loop until closed def show_popup(self, title, message, icon): """ Function to create a pop up window that blocks the event loop until it is closed. Used to send info or warning messages. Parameters: title (string) : Title of pop up window message (string) : Body text of pop up window icon : QMessageBox icon to be displayed """ # Create QMessageBox for pop up message self.popup_window = QMessageBox() # Set pop up title to passed in title self.popup_window.setWindowTitle(title) # Set pop up body text to passed in message self.popup_window.setText(message) # Set pop up icon to passed in icon self.popup_window.setIcon(icon) # Set pop up window to use Ok close button self.popup_window.setStandardButtons(QMessageBox.Ok) # Execute pop up window so that it blocks GUI loop until closed self.popup_window.exec() # Check state of state machine, take actions based on current state def check_state(self): """ Function to check the current state of the state machine. Calls check_earth_tips if in on state, calls stop_opencv if in off state. """ current_state = self.state_machine.configuration() if self.on in current_state: self.check_earth_tips() elif self.off in current_state: self.stop_opencv() def start_gesture_tips(self): """ Function to create PyHand Earth gesture navigation tips window. """ # Sets title of pop up window self.popup_title = "Welcome to PyHand Earth!" # Sets body text of pop up window self.popup_text = """\nThis program allows you to navigate the Google Earth Pro desktop application using only your Webcam and eight hand gestures. \n\t Instructions and Tips \n\nFor the best experience, please read the instructions below and then close this window: \n\n1. Position your webcam so that you have a blank, light-colored background behind you. \n\n2. Position your right hand and desired gesture in front of the webcam so that it fills a good portion of the orange bounding rectangle in the live video window once it opens. \n\n3. If the prediction is stuck on the wrong gesture, just shake your hand a little and let it reset. \n\n4. If you remove your hand completely and have a blank background, navigation should halt. \n\n5. Happy navigating! """ # Calls show_popup to create pop up window self.show_popup(self.popup_title, self.popup_text, QMessageBox.Information) def check_earth_tips(self): """ Called by check_state when state machine is in on state. Checks to see if Google Earth Start-up Tips window is open, and asks user to close the window with a pop up window message. If Google Earth Start-up Tips window is closed, calls open_camera. """ # Checks if Google Earth start-up tips window is open if self.google_earth.start_up_tips(): # Sets title of pop up window self.popup_title = "Gesture Navigation Warning Message" # Sets body text of pop up window self.popup_text = "Please make sure the Start-up Tips window is closed before " + \ "starting gesture navigation" # Calls show_popup to create pop up window self.show_popup(self.popup_title, self.popup_text, QMessageBox.Warning) else: # If Google Earth start-up tips window now open, calls open_camera self.open_camera() def open_camera(self): """ Function to create OpenCV VideoCapture object. If camera is not found, creates pop up window message to warn user and ask them to connect a camera. If camera is found, calls start_opencv. """ # Creates cv2 VideoCapture object, passing in -1 to find first active camera self.camera = cv2.VideoCapture(-1) # If camera is not found, create pop up window to warn the user if self.camera is None or not self.camera.isOpened(): # Sets title of pop up window self.popup_title = "No Camera Found Warning Message" # Sets body text of pop up window self.popup_text = "No camera has been detected. \n\nPlease connect a camera before " + \ "starting gesture navigation.\n" # Calls show_popup to create pop up window self.show_popup(self.popup_title, self.popup_text, QMessageBox.Warning) else: # If camera is found, calls start_opencv self.start_opencv() def start_opencv(self): """ Function to start the OpenCV gesture navigation window. Repositions the Google Earth window to take up half of the screen, then calls create_opencv to instantiate QtCapture window. The CommandThread class object is then instantiated to begin sending commands generated in the CaptureThread class to Google Earth. The QtCapture window is then displayed. Finally, the offSignal is emitted to change the state machine to the off state and the tips_button is disabled to prevent tips from being shown while gesture navigation is active. """ # Repositions Google Earth to take up one half of the available screen size self.google_earth.reposition_earth_small() # If opencv window not created, create it if not self.capture: self.create_opencv() else: self.capture = None self.create_opencv() # If command thread exists, remove it if self.command_thread: self.command_thread = None # Start command thread for sending commands to GE self.command_thread = CommandThread(self.capture, self.commands) self.command_thread.start() # Show opencv window self.capture.show() # Emits offSignal to ensure button in correct state self.offSignal.emit() # Disable tips button while gesture navigation is active self.tips_button.setEnabled(False) def create_opencv(self): """ Creates QtCapture window to display the OpenCV window frames. Resizes and repositions the QtCapture window based on current monitor resolution. """ # Create QtCapture window for rendering opencv window self.capture = QtCapture(self.desktop, self.screen, self.camera) self.capture.setParent(self.widget) self.capture.setWindowFlags(QtCore.Qt.Tool) self.capture.setWindowTitle("OpenCV Recording Window") # Get new height based on available screen space minus an offset for the window title new_height = int((self.desktop.height() * 3 / 4) - 35) # Get width that is half of the available screen space half_width = int(self.desktop.width() / 2) # Breakpoints to resize and reposition QtCapture window based on current monitor resolution if self.screen.width() > 1280: window_x = int(self.desktop.width() / 2) + (self.screen.width() - self.desktop.width()) self.capture.setGeometry(window_x, 0, half_width, new_height) elif self.screen.width() > 1152: new_width = int((self.desktop.width() * 29 / 64) + 3) window_x = int(half_width + (half_width - new_width) + (self.screen.width() - self.desktop.width())) self.capture.setGeometry(window_x, 0, new_width, new_height) elif self.screen.width() > 1024: new_width = int((self.desktop.width() * 25 / 64)) window_x = int(half_width + (half_width - new_width) + (self.screen.width() - self.desktop.width())) self.capture.setGeometry(window_x, 0, new_width, new_height) else: new_width = int((self.desktop.width() * 20 / 64) - 3) window_x = int(half_width + (half_width - new_width) + (self.screen.width() - self.desktop.width())) self.capture.setGeometry(window_x, 0, new_width, new_height) def stop_opencv(self): """ Function to close the QtCapture OpenCV window and stop commands being sent to Google Earth. """ # Sends request to end the Google Earth command thread self.command_thread.end_thread() time.sleep(1) # If capture object exists, end thread, release camera, and close window if self.capture: self.capture.stop_thread() time.sleep(1) self.capture.delete() self.capture.setParent(None) # Repositions Google Earth to take up full width of available screen space self.google_earth.reposition_earth_large() # Emits onSignal to ensure button in correct state self.onSignal.emit() # Enable tips when gesture navigation is not active self.tips_button.setEnabled(True) def exit(self): """ Slot function for exit button signal. Stops commands being sent to Google Earth, ends the OpenCV window thread if running, closes Google Earth, and exits the Qt application. """ # If the command thread is running, request thread end if self.command_thread: self.command_thread.end_thread() time.sleep(1) # If the capture thread is running, request thread end if self.capture: self.capture.stop_thread() time.sleep(1) # Close the Google Earth window self.google_earth.close_earth() # Quit the Qt application, returning to main QtCore.QCoreApplication.instance().quit()
from event_receiver_thread import EventReceiverThread from command_thread import CommandThread from command_tester import CommandTester # def signal_handler(signal, frame): # print('You pressed Ctrl+Z!') if __name__ == '__main__': # signal.signal(signal.SIGTSTP, signal_handler) outbound_queue = Queue() inbound_queue = Queue() command_thread = CommandThread(outbound_queue) command_thread.start() event_receiver_thread = EventReceiverThread(inbound_queue) event_receiver_thread.start() event_logger_thread = EventLogger(inbound_queue) event_logger_thread.start() command_tester = CommandTester(outbound_queue) command_tester.start() command_thread.join() event_receiver_thread.close() event_receiver_thread.join() event_logger_thread.join() command_tester.join()
def main(config, thread=False): """ 主函数 config: {'server': {host:, port:, db:} } """ server = config["server"] # 动态注册task for module in server["modules"].split(): try: __import__(module) except ImportError: modules = module.split(".") __import__(modules[0], globals(), locals(), modules[1]) # 连结服务器 redis_host = server["host"] redis_port = int(server["port"]) redis_db = int(server["db"]) ztq_core.setup_redis("default", host=redis_host, port=redis_port, db=redis_db) # 开启一个命令线程 alias = server.get("alias", "") if not alias: alias = get_ip() server["alias"] = alias command_thread = CommandThread(worker_name=alias) sys.stdout.write("Starting server in PID %s\n" % os.getpid()) worker_state = ztq_core.get_worker_state() active_config = server.get("active_config", "false") # 计算那些是需要根据线上配置启动的队列 active_queue_config = {} if active_config.lower() == "true" and command_thread.worker_name in worker_state: # 如果服务器有这个机器的配置信息,需要自动启动工作线程 worker_config = ztq_core.get_worker_config() active_queue_config = worker_config.get(command_thread.worker_name, {}) # 根据本地配置,启动的队列 local_queue_config = {} if config["queues"]: # 把worker监视队列的情况上报到服务器 queue_config = ztq_core.get_queue_config() # 如果配置有queues,自动启动线程监视 for queue_name, sleeps in config["queues"].items(): # 线上配置稍后再设置 if queue_name in active_queue_config: continue local_queue_config[queue_name] = [{"interval": int(sleep)} for sleep in sleeps.split(",")] if not queue_config.get(queue_name, []): queue_config[queue_name] = {"name": queue_name, "title": queue_name, "widget": 5} # 合并线上和线下的配置 active_queue_config.update(local_queue_config) init_job_threads(active_queue_config) loggers = config["log"] initlog(loggers.get("key", "ztq_worker"), loggers.get("handler_file"), loggers.get("level", "ERROR")) # 不是以线程启动 if thread: command_thread.setDaemon(True) command_thread.start() else: command_thread.run()
class ConfigLocalDialog(QDialog, Ui_ConfigLocalDialog): def __init__(self, window, just_save=False): QDialog.__init__(self) Ui_ConfigLocalDialog.__init__(self) self.setupUi(self) self.window = window self.backup = None self.just_save = just_save if self.just_save: self.confirm_password_line_edit.hide() self.label_3.hide() self.browse_button.pressed.connect(self.browse) def browse(self): directory = QFileDialog.getExistingDirectory() self.local_directory_line_edit.setText(directory) def command_done(self, res): self.setEnabled(True) ret, message = res if not ret: QMessageBox.warning(self.window, "Invalid details", message) return if self.just_save: Backups.save(self.backup) super().accept() def accept(self): name = self.name_line_edit.text().strip() password = self.password_line_edit.text() if self.just_save: confirm_password = password else: confirm_password = self.confirm_password_line_edit.text() directory = self.local_directory_line_edit.text() backup = Backup() backup.name = name backup.location = "Local Directory" backup.password = password backup.local_directory = directory self.backup = backup fs = [ Validator.validate_plan_name, Validator.validate_confirm_password, Validator.validate_local_path, Validator.validate_backend, Validator.validate_repo ] args = [(name, ), (password, confirm_password), (directory, ), (backup, ), (backup, self.just_save)] self.setEnabled(False) self.thread = CommandThread(config_worker, {"fs": fs, "args": args}) self.thread.result.connect(self.command_done) self.thread.start()
class BackupSettings(QDialog, Ui_BackupSettingsDialog): def __init__(self, backup, window, edit=False): QDialog.__init__(self) Ui_BackupSettingsDialog.__init__(self) self.setupUi(self) self.backup = backup self.window = window self.edit = edit self.paths = set() self.exclude_rules = set() self.map = { "mon": self.mon_checkbox, "tue": self.tue_checkbox, "wed": self.wed_checkbox, "thu": self.thu_checkbox, "fri": self.fri_checkbox, "sat": self.sat_checkbox, "sun": self.sun_checkbox } self.days_checked = set() prefix = self.backup.cloud_prefix if self.backup.cloud_prefix is not None else self.backup.local_directory window_title = f"{self.backup.location} ({prefix})" # Hiding unsupported add file button for now self.add_file_button.hide() self.add_button.pressed.connect(self.add_folder) self.add_file_button.pressed.connect(self.add_file) self.remove_button.pressed.connect(self.remove_folder) self.add_exclude_rule.pressed.connect(self.add_rule) self.remove_exclude_rule.pressed.connect(self.remove_rule) self.group_schedule = QButtonGroup() self.group_schedule.addButton(self.manual_radio_button) self.group_schedule.addButton(self.backup_every_radio_button) self.group_schedule.addButton(self.daily_radio_button) self.group_retention = QButtonGroup() self.group_retention.addButton(self.forever_radio_button) self.group_retention.addButton(self.keep_last_radio_button) self.forever_radio_button.setChecked(True) self.manual_radio_button.setChecked(True) self.daily_radio_button.pressed.connect(self.daily_radio_pressed) self.backup_every_radio_button.pressed.connect( self.backup_every_pressed) self.manual_radio_button.pressed.connect(self.manual_radio_pressed) self.forever_radio_button.pressed.connect( lambda: self.days_spin_box.setEnabled(False)) self.keep_last_radio_button.pressed.connect( lambda: self.days_spin_box.setEnabled(True)) self.mon_checkbox.clicked.connect( lambda: self.state_changed("mon", self.mon_checkbox)) self.tue_checkbox.clicked.connect( lambda: self.state_changed("tue", self.tue_checkbox)) self.wed_checkbox.clicked.connect( lambda: self.state_changed("wed", self.wed_checkbox)) self.thu_checkbox.clicked.connect( lambda: self.state_changed("thu", self.thu_checkbox)) self.fri_checkbox.clicked.connect( lambda: self.state_changed("fri", self.fri_checkbox)) self.sat_checkbox.clicked.connect( lambda: self.state_changed("sat", self.sat_checkbox)) self.sun_checkbox.clicked.connect( lambda: self.state_changed("sun", self.sun_checkbox)) self.activation_label.hide() self.setWindowTitle(window_title) self.thread_count_spin_box.setValue(DEFAULT_THREAD_COUNT) self.compression_level_spin_box.setValue(DEFAULT_COMPRESSION_LEVEL) self.populate() def daily_radio_pressed(self): self.set_days(True) self.set_every(False) def backup_every_pressed(self): self.set_every(True) self.set_days(False) def manual_radio_pressed(self): self.set_days(False) self.set_every(False) def state_changed(self, day, checkbox): if checkbox.isChecked(): self.days_checked.add(day) else: self.days_checked.remove(day) def set_every(self, status): self.hourly_spinbox.setEnabled(status) self.mins_spinbox.setEnabled(status) self.label_2.setEnabled(status) self.label_3.setEnabled(status) def set_days(self, status): self.schedule_time_edit.setEnabled(status) self.mon_checkbox.setEnabled(status) self.tue_checkbox.setEnabled(status) self.wed_checkbox.setEnabled(status) self.thu_checkbox.setEnabled(status) self.fri_checkbox.setEnabled(status) self.sat_checkbox.setEnabled(status) self.sun_checkbox.setEnabled(status) def populate(self): if self.backup.paths is not None: self.paths = self.backup.paths self.reload_paths() if self.backup.exclude_rules is not None: self.exclude_rules = self.backup.exclude_rules self.reload_exclude_rules() self.set_days(False) if self.backup.backup_daily_time is not None: self.set_days(True) self.daily_radio_button.setChecked(True) self.schedule_time_edit.setTime(self.backup.backup_daily_time) self.set_every(False) if self.backup.every_hour is not None and self.backup.every_min is not None: self.set_every(True) self.backup_every_radio_button.setChecked(True) self.hourly_spinbox.setValue(self.backup.every_hour) self.mins_spinbox.setValue(self.backup.every_min) self.days_spin_box.setEnabled(False) if self.backup.retention is not None: self.days_spin_box.setEnabled(True) self.keep_last_radio_button.setChecked(True) self.days_spin_box.setValue(self.backup.retention) if self.backup.backup_days is not None: days = self.backup.backup_days.split(",") for checkbox in self.map.values(): checkbox.setChecked(False) for day in days: self.days_checked.add(day) self.map[day].setChecked(True) self.thread_count_spin_box.setValue(self.backup.thread_count) self.compression_level_spin_box.setValue(self.backup.compression_level) def reload_exclude_rules(self): self.exclude_rules_list_widget.clear() for rule in self.exclude_rules: self.exclude_rules_list_widget.addItem(rule) def reload_paths(self): self.paths_list_widget.clear() for path in self.paths: self.paths_list_widget.addItem(path) def add_rule(self): input = QInputDialog(self.window) input.setWindowTitle("Add exclude rule") input.setLabelText("Exclude rule (eg: C:\\Users\\*\\Volumes\\*.iso)") if input.exec_(): exclude_rule = input.textValue() exclude_rule = exclude_rule.replace(os.sep, "/") self.exclude_rules.add(exclude_rule) self.reload_exclude_rules() def remove_rule(self): selected_item = self.exclude_rules_list_widget.currentItem() if selected_item is None: return rule = selected_item.text() self.exclude_rules.remove(rule) self.reload_exclude_rules() def add_file(self): path, _ = QFileDialog.getOpenFileName(self, dir=os.path.expanduser("~")) if len(path) is 0: return self.paths.add(path) self.reload_paths() def add_folder(self): path = QFileDialog.getExistingDirectory(self, dir=os.path.expanduser("~")) if len(path) is 0: return self.paths.add(path) self.reload_paths() def remove_folder(self): selected_item = self.paths_list_widget.currentItem() if selected_item is None: return path = selected_item.text() self.paths.remove(path) self.reload_paths() def worker(self, args): is_initialized = Repo(Utils.get_backend(self.backup)).is_initialized() if self.edit: if not is_initialized: return False else: Repo(Utils.get_backend(self.backup)).init( self.backup.password.encode()) return True def command_done(self, ret): self.setEnabled(True) if not ret: QMessageBox.warning( self.window, "Invalid details", f"Backup {self.backup.name} has not been initialized") return Backups.save(self.backup) self.window.app.scheduler.reload() super().accept() def accept(self): self.backup.paths = self.paths self.backup.exclude_rules = self.exclude_rules self.backup.retention = None if self.forever_radio_button.isChecked( ) else self.days_spin_box.value() self.backup.backup_daily_time = None if not self.daily_radio_button.isChecked( ) else self.schedule_time_edit.time() self.backup.backup_days = None if not self.daily_radio_button.isChecked( ) else ",".join(self.days_checked) self.backup.every_hour = None if not self.backup_every_radio_button.isChecked( ) else self.hourly_spinbox.value() self.backup.every_min = None if not self.backup_every_radio_button.isChecked( ) else self.mins_spinbox.value() self.backup.thread_count = self.thread_count_spin_box.value() self.backup.compression_level = self.compression_level_spin_box.value() if self.backup.backup_days == "": QMessageBox.warning(self.window, "Invalid details", "Please select some days of the week") return self.setEnabled(False) self.thread = CommandThread(self.worker, {}) self.thread.result.connect(self.command_done) self.thread.start()
class ConfigAzureDialog(QDialog, Ui_ConfigAzureDialog): def __init__(self, window, just_save): QDialog.__init__(self) Ui_ConfigAzureDialog.__init__(self) self.setupUi(self) self.window = window self.backup = None self.just_save = just_save if self.just_save: self.confirm_password_line_edit.hide() self.label_3.hide() def command_done(self, res): self.setEnabled(True) ret, message = res if not ret: QMessageBox.warning(self.window, "Invalid details", message) return if self.just_save: Backups.save(self.backup) super().accept() def accept(self): name = self.name_line_edit.text().strip() password = self.password_line_edit.text() if self.just_save: confirm_password = password else: confirm_password = self.confirm_password_line_edit.text() connection = self.connection_line_edit.text().strip() container = self.container_line_edit.text().strip() prefix = self.prefix_line_edit.text().strip() backup = Backup() backup.name = name backup.location = "Microsoft Azure" backup.password = password backup.azure_conn_str = connection backup.azure_container = container backup.cloud_prefix = prefix self.backup = backup fs = [ Validator.validate_plan_name, Validator.validate_confirm_password, Validator.validate_non_empty, Validator.validate_non_empty, Validator.validate_non_empty, Validator.validate_no_space, Validator.validate_no_space, Validator.validate_backend, Validator.validate_repo ] args = [(name, ), (password, confirm_password), ("Connection String", connection), ("Container", container), ("Prefix", prefix), ("Container", container), ("Prefix", prefix), (backup, ), (backup, self.just_save)] self.setEnabled(False) self.thread = CommandThread(config_worker, {"fs": fs, "args": args}) self.thread.result.connect(self.command_done) self.thread.start()