コード例 #1
0
    def OnDelete(self, evt):
        PDEBUG('NOT IMPLEMENT.')
        if self._clip is None:
            PDEBUG('oops')

        self.dropClip(self._clip)
        self._clip = None
コード例 #2
0
 def OnClipSelected(self, event):
     self._cur_item = event.GetItem()
     id = self._cur_item.GetData()
     txt = self._cur_item.GetText()
     PDEBUG('ID: %d -- %s', id, txt)
     self._clip = self.model.getClipById(id)
     PDEBUG('CLIP: %s', self._clip)
     pass
コード例 #3
0
    def OnSearch(self, evt):
        PDEBUG('ENTER')
        target = self.search.GetValue()
        args = target.split()
        if not args:
            PDEBUG('empty search target...')
            return

        it = self.model.searchClips(args)
        self.showClips('Result for "%s"' % target, it)
        pass
コード例 #4
0
    def dropClip(self, clip):
        """Move specified clip into blacklist.
        """
        SQL = ''' insert into blacklist select * from clippings where ID = %d''' % clip.id
        PDEBUG('SQL: %s', SQL)
        self.__execute__(SQL)

        SQL = '''delete from clippings where ID = %d''' % clip.id
        PDEBUG('SQL: %s', SQL)
        self.__execute__(SQL)

        pass
コード例 #5
0
    def OnRightClickClips(self, evt):
        """
        """
        PDEBUG('enter: %s', evt)

        # only do this part the first time so the events are only bound once
        if not hasattr(self, "popupID1"):
            self.popupID1 = wx.NewIdRef()
            self.popupID2 = wx.NewIdRef()
            self.popupID3 = wx.NewIdRef()
            self.popupID5 = wx.NewIdRef()
            self.popupID6 = wx.NewIdRef()

            self.Bind(wx.EVT_MENU, self.OnNew, id=self.popupID1)
            self.Bind(wx.EVT_MENU, self.OnEdit, id=self.popupID2)
            self.Bind(wx.EVT_MENU, self.OnDelete, id=self.popupID3)

        # make a menu
        menu = wx.Menu()
        # add some items
        menu.Append(self.popupID1, "New Clip")
        menu.Append(self.popupID2, "Edit Selected")
        menu.Append(self.popupID3, "Delete Selected")

        # Popup the menu.  If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.PopupMenu(menu)

        menu.Destroy()

        pass
コード例 #6
0
 def OnBookSelected(self, event):
     """
     """
     self._book_id = event.GetItem().GetData()
     PDEBUG('BOOK_ID: %d', self._book_id)
     self.showClipsOfBook()
     self._clip = None
     pass
コード例 #7
0
    def getClipsByBookId(self, id):
        sql = '''
        select clippings.id, books.name , pos, content from clippings
inner join books on clippings.book = books.id and books.id = %d
        ''' % id
        PDEBUG('SQL: %s', sql)
        cursor = self.__execute__(sql)
        return ClipIter(cursor)
コード例 #8
0
    def OnEdit(self, evt):
        """
        """
        PDEBUG('NOT IMPLEMENT.')
        self.detailPanel.Show(True)
        self.detailPanel.OnNew(evt)

        pass
コード例 #9
0
    def cleanUpBooks(self, callback=None):
        """
        """
        num = 0
        iter = self.getBooks()
        while iter.next():
            num += self.cleanUpBook(iter.name, callback)

        PDEBUG('Total %d records cleaned up.', num)
        return num
コード例 #10
0
 def refreshContents(self):
     """
     """
     self.fillBooks()
     total_books = self.book_list.GetItemCount()
     PDEBUG('BOOK_ID: %s, total: %s', self._book_id, total_books)
     if self._book_id is None:
         self.book_list.Select(0)
     elif self._book_id >= total_books:
         self.book_list.Select(total_books - 1)
     else:
         self.book_list.Select(self._book_id)
     pass
コード例 #11
0
    def UpdateContent(self, clip):
        self._clip = clip
        PDEBUG('POS: %s, DATE: %s', clip.pos, clip.date)
        self.editor.SetValue(clip.content)

        html = self.md_converter.getHtmlPage(clip.content)
        self.browser.SetPage(html, '')

        self.st_type.SetLabel(clip.typ)
        self.st_date.SetLabel(clip.date)
        self.st_location.SetLabel(clip.pos)

        self.Layout()
        self.sizer.Fit(self)

        pass
