def _import_records(self, node, records): ''' shared backend for insertion of references retrieved from pubmed or parsed from bibtex ''' errors = [] progress_bar = hub.progress_bar(target=len(records), title="Adding references to database") progress_bar.show() for i, record in enumerate(records): more_errors = self.add_reference(record, node, single_mode=False) errors.extend(more_errors) progress_bar.update(i + 1) self._db.commit() # hub.refresh_tree_item(node) # we need to refresh the tree in order to update the Imported pseudo-folder hub.clear_cache() hub.tree.refresh() if len(errors): hub.show_errors(errors) refs_imported = self.item_count('refs') - self.ref_count_before suffix = '' if refs_imported == 1 else 's' hub.set_status_bar('Imported %s reference%s' % (refs_imported, suffix))
def move_selected(self, node=None): ''' move selected items into current folder. Reset selected to 0. ''' if node is None: # invocation from menu will trigger this case node = hub.tree.focus_element() assert hub.is_branch(node) node_id = node[1] # get hold of all selected folders stmt = 'update branches set parent_id=(?), selected=0 where selected=1' c = self._db.execute(stmt, [node_id]) moved_items = c.rowcount errors = 0 stmt = ''' update reflink set branch_id=(?), selected = 0 where selected=1 and not ref_id in (select ref_id from reflink where branch_id=(?)) ''' try: c = self._db.execute(stmt, [node_id, node_id]) moved_items += c.rowcount except IntegrityError: hub.show_errors('Oopsie - something bad just happened') if not moved_items: hub.show_errors('Nothing was moved') else: self._db.commit() hub.clear_cache() hub.tree.refresh()
def recycle_trash(self): ''' recover all items from the trash and stuff it into the Recycled folder. ''' refs_before = self.item_count('reflink') recycled_id = self.recycled_node[1] stmt = "select ref_id from refs where ref_id not in (select distinct(ref_id) from reflink)" ref_ids = self._db.execute(stmt).fetchvalues() if not len(ref_ids): return for ref_id in ref_ids: self._db.insert('reflink', dict(ref_id=ref_id, branch_id=recycled_id)) self._db.commit() hub.clear_cache() hub.tree.refresh() refs_recycled = self.item_count('reflink') - refs_before refs_suffix = '' if refs_recycled == 1 else 's' hub.set_status_bar('Recycled %s reference%s' % (refs_recycled, refs_suffix))
def toggle_sort(self): ''' switch sorting and refresh display ''' self.sort_by_year = not self.sort_by_year hub.clear_cache() hub.tree.refresh()
def copy_selected(self, node=None): ''' copy selected references and folders into current folder. Should we also deselect? Because if we don't, it's less work, but might be annoying. Let's wait and see. Actually, we need a 'deselect all' anyway, so we might just call that at the end. ''' if node is None: # invocation from menu will trigger this case node = hub.tree.focus_element() assert hub.is_branch(node) node_id = node[1] # get hold of all selected folders stmt = 'select * from branches where selected=1' branches = self._db.execute(stmt).fetchall() errors = [] success = 0 for branch in branches: b = (hub.BRANCH, branch['branch_id'], branch['parent_id']) try: new_id = self.clone_branch(b, node_id) success += 1 except RefdbError as e: errors.append(e.message) # now on to the references stmt = 'select ref_id from reflink where selected=1' ref_ids = self._db.execute(stmt).fetchvalues() failed_refs = 0 for ref_id in ref_ids: try: self._db.insert('reflink', dict(ref_id=ref_id, branch_id=node_id)) success += 1 except IntegrityError: failed_refs += 1 if success: self._db.commit() hub.clear_cache() hub.tree.refresh() if failed_refs: suffix = '' if failed_refs == 1 else 's' errors.append("%s duplicate reference%s not copied" % (failed_refs, suffix)) if errors: hub.show_errors(errors) if success == len(errors) == 0: hub.show_errors('Nothing was selected')
def reset_search(self): ''' clear out previous results. strangely, the tree ''' self._db.execute('delete from reflink where branch_id=(?)', [self.search_id]) self._db.commit() hub.clear_cache() # needed to flush out the zombies hub.tree.refresh() # it is possible that stuff was ONLY in search, so we need
def filter_folders(self, search_string): ''' set a filter and refresh everything. ''' if search_string == self.branch_filter_string: return self.branch_filter_string = search_string hub.clear_cache() hub.tree.refresh() if search_string != '': hub.tree.set_focus(self.special_branch_nodes['References'])
def _update_or_delete_selected(self, stmt): ''' shared backend for simple operations on all selected items ''' affected = 0 for table in ("reflink", "branches"): c = self._db.execute(stmt % table) affected += c.rowcount if affected: self._db.commit() hub.clear_cache() hub.tree.refresh()
def select_refs(self, node=None): ''' select references immediately in this folder, but not sub-folders ''' if node is None: # invocation from menu will trigger this case node = hub.tree.focus_element() assert hub.is_branch(node) node_id = node[1] stmt = 'update reflink set selected = 1 where branch_id=(?) and selected = 0' c = self._db.execute(stmt, [node_id]) if c.rowcount != 0: self._db.commit() hub.clear_cache() hub.tree.refresh()
def flatten_folder(self, node=None): ''' - recursively collect all references below this folder - empty out this folder - insert the collect the references back into it. ''' if node is None: # invocation from menu will trigger this case node = hub.tree.focus_element() assert hub.is_branch(node) node_id = node[1] # collect all references from nested folders stmt = ''' with recursive branch_set(i) as ( select branch_id from branches where parent_id = (?) union select branch_id from branches, branch_set where branches.parent_id = branch_set.i ) select distinct(ref_id) from reflink where branch_id in branch_set ''' nested_references = self._db.execute(stmt, [node_id]).fetchvalues() # now, delete all nested folders stmt = '''delete from branches where parent_id=(?)''' self._db.execute(stmt, [node_id]) # collect any remaining references stmt = "select ref_id from reflink where branch_id=(?)" direct_references = self._db.execute(stmt, [node_id]).fetchvalues() # finally, insert all references directly into parent, omitting duplicates remaining = set(nested_references) - set(direct_references) for ref in remaining: self._db.insert('reflink', dict(ref_id=ref, branch_id=node_id, selected=0)) # finish up self._db.commit() hub.clear_cache() hub.tree.refresh()
def add_folder(self, parent, new_name): ''' not really a clipboard operation itself, but related. Should we guard against duplicated names in same folder? I guess so. ''' if not new_name: hub.show_errors("Folder name cannot be empty") return if not hub.is_branch(parent): hub.show_errors("Cannot create folder inside a reference") return parent_id = parent[1] if self.exists_folder(parent, new_name): hub.show_errors("Subfolder '%s' already exists - aborting" % new_name) return c = self._db.insert('branches', dict(name=new_name, parent_id=parent_id)) new_id = c.lastrowid self._db.commit() # clearing the cache shouldn't be needed, but it is - deleted folder nodes # somehow linger, and if an id gets reused, the zombies reappear hub.clear_cache() hub.tree.refresh() # now, we should be able to construct the new node signature without going # back to the database new_node = (hub.BRANCH, new_id, parent_id) hub.tree.set_focus(new_node) hub.tree.add_to_history(new_node)
def _empty_folder(self, folder_id): ''' used with at least two folders (recycled and recently added) ''' refs_before = self.item_count('reflink') stmt = "delete from reflink where branch_id = (?)" c = self._db.execute(stmt, [folder_id]) deleted = c.rowcount if deleted == 0: return self._db.commit() hub.clear_cache() hub.tree.refresh() refs_deleted = refs_before - self.item_count('reflink') if refs_deleted > 0: refs_suffix = '' if refs_deleted == 1 else 's' hub.set_status_bar('Deleted %s reference%s' % (refs_deleted, refs_suffix))
def toggle_select(self, node=None): ''' toggle selection status of reference or folder. - first, check if the current node is inside a folder that is currently selected. if it is, tell them that and exit. - if no parent is selected, then toggle selection status. When a folder is selected, we also reset the selections of all items below. Hm. How do we deal with stuff in the trash? With references, we have no reflink entries, so we have no place to store the 'selected' attribute. Darn. Why did I feel the need again to change this around? What exactly was wrong with having the selected attribute on the reference? ''' if node is None: # invocation from menu will trigger this case node = hub.tree.focus_element() node_type, node_id, parent_id = node is_branch = node_type == hub.BRANCH parents = self.get_branches_above(parent_id, include_start_branch=True) selected = sum([p['selected'] for p in parents]) if selected: hub.show_errors( 'This item is inside a selected folder and cannot be individually selected or deselected.' ) return if is_branch: if node_id in self.special_branch_ids: hub.show_errors( 'This folder is protected and cannot be moved or copied') return this_branch = self._db.execute( 'select * from branches where branch_id=(?)', [node_id]).fetchone() currently_selected = this_branch['selected'] if currently_selected == 0: # going to be 1 - deselect all individually selected # descendants. Is that sensible? Let's try it out. # deselect references. stmt = ''' with recursive branch_set( i ) as ( select branch_id from branches where parent_id = (?) union select branch_id from branches, branch_set where branches.parent_id = branch_set.i ) update reflink set selected = 0 where selected = 1 and branch_id in branch_set or branch_id = (?); ''' self._db.execute(stmt, [node_id, node_id]) # deselect branches stmt = ''' with recursive branch_set( i ) as ( select branch_id from branches where parent_id = (?) union select branch_id from branches, branch_set where branches.parent_id = branch_set.i ) update branches set selected = 0 where selected = 1 and branch_id in branch_set; ''' self._db.execute(stmt, [node_id]) # update branch itself stmt = 'update branches set selected=(?) where branch_id=(?)' self._db.execute(stmt, [1 - currently_selected, node_id]) else: stmt = ''' update reflink set selected = case selected when 1 then 0 else 1 end where ref_id = (?) and branch_id = (?) ''' self._db.execute(stmt, [node_id, parent_id]) self._db.commit() hub.clear_cache() hub.tree.refresh()