def create_widgets(self): try: clipboard = self.selection_get(selection="CLIPBOARD") except TclError: clipboard = '' log.debug(" detecting clipboard : %s", clipboard) if clipboard.startswith("http://"): self.url = ZEntry(self, label="Url : ", value=clipboard, width=50, state=DISABLED) self.title = ZEntry(self, label="Title : ", value=get_title(clipboard), width=50) else: self.url = ZEntry(self, label="Url : ", width=50) self.title = ZEntry(self, label="Title : ", width=50) self.url.add_listener("<Double-Button-1>", self.on_url_dbl_click) self.url.grid(row=1, column=1) self.title.grid(row=3, column=1) self.tags = ZEntry(self, label="Tags : ", width=50) self.tags.grid(row=5, column=1) self.tags.focus() box = Frame(self) w = Button(box, text="Save", command=self.save_post, width=10, default=ACTIVE) w.pack(side=LEFT, padx=5, pady=5) w = Button(box, text="Cancel", command=self.quit, width=10) w.pack(side=LEFT, padx=5, pady=5) self.winfo_toplevel().bind("<Return>", self.save_post) box.grid(row=7, column=1) self.tags_suggest = ZSuggestion(self.tags, multi=True)
def get_param(self, param_name): log.debug("getting %s...", param_name) param_value = self._fetchone('SELECT VALUE FROM PARAM WHERE KEY = ?', (param_name,)) if param_value: param_value = param_value[0] log.debug("getting %s...Ok(%s)", param_name, param_value) return param_value
def on_post_dbl_clicked(self, event): index = self.postList.get_current_index() post = self.posts[index] log.debug("selected post : %s", post) log.debug("goto url : %s", post[1]) webbrowser.open_new_tab(post[1])
def _fetchall(self, query, params=()): c = self.conn.cursor() try: log.debug(" executing query : %s", query) result = c.execute(query, params).fetchall() finally: c.close() return result
def clear_posts(self): log.debug("clearing posts...") c = self.conn.cursor() try: c.execute('DELETE FROM POST') self.conn.commit() finally: c.close() log.debug("clearing posts...Ok")
def clear_tags(self): log.debug("clearing tags...") c = self.conn.cursor() try: c.execute('DELETE FROM TAG') self.conn.commit() finally: c.close() log.debug("clearing tags...Ok")
def update_tags(self, tags): log.debug("updating tags... : %s", tags) c = self.conn.cursor() try: c.executemany('INSERT OR REPLACE INTO TAG(NAME, COUNT) VALUES(:tag, :count)', tags) self.conn.commit() finally: c.close() log.debug("updating tags...Ok")
def update_param(self, param_name, param_value): log.debug("updating %s with value %s...", param_name, param_value) c = self.conn.cursor() try: c.execute('INSERT OR REPLACE INTO PARAM(KEY, VALUE) VALUES(?, ?)', (param_name, param_value)) self.conn.commit() finally: c.close() log.debug("updating %s...Ok", param_name)
def accept(self): if not self.username.text(): QtGui.QMessageBox.warning(self, "Error", "Username not specified", "Ok") elif not self.password.text(): QtGui.QMessageBox.warning(self, "Error", "Password not specified", "Ok") else: config.username = str(self.username.text()) config.password = str(self.password.text()) log.debug(" login...username : %s, password : %s", config.username, config.password) QDialog.accept(self)
def find_tags(self, pattern, order): log.debug("getting tags...%s, order : %s", pattern, order) if order == ORDER_TAGS_COUNT: sort = "t.count desc" else: sort = "t.name" if pattern: result = self._fetchall('SELECT t.name FROM TAG t WHERE t.name LIKE ? ORDER BY ' + sort, (pattern + '%',)) else: result = self._fetchall('SELECT t.name FROM TAG t ORDER BY ' + sort) log.debug("getting tags...Ok(%s found)", len(result)) return result
def save(self): if self.config_dir: log.debug("saving config...") config_parser = ConfigParser.RawConfigParser() config_parser.add_section("main") if self.username: config_parser.set("main", "username", self.username) if self.password: config_parser.set("main", "password", self._crypt_password(self.password)) fo = open(os.path.join(self.config_dir, "config"), "w") config_parser.write(fo) fo.close() log.debug("saving config...Ok")
def find_posts_by_tag(self, tag, exact, order): log.debug("getting posts by tag %s, exact=%s...", tag, exact) if order == ORDER_POSTS_URL: sort = "p.url" elif order == ORDER_POSTS_TITLE: sort = "p.title" else: sort = "p.timestamp desc" if not exact: result = self._fetchall("""SELECT p.title, p.url, p.tag FROM POST p WHERE p.tag LIKE ? ORDER BY """ + sort, ("%" + tag + "%" ,)) else: result = self._fetchall("""SELECT p.title, p.url, p.tag FROM POST p WHERE p.tag LIKE ? OR p.tag LIKE ? OR p.tag LIKE ? ORDER BY """ + sort, ("% " + tag + " %" , tag + "%", "%" + tag)) log.debug("getting posts by tag...Ok(%s found)", len(result)) return result
def find_posts_by_pattern(self, pattern, order): log.debug("getting posts by pattern %s...", pattern) if order == ORDER_POSTS_URL: sort = "p.url" elif order == ORDER_POSTS_TITLE: sort = "p.title" else: sort = "p.timestamp desc" if pattern: any_pattern = '%' + pattern + '%' result = self._fetchall("""SELECT p.title, p.url, p.tag FROM POST p WHERE p.tag LIKE ? OR p.title LIKE ? or p.url LIKE ? ORDER BY """ + sort, (any_pattern, any_pattern, any_pattern)) else: result = self._fetchall("""SELECT p.title, p.url, p.tag FROM POST p ORDER BY """ + sort) log.debug("getting posts by pattern...Ok(%s found)", len(result)) return result
def __init__(self, parent=None): """ Constructor """ QMainWindow.__init__(self, parent) self.setupUi(self) if not config.username or not config.password: login = Login(self) login.setModal(True) login.show() self.setWindowTitle("Delicious bookmarks : %s : save a bookmark" % config.username) clipboard = unicode(QApplication.clipboard().text()) log.debug(" detecting clipboard : %s", clipboard) if clipboard.startswith("http://"): self.url.setText(clipboard) self.url.setDisabled(True) self.show_url.setEnabled(True) self.title.setText(get_title(clipboard)) self.tags.setFocus()
def save_post(self, post): log.debug("saving post...%s", post) self._update_tags_for_post(post['tag'].split()) c = self.conn.cursor() try: c.execute("""INSERT OR REPLACE INTO POST(URL, TITLE, NOTES, TAG, HASH, TIMESTAMP) VALUES(:href, :description, :extended, :tag, :hash, :time)""", post) self.conn.commit() finally: c.close() log.debug("saving post...Ok")
def update_posts(self, posts): log.debug("updating posts... : %s", posts) c = self.conn.cursor() try: c.executemany("""INSERT OR REPLACE INTO POST(URL, TITLE, NOTES, TAG, HASH, META, TIMESTAMP) VALUES(:href, :description, :extended, :tag, :hash, :meta, :time)""", posts) self.conn.commit() finally: c.close() log.debug("updating posts...Ok")
def _create_db(self): log.debug(" creating new database...") c = self.conn.cursor() try: c.executescript(""" CREATE TABLE TAG( NAME TEXT, COUNT INTEGER, PRIMARY KEY(NAME) ); CREATE TABLE POST( URL TEXT, TITLE TEXT, NOTES TEXT, TAG TEXT, HASH TEXT, META TEXT, TIMESTAMP TEXT, PRIMARY KEY(URL), FOREIGN KEY (TAG) REFERENCES TAG(NAME) ON DELETE CASCADE ); CREATE TABLE PARAM( KEY, VALUE, PRIMARY KEY(KEY) ); INSERT INTO PARAM(KEY, VALUE) VALUES ( 'cache_version', '0.1' ); """) finally: c.close() log.debug(" creating new database...Ok")
def _update_tags_for_post(self, tags): log.debug("updating tags for post...%s", tags) c = self.conn.cursor() try: for tag in tags: count = c.execute('SELECT COUNT FROM TAG WHERE NAME = ?', (tag,)).fetchone() if count: count = count[0] + 1 log.debug(" tag %s found -> increasing count to %s", tag, count) else: log.debug(" tag %s not found -> count=0", tag) count = 0 c.execute('INSERT OR REPLACE INTO TAG(NAME, COUNT) VALUES(?, ?)', (tag, count)) self.conn.commit() finally: c.close() log.debug("updating tags for post...Ok")
def __init__(self): log.debug("opening cache...") if not config.username: raise ValueError("username not specified") log.debug(" for delicious user : %s", config.username) self.dao = DAO(os.path.join(config.config_dir, "%s.cache" % config.username)) pydelicious.DEBUG = 0 pydelicious.Waiter = _FileWaiter(DLCS_WAIT_TIME, os.path.join(config.config_dir, "pydelicious.stamp")) self.api = DeliciousAPI(config.username, config.password) log.debug("opening cache...Ok")
def __init__(self, database): log.debug(" opening database...%s", database) self.conn = sqlite3.connect(database) c = self.conn.cursor() try: cache_version = c.execute('SELECT VALUE FROM PARAM WHERE KEY = ?', ("cache_version",)).fetchone()[0] log.debug(" database found, cache version : %s", cache_version) except sqlite3.OperationalError: self._create_db() finally: c.close() log.debug(" opening database...Ok")
def __init__(self): log.debug("loading config...") self.config_dir = APP_HOME_DIR if not os.path.exists(self.config_dir) or not os.path.isdir(self.config_dir): os.mkdir(self.config_dir) self.username = None self.password = None if os.path.exists(os.path.join(self.config_dir, "config")): config_parser = ConfigParser.RawConfigParser() config_parser.read(os.path.join(self.config_dir, "config")) if config_parser.has_option("main", "username"): self.username = config_parser.get("main", "username") log.debug(" loading username from config : %s", self.username) if config_parser.has_option("main", "password"): self.password = self._decrypt_password(config_parser.get("main", "password")) log.debug(" loading password from config : %s", self.password) log.debug("loading config...Ok")
def refresh(self): last_sync = self.dao.get_last_sync() if not last_sync or last_sync and time.time() - float(last_sync) > sync_timeout: if last_sync and time.time() - float(last_sync) > sync_timeout: log.debug(" sync timeout exceeded : %s", time.time() - float(last_sync)) last_update_in_cache = self.dao.get_last_update() ttt = self.api.posts_update() last_update = time.strftime("%a, %d %b %Y %H:%M:%S +0000", ttt["update"]["time"]) log.debug(" last_update : %s, in cache : %s", last_update, last_update_in_cache) self._update_last_sync() if(last_update != last_update_in_cache): log.debug("refreshing cache...") tags = self.api.tags_get()['tags'] posts = self.api.posts_all()['posts'] self.dao.clear_posts() self.dao.clear_tags() self.dao.update_tags(tags) self.dao.update_posts(posts) self.dao.update_last_update(last_update) log.debug("refreshing cache...Ok") return True return False
def on_postList_itemDoubleClicked(self, item): index = self.postList.currentRow() post = self.posts[index] log.debug("selected post : %s", post) log.debug("goto url : %s", post[1]) webbrowser.open_new_tab(post[1])
def apply(self): config.username = self.username.value() config.password = self.password.value() log.debug(" login...username : %s, password : %s", config.username, config.password)
def _import_qt(self): import fastlink.qt.list as list import fastlink.qt.detail as detail log.debug("QT4 UI loaded") return (list, detail)
def save_post(self, url, title, tags): log.debug("saving post...") try: self.api.posts_add(url=url, description=title, tags=tags) except DeliciousItemExistsError, url: raise SaveException('Item already exists : %s' % url) except DeliciousError, message: raise SaveException(message) last_added = self.api.posts_recent(count=1)['posts'][0] self.dao.save_post(last_added) self._update_last_sync() ttt = self.api.posts_update() last_update = time.strftime("%a, %d %b %Y %H:%M:%S +0000", ttt["update"]["time"]) self.dao.update_last_update(last_update) log.debug("saving post...Ok") class SaveException(Exception): pass class _FileWaiter: """Waiter makes sure a certain amount of time passes between successive calls of `Waiter()`. Some attributes: :last: time of last call :wait: the minimum time needed between calls :waited: the number of calls throttled pydelicious.Waiter is an instance created when the module is loaded. """
def __del__(self): log.debug(" closing database...") self.conn.close() log.debug(" closing database...Ok")
def save_post(self, url, title, tags): log.debug("saving post...") try: self.api.posts_add(url=url, description=title, tags=tags) except DeliciousItemExistsError, url: raise SaveException('Item already exists : %s' % url)
def _import_tkinter(self): import fastlink.tkinter.list as list import fastlink.tkinter.detail as detail log.debug("Tkinter UI loaded") return (list, detail)