def remove_dir(self, store_path, store_id): filesystem = FileSystemWrapper() filesystem.delete_dir(store_path) config = ConfigWrapper("../tsresources/conf/tagstore.cfg") config.remove_store(store_id) assert (not filesystem.is_directory(store_path))
def remove_dir(self, store_path, store_id): filesystem = FileSystemWrapper() filesystem.delete_dir(store_path) config = ConfigWrapper("../tsresources/conf/tagstore.cfg") config.remove_store(store_id) assert(not filesystem.is_directory(store_path))
def test_remove_store(self): """ create a store create an item with tags in the store place a "not allowed" item in the navigation hierarchy call the "remove" method of the store check if everything has been removed properly """ STORE_PATH = "./test_store/" STORAGE_DIR = "storage" NEW_ITEM_NAME = "test_item" store = self.create_new_store_object(STORE_PATH, STORAGE_DIR) filesystem = FileSystemWrapper() ## place a new item in the store file_path = "%s%s/%s" % (STORE_PATH, STORAGE_DIR, NEW_ITEM_NAME) filesystem.create_file(file_path) config = ConfigWrapper("../tsresources/conf/tagstore.cfg") ## write the new store also to the config store_id = config.add_new_store(STORE_PATH) ## now tag it manually store.add_item_with_tags(NEW_ITEM_NAME, ["should", "not"], ["get", "this"]) ## create a new file in a tag-dir to test if it is removed as well file_path = "%s%s/%s" % (STORE_PATH, "descriptions/should", "i_should_not_be_here.file") filesystem.create_file(file_path) ## now remove the store store.remove() ##check if this is done properly ##this one should not exist ... assert (not filesystem.path_exists(file_path)) ## this path should still exist assert (filesystem.path_exists(STORE_PATH)) self.remove_dir(STORE_PATH, store_id) assert (not filesystem.path_exists(STORE_PATH)) config.remove_store(store_id)
def test_remove_store(self): """ create a store create an item with tags in the store place a "not allowed" item in the navigation hierarchy call the "remove" method of the store check if everything has been removed properly """ STORE_PATH = "./test_store/" STORAGE_DIR = "storage" NEW_ITEM_NAME = "test_item" store = self.create_new_store_object(STORE_PATH, STORAGE_DIR) filesystem = FileSystemWrapper() ## place a new item in the store file_path = "%s%s/%s" % (STORE_PATH, STORAGE_DIR, NEW_ITEM_NAME) filesystem.create_file(file_path) config = ConfigWrapper("../tsresources/conf/tagstore.cfg") ## write the new store also to the config store_id = config.add_new_store(STORE_PATH) ## now tag it manually store.add_item_with_tags(NEW_ITEM_NAME, ["should", "not"], ["get", "this"]) ## create a new file in a tag-dir to test if it is removed as well file_path = "%s%s/%s" % (STORE_PATH, "descriptions/should", "i_should_not_be_here.file") filesystem.create_file(file_path) ## now remove the store store.remove() ##check if this is done properly ##this one should not exist ... assert(not filesystem.path_exists(file_path)) ## this path should still exist assert(filesystem.path_exists(STORE_PATH)) self.remove_dir(STORE_PATH, store_id) assert(not filesystem.path_exists(STORE_PATH)) config.remove_store(store_id)
class Administration(QtCore.QObject): def __init__(self, application, verbose): QtCore.QObject.__init__(self) self.__log = None self.__main_config = None self.__admin_dialog = None self.__retag_dialog = None self.__verbose_mode = verbose # the main application which has the translator installed self.__application = application self.LOG_LEVEL = logging.INFO if verbose: self.LOG_LEVEL = logging.DEBUG 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.__system_locale = unicode(QtCore.QLocale.system().name())[0:2] self.__translator = QtCore.QTranslator() if self.__translator.load("ts_" + self.__system_locale + ".qm", "tsresources/"): self.__application.installTranslator(self.__translator) # "en" is automatically translated to the current language e.g. en -> de self.CURRENT_LANGUAGE = self.__get_locale_language() #dir names for all available languages 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 = {} # catch all "possible" dir-names for lang in self.SUPPORTED_LANGUAGES: self.change_language(lang) 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)) self.STORE_NAVIGATION_DIRS.append(self.trUtf8("navigation")) self.__log = LogHelper.get_app_logger(self.LOG_LEVEL) self.__init_configuration() def __init_configuration(self): """ initializes the configuration. This method is called every time the config file changes """ self.__log.info("initialize configuration") if self.__main_config is None: self.__main_config = ConfigWrapper(TsConstants.CONFIG_PATH) #self.connect(self.__main_config, QtCore.SIGNAL("changed()"), self.__init_configuration) self.CURRENT_LANGUAGE = self.__main_config.get_current_language() if self.CURRENT_LANGUAGE is None or self.CURRENT_LANGUAGE == "": self.CURRENT_LANGUAGE = self.__get_locale_language() # switch back to the configured language self.change_language(self.CURRENT_LANGUAGE) ## connect to all the signals the admin gui is sending if self.__admin_dialog is None: self.__admin_dialog = StorePreferencesController() self.connect(self.__admin_dialog, QtCore.SIGNAL("create_new_store"), self.__handle_new_store) self.connect(self.__admin_dialog, QtCore.SIGNAL("rename_desc_tag"), self.__handle_tag_rename) self.connect(self.__admin_dialog, QtCore.SIGNAL("rename_cat_tag"), self.__handle_tag_rename) self.connect(self.__admin_dialog, QtCore.SIGNAL("retag"), self.__handle_retagging) self.connect(self.__admin_dialog, QtCore.SIGNAL("rebuild_store"), self.__handle_store_rebuild) self.connect(self.__admin_dialog, QtCore.SIGNAL("rename_store"), self.__handle_store_rename) self.connect(self.__admin_dialog, QtCore.SIGNAL("delete_store"), self.__handle_store_delete) self.connect(self.__admin_dialog, QtCore.SIGNAL("synchronize"), self.__handle_synchronization) self.__admin_dialog.set_main_config(self.__main_config) self.__prepare_store_params() self.__create_stores() ## create a temporary store list ## add the desc and cat tags which are needed in the admin-dialog tmp_store_list = [] for current_store_item in self.__main_config.get_stores(): store_name = current_store_item["path"].split("/").pop() current_store_item["desc_tags"] = self.__store_dict[ store_name].get_tags() current_store_item["cat_tags"] = self.__store_dict[ store_name].get_categorizing_tags() tmp_store_list.append(current_store_item) self.__admin_dialog.set_store_list(tmp_store_list) if self.__main_config.get_first_start(): self.__admin_dialog.set_first_start(True) def __handle_synchronization(self, store_name): """ do all the necessary synchronization stuff here ... """ store_to_sync = self.__store_dict[str(store_name)] print "####################" print "synchronize " + store_name print "####################" store_to_sync.add_item_list_with_tags(["item_one", "item_two"], ["be", "tough"]) def __handle_store_delete(self, store_name): self.__admin_dialog.start_progressbar( self.trUtf8("Deleting store ...")) store = self.__store_dict[str(store_name)] self.__store_to_be_deleted = store_name self.connect(store, QtCore.SIGNAL("store_delete_end"), self.__handle_store_deleted) ## remove the directories store.remove() self.disconnect(store, QtCore.SIGNAL("store_delete_end"), self.__dummy) ## remove the config entry self.__main_config.remove_store(store.get_id()) def __dummy(self): return "dummy" def __handle_store_deleted(self, id): #second remove the item in the admin_dialog self.__admin_dialog.remove_store_item(self.__store_to_be_deleted) def __handle_store_rename(self, store_name, new_store_name): """ the whole store directory gets moved to the new directory the store will be rebuilt then to make sure all links are updated """ ## show a progress bar at the admin dialog self.__admin_dialog.start_progressbar(self.trUtf8("Moving store ...")) store = self.__store_dict.pop(str(store_name)) self.__main_config.rename_store(store.get_id(), new_store_name) ## connect to the rebuild signal because after the moving there is a rebuild routine started self.connect(store, QtCore.SIGNAL("store_rebuild_end"), self.__handle_store_rebuild) store.move(new_store_name) self.disconnect(store, QtCore.SIGNAL("store_rebuild_end")) self.__init_configuration() def __handle_store_rebuild(self, store_name): """ the whole store structure will be rebuild according to the records in store.tgs file """ ## show a progress bar at the admin dialog self.__admin_dialog.start_progressbar( self.trUtf8("Rebuilding store ...")) store = self.__store_dict[str(store_name)] self.connect(store, QtCore.SIGNAL("store_rebuild_end"), self.__handle_store_rebuild) store.rebuild() self.disconnect(store, QtCore.SIGNAL("store_rebuild_end"), self.__get_locale_language) def __hide_progress_dialog(self, store_name): self.__admin_dialog.stop_progressbar() def __get_locale_language(self): """ returns the translation of "en" in the system language """ return self.trUtf8("en") def __handle_tag_rename(self, old_tag, new_tag, store_name): store = self.__store_dict[store_name] old_ba = old_tag.toUtf8() old_str = str(old_ba) new_ba = new_tag.toUtf8() new_str = str(new_ba) store.rename_tag(unicode(old_str, "utf-8"), unicode(new_str, "utf-8")) 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_retagging(self, store_name, item_name): """ creates and configures a tag-dialog with all store-params and tags """ store = self.__store_dict[store_name] ## make a string object of the QListWidgetItem, so other methods can use it item_name = item_name.text() self.__log.info("retagging item %s at store %s..." % (item_name, store_name)) #if(self.__retag_dialog is None): ## create the object self.__retag_dialog = ReTagController(self.__application, store.get_store_path(), item_name, True, self.__verbose_mode) ## connect to the signal(s) self.connect(self.__retag_dialog, QtCore.SIGNAL("retag_error"), self.__handle_retag_error) self.connect(self.__retag_dialog, QtCore.SIGNAL("retag_cancel"), self.__handle_retag_cancel) self.connect(self.__retag_dialog, QtCore.SIGNAL("retag_success"), self.__handle_retag_success) self.__retag_dialog.start() def __kill_tag_dialog(self): """ hide the dialog and set it to None """ self.__retag_dialog.hide_tag_dialog() self.__retag_dialog = None def __handle_retag_error(self): self.__kill_tag_dialog() self.__admin_dialog.show_tooltip( self.trUtf8("An error occurred while re-tagging")) def __handle_retag_success(self): self.__kill_tag_dialog() self.__admin_dialog.show_tooltip(self.trUtf8("Re-tagging successful!")) def __handle_retag_cancel(self): """ the "postpone" button in the re-tag dialog has been clicked """ self.__kill_tag_dialog() def __set_tag_information_to_dialog(self, store): """ convenience method for setting the tag data at the gui-dialog """ self.__retag_dialog.set_tag_list(store.get_tags()) num_pop_tags = self.__main_config.get_num_popular_tags() tag_set = set(store.get_popular_tags( self.__main_config.get_max_tags())) tag_set = tag_set | set(store.get_recent_tags(num_pop_tags)) cat_set = set(store.get_popular_categories(num_pop_tags)) cat_set = cat_set | set(store.get_recent_categories(num_pop_tags)) cat_list = list(cat_set) if store.is_controlled_vocabulary(): allowed_set = set(store.get_controlled_vocabulary()) self.__retag_dialog.set_category_list(list(allowed_set)) ## just show allowed tags - so make the intersection of popular tags ant the allowed tags cat_list = list(cat_set.intersection(allowed_set)) else: self.__retag_dialog.set_category_list( store.get_categorizing_tags()) if len(cat_list) > num_pop_tags: cat_list = cat_list[:num_pop_tags] self.__retag_dialog.set_popular_categories(cat_list) ## make a list out of the set, to enable indexing, as not all tags cannot be used tag_list = list(tag_set) if len(tag_list) > num_pop_tags: tag_list = tag_list[:num_pop_tags] self.__retag_dialog.set_popular_tags(tag_list) self.__retag_dialog.set_store_name(store.get_name()) def __retag_item_action(self, store_name, item_name, tag_list, category_list): """ the "tag!" button in the re-tag dialog has been clicked """ store = self.__store_dict[store_name] try: ## 1. write the data to the store-file store.add_item_with_tags(item_name, tag_list, category_list) self.__log.debug("added item %s to store-file", item_name) except NameInConflictException, e: c_type = e.get_conflict_type() c_name = e.get_conflicted_name() if c_type == EConflictType.FILE: self.__retag_dialog.show_message( self.trUtf8( "The filename - %s - is in conflict with an already existing tag. Please rename!" % c_name)) elif c_type == EConflictType.TAG: self.__retag_dialog.show_message( self.trUtf8( "The tag - %s - is in conflict with an already existing file" % c_name)) else: self.trUtf8( "A tag or item is in conflict with an already existing tag/item" ) #raise except InodeShortageException, e: self.__retag_dialog.show_message( self.trUtf8( "The Number of free inodes is below the threshold of %s%" % e.get_threshold()))
class Tagstore(QtCore.QObject): def __init__(self, application, parent=None, verbose=False, dryrun=False): """ initializes the configuration. This method is called every time the config file changes """ QtCore.QObject.__init__(self) self.__application = application self.__admin_widget = None self.DRY_RUN = dryrun ## initialize localization self.__system_locale = unicode(QtCore.QLocale.system().name())[0:2] self.__translator = QtCore.QTranslator() if self.__translator.load("ts_" + self.__system_locale + ".qm", "tsresources/"): self.__application.installTranslator(self.__translator) # "en" is automatically translated to the current language e.g. en -> de self.CURRENT_LANGUAGE = self.trUtf8("en") self.SUPPORTED_LANGUAGES = TsConstants.DEFAULT_SUPPORTED_LANGUAGES ## global settings/defaults (only used if reading config file failed or invalid!) 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 #get dir names for all available languages store_current_language = self.CURRENT_LANGUAGE self.STORE_STORAGE_DIRS = [] self.STORE_DESCRIBING_NAV_DIRS = [] self.STORE_CATEGORIZING_NAV_DIRS = [] self.STORE_EXPIRED_DIRS = [] self.STORE_NAVIGATION_DIRS = [] 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(store_current_language) self.EXPIRY_PREFIX = TsConstants.DEFAULT_EXPIRY_PREFIX self.TAG_SEPERATOR = TsConstants.DEFAULT_TAG_SEPARATOR self.NUM_RECENT_TAGS = TsConstants.DEFAULT_RECENT_TAGS self.NUM_POPULAR_TAGS = TsConstants.DEFAULT_POPULAR_TAGS self.MAX_TAGS = TsConstants.DEFAULT_MAX_TAGS self.MAX_CLOUD_TAGS = TsConstants.DEFAULT_MAX_CLOUD_TAGS self.STORES = [] ## dict for dialogs identified by their store id self.DIALOGS = {} ## init configurations self.__app_config_wrapper = None self.__log = None self.LOG_LEVEL = logging.INFO if verbose: self.LOG_LEVEL = logging.DEBUG self.__log = LogHelper.get_app_logger(self.LOG_LEVEL) self.__log.info("starting tagstore watcher") self.__init_configurations() def __init_configurations(self): """ initializes the configuration. This method is called every time the config file changes """ self.__log.info("initialize configuration") ## reload config file - overwrite default settings self.__app_config_wrapper = ConfigWrapper(TsConstants.CONFIG_PATH) self.__app_config_wrapper.connect(self.__app_config_wrapper, QtCore.SIGNAL("changed()"), self.__init_configurations) self.__app_config_wrapper.print_app_config_to_log() tag_seperator = self.__app_config_wrapper.get_tag_seperator() if tag_seperator.strip() != "": self.TAG_SEPERATOR = tag_seperator expiry_prefix = self.__app_config_wrapper.get_expiry_prefix() if expiry_prefix.strip() != "": self.EXPIRY_PREFIX = expiry_prefix self.NUM_RECENT_TAGS = self.__app_config_wrapper.get_num_popular_tags() self.NUM_POPULAR_TAGS = self.__app_config_wrapper.get_num_popular_tags() self.MAX_TAGS = self.__app_config_wrapper.get_max_tags() self.CURRENT_LANGUAGE = self.__app_config_wrapper.get_current_language(); if self.CURRENT_LANGUAGE is None or self.CURRENT_LANGUAGE == "": self.CURRENT_LANGUAGE = self.trUtf8("en") self.change_language(self.CURRENT_LANGUAGE) config_dir = self.__app_config_wrapper.get_store_config_directory() if config_dir != "": self.STORE_CONFIG_DIR = config_dir config_file_name = self.__app_config_wrapper.get_store_configfile_name() if config_file_name != "": self.STORE_CONFIG_FILE_NAME = config_file_name tags_file_name = self.__app_config_wrapper.get_store_tagsfile_name() if tags_file_name != "": self.STORE_TAGS_FILE_NAME = tags_file_name vocabulary_file_name = self.__app_config_wrapper.get_store_vocabularyfile_name() if vocabulary_file_name != "": self.STORE_VOCABULARY_FILE_NAME = vocabulary_file_name # self.SUPPORTED_LANGUAGES = self.__app_config_wrapper.get_supported_languages() # current_language = self.CURRENT_LANGUAGE # self.STORE_STORAGE_DIRS = [] # self.STORE_NAVIGATION_DIRS = [] # for lang in self.SUPPORTED_LANGUAGES: # self.change_language(lang) # self.STORE_STORAGE_DIRS.append(self.trUtf8("storage")) # self.STORE_NAVIGATION_DIRS.append(self.trUtf8("navigation")) # ## reset language # self.change_language(current_language) ## get stores from config file config_store_items = self.__app_config_wrapper.get_stores() config_store_ids = self.__app_config_wrapper.get_store_ids() deleted_stores = [] for store in self.STORES: id = store.get_id() if id in config_store_ids: ## update changed stores store.set_path(self.__app_config_wrapper.get_store_path(id), 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) store.change_expiry_prefix(self.EXPIRY_PREFIX) config_store_ids.remove(id) ## remove already updated items else: ## remove deleted stores deleted_stores.append(store) ## update deleted stores from global list after iterating through it for store in deleted_stores: self.STORES.remove(store) self.__log.debug("removed store: %s", store.get_name()) ## add new stores for store_item in config_store_items: if store_item["id"] in config_store_ids: ## new store = Store(store_item["id"], store_item["path"], 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.EXPIRY_PREFIX) store.connect(store, QtCore.SIGNAL("removed(PyQt_PyObject)"), self.store_removed) store.connect(store, QtCore.SIGNAL("renamed(PyQt_PyObject, QString)"), self.store_renamed) store.connect(store, QtCore.SIGNAL("file_renamed(PyQt_PyObject, QString, QString)"), self.file_renamed) store.connect(store, QtCore.SIGNAL("file_removed(PyQt_PyObject, QString)"), self.file_removed) store.connect(store, QtCore.SIGNAL("pending_operations_changed(PyQt_PyObject)"), self.pending_file_operations) store.connect(store, QtCore.SIGNAL("vocabulary_changed"), self.__handle_vocabulary_changed) store.connect(store, QtCore.SIGNAL("store_config_changed"), self.__handle_store_config_changed) extensions = self.__app_config_wrapper.get_additional_ignored_extension() ##if there comes a value from the config -> set it if len(extensions) > 0 and extensions[0] != "": store.add_ignored_extensions(extensions) self.STORES.append(store) self.__log.debug("init store: %s", store.get_name()) ## create a dialogcontroller for each store ... tmp_dialog = TagDialogController(store.get_name(), store.get_id(), self.MAX_TAGS, self.TAG_SEPERATOR, self.EXPIRY_PREFIX) tmp_dialog.connect(tmp_dialog, QtCore.SIGNAL("tag_item"), self.tag_item_action) tmp_dialog.connect(tmp_dialog, QtCore.SIGNAL("handle_cancel()"), self.handle_cancel) tmp_dialog.connect(tmp_dialog, QtCore.SIGNAL("open_store_admin_dialog()"), self.show_admin_dialog) self.DIALOGS[store.get_id()] = tmp_dialog ## call init to initialize new store instance (after adding the event handler) ## necessary if store was renamed during tagstore was not running (to write config) store.init() self.connect(tmp_dialog, QtCore.SIGNAL("item_selected"), self.__set_tag_information_to_dialog_wrapper) self.__configure_tag_dialog(store, tmp_dialog) def __configure_tag_dialog(self, store, tmp_dialog): """ given a store and a tag dialog - promote all settings to the dialog """ format_setting = store.get_datestamp_format() is_hidden = store.get_datestamp_hidden() ##check if auto datestamp is enabled if format_setting != EDateStampFormat.DISABLED: tmp_dialog.show_datestamp(True) ## set the format format = None if format_setting == EDateStampFormat.DAY: format = TsConstants.DATESTAMP_FORMAT_DAY elif format_setting == EDateStampFormat.MONTH: format = TsConstants.DATESTAMP_FORMAT_MONTH tmp_dialog.set_datestamp_format(format, is_hidden) tmp_dialog.show_category_line(store.get_show_category_line()) tmp_dialog.set_category_mandatory(store.get_category_mandatory()) def __handle_vocabulary_changed(self, store): self.__set_tag_information_to_dialog(store) def __handle_store_config_changed(self, store): ## at first get the store-corresponding dialog controller dialog_controller = self.DIALOGS[store.get_id()] self.__configure_tag_dialog(store, dialog_controller) def show_admin_dialog(self): self.__admin_widget = Administration(self.__application, verbose=verbose_mode) self.__admin_widget.set_modal(True) self.__admin_widget.set_parent(self.sender().get_view()) #admin_widget.set_parent(self.__tag_dialog) self.__admin_widget.show_admin_dialog(True) def store_removed(self, store): """ event handler of the stores remove event """ self.__app_config_wrapper.remove_store(store.get_id()) ## __init_configuration is called due to config file changes def store_renamed(self, store, new_path): """ event handler of the stores rename event """ self.__app_config_wrapper.rename_store(store.get_id(), new_path) ## __init_configuration is called due to config file changes def file_renamed(self, store, old_file_name, new_file_name): """ event handler for: file renamed """ self.__log.debug("..........file renamed %s, %s" % (old_file_name, new_file_name)) store.rename_file(old_file_name, new_file_name) def file_removed(self, store, file_name): """ event handler for: file renamed """ self.__log.debug("...........file removed %s" % file_name) store.remove_file(file_name) def pending_file_operations(self, store): """ event handler: handles all operations with user interaction """ self.__log.info("new pending file operation added") dialog_controller = self.DIALOGS[store.get_id()] #dialog_controller.clear_store_children(store.get_name()) # dialog_controller.clear_all_items() dialog_controller.clear_tagdialog() added_list = set(store.get_pending_changes().get_items_by_event(EFileEvent.ADDED)) added_renamed_list = set(store.get_pending_changes().get_items_by_event(EFileEvent.ADDED_OR_RENAMED)) whole_list = added_list | added_renamed_list if whole_list is None or len(whole_list) == 0: dialog_controller.hide_dialog() return self.__log.debug("store: %s, item: %s " % (store.get_id(), store.get_pending_changes().to_string())) for item in whole_list: dialog_controller.add_pending_item(item) self.__set_tag_information_to_dialog(store) dialog_controller.show_dialog() def handle_cancel(self): dialog_controller = self.sender() if dialog_controller is None or not isinstance(dialog_controller, TagDialogController): return dialog_controller.hide_dialog() def __set_tag_information_to_dialog_wrapper(self, store_id): for store in self.STORES: if store.get_id() == store_id: self.__set_tag_information_to_dialog(store) def __set_tag_information_to_dialog(self, store): """ convenience method for refreshing the tag data at the gui-dialog """ self.__log.debug("refresh tag information on dialog") dialog_controller = self.DIALOGS[store.get_id()] dialog_controller.set_tag_list(store.get_tags()) item_list = dialog_controller.get_selected_item_list_public() if item_list is not None: if len(item_list) > 0 and item_list[0] is not None: if store.get_tagline_config() == 1 or store.get_tagline_config() == 2 or store.get_tagline_config() == 3: tmp_cat_list = store.get_cat_recommendation(self.NUM_POPULAR_TAGS, str(item_list[0].text())) cat_list = [] if store.is_controlled_vocabulary(): allowed_set = set(store.get_controlled_vocabulary()) dialog_controller.set_category_list(list(allowed_set)) ## just show allowed tags - so make the intersection of popular tags ant the allowed tags for cat in tmp_cat_list: if cat in list(allowed_set): cat_list.append(cat) #for cat in list(allowed_set): # if cat not in cat_list: # cat_list.append(cat) #cat_list = list(cat_set.intersection(allowed_set)) else: dialog_controller.set_category_list(store.get_categorizing_tags()) cat_list = tmp_cat_list #print cat_list #if len(cat_list) > self.NUM_POPULAR_TAGS: # cat_list = cat_list[:self.NUM_POPULAR_TAGS] #dialog_controller.set_popular_categories(cat_list) dict = store.get_cat_cloud(str(item_list[0].text())) dialog_controller.set_cat_cloud(dict, cat_list, self.MAX_CLOUD_TAGS) ## make a list out of the set, to enable indexing, as not all tags cannot be used #tag_list = list(tag_set) if store.get_tagline_config() == 1 or store.get_tagline_config() == 2 or store.get_tagline_config() == 0: tag_list = store.get_tag_recommendation(self.NUM_POPULAR_TAGS, str(item_list[0].text())) #if len(tag_list) > self.NUM_POPULAR_TAGS: # tag_list = tag_list[:self.NUM_POPULAR_TAGS] #dialog_controller.set_popular_tags(tag_list) dict = store.get_tag_cloud(str(item_list[0].text())) dialog_controller.set_tag_cloud(dict, tag_list, self.MAX_CLOUD_TAGS) #if len(self.DIALOGS) > 1: dialog_controller.set_store_name(store.get_name()) def tag_item_action(self, store_name, item_name_list, tag_list, category_list): """ write the tags for the given item to the store """ store = None ## find the store where the item should be saved for loop_store in self.STORES: if store_name == loop_store.get_name(): store = loop_store break if store is not None: dialog_controller = self.DIALOGS[store.get_id()] try: ## 1. write the data to the store-file store.add_item_list_with_tags(item_name_list, tag_list, category_list) self.__log.debug("added items %s to store-file", item_name_list) except NameInConflictException, e: c_type = e.get_conflict_type() c_name = e.get_conflicted_name() if c_type == EConflictType.FILE: dialog_controller.show_message(self.trUtf8("The filename - %s - is in conflict with an already existing tag. Please rename!" % c_name)) elif c_type == EConflictType.TAG: dialog_controller.show_message(self.trUtf8("The tag - %s - is in conflict with an already existing file" % c_name)) else: self.trUtf8("A tag or item is in conflict with an already existing tag/item") #raise except InodeShortageException, e: dialog_controller.show_message(self.trUtf8("The Number of free inodes is below the threshold of %s%" % e.get_threshold())) #raise except Exception, e: dialog_controller.show_message(self.trUtf8("An error occurred while tagging")) raise
class Administration(QtCore.QObject): def __init__(self, application, verbose): QtCore.QObject.__init__(self) self.__log = None self.__main_config = None self.__admin_dialog = None self.__retag_dialog = None self.__verbose_mode = verbose # the main application which has the translator installed self.__application = application self.LOG_LEVEL = logging.INFO if verbose: self.LOG_LEVEL = logging.DEBUG 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.__system_locale = unicode(QtCore.QLocale.system().name())[0:2] self.__translator = QtCore.QTranslator() if self.__translator.load("ts_" + self.__system_locale + ".qm", "tsresources/"): self.__application.installTranslator(self.__translator) # "en" is automatically translated to the current language e.g. en -> de self.CURRENT_LANGUAGE = self.__get_locale_language() #dir names for all available languages 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 = {} # catch all "possible" dir-names for lang in self.SUPPORTED_LANGUAGES: self.change_language(lang) 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)) self.STORE_NAVIGATION_DIRS.append(self.trUtf8("navigation")) self.__log = LogHelper.get_app_logger(self.LOG_LEVEL) self.__init_configuration() def __init_configuration(self): """ initializes the configuration. This method is called every time the config file changes """ self.__log.info("initialize configuration") if self.__main_config is None: self.__main_config = ConfigWrapper(TsConstants.CONFIG_PATH) #self.connect(self.__main_config, QtCore.SIGNAL("changed()"), self.__init_configuration) self.CURRENT_LANGUAGE = self.__main_config.get_current_language(); if self.CURRENT_LANGUAGE is None or self.CURRENT_LANGUAGE == "": self.CURRENT_LANGUAGE = self.__get_locale_language() # switch back to the configured language self.change_language(self.CURRENT_LANGUAGE) ## connect to all the signals the admin gui is sending if self.__admin_dialog is None: self.__admin_dialog = StorePreferencesController() self.connect(self.__admin_dialog, QtCore.SIGNAL("create_new_store"), self.__handle_new_store) self.connect(self.__admin_dialog, QtCore.SIGNAL("rename_desc_tag"), self.__handle_tag_rename) self.connect(self.__admin_dialog, QtCore.SIGNAL("rename_cat_tag"), self.__handle_tag_rename) self.connect(self.__admin_dialog, QtCore.SIGNAL("retag"), self.__handle_retagging) self.connect(self.__admin_dialog, QtCore.SIGNAL("rebuild_store"), self.__handle_store_rebuild) self.connect(self.__admin_dialog, QtCore.SIGNAL("rename_store"), self.__handle_store_rename) self.connect(self.__admin_dialog, QtCore.SIGNAL("delete_store"), self.__handle_store_delete) self.connect(self.__admin_dialog, QtCore.SIGNAL("synchronize"), self.__handle_synchronization) self.__admin_dialog.set_main_config(self.__main_config) self.__prepare_store_params() self.__create_stores() ## create a temporary store list ## add the desc and cat tags which are needed in the admin-dialog tmp_store_list = [] for current_store_item in self.__main_config.get_stores(): store_name = current_store_item["path"].split("/").pop() current_store_item["desc_tags"] = self.__store_dict[store_name].get_tags() current_store_item["cat_tags"] = self.__store_dict[store_name].get_categorizing_tags() tmp_store_list.append(current_store_item) self.__admin_dialog.set_store_list(tmp_store_list) if self.__main_config.get_first_start(): self.__admin_dialog.set_first_start(True) def __handle_synchronization(self, store_name): """ do all the necessary synchronization stuff here ... """ store_to_sync = self.__store_dict[str(store_name)] print "####################" print "synchronize " + store_name print "####################" store_to_sync.add_item_list_with_tags(["item_one", "item_two"], ["be", "tough"]) def __handle_store_delete(self, store_name): self.__admin_dialog.start_progressbar(self.trUtf8("Deleting store ...")) store = self.__store_dict[str(store_name)] self.__store_to_be_deleted = store_name self.connect(store, QtCore.SIGNAL("store_delete_end"), self.__handle_store_deleted) ## remove the directories store.remove() self.disconnect(store, QtCore.SIGNAL("store_delete_end"), self.__dummy) ## remove the config entry self.__main_config.remove_store(store.get_id()) def __dummy(self): return "dummy" def __handle_store_deleted(self, id): #second remove the item in the admin_dialog self.__admin_dialog.remove_store_item(self.__store_to_be_deleted) def __handle_store_rename(self, store_name, new_store_name): """ the whole store directory gets moved to the new directory the store will be rebuilt then to make sure all links are updated """ ## show a progress bar at the admin dialog self.__admin_dialog.start_progressbar(self.trUtf8("Moving store ...")) store = self.__store_dict.pop(str(store_name)) self.__main_config.rename_store(store.get_id(), new_store_name) ## connect to the rebuild signal because after the moving there is a rebuild routine started self.connect(store, QtCore.SIGNAL("store_rebuild_end"), self.__handle_store_rebuild) store.move(new_store_name) self.disconnect(store, QtCore.SIGNAL("store_rebuild_end")) self.__init_configuration() def __handle_store_rebuild(self, store_name): """ the whole store structure will be rebuild according to the records in store.tgs file """ ## show a progress bar at the admin dialog self.__admin_dialog.start_progressbar(self.trUtf8("Rebuilding store ...")) store = self.__store_dict[str(store_name)] self.connect(store, QtCore.SIGNAL("store_rebuild_end"), self.__handle_store_rebuild) store.rebuild() self.disconnect(store, QtCore.SIGNAL("store_rebuild_end"), self.__get_locale_language) def __hide_progress_dialog(self, store_name): self.__admin_dialog.stop_progressbar() def __get_locale_language(self): """ returns the translation of "en" in the system language """ return self.trUtf8("en") def __handle_tag_rename(self, old_tag, new_tag, store_name): store = self.__store_dict[store_name] old_ba = old_tag.toUtf8() old_str = str(old_ba) new_ba = new_tag.toUtf8() new_str = str(new_ba) store.rename_tag(unicode(old_str, "utf-8"), unicode(new_str, "utf-8")) 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_retagging(self, store_name, item_name): """ creates and configures a tag-dialog with all store-params and tags """ store = self.__store_dict[store_name] ## make a string object of the QListWidgetItem, so other methods can use it item_name = item_name.text() self.__log.info("retagging item %s at store %s..." % (item_name, store_name)) #if(self.__retag_dialog is None): ## create the object self.__retag_dialog = ReTagController(self.__application, store.get_store_path(), item_name, True, self.__verbose_mode) ## connect to the signal(s) self.connect(self.__retag_dialog, QtCore.SIGNAL("retag_error"), self.__handle_retag_error) self.connect(self.__retag_dialog, QtCore.SIGNAL("retag_cancel"), self.__handle_retag_cancel) self.connect(self.__retag_dialog, QtCore.SIGNAL("retag_success"), self.__handle_retag_success) self.__retag_dialog.start() def __kill_tag_dialog(self): """ hide the dialog and set it to None """ self.__retag_dialog.hide_tag_dialog() self.__retag_dialog = None def __handle_retag_error(self): self.__kill_tag_dialog() self.__admin_dialog.show_tooltip(self.trUtf8("An error occurred while re-tagging")) def __handle_retag_success(self): self.__kill_tag_dialog() self.__admin_dialog.show_tooltip(self.trUtf8("Re-tagging successful!")) def __handle_retag_cancel(self): """ the "postpone" button in the re-tag dialog has been clicked """ self.__kill_tag_dialog() def __set_tag_information_to_dialog(self, store): """ convenience method for setting the tag data at the gui-dialog """ self.__retag_dialog.set_tag_list(store.get_tags()) num_pop_tags = self.__main_config.get_num_popular_tags() tag_set = set(store.get_popular_tags(self.__main_config.get_max_tags())) tag_set = tag_set | set(store.get_recent_tags(num_pop_tags)) cat_set = set(store.get_popular_categories(num_pop_tags)) cat_set = cat_set | set(store.get_recent_categories(num_pop_tags)) cat_list = list(cat_set) if store.is_controlled_vocabulary(): allowed_set = set(store.get_controlled_vocabulary()) self.__retag_dialog.set_category_list(list(allowed_set)) ## just show allowed tags - so make the intersection of popular tags ant the allowed tags cat_list = list(cat_set.intersection(allowed_set)) else: self.__retag_dialog.set_category_list(store.get_categorizing_tags()) if len(cat_list) > num_pop_tags: cat_list = cat_list[:num_pop_tags] self.__retag_dialog.set_popular_categories(cat_list) ## make a list out of the set, to enable indexing, as not all tags cannot be used tag_list = list(tag_set) if len(tag_list) > num_pop_tags: tag_list = tag_list[:num_pop_tags] self.__retag_dialog.set_popular_tags(tag_list) self.__retag_dialog.set_store_name(store.get_name()) def __retag_item_action(self, store_name, item_name, tag_list, category_list): """ the "tag!" button in the re-tag dialog has been clicked """ store = self.__store_dict[store_name] try: ## 1. write the data to the store-file store.add_item_with_tags(item_name, tag_list, category_list) self.__log.debug("added item %s to store-file", item_name) except NameInConflictException, e: c_type = e.get_conflict_type() c_name = e.get_conflicted_name() if c_type == EConflictType.FILE: self.__retag_dialog.show_message(self.trUtf8("The filename - %s - is in conflict with an already existing tag. Please rename!" % c_name)) elif c_type == EConflictType.TAG: self.__retag_dialog.show_message(self.trUtf8("The tag - %s - is in conflict with an already existing file" % c_name)) else: self.trUtf8("A tag or item is in conflict with an already existing tag/item") #raise except InodeShortageException, e: self.__retag_dialog.show_message(self.trUtf8("The Number of free inodes is below the threshold of %s%" % e.get_threshold()))