def prevalidate(self): ''' make sure we are in the right kind of folder ''' node = hub.tree.focus_element() return hub.is_branch( node) and node[1] not in hub.coredb.special_branch_ids
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 __getitem__(self, pos): ''' obtain one tree item for display. Must check back with the database to look for updates. ''' text_tuple, selected = hub.get_node_display_info(pos) key, title = text_tuple if selected == 0: low, high = 'body', 'focus' elif selected == hub.SELECTED: low, high = 'selected body', 'selected focus' else: low, high = 'in selection body', 'in selection focus' nodeinfo = str(pos) if self.debug else '' if title is None or hub.is_branch(pos): return widgets.FocusableText(key + nodeinfo, low, high) else: widget = urwid.Pile([ ReferenceDisplay(key, nodeinfo + title, low, high), urwid.Divider() ]) return widget
def prevalidate(self): ''' make sure we are in the right kind of folder ''' node = hub.tree.focus_element() return hub.is_branch(node) \ and (node[1] not in hub.coredb.special_branch_ids \ or hub.coredb.special_branch_names['References'] == node[1])
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 toggle_refs(self): ''' show/hide refs within the tree ''' node = self.focus_element() branch = node if hub.is_branch(node) else hub.get_parent_node(node) hub.toggle_branches_only() self.refresh() try: self.set_focus(branch) except: # strange things happen if we press F3 immediately after program start pass
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 exists_folder(self, parent, subfolder_name): ''' check if a folder name is already present inside a target parent folder. parent may be a node or just a branch_id. ''' try: parent_id = int(parent) stmt = "select parent_id from branches where branch_id = (?)" ppid = self._db.execute(stmt, [parent_id]).fetchvalue() parent = (hub.BRANCH, parent_id, ppid) except TypeError: pass # assume it's already a tuple assert hub.is_branch(parent) branch_names = [ hub.get_branch_title(b) for b in self.get_child_branches(parent) ] return subfolder_name in branch_names
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 add_reference(self, new_data, node=None, single_mode=True): ''' What do we do here if constraints are violated? I think in the case of missing or reduplicated bibtex keys we just concatenate a random string and try again. For title, we can just supply a dummy title. single_mode: we also use this as a backend for importers, so we don't commit and display errors right here in that case. ''' if node is None: node = hub.tree.focus_element() assert hub.is_branch(node) values = [_f for _f in list(new_data.values()) if _f] if not values: hub.show_errors("No data provided - aborting.") return # I guess from here we will insert something, even if it is crap. # we just keep track of the errors and show them at the end. errors = [] orig_bibtexkey = new_data.get('bibtexkey') new_bibtexkey = new_data['bibtexkey'] = self.make_bibtex_key(new_data) #if orig_bibtexkey and orig_bibtexkey != new_bibtexkey: don't nag the user #hub.show_message("bibtexkey '%s' changed to '%s'" % (orig_bibtexkey, new_bibtexkey)) new_data['title'] = new_data['title'].rstrip('.') if not new_data['title']: new_data['title'] = "Title can't be empty -- please fix" errors.append(new_data['title']) if new_data['reftype'] not in self.ref_types: errors.append("reftype was empty or faulty - set to 'article'") new_data['reftype'] = 'article' # at this point, we should have everything in place. Now, we can still fail to # insert a reference if we have a duplicate bibtexkey, in which case we need to fix. # I suppose I will fix it up with appending a short random string. ref_data = dict(reftype_id=self.ref_types[new_data['reftype']], title=new_data['title'], bibtexkey=new_bibtexkey) c = self._db.insert('refs', ref_data) ref_id = c.lastrowid try: errors += self.update_reference(dict(ref_id=ref_id), new_data, add_reference=True) except IntegrityError: errors.append("Record '%s...' not imported (likely duplicate)" % new_data['title'][:50]) # also need to revert partial import self._db.execute('delete from refs where ref_id=(?)', [ref_id]) return errors # Associate the new reference with the current branch branch_id = node[1] for branch_id in (node[1], self.recently_added_id): self._db.insert('reflink', dict(ref_id=ref_id, branch_id=branch_id)) if single_mode: self._db.commit() hub.refresh_tree_item(node) if errors: hub.show_errors(errors) else: # collect errors for display later on. return errors