class SyncController(QtCore.QObject): def __init__(self, application, source_store_path, target_store_path, auto_sync, verbose = False): """ initialize the controller """ QtCore.QObject.__init__(self) # init components self.__application = application self.__source_store_path = source_store_path self.__target_store_path = target_store_path self.__auto_sync = auto_sync self.__main_config = None self.__store_config = None self.__source_store = None self.__target_store = None self.__sync_dialog = None self.__conflict_file_list = None self.__source_items = None self.__target_items = None self.__target_sync_items = None # default values self.STORE_CONFIG_DIR = TsConstants.DEFAULT_STORE_CONFIG_DIR self.STORE_CONFIG_FILE_NAME = TsConstants.DEFAULT_STORE_CONFIG_FILENAME self.STORE_TAGS_FILE_NAME = TsConstants.DEFAULT_STORE_TAGS_FILENAME self.STORE_VOCABULARY_FILE_NAME = TsConstants.DEFAULT_STORE_VOCABULARY_FILENAME self.STORE_SYNC_FILE_NAME = TsConstants.DEFAULT_STORE_SYNC_TAGS_FILENAME # load translators locale = unicode(QtCore.QLocale.system().name())[0:2] self.__translator = QtCore.QTranslator() if self.__translator.load("ts_" + locale + ".qm", "tsresources/"): self.__application.installTranslator(self.__translator) #get dir names for all available languages self.CURRENT_LANGUAGE = self.trUtf8("en") self.STORE_STORAGE_DIRS = [] self.STORE_DESCRIBING_NAV_DIRS = [] self.STORE_CATEGORIZING_NAV_DIRS = [] self.STORE_EXPIRED_DIRS = [] self.STORE_NAVIGATION_DIRS = [] self.SUPPORTED_LANGUAGES = TsConstants.DEFAULT_SUPPORTED_LANGUAGES self.__store_dict = {} for lang in self.SUPPORTED_LANGUAGES: self.change_language(lang) self.STORE_NAVIGATION_DIRS.append(self.trUtf8("navigation")) self.STORE_STORAGE_DIRS.append(self.trUtf8("storage"))#self.STORE_STORAGE_DIR_EN)) self.STORE_DESCRIBING_NAV_DIRS.append(self.trUtf8("descriptions"))#self.STORE_DESCRIBING_NAVIGATION_DIR_EN)) self.STORE_CATEGORIZING_NAV_DIRS.append(self.trUtf8("categories"))#self.STORE_CATEGORIZING_NAVIGATION_DIR_EN)) self.STORE_EXPIRED_DIRS.append(self.trUtf8("expired_items"))#STORE_EXPIRED_DIR_EN)) ## reset language self.change_language(self.CURRENT_LANGUAGE) # init logger component self.LOG_LEVEL = logging.INFO if verbose: self.LOG_LEVEL = logging.DEBUG # get logger self.__log = LogHelper.get_app_logger(self.LOG_LEVEL) def start(self): """ call this method to launch the sync dialog """ self.__init_configuration() def __init_configuration(self): """ initializes the configuration """ # informal debug self.__log.info("__init_configuration") # construct config wrapper self.__main_config = ConfigWrapper(TsConstants.CONFIG_PATH) if self.__main_config is None: self.__emit_not_syncable(self.trUtf8("No config file found for the given path")) return search_source_path = False found_source_path = False if self.__source_store_path != None and self.__source_store_path != "": search_source_path = True search_target_path = False found_target_path = False if self.__target_store_path != None and self.__target_store_path != "": search_target_path = True ## create a temporary store list ## add the desc and cat tags which are needed in the admin-dialog tmp_store_list = [] store_list = self.__main_config.get_stores() # add android store # when registered android_source_path = self.__main_config.get_android_store_path() if android_source_path != None and android_source_path != "": store_item = {} store_item["path"] = android_source_path store_item["name"] = "Android" store_list.append(store_item) # enumerate all stores and add their names and paths store_name = None for current_store_item in store_list: if current_store_item.has_key("name"): store_name = current_store_item["name"] else: store_name = current_store_item["path"].split("/").pop() store_path = current_store_item["path"] current_store_item["name"] = store_name current_store_item["path"] = store_path tmp_store_list.append(current_store_item) # find source target list if search_source_path: if store_path == self.__source_store_path: found_source_path = True if search_target_path: if store_path == self.__target_store_path: found_target_path = True if search_source_path and found_source_path == False: # source store is not registered self.__emit_not_syncable(self.trUtf8("Source tagstore not registered in main config")) return if search_target_path and found_target_path == False: # source store is not registered self.__emit_not_syncable(self.trUtf8("Target tagstore not registered in main config")) return if self.__sync_dialog is None: self.__sync_dialog = SyncDialogController(tmp_store_list, self.__source_store_path, self.__target_store_path, self.__auto_sync) self.__sync_dialog.get_view().setModal(True) #self.__tag_dialog.set_parent(self.sender().get_view()) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("sync_store"), self.__sync_store_action) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("sync_conflict"), self.__handle_resolve_conflict) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("handle_cancel()"), self.__handle_sync_cancel) self.__sync_dialog.show_dialog() if self.__auto_sync: self.__sync_dialog.start_auto_sync() def __handle_resolve_conflict(self, file_item, action): # remove item from conflict list self.__conflict_file_list.remove(file_item) source_item = file_item["source_item"] target_item = file_item["target_item"] source_store = file_item["source_store"] target_store = file_item["target_store"] target_file_path = self.__create_target_file_path(target_store, target_item) self.__log.info("handle_resolve_conclict: source_item %s target_item %s action % s" %(source_item, target_item, action)) if action == "replace": # sync the file and their tags self.__sync_conflict_file(source_store, target_store, source_item, target_item, target_file_path) # launch conflict dialog self.__show_conflict_dialog() def __remove_lock_file(self): """ removes the lock from the affected tagstores """ self.__source_store.remove_sync_lock_file() self.__target_store.remove_sync_lock_file() def __create_lock_file(self): """ creates the lock files for the affected tagstores """ # check if the store is in use by another sync operation if self.__source_store.is_sync_active() or self.__target_store.is_sync_active(): # sync is already active return False # create lock file in source tagstore result = self.__source_store.create_sync_lock_file() if not result: # failed to create lock file return result # create lock in target tagstore result = self.__target_store.create_sync_lock_file() if not result: # delete lock file from source tagstore self.__source_store.remove_sync_lock_file() # done return result def __show_conflict_dialog(self): """ displays the conflict dialogs when there are one or more conflicts """ while len(self.__conflict_file_list) > 0: # get first item current_item = self.__conflict_file_list[0] # extract paramters source_item = current_item["source_item"] target_item = current_item["target_item"] source_store = current_item["source_store"] target_store = current_item["target_store"] target_items = current_item["target_items"] target_sync_items = current_item["target_sync_items"] # do we need to sync sync_success = self.__sync_item(source_store, target_store, target_items, target_sync_items, source_item, False) if sync_success: # remove item # conflict has been solved by a previous conflict resolution self.__conflict_file_list.remove(current_item) continue # update status dialog message = ("Syncing %s" % source_item) self.__sync_dialog.set_status_msg(message) # replace dialog message message = ("Do you want to replace file %s with %s" % (self.__get_full_file_path(target_store, target_item), self.__get_full_file_path(source_store, source_item))) self.__sync_dialog.show_conflict_dialog("Conflict", message, current_item) return # end while # conflict list empty msg = "Sync completed on " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") # flush all changes self.__flush_changes() self.__sync_dialog.set_status_msg(msg) self.__sync_dialog.toggle_sync_button(True) self.__sync_dialog.set_close_button_text(self.trUtf8("Finish")) self.__remove_lock_file() def __create_source_store(self, source_store): """ create the source store object """ # construct config wrapper for the tagstore self.__store_config = ConfigWrapper(source_store) if self.__store_config is None: self.__emit_not_syncable(self.trUtf8("No source store found for the given path")) return # construct store object self.__source_store = Store(self.__store_config.get_store_id(), source_store, self.STORE_CONFIG_DIR + "/" + self.STORE_CONFIG_FILE_NAME, self.STORE_CONFIG_DIR + "/" + self.STORE_TAGS_FILE_NAME, self.STORE_CONFIG_DIR + "/" + self.STORE_VOCABULARY_FILE_NAME, self.STORE_NAVIGATION_DIRS, self.STORE_STORAGE_DIRS, self.STORE_DESCRIBING_NAV_DIRS, self.STORE_CATEGORIZING_NAV_DIRS, self.STORE_EXPIRED_DIRS, self.__main_config.get_expiry_prefix()) self.__source_store.init() def __flush_changes(self): if self.__source_store != None: self.__source_store.finish_sync() if self.__target_store != None: self.__target_store.finish_sync() def __create_target_store(self, target_store): """ create the target store object """ # construct target store config object self.__target_store_config = ConfigWrapper(target_store) if self.__target_store_config is None: self.__emit_not_syncable(self.trUtf8("No target store found for the given path")) return # construct target store object self.__target_store = Store(self.__target_store_config.get_store_id(), target_store, self.STORE_CONFIG_DIR + "/" + self.STORE_CONFIG_FILE_NAME, self.STORE_CONFIG_DIR + "/" + self.STORE_TAGS_FILE_NAME, self.STORE_CONFIG_DIR + "/" + self.STORE_VOCABULARY_FILE_NAME, self.STORE_NAVIGATION_DIRS, self.STORE_STORAGE_DIRS, self.STORE_DESCRIBING_NAV_DIRS, self.STORE_CATEGORIZING_NAV_DIRS, self.STORE_EXPIRED_DIRS, self.__main_config.get_expiry_prefix()) self.__target_store.init() def __get_file_items_with_sync_tag(self): """ returns all files which have the associated sync tag """ # get source items source_items = self.__source_store.get_items() # get current sync tag sync_tag = self.__main_config.get_sync_tag() # build empty result list source_sync_items = [] # enumerate all items for source_item in source_items: if self.__has_sync_tag(self.__source_store, source_item, sync_tag): # item is tagged with sync tag source_sync_items.append(source_item) continue # done return source_sync_items def __prepare_sync(self, source_store, target_store): """ prepares the sync """ # initialize the store objects self.__init_stores(source_store, target_store) # get sync style android_sync = self.__source_store.is_android_store() or self.__target_store.is_android_store() # get source items if android_sync: self.__source_items = self.__get_file_items_with_sync_tag() else: self.__source_items = self.__source_store.get_items() # get target items self.__target_items = self.__target_store.get_items() # get target sync items self.__target_sync_items = self.__target_store.get_sync_items() def __sync_store_action(self, source_store, target_store): """ initializes the sync """ # conflict list self.__conflict_file_list = [] # prepare the sync self.__prepare_sync(source_store, target_store) # now create the lock files lock_file = self.__create_lock_file() if not lock_file: self.__log.info("another sync is in progress please wait until it is finished") self.__sync_dialog.set_status_msg("Another sync is pending, please wait until it is finished") self.__sync_dialog.set_close_button_text(self.trUtf8("Finish")) return # start with source tagstore -> target tagstore self.__handle_sync() # switch stores self.__prepare_sync(target_store, source_store) # push changes from target store to source tagstore self.__handle_sync() self.__log.info("Number of conflicts %d" %(len(self.__conflict_file_list))) # launch conflict dialog self.__show_conflict_dialog() def __handle_sync(self): """ executes a sync """ # start the sync self.__start_sync(self.__source_store, self.__target_store, self.__source_items, self.__target_items, self.__target_sync_items) def __sync_item(self, source_store, target_store, target_items, target_sync_items, source_item, add_conflict_list=True): # is there such an item in the target tagstore target_item = self.__find_item_in_store(target_items, source_item) # does the file exist in the target tagstore if target_item != None: return self.__sync_existing_item(source_store, target_store, target_items, target_sync_items, source_item, target_item, add_conflict_list) else: return self.__sync_new_item(source_store, target_store, target_items, target_sync_items, source_item, add_conflict_list) def __sync_new_item(self, source_store, target_store, target_items, target_sync_items, source_item, add_conflict_list): # file does not exist # was it already synced once? target_sync_item = self.__find_item_in_store(target_sync_items, source_item) if target_sync_item: #the file was already synced once, skipping self.__log.info("[SKIP] File '%s' was already synced once" % target_sync_item) return True # file was not synced before, lets check if it exists in the target destination store # create target path target_file_path = self.__create_target_file_path(target_store, source_item) # check if file already exists if not os.path.exists(target_file_path): # file does not yet exist self.__log.info("[SYNC] New File: '%s' is synced" % source_item) self.__sync_new_file(source_store, target_store, source_item, target_file_path) return True # create target item target_item = self.__create_target_file_item(target_store, source_item) # the file already exists # is it the same file files_equal = self.__are_files_equal(source_store, target_store, source_item, target_item) if files_equal: # file is present, just sync the tags self.__log.info("[SYNC] File '%s' already present in target, syncing tags only" % source_item) self.__sync_new_file(source_store, target_store, source_item, target_file_path, copy_file=False) return False # sync conflict self.__log.info("[Conflict] File: '%s' already exists" % target_file_path) if add_conflict_list: self.__add_conflict_item(source_store, target_store, target_items, target_sync_items, source_item, target_item) return False def __sync_existing_item(self, source_store, target_store, target_items, target_sync_items, source_item, target_item, add_conflict_list): """ syncs an existing item """ # check if the source file is equal files_equal = self.__are_files_equal(source_store, target_store, source_item, target_item) if files_equal: # files are equal # sync tags self.__log.info("[SYNC] Tags of file '%s' are synced" % source_item) self.__sync_new_tags(source_store, target_store, source_item, target_item) return True # okay files are not equal, lets get a sync date target_sync_item = (target_item in target_sync_items) if not target_sync_item: # there is no sync item for file self.__log.info("[Conflict] File '%s' -> %s' was added in the tagstore simultaneously" % (source_item, target_item)) if add_conflict_list: self.__add_conflict_item(source_store, target_store, target_items, target_sync_items, source_item, target_item) return False # get sync time str_sync_gm_time = target_store.get_sync_file_timestamp(target_item) sync_gm_time = time.strptime(str_sync_gm_time, "%Y-%m-%d %H:%M:%S") # get source modification time mod_time = os.path.getmtime(self.__get_full_file_path(source_store, source_item)) source_gm_time = time.gmtime(mod_time) # get target modification time mod_time = os.path.getmtime(self.__get_full_file_path(target_store, target_item)) target_gm_time = time.gmtime(mod_time) # was source file modified if source_gm_time <= sync_gm_time: # file was not modified since last sync # sync new tags self.__log.info("[SYNC] No source modification, tags of file '%s' are synced" % source_item) self.__sync_new_tags(source_store, target_store, source_item, target_item) return True # source modified, lets check target file if target_gm_time <= sync_gm_time: # target file was not modified self.__log.info("[SYNC] Updating file '%s' and tags" % source_item) shutil.copy2(self.__get_full_file_path(source_store, source_item), self.__get_full_file_path(target_store, target_item)) self.__sync_new_tags(source_store, target_store, source_item, target_item) return True # source and target file have been modified, do their tags match if self.__are_all_tags_equal(source_store, target_store, source_item, target_item): # sync the file self.__log.info("[Conflict] Both files have been modified '%s'" % target_item) if add_conflict_list: self.__add_conflict_item(source_store, target_store, target_items, target_sync_items, source_item, target_item) return False # both files and tags are modified self.__log.info("[Conflict] Both files and tags are modified '%s'" % target_item) if add_conflict_list: self.__add_conflict_item(source_store, target_store, target_items, target_sync_items, source_item, target_item) return False def __start_sync(self, source_store, target_store, source_items, target_items, target_sync_items): """ starts the sync """ for source_item in source_items: # sync item self.__log.info("[SYNC] Current Item: %s" % source_item) self.__sync_item(source_store, target_store, target_items, target_sync_items, source_item) def __are_all_tags_equal(self, source_store, target_store, source_item, target_item): """ checks if all tags from the source item and target item are equal """ source_describing_tags = source_store.get_describing_tags_for_item(source_item) target_describing_tags = target_store.get_describing_tags_for_item(target_item) if source_describing_tags != target_describing_tags: return False # get categorizing tags source_categorising_tags = source_store.get_categorizing_tags_for_item(source_item) target_categorising_tags = target_store.get_categorizing_tags_for_item(target_item) if source_categorising_tags != target_categorising_tags: return False # all equal return True def __sync_new_tags(self, source_store, target_store, source_item, target_item): """ syncs new tags """ # get describing tags target_describing_sync_tags = set(target_store.get_describing_sync_tags_for_item(target_item)) target_describing_tags = set(target_store.get_describing_tags_for_item(target_item)) source_describing_tags = set(source_store.get_describing_tags_for_item(source_item)) # get categorizing tags target_categorizing_sync_tags = set(target_store.get_categorizing_sync_tags_for_item(target_item)) target_categorizing_tags = set(target_store.get_categorizing_tags_for_item(target_item)) source_categorizing_tags = set(source_store.get_categorizing_tags_for_item(source_item)) if target_describing_tags == source_describing_tags and\ target_categorizing_tags == source_categorizing_tags: self.__log.info("no changes found") target_store.set_sync_tags(target_item, source_describing_tags, source_categorizing_tags) return new_describing_tags = (source_describing_tags - target_describing_sync_tags) | target_describing_tags # remove tag support #removed_describing_tags = target_describing_sync_tags - source_describing_tags #new_describing_tags -= removed_describing_tags #if len(removed_describing_tags) > 0: # for item in removed_describing_tags: # self.__log.info("removed tag: '%s'" %item) new_categorizing_tags = (source_categorizing_tags - target_categorizing_sync_tags) | target_categorizing_tags # now sync the tags target_store.add_item_with_tags(target_item, new_describing_tags, new_categorizing_tags) # update the sync tags target_store.set_sync_tags(target_item, source_describing_tags, source_categorizing_tags) def __sync_conflict_file(self, source_store, target_store, source_item, target_item, target_file_path): """ replaces the target file with the source file """ # get describing tags from file describing_tag_list = source_store.get_describing_tags_for_item(source_item) # get categorizing tags from file categorizing_tag_list = source_store.get_categorizing_tags_for_item(source_item) # replace file shutil.copy2(self.__get_full_file_path(source_store, source_item), target_file_path) # replace current entry target_store.add_item_with_tags(target_item, describing_tag_list, categorizing_tag_list) # set the sync tags target_store.set_sync_tags(target_item, describing_tag_list, categorizing_tag_list) def __sync_new_file(self, source_store, target_store, source_item, target_file_path, copy_file=True): """ copies the new file and its associated tags """ # get describing tags from file describing_tag_list = source_store.get_describing_tags_for_item(source_item) # get categorizing tags from file categorizing_tag_list = source_store.get_categorizing_tags_for_item(source_item) if copy_file: # copy file shutil.copy2(self.__get_full_file_path(source_store, source_item), target_file_path) # create target file item name target_item = self.__create_target_file_item(target_store, source_item) # add to tagstore target_store.add_item_with_tags(target_item, describing_tag_list, categorizing_tag_list) # set the sync tags target_store.set_sync_tags(target_item, describing_tag_list, categorizing_tag_list) def __create_target_file_item(self, target_store, source_item): """ creates the target file name """ position = source_item.rfind("\\") if position != -1: source_item = source_item[position+1:len(source_item)] if target_store.is_android_store(): # get directories storage_dir = target_store.get_android_root_directory() tagstore_dir = target_store.get_storage_directory() # extract storage directory name # replace path seperators with %5C which is required directory = tagstore_dir[len(storage_dir)+1:len(tagstore_dir)] + "\\" + source_item directory = directory.replace("/", "\\") return directory else: return source_item def __create_target_file_path(self, target_store, source_item): """ creates the target file path """ position = source_item.rfind("\\") if position != -1: source_item = source_item[position+1:len(source_item)] return target_store.get_storage_directory() + "/" + source_item def __get_full_file_path(self, store, file_item): # check if it is an android store if store.is_android_store(): # android store items have the full path encoded from the root directory return store.get_android_root_directory() + "/" + file_item else: # normal tagstores include their files in the storage directory return store.get_storage_directory() + "/" + file_item def __are_files_equal(self, source_store, target_store, source_file, target_file): """ compares both files if there are equal """ # get file locations source_path = self.__get_full_file_path(source_store, source_file) target_path = self.__get_full_file_path(target_store, target_file) # check for equality return filecmp.cmp(source_path, target_path, 0) def __find_item_in_store(self, store_items, source_item): """ finds an item which has the same name It is required to remove directory from the searched entries. The reasons is that an Android tagstore has multiple virtual directories attached. """ position = source_item.rfind("\\") if position != -1: source_item = source_item[position+1:len(source_item)] # look up all items in the target store for file_name in store_items: # is there a directory in the path position = file_name.rfind("\\") if position != -1: fname = file_name[position+1:len(file_name)] else: fname = file_name # does the name now match if fname == source_item: return file_name # no item found return None def __emit_not_syncable(self, err_msg): self.__log.error(err_msg) self.emit(QtCore.SIGNAL("sync_error")) def set_application(self, application): """ if the manager is called from another qt application (e.g. tagstore.py) you must set the calling application here for proper i18n """ self.__application = application def __handle_sync_cancel(self): """ the cancel button has been pressed """ self.emit(QtCore.SIGNAL("sync_cancel")) #self.__tag_dialog.hide_dialog() def __prepare_store_params(self): """ initializes all necessary parameters for creating a store object """ for lang in self.SUPPORTED_LANGUAGES: #self.change_language(lang) self.STORE_STORAGE_DIRS.append(self.trUtf8("storage")) self.STORE_DESCRIBING_NAV_DIRS.append(self.trUtf8("navigation")) self.STORE_CATEGORIZING_NAV_DIRS.append(self.trUtf8("categorization")) self.STORE_EXPIRED_DIRS.append(self.trUtf8("expired_items")) ## reset language #self.change_language(store_current_language) config_dir = self.__main_config.get_store_config_directory() if config_dir != "": self.STORE_CONFIG_DIR = config_dir config_file_name = self.__main_config.get_store_configfile_name() if config_file_name != "": self.STORE_CONFIG_FILE_NAME = config_file_name tags_file_name = self.__main_config.get_store_tagsfile_name() if tags_file_name != "": self.STORE_TAGS_FILE_NAME = tags_file_name vocabulary_file_name = self.__main_config.get_store_vocabularyfile_name() if vocabulary_file_name != "": self.STORE_VOCABULARY_FILE_NAME = vocabulary_file_name def change_language(self, locale): """ changes the current application language please notice: this method is used to find all available storage/navigation directory names this is why it should not be extended to call any UI update methods directly """ ## delete current translation to switch to default strings self.__application.removeTranslator(self.__translator) ## load new translation file self.__translator = QtCore.QTranslator() language = unicode(locale) if self.__translator.load("ts_" + language + ".qm", "tsresources/"): self.__application.installTranslator(self.__translator) ## update current language # self.CURRENT_LANGUAGE = self.trUtf8("en") self.CURRENT_LANGUAGE = self.trUtf8(locale) def __init_stores(self, source_store, target_store): """ initializes the store objects """ # get current language from main config file and apply it self.CURRENT_LANGUAGE = self.__main_config.get_current_language(); self.change_language(self.CURRENT_LANGUAGE) # prepare all parameters for creating the store object self.__prepare_store_params() # create the source store self.__create_source_store(source_store) # create the target store self.__create_target_store(target_store) #init sync log for the source store self.__source_store.init_sync_log(self.__target_store.get_name()) # init sync log for the target store self.__target_store.init_sync_log(self.__source_store.get_name()) def __has_sync_tag(self, source_store, source_item, sync_tag): """ checks if the file has the sync tag associated """ # get describing tags source_item_describing_tags = source_store.get_describing_tags_for_item(source_item) if source_item_describing_tags != None: if sync_tag in source_item_describing_tags: return True # get categorising tags source_item_categorising_tags = source_store.get_categorizing_tags_for_item(source_item) if source_item_categorising_tags != None: if sync_tag in source_item_categorising_tags: return True # tag not found return False def __add_conflict_item(self, source_store, target_store, target_items, target_sync_items, source_item, target_item): """ adds a conflict item to the conflict list """ current_item = {} current_item["source_item"] = source_item current_item["target_item"] = target_item current_item["source_store"] = source_store current_item["target_store"] = target_store current_item["target_items"] = target_items current_item["target_sync_items"] = target_sync_items self.__conflict_file_list.append(current_item)
class SyncController(QtCore.QObject): def __init__(self, application, source_store_path, target_store_path, auto_sync, verbose=False): """ initialize the controller """ QtCore.QObject.__init__(self) # init components self.__application = application self.__source_store_path = source_store_path self.__target_store_path = target_store_path self.__auto_sync = auto_sync self.__main_config = None self.__store_config = None self.__source_store = None self.__target_store = None self.__sync_dialog = None self.__conflict_file_list = None self.__source_items = None self.__target_items = None self.__target_sync_items = None # default values self.STORE_CONFIG_DIR = TsConstants.DEFAULT_STORE_CONFIG_DIR self.STORE_CONFIG_FILE_NAME = TsConstants.DEFAULT_STORE_CONFIG_FILENAME self.STORE_TAGS_FILE_NAME = TsConstants.DEFAULT_STORE_TAGS_FILENAME self.STORE_VOCABULARY_FILE_NAME = TsConstants.DEFAULT_STORE_VOCABULARY_FILENAME self.STORE_SYNC_FILE_NAME = TsConstants.DEFAULT_STORE_SYNC_TAGS_FILENAME # load translators locale = unicode(QtCore.QLocale.system().name())[0:2] self.__translator = QtCore.QTranslator() if self.__translator.load("ts_" + locale + ".qm", "tsresources/"): self.__application.installTranslator(self.__translator) #get dir names for all available languages self.CURRENT_LANGUAGE = self.trUtf8("en") self.STORE_STORAGE_DIRS = [] self.STORE_DESCRIBING_NAV_DIRS = [] self.STORE_CATEGORIZING_NAV_DIRS = [] self.STORE_EXPIRED_DIRS = [] self.STORE_NAVIGATION_DIRS = [] self.SUPPORTED_LANGUAGES = TsConstants.DEFAULT_SUPPORTED_LANGUAGES self.__store_dict = {} for lang in self.SUPPORTED_LANGUAGES: self.change_language(lang) self.STORE_NAVIGATION_DIRS.append(self.trUtf8("navigation")) self.STORE_STORAGE_DIRS.append( self.trUtf8("storage")) #self.STORE_STORAGE_DIR_EN)) self.STORE_DESCRIBING_NAV_DIRS.append(self.trUtf8( "descriptions")) #self.STORE_DESCRIBING_NAVIGATION_DIR_EN)) self.STORE_CATEGORIZING_NAV_DIRS.append(self.trUtf8( "categories")) #self.STORE_CATEGORIZING_NAVIGATION_DIR_EN)) self.STORE_EXPIRED_DIRS.append( self.trUtf8("expired_items")) #STORE_EXPIRED_DIR_EN)) ## reset language self.change_language(self.CURRENT_LANGUAGE) # init logger component self.LOG_LEVEL = logging.INFO if verbose: self.LOG_LEVEL = logging.DEBUG # get logger self.__log = LogHelper.get_app_logger(self.LOG_LEVEL) def start(self): """ call this method to launch the sync dialog """ self.__init_configuration() def __init_configuration(self): """ initializes the configuration """ # informal debug self.__log.info("__init_configuration") # construct config wrapper self.__main_config = ConfigWrapper(TsConstants.CONFIG_PATH) if self.__main_config is None: self.__emit_not_syncable( self.trUtf8("No config file found for the given path")) return search_source_path = False found_source_path = False if self.__source_store_path != None and self.__source_store_path != "": search_source_path = True search_target_path = False found_target_path = False if self.__target_store_path != None and self.__target_store_path != "": search_target_path = True ## create a temporary store list ## add the desc and cat tags which are needed in the admin-dialog tmp_store_list = [] store_list = self.__main_config.get_stores() # add android store # when registered android_source_path = self.__main_config.get_android_store_path() if android_source_path != None and android_source_path != "": store_item = {} store_item["path"] = android_source_path store_item["name"] = "Android" store_list.append(store_item) # enumerate all stores and add their names and paths store_name = None for current_store_item in store_list: if current_store_item.has_key("name"): store_name = current_store_item["name"] else: store_name = current_store_item["path"].split("/").pop() store_path = current_store_item["path"] current_store_item["name"] = store_name current_store_item["path"] = store_path tmp_store_list.append(current_store_item) # find source target list if search_source_path: if store_path == self.__source_store_path: found_source_path = True if search_target_path: if store_path == self.__target_store_path: found_target_path = True if search_source_path and found_source_path == False: # source store is not registered self.__emit_not_syncable( self.trUtf8("Source tagstore not registered in main config")) return if search_target_path and found_target_path == False: # source store is not registered self.__emit_not_syncable( self.trUtf8("Target tagstore not registered in main config")) return if self.__sync_dialog is None: self.__sync_dialog = SyncDialogController(tmp_store_list, self.__source_store_path, self.__target_store_path, self.__auto_sync) self.__sync_dialog.get_view().setModal(True) #self.__tag_dialog.set_parent(self.sender().get_view()) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("sync_store"), self.__sync_store_action) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("sync_conflict"), self.__handle_resolve_conflict) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("handle_cancel()"), self.__handle_sync_cancel) self.__sync_dialog.show_dialog() if self.__auto_sync: self.__sync_dialog.start_auto_sync() def __handle_resolve_conflict(self, file_item, action): # remove item from conflict list self.__conflict_file_list.remove(file_item) source_item = file_item["source_item"] target_item = file_item["target_item"] source_store = file_item["source_store"] target_store = file_item["target_store"] target_file_path = self.__create_target_file_path( target_store, target_item) self.__log.info( "handle_resolve_conclict: source_item %s target_item %s action % s" % (source_item, target_item, action)) if action == "replace": # sync the file and their tags self.__sync_conflict_file(source_store, target_store, source_item, target_item, target_file_path) # launch conflict dialog self.__show_conflict_dialog() def __remove_lock_file(self): """ removes the lock from the affected tagstores """ self.__source_store.remove_sync_lock_file() self.__target_store.remove_sync_lock_file() def __create_lock_file(self): """ creates the lock files for the affected tagstores """ # check if the store is in use by another sync operation if self.__source_store.is_sync_active( ) or self.__target_store.is_sync_active(): # sync is already active return False # create lock file in source tagstore result = self.__source_store.create_sync_lock_file() if not result: # failed to create lock file return result # create lock in target tagstore result = self.__target_store.create_sync_lock_file() if not result: # delete lock file from source tagstore self.__source_store.remove_sync_lock_file() # done return result def __show_conflict_dialog(self): """ displays the conflict dialogs when there are one or more conflicts """ while len(self.__conflict_file_list) > 0: # get first item current_item = self.__conflict_file_list[0] # extract paramters source_item = current_item["source_item"] target_item = current_item["target_item"] source_store = current_item["source_store"] target_store = current_item["target_store"] target_items = current_item["target_items"] target_sync_items = current_item["target_sync_items"] # do we need to sync sync_success = self.__sync_item(source_store, target_store, target_items, target_sync_items, source_item, False) if sync_success: # remove item # conflict has been solved by a previous conflict resolution self.__conflict_file_list.remove(current_item) continue # update status dialog message = ("Syncing %s" % source_item) self.__sync_dialog.set_status_msg(message) # replace dialog message message = ("Do you want to replace file %s with %s" % (self.__get_full_file_path(target_store, target_item), self.__get_full_file_path(source_store, source_item))) self.__sync_dialog.show_conflict_dialog("Conflict", message, current_item) return # end while # conflict list empty msg = "Sync completed on " + datetime.datetime.utcnow().strftime( "%Y-%m-%d %H:%M:%S") # flush all changes self.__flush_changes() self.__sync_dialog.set_status_msg(msg) self.__sync_dialog.toggle_sync_button(True) self.__sync_dialog.set_close_button_text(self.trUtf8("Finish")) self.__remove_lock_file() def __create_source_store(self, source_store): """ create the source store object """ # construct config wrapper for the tagstore self.__store_config = ConfigWrapper(source_store) if self.__store_config is None: self.__emit_not_syncable( self.trUtf8("No source store found for the given path")) return # construct store object self.__source_store = Store( self.__store_config.get_store_id(), source_store, self.STORE_CONFIG_DIR + "/" + self.STORE_CONFIG_FILE_NAME, self.STORE_CONFIG_DIR + "/" + self.STORE_TAGS_FILE_NAME, self.STORE_CONFIG_DIR + "/" + self.STORE_VOCABULARY_FILE_NAME, self.STORE_NAVIGATION_DIRS, self.STORE_STORAGE_DIRS, self.STORE_DESCRIBING_NAV_DIRS, self.STORE_CATEGORIZING_NAV_DIRS, self.STORE_EXPIRED_DIRS, self.__main_config.get_expiry_prefix()) self.__source_store.init() def __flush_changes(self): if self.__source_store != None: self.__source_store.finish_sync() if self.__target_store != None: self.__target_store.finish_sync() def __create_target_store(self, target_store): """ create the target store object """ # construct target store config object self.__target_store_config = ConfigWrapper(target_store) if self.__target_store_config is None: self.__emit_not_syncable( self.trUtf8("No target store found for the given path")) return # construct target store object self.__target_store = Store( self.__target_store_config.get_store_id(), target_store, self.STORE_CONFIG_DIR + "/" + self.STORE_CONFIG_FILE_NAME, self.STORE_CONFIG_DIR + "/" + self.STORE_TAGS_FILE_NAME, self.STORE_CONFIG_DIR + "/" + self.STORE_VOCABULARY_FILE_NAME, self.STORE_NAVIGATION_DIRS, self.STORE_STORAGE_DIRS, self.STORE_DESCRIBING_NAV_DIRS, self.STORE_CATEGORIZING_NAV_DIRS, self.STORE_EXPIRED_DIRS, self.__main_config.get_expiry_prefix()) self.__target_store.init() def __get_file_items_with_sync_tag(self): """ returns all files which have the associated sync tag """ # get source items source_items = self.__source_store.get_items() # get current sync tag sync_tag = self.__main_config.get_sync_tag() # build empty result list source_sync_items = [] # enumerate all items for source_item in source_items: if self.__has_sync_tag(self.__source_store, source_item, sync_tag): # item is tagged with sync tag source_sync_items.append(source_item) continue # done return source_sync_items def __prepare_sync(self, source_store, target_store): """ prepares the sync """ # initialize the store objects self.__init_stores(source_store, target_store) # get sync style android_sync = self.__source_store.is_android_store( ) or self.__target_store.is_android_store() # get source items if android_sync: self.__source_items = self.__get_file_items_with_sync_tag() else: self.__source_items = self.__source_store.get_items() # get target items self.__target_items = self.__target_store.get_items() # get target sync items self.__target_sync_items = self.__target_store.get_sync_items() def __sync_store_action(self, source_store, target_store): """ initializes the sync """ # conflict list self.__conflict_file_list = [] # prepare the sync self.__prepare_sync(source_store, target_store) # now create the lock files lock_file = self.__create_lock_file() if not lock_file: self.__log.info( "another sync is in progress please wait until it is finished") self.__sync_dialog.set_status_msg( "Another sync is pending, please wait until it is finished") self.__sync_dialog.set_close_button_text(self.trUtf8("Finish")) return # start with source tagstore -> target tagstore self.__handle_sync() # switch stores self.__prepare_sync(target_store, source_store) # push changes from target store to source tagstore self.__handle_sync() self.__log.info("Number of conflicts %d" % (len(self.__conflict_file_list))) # launch conflict dialog self.__show_conflict_dialog() def __handle_sync(self): """ executes a sync """ # start the sync self.__start_sync(self.__source_store, self.__target_store, self.__source_items, self.__target_items, self.__target_sync_items) def __sync_item(self, source_store, target_store, target_items, target_sync_items, source_item, add_conflict_list=True): # is there such an item in the target tagstore target_item = self.__find_item_in_store(target_items, source_item) # does the file exist in the target tagstore if target_item != None: return self.__sync_existing_item(source_store, target_store, target_items, target_sync_items, source_item, target_item, add_conflict_list) else: return self.__sync_new_item(source_store, target_store, target_items, target_sync_items, source_item, add_conflict_list) def __sync_new_item(self, source_store, target_store, target_items, target_sync_items, source_item, add_conflict_list): # file does not exist # was it already synced once? target_sync_item = self.__find_item_in_store(target_sync_items, source_item) if target_sync_item: #the file was already synced once, skipping self.__log.info("[SKIP] File '%s' was already synced once" % target_sync_item) return True # file was not synced before, lets check if it exists in the target destination store # create target path target_file_path = self.__create_target_file_path( target_store, source_item) # check if file already exists if not os.path.exists(target_file_path): # file does not yet exist self.__log.info("[SYNC] New File: '%s' is synced" % source_item) self.__sync_new_file(source_store, target_store, source_item, target_file_path) return True # create target item target_item = self.__create_target_file_item(target_store, source_item) # the file already exists # is it the same file files_equal = self.__are_files_equal(source_store, target_store, source_item, target_item) if files_equal: # file is present, just sync the tags self.__log.info( "[SYNC] File '%s' already present in target, syncing tags only" % source_item) self.__sync_new_file(source_store, target_store, source_item, target_file_path, copy_file=False) return False # sync conflict self.__log.info("[Conflict] File: '%s' already exists" % target_file_path) if add_conflict_list: self.__add_conflict_item(source_store, target_store, target_items, target_sync_items, source_item, target_item) return False def __sync_existing_item(self, source_store, target_store, target_items, target_sync_items, source_item, target_item, add_conflict_list): """ syncs an existing item """ # check if the source file is equal files_equal = self.__are_files_equal(source_store, target_store, source_item, target_item) if files_equal: # files are equal # sync tags self.__log.info("[SYNC] Tags of file '%s' are synced" % source_item) self.__sync_new_tags(source_store, target_store, source_item, target_item) return True # okay files are not equal, lets get a sync date target_sync_item = (target_item in target_sync_items) if not target_sync_item: # there is no sync item for file self.__log.info( "[Conflict] File '%s' -> %s' was added in the tagstore simultaneously" % (source_item, target_item)) if add_conflict_list: self.__add_conflict_item(source_store, target_store, target_items, target_sync_items, source_item, target_item) return False # get sync time str_sync_gm_time = target_store.get_sync_file_timestamp(target_item) sync_gm_time = time.strptime(str_sync_gm_time, "%Y-%m-%d %H:%M:%S") # get source modification time mod_time = os.path.getmtime( self.__get_full_file_path(source_store, source_item)) source_gm_time = time.gmtime(mod_time) # get target modification time mod_time = os.path.getmtime( self.__get_full_file_path(target_store, target_item)) target_gm_time = time.gmtime(mod_time) # was source file modified if source_gm_time <= sync_gm_time: # file was not modified since last sync # sync new tags self.__log.info( "[SYNC] No source modification, tags of file '%s' are synced" % source_item) self.__sync_new_tags(source_store, target_store, source_item, target_item) return True # source modified, lets check target file if target_gm_time <= sync_gm_time: # target file was not modified self.__log.info("[SYNC] Updating file '%s' and tags" % source_item) shutil.copy2(self.__get_full_file_path(source_store, source_item), self.__get_full_file_path(target_store, target_item)) self.__sync_new_tags(source_store, target_store, source_item, target_item) return True # source and target file have been modified, do their tags match if self.__are_all_tags_equal(source_store, target_store, source_item, target_item): # sync the file self.__log.info("[Conflict] Both files have been modified '%s'" % target_item) if add_conflict_list: self.__add_conflict_item(source_store, target_store, target_items, target_sync_items, source_item, target_item) return False # both files and tags are modified self.__log.info("[Conflict] Both files and tags are modified '%s'" % target_item) if add_conflict_list: self.__add_conflict_item(source_store, target_store, target_items, target_sync_items, source_item, target_item) return False def __start_sync(self, source_store, target_store, source_items, target_items, target_sync_items): """ starts the sync """ for source_item in source_items: # sync item self.__log.info("[SYNC] Current Item: %s" % source_item) self.__sync_item(source_store, target_store, target_items, target_sync_items, source_item) def __are_all_tags_equal(self, source_store, target_store, source_item, target_item): """ checks if all tags from the source item and target item are equal """ source_describing_tags = source_store.get_describing_tags_for_item( source_item) target_describing_tags = target_store.get_describing_tags_for_item( target_item) if source_describing_tags != target_describing_tags: return False # get categorizing tags source_categorising_tags = source_store.get_categorizing_tags_for_item( source_item) target_categorising_tags = target_store.get_categorizing_tags_for_item( target_item) if source_categorising_tags != target_categorising_tags: return False # all equal return True def __sync_new_tags(self, source_store, target_store, source_item, target_item): """ syncs new tags """ # get describing tags target_describing_sync_tags = set( target_store.get_describing_sync_tags_for_item(target_item)) target_describing_tags = set( target_store.get_describing_tags_for_item(target_item)) source_describing_tags = set( source_store.get_describing_tags_for_item(source_item)) # get categorizing tags target_categorizing_sync_tags = set( target_store.get_categorizing_sync_tags_for_item(target_item)) target_categorizing_tags = set( target_store.get_categorizing_tags_for_item(target_item)) source_categorizing_tags = set( source_store.get_categorizing_tags_for_item(source_item)) if target_describing_tags == source_describing_tags and\ target_categorizing_tags == source_categorizing_tags: self.__log.info("no changes found") target_store.set_sync_tags(target_item, source_describing_tags, source_categorizing_tags) return new_describing_tags = ( source_describing_tags - target_describing_sync_tags) | target_describing_tags # remove tag support #removed_describing_tags = target_describing_sync_tags - source_describing_tags #new_describing_tags -= removed_describing_tags #if len(removed_describing_tags) > 0: # for item in removed_describing_tags: # self.__log.info("removed tag: '%s'" %item) new_categorizing_tags = ( source_categorizing_tags - target_categorizing_sync_tags) | target_categorizing_tags # now sync the tags target_store.add_item_with_tags(target_item, new_describing_tags, new_categorizing_tags) # update the sync tags target_store.set_sync_tags(target_item, source_describing_tags, source_categorizing_tags) def __sync_conflict_file(self, source_store, target_store, source_item, target_item, target_file_path): """ replaces the target file with the source file """ # get describing tags from file describing_tag_list = source_store.get_describing_tags_for_item( source_item) # get categorizing tags from file categorizing_tag_list = source_store.get_categorizing_tags_for_item( source_item) # replace file shutil.copy2(self.__get_full_file_path(source_store, source_item), target_file_path) # replace current entry target_store.add_item_with_tags(target_item, describing_tag_list, categorizing_tag_list) # set the sync tags target_store.set_sync_tags(target_item, describing_tag_list, categorizing_tag_list) def __sync_new_file(self, source_store, target_store, source_item, target_file_path, copy_file=True): """ copies the new file and its associated tags """ # get describing tags from file describing_tag_list = source_store.get_describing_tags_for_item( source_item) # get categorizing tags from file categorizing_tag_list = source_store.get_categorizing_tags_for_item( source_item) if copy_file: # copy file shutil.copy2(self.__get_full_file_path(source_store, source_item), target_file_path) # create target file item name target_item = self.__create_target_file_item(target_store, source_item) # add to tagstore target_store.add_item_with_tags(target_item, describing_tag_list, categorizing_tag_list) # set the sync tags target_store.set_sync_tags(target_item, describing_tag_list, categorizing_tag_list) def __create_target_file_item(self, target_store, source_item): """ creates the target file name """ position = source_item.rfind("\\") if position != -1: source_item = source_item[position + 1:len(source_item)] if target_store.is_android_store(): # get directories storage_dir = target_store.get_android_root_directory() tagstore_dir = target_store.get_storage_directory() # extract storage directory name # replace path seperators with %5C which is required directory = tagstore_dir[len(storage_dir) + 1:len(tagstore_dir)] + "\\" + source_item directory = directory.replace("/", "\\") return directory else: return source_item def __create_target_file_path(self, target_store, source_item): """ creates the target file path """ position = source_item.rfind("\\") if position != -1: source_item = source_item[position + 1:len(source_item)] return target_store.get_storage_directory() + "/" + source_item def __get_full_file_path(self, store, file_item): # check if it is an android store if store.is_android_store(): # android store items have the full path encoded from the root directory return store.get_android_root_directory() + "/" + file_item else: # normal tagstores include their files in the storage directory return store.get_storage_directory() + "/" + file_item def __are_files_equal(self, source_store, target_store, source_file, target_file): """ compares both files if there are equal """ # get file locations source_path = self.__get_full_file_path(source_store, source_file) target_path = self.__get_full_file_path(target_store, target_file) # check for equality return filecmp.cmp(source_path, target_path, 0) def __find_item_in_store(self, store_items, source_item): """ finds an item which has the same name It is required to remove directory from the searched entries. The reasons is that an Android tagstore has multiple virtual directories attached. """ position = source_item.rfind("\\") if position != -1: source_item = source_item[position + 1:len(source_item)] # look up all items in the target store for file_name in store_items: # is there a directory in the path position = file_name.rfind("\\") if position != -1: fname = file_name[position + 1:len(file_name)] else: fname = file_name # does the name now match if fname == source_item: return file_name # no item found return None def __emit_not_syncable(self, err_msg): self.__log.error(err_msg) self.emit(QtCore.SIGNAL("sync_error")) def set_application(self, application): """ if the manager is called from another qt application (e.g. tagstore.py) you must set the calling application here for proper i18n """ self.__application = application def __handle_sync_cancel(self): """ the cancel button has been pressed """ self.emit(QtCore.SIGNAL("sync_cancel")) #self.__tag_dialog.hide_dialog() def __prepare_store_params(self): """ initializes all necessary parameters for creating a store object """ for lang in self.SUPPORTED_LANGUAGES: #self.change_language(lang) self.STORE_STORAGE_DIRS.append(self.trUtf8("storage")) self.STORE_DESCRIBING_NAV_DIRS.append(self.trUtf8("navigation")) self.STORE_CATEGORIZING_NAV_DIRS.append( self.trUtf8("categorization")) self.STORE_EXPIRED_DIRS.append(self.trUtf8("expired_items")) ## reset language #self.change_language(store_current_language) config_dir = self.__main_config.get_store_config_directory() if config_dir != "": self.STORE_CONFIG_DIR = config_dir config_file_name = self.__main_config.get_store_configfile_name() if config_file_name != "": self.STORE_CONFIG_FILE_NAME = config_file_name tags_file_name = self.__main_config.get_store_tagsfile_name() if tags_file_name != "": self.STORE_TAGS_FILE_NAME = tags_file_name vocabulary_file_name = self.__main_config.get_store_vocabularyfile_name( ) if vocabulary_file_name != "": self.STORE_VOCABULARY_FILE_NAME = vocabulary_file_name def change_language(self, locale): """ changes the current application language please notice: this method is used to find all available storage/navigation directory names this is why it should not be extended to call any UI update methods directly """ ## delete current translation to switch to default strings self.__application.removeTranslator(self.__translator) ## load new translation file self.__translator = QtCore.QTranslator() language = unicode(locale) if self.__translator.load("ts_" + language + ".qm", "tsresources/"): self.__application.installTranslator(self.__translator) ## update current language # self.CURRENT_LANGUAGE = self.trUtf8("en") self.CURRENT_LANGUAGE = self.trUtf8(locale) def __init_stores(self, source_store, target_store): """ initializes the store objects """ # get current language from main config file and apply it self.CURRENT_LANGUAGE = self.__main_config.get_current_language() self.change_language(self.CURRENT_LANGUAGE) # prepare all parameters for creating the store object self.__prepare_store_params() # create the source store self.__create_source_store(source_store) # create the target store self.__create_target_store(target_store) #init sync log for the source store self.__source_store.init_sync_log(self.__target_store.get_name()) # init sync log for the target store self.__target_store.init_sync_log(self.__source_store.get_name()) def __has_sync_tag(self, source_store, source_item, sync_tag): """ checks if the file has the sync tag associated """ # get describing tags source_item_describing_tags = source_store.get_describing_tags_for_item( source_item) if source_item_describing_tags != None: if sync_tag in source_item_describing_tags: return True # get categorising tags source_item_categorising_tags = source_store.get_categorizing_tags_for_item( source_item) if source_item_categorising_tags != None: if sync_tag in source_item_categorising_tags: return True # tag not found return False def __add_conflict_item(self, source_store, target_store, target_items, target_sync_items, source_item, target_item): """ adds a conflict item to the conflict list """ current_item = {} current_item["source_item"] = source_item current_item["target_item"] = target_item current_item["source_store"] = source_store current_item["target_store"] = target_store current_item["target_items"] = target_items current_item["target_sync_items"] = target_sync_items self.__conflict_file_list.append(current_item)
def __init_configuration(self): """ initializes the configuration """ # informal debug self.__log.info("__init_configuration") # construct config wrapper self.__main_config = ConfigWrapper(TsConstants.CONFIG_PATH) if self.__main_config is None: self.__emit_not_syncable(self.trUtf8("No config file found for the given path")) return search_source_path = False found_source_path = False if self.__source_store_path != None and self.__source_store_path != "": search_source_path = True search_target_path = False found_target_path = False if self.__target_store_path != None and self.__target_store_path != "": search_target_path = True ## create a temporary store list ## add the desc and cat tags which are needed in the admin-dialog tmp_store_list = [] store_list = self.__main_config.get_stores() # add android store # when registered android_source_path = self.__main_config.get_android_store_path() if android_source_path != None and android_source_path != "": store_item = {} store_item["path"] = android_source_path store_item["name"] = "Android" store_list.append(store_item) # enumerate all stores and add their names and paths store_name = None for current_store_item in store_list: if current_store_item.has_key("name"): store_name = current_store_item["name"] else: store_name = current_store_item["path"].split("/").pop() store_path = current_store_item["path"] current_store_item["name"] = store_name current_store_item["path"] = store_path tmp_store_list.append(current_store_item) # find source target list if search_source_path: if store_path == self.__source_store_path: found_source_path = True if search_target_path: if store_path == self.__target_store_path: found_target_path = True if search_source_path and found_source_path == False: # source store is not registered self.__emit_not_syncable(self.trUtf8("Source tagstore not registered in main config")) return if search_target_path and found_target_path == False: # source store is not registered self.__emit_not_syncable(self.trUtf8("Target tagstore not registered in main config")) return if self.__sync_dialog is None: self.__sync_dialog = SyncDialogController(tmp_store_list, self.__source_store_path, self.__target_store_path, self.__auto_sync) self.__sync_dialog.get_view().setModal(True) #self.__tag_dialog.set_parent(self.sender().get_view()) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("sync_store"), self.__sync_store_action) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("sync_conflict"), self.__handle_resolve_conflict) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("handle_cancel()"), self.__handle_sync_cancel) self.__sync_dialog.show_dialog() if self.__auto_sync: self.__sync_dialog.start_auto_sync()
def __init_configuration(self): """ initializes the configuration """ # informal debug self.__log.info("__init_configuration") # construct config wrapper self.__main_config = ConfigWrapper(TsConstants.CONFIG_PATH) if self.__main_config is None: self.__emit_not_syncable( self.trUtf8("No config file found for the given path")) return search_source_path = False found_source_path = False if self.__source_store_path != None and self.__source_store_path != "": search_source_path = True search_target_path = False found_target_path = False if self.__target_store_path != None and self.__target_store_path != "": search_target_path = True ## create a temporary store list ## add the desc and cat tags which are needed in the admin-dialog tmp_store_list = [] store_list = self.__main_config.get_stores() # add android store # when registered android_source_path = self.__main_config.get_android_store_path() if android_source_path != None and android_source_path != "": store_item = {} store_item["path"] = android_source_path store_item["name"] = "Android" store_list.append(store_item) # enumerate all stores and add their names and paths store_name = None for current_store_item in store_list: if current_store_item.has_key("name"): store_name = current_store_item["name"] else: store_name = current_store_item["path"].split("/").pop() store_path = current_store_item["path"] current_store_item["name"] = store_name current_store_item["path"] = store_path tmp_store_list.append(current_store_item) # find source target list if search_source_path: if store_path == self.__source_store_path: found_source_path = True if search_target_path: if store_path == self.__target_store_path: found_target_path = True if search_source_path and found_source_path == False: # source store is not registered self.__emit_not_syncable( self.trUtf8("Source tagstore not registered in main config")) return if search_target_path and found_target_path == False: # source store is not registered self.__emit_not_syncable( self.trUtf8("Target tagstore not registered in main config")) return if self.__sync_dialog is None: self.__sync_dialog = SyncDialogController(tmp_store_list, self.__source_store_path, self.__target_store_path, self.__auto_sync) self.__sync_dialog.get_view().setModal(True) #self.__tag_dialog.set_parent(self.sender().get_view()) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("sync_store"), self.__sync_store_action) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("sync_conflict"), self.__handle_resolve_conflict) self.__sync_dialog.connect(self.__sync_dialog, QtCore.SIGNAL("handle_cancel()"), self.__handle_sync_cancel) self.__sync_dialog.show_dialog() if self.__auto_sync: self.__sync_dialog.start_auto_sync()