def __init__(self): self.lgr = logging.getLogger('setting') self.trans = TranslateIt('') self.__ROOT_CFG_PATH = os.path.expanduser("~") self.__CONFIG_NAME = ".trans" self.__config = _DEFAULT_CONFIG self.check_path() if self.loadConfig(): if self.keyIsValid(self.yandex_api_key): self.status_key = True else: self.status_key = False
def __init__(self): Gtk.Application.__init__(self, flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE) self.lgr = logging.getLogger('') self.settings = SettingManager() self._translator = TranslateIt(self.settings.yandex_api_key)
class SettingManager: def __init__(self): self.lgr = logging.getLogger('setting') self.trans = TranslateIt('') self.__ROOT_CFG_PATH = os.path.expanduser("~") self.__CONFIG_NAME = ".trans" self.__config = _DEFAULT_CONFIG self.check_path() if self.loadConfig(): if self.keyIsValid(self.yandex_api_key): self.status_key = True else: self.status_key = False def check_path(self): if not os.path.exists(self.__ROOT_CFG_PATH): raise OSError(2, 'No such file or directory') if not os.path.isdir(self.__ROOT_CFG_PATH): raise Exception('Invalid config path') if not os.access(self.__ROOT_CFG_PATH, os.W_OK): raise Exception('Access wrote in path fail') if not os.path.exists(self.config_name): self.lgr.warning('No config file try create: ') self.saveConfig() # raise Exception('No config file!') return True @property def config_name(self): return self.__ROOT_CFG_PATH + '/' + self.__CONFIG_NAME @config_name.setter # @debug def config_name(self, new_name): """ ONLY FOR DEBUG! :param new_name: string $HOME full path cfg is($HOME + /.trans) :return: """ # set invalid name! self.__ROOT_CFG_PATH = new_name def get_cfg_value(self, key): if key not in self.config: self.lgr.error("No key '%s' in config... ", key) # warning! return None else: return self.config[key] def set_cfg_value(self, key, val): if val is None: self.lgr.error("Skip null value for key %s", key) return False if key not in self.config: if key in _DEFAULT_CONFIG: self.lgr.debug('CFG without key %s - add new', key) self.config[key] = val return True else: self.lgr.error('Key %s invalid for $VERSION: %s', key, _VERSION) return False else: self.config[key] = val return True @property def config(self): """ setup cfg from config file :return: dict{} example see _DEFAULT_CONFIG """ if self.__config is None: self.lgr.error("config is None... halt?...") return self.__config @config.setter def config(self, cfg): if cfg is not None: self.__config = cfg @property def window_size(self): """ Setup main wnd size width and height :return: wingeometry.Size() """ return Size(self.get_cfg_value('WIDTH'), self.get_cfg_value('HEIGHT')) @window_size.setter def window_size(self, _size): if not type(_size) is Size: self.lgr.debug("The Size param required '%s' received ", type(_size)) raise ValueError() if not self.set_cfg_value('WIDTH', _size.WIDTH): self.lgr.warning("Fail save width window...") if not self.set_cfg_value('HEIGHT', _size.HEIGHT): self.lgr.warning("Fail save HEIGHT window...") @property def window_position(self): """ Setup Position Main window (TOP / LEFT) :return: wingeometry.Pos() """ return Pos(self.get_cfg_value('POS_TOP'), self.get_cfg_value('POS_LEFT')) @window_position.setter def window_position(self, new_pos): if not self.set_cfg_value('POS_TOP', new_pos.TOP): self.lgr.warning("Failed save '%d' top position window ", new_pos.TOP) if not self.set_cfg_value('POS_LEFT', new_pos.LEFT): self.lgr.warning("Failed save '%d' top position window ", new_pos.LEFT) @property def switch(self): """ Store status switch in setting :return: Boolean True / False """ switch = self.get_cfg_value('SWITCH') if switch is not None: type_val = type(switch) if type_val is bool: return self.get_cfg_value('SWITCH') else: self.lgr.error('Wrong type of switch `%s`, Boolean required!', type_val) else: self.lgr.error('Switch not determined in the configuration file') # by default return False @switch.setter def switch(self, state=0): self.set_cfg_value('SWITCH', state) @property def single_mode(self): """ store View All / Single :return: Boolean True / False """ show_all = self.get_cfg_value('SHOW_ALL') if show_all is not None: if type(show_all) is bool: return show_all else: self.lgr.debug('wrong cfg value, use default') return False @single_mode.setter def single_mode(self, state): self.set_cfg_value('SHOW_ALL', state) @property def yandex_api_key(self): """ Store yandex Key need for translation :return: string """ return self.get_cfg_value('API_KEY') @yandex_api_key.setter def yandex_api_key(self, __key): if not self.keyIsValid(__key): raise ValueError('Invalid key API') else: self.set_cfg_value('API_KEY', __key) self.saveConfig() def keyIsValid(self, __key): return self.trans.valid_key(__key) def loadConfig(self): self.lgr.debug('load from %s', self.config_name) config_name = self.config_name try: if not os.path.exists(config_name): self.lgr.debug('File "%s" doesnt exist...', config_name) return False with open(config_name, 'r') as f: config = json.load(f) except Exception as err: self.lgr.exception('Failed load "%s" cfg: %s', config_name, err) return False if config is not None: self.config = config else: self.lgr.error('Error load setting!') return True def saveConfig(self): self.lgr.debug('Save config %s', self.config_name) try: with open(self.config_name, 'w') as f: status = json.dump(self.config, f) except Exception as err: self.lgr.exception('Failed save "%s": %s ', self.config_name, err) return False return True
class TransApplication(Gtk.Application): def __init__(self): Gtk.Application.__init__(self, flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE) self.lgr = logging.getLogger('') self.settings = SettingManager() self._translator = TranslateIt(self.settings.yandex_api_key) def do_startup(self): Gtk.Application.do_startup(self) def do_activate(self): if self.create_main_wnd(): self.ok_run() else: self.show_get_apikey_dialog() def do_command_line(self, args): Gtk.Application.do_command_line(self, args) parser = argparse.ArgumentParser() parser.add_argument('-v', '--verbose', action='store_true', help='set logger level to verbose') args = parser.parse_args(args.get_arguments()[1:]) if args.verbose: print('DEBUG mode on..') self.create_logger(logging.DEBUG) else: self.create_logger() self.do_activate() return 0 def do_shutdown(self): exit(0) def ok_run(self): self.timer.start() self.load_other_settings() if self.settings.single_mode: self.lgr.debug('Single mode = True') self.win.clipboard_primary_status = not self.settings.switch self.win.clipboard_selection_status = self.settings.switch else: self.win.clipboard_primary_status = not self.settings.switch self.win.clipboard_selection_status = True def msg_dialog_global_err(self): dialog = Gtk.MessageDialog(transient_for=self.win, destroy_with_parent=True, message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK, modal=True, text="Connection aborted: Temporary failure in name resolution") dialog.run() dialog.destroy() def show_get_apikey_dialog(self): self.key_wnd = guigetkey.GeTokenWnd(self) self.key_wnd.wnd.set_transient_for(self.win) self.key_wnd.wnd.set_modal(True) self.key_wnd.wnd.connect("response", self.get_api_dialog_response) self.key_wnd.wnd.show_all() def get_api_dialog_response(self, widget, response_id): if response_id == Gtk.ResponseType.OK: key = self.key_wnd.edit.get_text() if not self.settings.keyIsValid(key): self.lgr.debug('The key "%s" is not passed server validation', key) self.key_wnd.show_error('invalid key!') return 0 else: # 3 time key_valid run! self.settings.yandex_api_key = key self._translator.key = key self.ok_run() else: self.quit() widget.destroy() # timer use there! def timer_start(self): self.timer.work = True def timer_stop(self): self.timer.work = False def timer_halt(self): self.timer.work = False self.timer.halt() def translate(self, txt): if len(txt) > 1: return self._translator.translate(txt) else: self.lgr.debug('skip text (len <=1)') def create_logger(self, level=logging.ERROR): ch = logging.StreamHandler() formt = logging.Formatter('%(levelname)s: \t%(asctime)s | %(process)d | %(lineno)d: ' '%(module)s.%(funcName)s | %(name)s | %(message)s') ch.setFormatter(formt) self.lgr.setLevel(level) ch.setLevel(level) self.lgr.addHandler(ch) self.lgr.info('Load logger done: ') # timer call back fn: def callback_end_time(self): """callback for timer""" self.win.pb.set_visible(False) if not self.win.clipboard_primary_status: self.lgr.debug('Clipboard primary disable...') return False txt = self.win.primary_text if len(txt) < 1: self.lgr.debug('The text is too short: %s`', txt) return False answer = self.translate(txt) self.win.translated_primary_text = answer # timer tick call back: def call_back_pulse(self): self.win.pb.pulse() # settings: def load_other_settings(self): self.win.single_mode = self.settings.single_mode if self.win.single_mode: self.act_view_behavior_single.activate() if self.win.switch.get_state() == self.settings.switch: # on switch setup: clipboard_primary_status /clipboard_selection_status self.win.on_switch_change(self.win.switch, None) else: self.win.switch.set_state(self.settings.switch) def load_window_geometry(self): pos_from_setting = self.settings.window_position self.lgr.debug('Set window position `%d`x`%d` ', pos_from_setting.TOP, pos_from_setting.LEFT) self.win.move(pos_from_setting.TOP, pos_from_setting.LEFT) size_from_setting = self.settings.window_size self.lgr.debug("Set window size `%d`x`%d` ", size_from_setting.WIDTH, size_from_setting.HEIGHT) self.win.set_default_size(size_from_setting.WIDTH, size_from_setting.HEIGHT) def save_settings(self): current_win_pos = self.win.get_position() _pos = Pos(current_win_pos[0], current_win_pos[1]) self.lgr.info('save windows position: %d x %d', _pos.TOP, _pos.LEFT) self.settings.window_position = _pos current_win_size = self.win.get_size() _size = Size(current_win_size[0], current_win_size[1]) self.lgr.info('windows size to save: %d x %d', _size.WIDTH, _size.HEIGHT) self.settings.window_size = _size self.settings.single_mode = self.win.single_mode self.settings.switch = self.win.switch.get_active() self.settings.saveConfig() # actions: def on_close_mainwnd(self, *args): self.act_quit.activate() def act_quit_execute(self, action, parameter): self.timer_halt() self.save_settings() self.quit() # velodrome def view_behavior_all(self, act, *args): self.gsubmenu.remove_all() self.gsubmenu.append('* all', "app.view_all") self.gsubmenu.append('single', "app.view_single") self.win.single_mode = False def view_behavior_single(self, act, *args): self.gsubmenu.remove_all() self.gsubmenu.append('all', "app.view_all") self.gsubmenu.append('* single', "app.view_single") self.win.single_mode = True # GUI: def create_main_wnd(self): """ Create Main window :return: True if yandex api key is valid """ self.win = MainWnd(self) self.add_window(self.win) self.menu_main = Gio.Menu() self.gsubmenu = Gio.Menu() self.menu_main.append_submenu('show', self.gsubmenu) # self.radio_all = True -> * show all esle show single self.gsubmenu.append('* all', "app.view_all") self.gsubmenu.append('single', "app.view_single") self.menu_main.append("About", "app.about") self.menu_main.append("_____________") self.menu_main.append("Quit", "app.quit") self.set_app_menu(self.menu_main) self.timer = Timer(self.callback_end_time, self.call_back_pulse) self.win.connect("delete_event", self.on_close_mainwnd) self.act_view_behavior_all = Gio.SimpleAction.new("view_all", None) self.act_view_behavior_all.connect("activate", self.view_behavior_all) self.add_action(self.act_view_behavior_all) self.act_view_behavior_single = Gio.SimpleAction.new("view_single", None) self.act_view_behavior_single.connect("activate", self.view_behavior_single) self.add_action(self.act_view_behavior_single) self.act_about = Gio.SimpleAction.new("about", None) self.act_about.connect("activate", self.win.act_about_execute) self.add_action(self.act_about) self.act_quit = Gio.SimpleAction.new("quit", None) self.act_quit.connect("activate", self.act_quit_execute) self.add_action(self.act_quit) self.load_window_geometry() self.win.show_all() status_key = self.settings.keyIsValid(self.settings.yandex_api_key) if status_key: if status_key == yatranslate.ERR_CONNECTION_ABORTED: self.lgr.error('Cannot connect to server, exit..') self.msg_dialog_global_err() sys.exit(0) return True return False