コード例 #12
0
    def dropClip(self, clip):
        idx = self._cur_item.GetId()
        PDEBUG('DELETE IDX: %d', idx)
        self.model.dropClip(clip)
        self.clip_list.DeleteItem(idx)
        if idx < self.clip_list.GetItemCount():
            self.clip_list.Select(idx)

        self.Refresh()
        self.clip_list.SetFocus()

        # If there are no clips left for current book, ask if we should remove
        # current book...
        if self.clip_list.GetItemCount() == 0:
            self.refreshContents()
        pass
コード例 #13
0
    def __execute__(self, sql, commit=True):
        """
        Execute sql, and commit commit if asked.
        """
        cursor = None
        PDEBUG('Executing SQL: %s' % sql)
        try:
            cursor = self.conn.execute(sql)
        except sqlite3.IntegrityError as e:
            print('DUP: %s' % e)
        except Exception as e:
            print('FATAL: %s -- %s' % (e, sql))
        else:
            if commit:
                self.conn.commit()

        return cursor
コード例 #14
0
    def __cleanClipsById__(self, ids):
        if ids is None or len(ids) == 0:
            return

        PDEBUG('ids: %s', ids)
        id_strs = []
        for id in ids:
            id_strs.append("'%d'" % id)

        sql = '''insert into blacklist select * from clippings where id in (%s)''' % ", ".join(
            id_strs)
        self.__execute__(sql, False)

        sql = '''delete from clippings where id in (%s)''' % ", ".join(id_strs)

        self.__execute__(sql, True)
        pass
コード例 #15
0
    def showClipsOfBook(self):
        """Show clips of book.
        """

        PDEBUG('BOOK_ID: %d', self._book_id)

        book_iter = self.model.getBookById(self._book_id)
        if not book_iter.next():
            print('Failed to load book info, book_id: %d' % (self._book_id))
            sys.exit(1)

        book = book_iter.name
        author = book_iter.author

        iter = self.model.getClipsByBookId(self._book_id)
        self.showClips(book, author, iter)
        pass
コード例 #16
0
def getDBPath(readonly=False):
    """Return path of database.
    """
    path = None
    if sys.platform == 'darwin':
        path = '%s/Library/Application Support/Klip/' % os.getenv("HOME")
    else:
        home = os.getenv('HOME')
        if home is None:
            raise Exception("Platform %s not support." % sys.platform)
        else:
            path = '%s/.config/klip/' % (os.getenv('HOME'))

    if not os.path.exists(path):
        os.mkdir(path)
    path += 'klip.db'

    if readonly:
        path += '?mode = ro'

    PDEBUG('DB_PATH: %s', path)
    return path
コード例 #17
0
def processQuery(j):
    """
    """
    PDEBUG('Query: %s', j)

    r = {}
    cmd = j.get('cmd', None)
    if cmd is None:
        r['err'] = 'No command is specified.'
    elif cmd == 'get-books':
        r = getBooks()
        pass
    elif cmd == 'get-clips':
        book_id = j.get('book-id', None)
        if book_id is None:
            r['err'] = 'Book id not specified.'
        else:
            r = getClips(book_id)
        pass
    else:
        r['err'] = 'Unsupported command: %s' % cmd

    return json.dumps(r)
    pass
コード例 #18
0
    def loadFile(self, path):
        """Load clippings from file.

        Arguments:

        - `path`: path of file
        """
        books_added = 0
        records_added = 0
        books_to_clean = set()

        PDEBUG('Loading from file: %s', path)

        with open(path) as fd:
            while True:
                content = fd.read(PAGE_SIZE)
                if content is None:
                    break
                if len(content) == 0:
                    break
                pos = 0
                while True:
                    m = R_MATCH_ENTRY.search(content, pos)
                    if m is None:
                        new_content = fd.read(PAGE_SIZE)
                        if len(new_content) == 0:
                            print('New books: %d, new records: %d' %
                                  (books_added, records_added))
                            print('EOF reached...')
                            return (books_added, records_added)
                        else:
                            content = content[pos:] + new_content
                            pos = 0
                    else:
                        (book, author) = process_book_name(m.group(1))
                        book = handleStr(book)
                        author = handleStr(author)
                        page = handleStr(m.group(2).strip())
                        time = handleStr(m.group(3).strip())
                        mark = handleStr(m.group(4).strip())
                        pos = m.end(0)

                        bts = book.encode()
                        if bts[0:3] == codecs.BOM_UTF8:
                            PDEBUG('oops: ')
                            PDEBUG('%X-%X-%X', bts[0], bts[1], bts[2])

                            sys.exit()

                        if len(mark) == 0:
                            continue

                        res = R_MATCH_POS.match(page)
                        if res is None:
                            res = R_MATCH_PAGE.match(page)
                            if res is None:
                                PDEBUG('oops: %s -- %s', book, page)
                                sys.exit(1)

                        pos_str = res.group(1)
                        typ_str = res.group(2)

                        (new_book, new_clip) = \
                            self.__addEntry__(
                                book, author, pos_str, typ_str, time, mark)

                        if new_book:
                            books_added += 1

                        if new_clip:
                            books_to_clean.add(book)
                            records_added += 1

        if books_to_clean:
            PDEBUG('Books to clean: %s', books_to_clean)

        for book in books_to_clean:
            self.cleanUpBook(book)

        print('Total books added: %d, clips added:%d' %
              (books_added, records_added))

        return (books_added, records_added)
