def get_active_open(self): '''Get last directory used for file opening, ctrl[open]''' dprint(3, "\nDatabaseBinding::get_active_open") if "open" in self.__ctrl.keys(): return self.__ctrl["open"] else: return self.__ctrl["loc"]
def _traverse_conf(doc, nd, parent): '''Internal function: map an XML.DOM.MINIDOM document to a Configuration complex''' dprint(3, "\nextconf.py::_traverse_conf") if len(nd.childNodes)==1: # either we have data, or we have a tag-within-a-tag if nd.childNodes[0].nodeType == nd.childNodes[0].TEXT_NODE: return str(nd.childNodes[0].data) else: holder = Configuration(doc, nd, parent) holder.add_attr(nd.attributes) holder.add_data_from_xml(nd.childNodes[0].tagName, _traverse_conf(doc, nd.childNodes[0], nd)) return holder else: # multiple children, we must skip any text (scrubber.py should have removed any) # this is a limitation: this extconf construct can't handle a tag w/ both data + children holder = Configuration(doc, nd, parent) holder.add_attr(nd.attributes) for child in nd.childNodes: if child.nodeType is child.TEXT_NODE: continue # else, it's an element: # holder.add_data_from_xml(child.tagName, _traverse_conf(doc, child, nd)) return holder
def load_string(scrub): '''Process XML string into Configuratio-complex representation''' dprint(3, "\nextconf.py::load_string") if scrub is not None: doc = xml.dom.minidom.parseString(scrub) extconf = _traverse_conf(doc, doc.childNodes[0], doc) return extconf
def get_active_save(self): '''Get last directory used for file saving, ctrl[save]''' dprint(3, "\nDatabaseBinding::get_active_save") if "save" in self.__ctrl.keys(): return self.__ctrl["save"] else: return self.__ctrl["loc"]
def get_attr_keys(self): '''Get list of attributes''' # returns the list of keys, not the values dprint(3, "\nConfiguration::get_attr_keys") if self.__attr: return self.__attr.items() return None
def populate(self): '''Scan sources for files with marks''' dprint(3, "\nDatabaseBinding::populate") if not self._src: return try: if isinstance(self.__ctrl["db"]["scan"], str): self.__scan_list = [self.__ctrl["db"]["scan"]] else: self.__scan_list = list(self.__ctrl["db"]["scan"]) except: # create a node and attach it newc = extconf.Configuration(self.__dex.getdoc()) extconf.fill_configuration(newc, "db", members={"scan": "."}) extconf.attach_configuration(self.__dex, "db", newc) if self.__scan_list: for dir_name in self.__scan_list: self.__delve(Path(dir_name)) self._src.commit() if self._error: dprint( 1, "\nDatabaseBinding::populate: Errors were encountered while populating database" ) print("Errors were encountered while populating database:") for error in self._error: print(error) self._error = [] if self.__dex: self.__load_index() if self._error: for error in self._error: print(error) self._error = []
def write_skeleton_index(path, filepath): '''Return string containing contains of skeleton index.xml''' dprint(3, "\nempty.write_skeleton_index") with open(path + filepath, "w") as f: f.write('''<?xml version="1.0" ?> <contents> </contents>''')
def __set_page(self): '''Dialogue for navigation by page number''' dprint(3, "\nPDFCanvas::__set_page") def __apply_page(canv, widge, dia): try: page = int(dia.get()) - 1 if (page > -1) and (page < len(self._src)): self.__goto(page) widge.destroy() except Exception as e: print(e) dialog_win = tkinter.Toplevel(self._frame) dialog_frame = tkinter.Frame(dialog_win) instructions = tkinter.Label(dialog_frame, text="Page #:") dialog = tkinter.Entry(dialog_frame, width=8) dialog.insert(0, str(self._scale + 1)) dialog_apply = tkinter.Button( dialog_frame, text="Apply", command=lambda: __apply_page(self, dialog_win, dialog)) dialog_win.bind("<Return>", lambda e: dialog_apply.invoke()) instructions.pack(side="left") dialog.pack(side="left") dialog_apply.pack(side="left") dialog_frame.pack()
def __make_note_ref(self, doc, docpath, bodycopy=False): '''Make note path: create and associate a note with current file and return it''' # this function is used in save-note methods: # we must have an associated note if we wish to save marks to memobook. # This function sets up the note so that we can perform the save. try: note = Note() note.title = os.path.basename(docpath) note.ID = docpath note.mime = NoteMime.TEXT docbody = doc.get_text(doc.get_start_iter(), doc.get_end_iter(), True) if bodycopy: note.body = docbody note.tags = Tag(parse.parse(docbody)) note.tags.silent = index_search(self.index, docpath, None) except Exception as e: dprint(1, "\nError: " + str(e)) return None else: self.__open_notes.append(note) return note
def pop(self): '''Pop item from stack''' dprint(3, "\nStack::pop") if self.__top == 0: return None self.__top -= 1 return self.__list.pop(self.__top)
def _set_zoom(self): '''Set zoom level for image in canvas''' dprint(3, "\nScrolledCanvas::_set_zoom") def __apply_zoom(canv, widge, dia): try: zoom = float(dia.get()) if (zoom > 0.) and (zoom <= 500.0): self._scale = zoom/100.0 self._resize() widge.destroy() except Exception as e: print(e) dialog_win = tkinter.Toplevel(self._frame) dialog_frame = tkinter.Frame(dialog_win) instructions = tkinter.Label(dialog_frame, text="Zoom (%):") dialog = tkinter.Entry(dialog_frame, width=8) dialog.insert(0, str(self._scale*100.0)) dialog_apply = tkinter.Button(dialog_frame, text="Apply", command=lambda:__apply_zoom(self, dialog_win, dialog)) dialog_win.bind("<Return>", lambda e:dialog_apply.invoke()) instructions.pack(side="left") dialog.pack(side="left") dialog_apply.pack(side="left") dialog_frame.pack()
def push(self, item): '''Push item onto stack''' dprint(3, "\nStack::push") if self.__top == self.__depth: raise Exception("Stack depth (" + str(self.__depth) + ") exceeded") self.__top += 1 self.__list.append(item)
def __str__(self): dprint(3, "\nNote::__str__") output = "" if self.body is not None: output += str(self.body) output += " " + str(self.tags) return output
def append(self, mtrl): '''Replace the silent tags for the associated file''' ### 'append' for Image is actually a 'replace' action dprint(3, "\nPDFPage::append") self.note.tags = note.Tag() for item in mtrl: self.note.tags.silent.append(str(item))
def save_note_as(self): '''Save-as functionality: save note to disk, save marks to memobook. Calls _process_save_target.''' dprint(3, "\n TkMemobook::save_note_as:: ") index = self.tabs.index("current") dprint(3, "Index is " + str(index) + ". ") save_nt = self.tabs.getnoteref(index) save_nt.body = self.tabs.getpageref(index).dump() if not save_nt.body: dprint(3, "No note body, returning.") return ret_targ = self._process_save_target(save_nt, saveas=True, callback=lambda c:self.tabs.tab(index,text=c)) if (ret_targ > 0): dprint(2, "Unable to process save target. Aborting.\n") messagebox.showinfo("Save target error", "Unable to process save target") return if (ret_targ < 0): return if self.data.save_note(save_nt): dprint(2, "Save error in data.save_note. Aborting.\n") messagebox.showinfo("Save error", "Unable to save note: " + str(self.data.get_last_error()) ) return self.tabs.clearchanges(index)
def save_note_nowrite(self, nt): '''Write note information to the source without writing note.body to memory''' dprint(3, "\nDatabaseBinding::save_note_nowrite") if nt is None: e = Exception("save_note_nowrite argument requires note object") self._error.append(e) return True if nt.mime is not NoteMime.TEXT: # silent fail: writing is not supported for images or pdfs return False ### compare/update marks ### self.__cursor.execute( '''select rowid,mark from bookmarks where file=?''', (nt.ID, )) db_hits = self.__cursor.fetchall() for item in db_hits: if not (item[1] in nt.tags): self.__cursor.execute( '''delete from bookmarks where rowid=?''', (item[0], )) self._src.commit() for tag in nt.tags: if not (tag in [item[1] for item in db_hits]): self.__cursor.execute( '''insert into bookmarks (mark,file,type) values (?,?,?)''', (tag, nt.ID, nt.mime.value)) self._src.commit() return False
def open_pop(self, hook_remove, hook_add, hook_apply): '''Manage bookmark sources: Major dialogue''' dprint(3, "\nTkMemobook::open_pop:: ") manager = Toplevel(self.root) manager_list = ListboxHV(manager, selectmode="multiple") manager_items = self.ctrl["db"]["scan"] if isinstance(manager_items, str): manager_items = [ manager_items ] else: manager_items = list(manager_items) manager_items.sort() for item in manager_items: manager_list.insert(END, item) manager_list.grid_columnconfigure(0, weight=1) manager_list.grid_rowconfigure(0, weight=1) manager_list.grid(sticky="nswe") buttons = Frame(manager) rembutt = Button(buttons, text="Remove", command=lambda: hook_remove(manager_list, manager_items) ) addbutt = Button(buttons, text="Add Other...", command=lambda: hook_add(manager, manager_list, manager_items) ) appbutt = Button(buttons, text="Apply", command=lambda: self.__get_busy_with(None, hook_apply, manager, manager_items) ) rembutt.grid(row=1, column=0) addbutt.grid(row=1, column=1) appbutt.grid(row=1, column=2) buttons.grid_columnconfigure(1, weight=1) buttons.grid_rowconfigure(1, weight=1) buttons.grid(stick="nswe") manager.grid_columnconfigure(0, weight=1) manager.grid_rowconfigure(0, weight=1)
def __setitem__(self, key, val): '''Assign value to key in Configuration. Create element, node if appropriate''' dprint(3, "\nConfiguration::__setitem__") target_nodes = [] for c in self.__src.childNodes: if c.nodeType is c.TEXT_NODE: continue else: if c.tagName == key: target_nodes.append(c) for target in target_nodes: self.__src.removeChild(target) if isinstance(val, Configuration): self.__src.appendChild(val.getnode()) dict.__setitem__(self, key, val) elif isinstance(val, tuple) or isinstance(val, list): for v in val: if isinstance(v, Configuration): self.__src.appendChild(v.getnode()) else: newn = self.__doc.createElement(key) newt = self.__doc.createTextNode(str(v)) newn.appendChild(newt) self.__src.appendChild(newn) dict.__setitem__(self, key, tuple(val)) else: newn = self.__doc.createElement(key) newt = self.__doc.createTextNode(str(val)) newn.appendChild(newt) self.__src.appendChild(newn) dict.__setitem__(self, key, val)
def togglewrap(self): '''Toggle word-wrap for current tab''' dprint(3, "\nBook::togglewrap") if len(self._pgs) == 1: self.togglewrapall() else: self._pgs[self.index("current")].toggle_wrap()
def _drag(self, x, y): '''Drag pdf page to new position using mouse''' dprint(3, "\nPDFCanvas::_drag") ### to meet inheritance needs, override __drag, call parent.__drag, then set self.__pos, then return ScrolledCanvas._drag(self, x, y) self.__pos[self.__current][0] = self.xview()[0] self.__pos[self.__current][1] = self.yview()[0]
def __open_mark(self): '''Open files by mark: Major dialogue for mark choices and logic''' ### despite using select, invoke, focus_set, event_generate, ### tk wouldn't set the OR radiobutton as default. ### So the following sub-function is a workaround to force the issue. def default_selection(var): var.set("or") def lookup(toc,gl,word): l = len(word) for i, item in enumerate(toc): if item.find(word,0,l) > -1: gl.see(i) break dprint(3, "\nTkMemobook::open_mark:: ") toc = [ item for item in self.data.toc() ] toc.sort(key=lambda x: x.lower()) getter = Toplevel(self.root) getter_list = ListboxHV(getter, selectmode="multiple") for item in toc: getter_list.insert(END, item) getter_list.pack(fill="both", expand="true") quick_var = StringVar() quick_var.trace_add("write", lambda i,j,k: lookup(toc,getter_list,quick_var.get())) quick_frame = Frame(getter) quick_label = Label(quick_frame, text="Quick lookup:") quick_enter = Entry(quick_frame, textvariable=quick_var, width=24) quick_label.pack(side="left") quick_enter.pack(side="left") button_frame = Frame(getter) logic_variable = StringVar(None, "or") radiobutt_OR = Radiobutton(button_frame, text="OR", variable=logic_variable, command=lambda: default_selection(logic_variable), # get tk to give default selection value="or") radiobutt_AND = Radiobutton(button_frame, text="AND", variable=logic_variable, value="and") retbutt = Button(button_frame, text="Apply", command=lambda: self.__open_mark_confirm(getter, [ toc[int(j)] for j in getter_list.curselection() ], logic_variable.get())) cancbutt = Button(button_frame, text="Cancel", command=lambda: getter.destroy()) radiobutt_OR.pack(side="left") radiobutt_AND.pack(side="left") cancbutt.pack(side="left") retbutt.pack(side="left") button_frame.pack(side="bottom") quick_frame.pack(side="bottom") radiobutt_OR.invoke()
def _drag_start(self,x,y): '''Mouse button down; begin drag operation; collect position information''' dprint(3, "\nScrolledCanvas::_drag_start") self._x = x self._y = y bounding = self.bbox(self._canvas_ref) self._inc_x = 1./float(bounding[2]-bounding[0]) self._inc_y = 1./float(bounding[3]-bounding[1])
def _on_frame_configure(self,eventflag): '''Reset the scroll region to encompass the inner frame''' dprint(3, "\nImageCanvas::_on_frame_configure") if eventflag and (self._auto_resize.get() == 1): self._scale = (self._frame._nametowidget(self._frame.winfo_parent()).winfo_width() - self._scroll_v.winfo_reqwidth()) / self.__sz[0] self._resize() ScrolledCanvas._on_frame_configure(self, eventflag)
def _process_save_target(self, note, saveas=False, callback=None): # select file name for saving dprint( 3, "\nMemobook::__process_save_target:: Note title is " + note.title + ", saveas=" + str(saveas) + ". ") return 0
def _resize(self): '''Re-process page image for current (x,y)-sizing and display it''' dprint(3, "\nPDFCanvas::_resize") self.__src_tk = ImageTk.PhotoImage(self._src[self.__current].resize( (int(self._scale * float(self.__sz[self.__current][0])), int(self._scale * float(self.__sz[self.__current][1]))))) self.itemconfig(self._canvas_ref, image=self.__src_tk) self._on_frame_configure(False)
def get_attr(self, key): '''Get attribute value associated with key''' dprint(3, "\nConfiguration::get_attr") attr_dict = dict(self.__attr.items()) if key in attr_dict.keys(): return attr_dict[key] else: return None
def set_changed(self, ch): '''Force changed state''' dprint(3, "\nTextPage::set_changed") if ch: self._state = State.EDIT else: self._state = State.NBLNK self.plate.edit_modified(ch)
def __open_pop_remove(self, manlist, manitems): '''Manage sources: remove directory.''' dprint(3, "\nTkMemobook::__open_pop_remove:: ") index_list = list(manlist.curselection()) index_list.sort(reverse=True) for index in index_list: manitems.pop(index) manlist.delete(index)
def __init__(self, *args, **kwargs): dprint(3, "\nNotebookCloseTab::__init") self.__set_style() kwargs["style"] = "NotebookCloseTab" ttk.Notebook.__init__(self, *args, **kwargs) self._active = None self.bind("<ButtonPress-1>", self.on_close_press, True) self.bind("<ButtonRelease-1>", self.on_close_release)
def on_close_press(self, event): '''Callback function for pressing close-button on tab''' dprint(3, "\nNotebookCloseTab::on_close_press") element = self.identify(event.x, event.y) if "close" in element: index = self.index("@%d,%d" % (event.x, event.y)) self.state(['pressed']) self._active = index