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
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)