コード例 #19
0
    def cleanUpBook(self, book, callback=None):
        """Clean up book
        """
        PDEBUG('Cleaning book: %s', book)
        clips = {}  # pos - (id, content)
        dup_id = []  # array of cons, where cdr should be dropped...

        iter = self.getClipsByBookName(book)
        total_clips = 0
        while iter.next():
            total_clips += 1

            id = iter.id
            pos = iter.pos

            # simply ignore it if '-' not in pos.
            if '-' not in pos:
                continue

            if pos.startswith('-'):
                continue

            pos_array = []
            for p in pos.split('-'):
                pos_array.append(int(p))

            # Find nearest position, for now, linear search, change to binary
            # search later....

            action = Action.APPEND  # 0: append, 1: use new, 2: use old
            key_new = Range(pos_array[0], pos_array[1])

            for key in clips.keys():
                if key.covers(key_new):
                    action = Action.USE_OLD
                    break
                elif key_new.covers(key):
                    action = Action.USE_NEW
                    break
                pass

            if action == Action.APPEND:
                clips[key_new] = id
            elif action == Action.USE_NEW:
                old_id = clips.pop(key)
                dup_id.append((id, old_id))
                clips[key_new] = id
            elif action == Action.USE_OLD:
                old_id = clips[key]
                dup_id.append((old_id, id))
            else:
                print('Should not be here: %s' % (action))

        ret = 0
        if dup_id:
            do_remove = True
            if callback:
                to_be_remove = []
                for (keep, drop) in dup_id:
                    clip_keep = self.getClipById(keep)
                    clip_drop = self.getClipById(drop)

                    to_be_remove.append((clip_keep.content, clip_drop.content))

                do_remove = callback(book, to_be_remove)

            if do_remove:
                ids = []
                for id in dup_id:
                    ids.append(id[1])

                self.__cleanClipsById__(ids)
                ret += len(dup_id)

        return ret
