コード例 #1
0
ファイル: detail.py プロジェクト: gkonst/fastlink
    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)
コード例 #2
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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
コード例 #3
0
ファイル: list.py プロジェクト: gkonst/fastlink
 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]) 
     
コード例 #4
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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   
コード例 #5
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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")
コード例 #6
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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")
コード例 #7
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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")
コード例 #8
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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)
コード例 #9
0
ファイル: login.py プロジェクト: gkonst/fastlink
 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)
コード例 #10
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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
コード例 #11
0
ファイル: config.py プロジェクト: gkonst/fastlink
 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")
コード例 #12
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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
コード例 #13
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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
コード例 #14
0
ファイル: detail.py プロジェクト: gkonst/fastlink
 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()
コード例 #15
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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")
コード例 #16
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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")
コード例 #17
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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")
コード例 #18
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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")
コード例 #19
0
ファイル: cache.py プロジェクト: gkonst/fastlink
 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")
コード例 #20
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 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")
コード例 #21
0
ファイル: config.py プロジェクト: gkonst/fastlink
    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")
コード例 #22
0
ファイル: cache.py プロジェクト: gkonst/fastlink
 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
コード例 #23
0
ファイル: list.py プロジェクト: gkonst/fastlink
 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])
コード例 #24
0
ファイル: login.py プロジェクト: gkonst/fastlink
 def apply(self):
     config.username = self.username.value()
     config.password = self.password.value()
     log.debug(" login...username : %s, password : %s", config.username, config.password)
コード例 #25
0
ファイル: main.py プロジェクト: gkonst/fastlink
 def _import_qt(self):
     import fastlink.qt.list as list
     import fastlink.qt.detail as detail
     log.debug("QT4 UI loaded")
     return (list, detail)
コード例 #26
0
ファイル: cache.py プロジェクト: gkonst/fastlink
    
    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.
    """
コード例 #27
0
ファイル: dao.py プロジェクト: gkonst/fastlink
 def __del__(self):
     log.debug(" closing database...")
     self.conn.close()
     log.debug(" closing database...Ok")
コード例 #28
0
ファイル: cache.py プロジェクト: gkonst/fastlink
 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)
コード例 #29
0
ファイル: main.py プロジェクト: gkonst/fastlink
 def _import_tkinter(self):
     import fastlink.tkinter.list as list
     import fastlink.tkinter.detail as detail
     log.debug("Tkinter UI loaded")         
     return (list, detail)