コード例 #20
0
    def __init__(self, model_):
        """
        """
        self.model = model_
        self._book = None
        self._book_id = None
        self._search_target = None

        super(KlipFrame, self).__init__(None,
                                        size=wx.Size(1200, 760),
                                        title='Klip',
                                        name='Klip')
        # ensure the parent's __init__ is called

        icon = icons.klip.GetIcon()
        self.SetIcon(icon)

        self.tb = TaskBarIcon(wx.adv.TBI_DOCK)
        self.tb.SetIcon(icon)

        sp = wx.SplitterWindow(self, style=wx.SP_BORDER | wx.SP_3DBORDER)
        sp.SetSplitMode(wx.SPLIT_VERTICAL)
        sp.SetMinimumPaneSize(50)
        self.detailPanel = KlipDetailWindow(self)
        self.SetMinSize(wx.Size(800, 600))

        # create a panel in the frame
        pnl_books = wx.Panel(sp)
        pnl_clips = wx.Panel(sp)
        pnl_clips.SetBackgroundColour(wx.Colour(255, 255, 255))

        sp.SplitVertically(pnl_books, pnl_clips,
                           int(round(self.GetSize().GetWidth() * 0.3)))

        sizer = wx.BoxSizer(wx.VERTICAL)

        self.search = wx.SearchCtrl(pnl_books,
                                    size=(200, -1),
                                    style=wx.TE_PROCESS_ENTER)
        self.search.ShowSearchButton(True)
        self.search.ShowCancelButton(True)

        self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.OnSearch, self.search)
        self.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN, self.OnCancelSearch,
                  self.search)

        sizer.Add(self.search, 0, wx.EXPAND, 0)

        self.book_list = KlipListCtrl(pnl_books,
                                      wx.ID_ANY,
                                      style=wx.LC_REPORT | wx.LC_NO_HEADER
                                      | wx.LC_HRULES | wx.LC_SINGLE_SEL)

        font = self.book_list.GetFont()
        font.PointSize += 5
        # font = font.Bold()
        self.book_list.SetFont(font)
        self.book_list.SetForegroundColour(wx.Colour(0x43, 0x43, 0x43))
        self.book_list.ClearAll()
        self.book_list.SetBackgroundColour(wx.Colour(0xf6, 0xf6, 0xf6))

        self.bl_width = self.book_list.GetSize().GetWidth() * 0.5

        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnBookSelected,
                  self.book_list)

        self._total_books = wx.StaticText(pnl_books,
                                          label="BOOKS (%d)" % 0,
                                          pos=(25, 25))

        sizer.Add(self._total_books, 0, wx.LEFT, 0)

        sizer.Add(self.book_list, 1, wx.EXPAND | wx.ALL, 0)

        pnl_books.SetSizer(sizer)

        # init right panel, show clippings.
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.book_title = wx.StaticText(pnl_clips, label='')

        font = self.book_title.GetFont()
        font.PointSize += 10
        font.Bold()
        self.book_title.SetFont(font)
        self.book_title.SetForegroundColour(wx.Colour(0x25, 0x91, 0xff))
        sizer.Add(self.book_title, 0, wx.EXPAND, 10)

        self.book_info = wx.StaticText(pnl_clips, label='')

        font = self.book_info.GetFont()
        font.PointSize += 5
        font.Bold()
        self.book_info.SetFont(font)
        # self.book_info.SetForegroundColour(wx.Colour(0x25, 0x91, 0xff))

        sizer.Add(self.book_info, 0, wx.EXPAND, 10)

        self.clip_list = KlipListCtrl(pnl_clips,
                                      wx.ID_ANY,
                                      style=wx.LC_REPORT | wx.LC_NO_HEADER
                                      | wx.LC_HRULES | wx.LC_SINGLE_SEL)

        self.clip_list.InsertColumn(0, "Clip")

        # books = self.fillBooks()

        sizer.Add(self.clip_list, 1, wx.EXPAND | wx.ALL, 0)

        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.showClipDetail,
                  self.clip_list)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnClipSelected,
                  self.clip_list)

        pnl_clips.SetSizer(sizer)

        font = self.clip_list.GetFont()
        font.PointSize += 3
        self.clip_list.SetFont(font)

        width = self.clip_list.GetSize().GetWidth() * 0.5
        PDEBUG('Update Column Width: %d' % width)
        self.clip_list.SetColumnWidth(0, width)

        self.clip_list.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK,
                            self.OnRightClickClips)

        self.refreshContents()

        # create a menu bar
        self.makeMenuBar()
コード例 #21
0
def startServer(model_):
    """
    """
    global model
    model = model_

    HOST, PORT = "localhost", 9999

    with socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) as s:
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
                     struct.pack('ii', 0, 0))

        s.bind((HOST, PORT))
        s.listen(1)
        PDEBUG('Listening on %s:%d', HOST, PORT)
        while True:
            conn, addr = s.accept()
            with conn:
                PDEBUG('Connected by: %s', addr)
                data = ''

                while True:

                    if len(data) < 4:  # header length
                        # Read Length, 4 bytes
                        data = conn.recv(1024)
                        if not data:
                            PDEBUG('No data, break...')
                            break

                    PDEBUG('LEN: %d' % (len(data)))
                    PDEBUG('DATA: %s', data)

                    # Now parse header...
                    total = len(data)
                    l = struct.unpack_from('!I', data, 0)[0]
                    total -= 4
                    PDEBUG('L: %d, total: %d' % (l, total))

                    body = data[4:]
                    PDEBUG('BODY: %s', body)
                    if total < l:
                        expected = l - total
                        while expected > 0:
                            PDEBUG('1: Needs to read %d bytes...', expected)
                            data = conn.recv(1024)
                            PDEBUG('Got data: %s, len: %d', data, len(data))
                            to_copy = min(len(data), expected)
                            expected -= to_copy
                            body += data[:to_copy]
                            PDEBUG('2: Needs to read %d bytes...', expected)

                            if expected == 0:
                                data = data[to_copy:]
                    else:
                        data = data[4 + l:]

                    # Now we should have a complete json string...
                    PDEBUG('BODY: %s', body)
                    j = json.loads(body)

                    PDEBUG('GOT: %s' % (j))

                    ret = processQuery(j)
                    PDEBUG('RET: %s' % (ret))

                    ret_txt = ret.encode()
                    rsp = struct.pack('!I', len(ret_txt))
                    rsp += ret_txt

                    conn.sendall(rsp)
コード例 #22
0
 def OnCancelSearch(self, evt):
     PDEBUG('ENTER')
     self.showClipsOfBook()