Beispiel #1
0
    def save_threaded(self):
        for k, n in self.notes.items():
            savedate = float(n.get('savedate'))
            if float(n.get('modifydate')) > savedate or \
               float(n.get('syncdate')) > savedate:
                cn = copy.deepcopy(n)
                # put it on my queue as a save
                o = utils.KeyValueObject(action=ACTION_SAVE, key=k, note=cn)
                self.q_save.put(o)

        # in this same call, we process stuff that might have been put on the result queue
        nsaved = 0
        something_in_queue = True
        while something_in_queue:
            try:
                o = self.q_save_res.get_nowait()

            except Empty:
                something_in_queue = False

            else:
                # o (.action, .key, .note) is something that was written to disk
                # we only record the savedate.
                self.notes[o.key]['savedate'] = o.note['savedate']
                self.notify_observers(
                    'change:note-status',
                    utils.KeyValueObject(what='savedate', key=o.key))
                nsaved += 1

        return nsaved
Beispiel #2
0
    def filter_notes(self, search_string=None):
        """Return list of notes filtered with search_string, 
        a regular expression, each a tuple with (local_key, note). 
        """

        if search_string:
            try:
                if self.config.case_sensitive == 0:
                    sspat = re.compile(search_string, re.I)
                else:
                    sspat = re.compile(search_string)
            except re.error:
                sspat = None

        else:
            sspat = None

        filtered_notes = []
        for k in self.notes:
            n = self.notes[k]
            c = n.get('content')
            if self.config.search_tags == 1:
                t = n.get('tags')
                if not n.get('deleted') and sspat:
                    if filter(sspat.search, t):
                        # we have to store our local key also
                        filtered_notes.append(
                            utils.KeyValueObject(key=k, note=n, tagfound=1))
                    elif sspat.search(c):
                        # we have to store our local key also
                        filtered_notes.append(
                            utils.KeyValueObject(key=k, note=n, tagfound=0))
                elif not n.get('deleted') and not sspat:
                    # we have to store our local key also
                    filtered_notes.append(
                        utils.KeyValueObject(key=k, note=n, tagfound=0))
            else:
                if not n.get('deleted') and (not sspat or sspat.search(c)):
                    # we have to store our local key also
                    filtered_notes.append(
                        utils.KeyValueObject(key=k, note=n, tagfound=0))

        if self.config.sort_mode == 0:
            if self.config.pinned_ontop == 0:
                # sort alphabetically on title
                filtered_notes.sort(key=lambda o: utils.get_note_title(o.note))
            else:
                filtered_notes.sort(utils.sort_by_title_pinned)

        else:
            if self.config.pinned_ontop == 0:
                # last modified on top
                filtered_notes.sort(
                    key=lambda o: -float(o.note.get('modifydate', 0)))
            else:
                filtered_notes.sort(utils.sort_by_modify_date_pinned,
                                    reverse=True)

        return filtered_notes
Beispiel #3
0
 def wrapper():
     try:
         sync_from_server_errors = self.sync_full_unthreaded()
         self.notify_observers(
             'complete:sync_full',
             utils.KeyValueObject(errors=sync_from_server_errors))
     except Exception as e:
         self.notify_observers(
             'error:sync_full',
             utils.KeyValueObject(error=e, exc_info=sys.exc_info()))
         raise
Beispiel #4
0
 def cmd_root_new(self, evt=None):
     # this'll get caught by a controller event handler
     self.notify_observers(
         'create:note',
         utils.KeyValueObject(title=self.get_search_entry_text()))
     # the note will be created synchronously, so we can focus the text area already
     self.text_note.focus()
Beispiel #5
0
    def filter_notes(self, search_string=None):
        """Return list of notes filtered with search_string, 
        a regular expression, each a tuple with (local_key, note). 
        """

        if search_string:
            try:
                sspat = re.compile(search_string)
            except re.error:
                sspat = None

        else:
            sspat = None

        filtered_notes = []
        for k in self.notes:
            n = self.notes[k]
            c = n.get('content')
            if not n.get('deleted') and (not sspat or sspat.search(c)):
                # we have to store our local key also
                filtered_notes.append(utils.KeyValueObject(key=k, note=n))

        if self.config.sort_mode == 0:
            # sort alphabetically on title
            filtered_notes.sort(key=lambda o: utils.get_note_title(o.note))

        else:
            # last modified on top
            filtered_notes.sort(
                key=lambda o: -float(o.note.get('modifydate', 0)))

        return filtered_notes
Beispiel #6
0
 def delete_note_tag(self, key, tag):
     note = self.notes[key]
     note_tags = note.get('tags')
     note_tags.remove(tag)
     note['tags'] = note_tags
     note['modifydate'] = time.time()
     self.notify_observers('change:note-status',
                           utils.KeyValueObject(what='modifydate', key=key))
Beispiel #7
0
 def set_note_content(self, key, content):
     n = self.notes[key]
     old_content = n.get('content')
     if content != old_content:
         n['content'] = content
         n['modifydate'] = time.time()
         self.notify_observers(
             'change:note-status',
             utils.KeyValueObject(what='modifydate', key=key))
Beispiel #8
0
 def add_note_tags(self, key, comma_seperated_tags):
     note = self.notes[key]
     note_tags = note.get('tags')
     new_tags = utils.sanitise_tags(comma_seperated_tags)
     note_tags.extend(new_tags)
     note['tags'] = note_tags
     note['modifydate'] = time.time()
     self.notify_observers('change:note-status',
                           utils.KeyValueObject(what='modifydate', key=key))
Beispiel #9
0
 def set_note_tags(self, key, tags):
     n = self.notes[key]
     old_tags = n.get('tags')
     tags = utils.sanitise_tags(tags)
     if tags != old_tags:
         n['tags'] = tags
         n['modifydate'] = time.time()
         self.notify_observers(
             'change:note-status',
             utils.KeyValueObject(what='modifydate', key=key))
Beispiel #10
0
    def handler_search_enter(self, evt):
        # user has pressed enter whilst searching
        # 1. if a note is selected, focus that
        # 2. if nothing is selected, create a new note with this title

        if self.get_selected_idx() >= 0:
            self.text_note.focus()
            
        else:
            # nothing selected
            self.notify_observers('create:note', utils.KeyValueObject(title=self.get_search_entry_text()))
            # the note will be created synchronously, so we can focus the text area already
            self.text_note.focus()
Beispiel #11
0
    def set_notes(self, notes):
        # clear the notes list
        self.notes_list.clear()
        taglist = []
        
        for o in notes:
            tags = o.note.get('tags')
            if tags:
                taglist += tags
            self.notes_list.append(o.note, utils.KeyValueObject(tagfound=o.tagfound))

        taglist = list(set(self.taglist + taglist))
        if len(taglist) > len(self.taglist):
            self.taglist=taglist
            self.search_entry.set_completion_list(self.taglist)
Beispiel #12
0
    def get_note_status(self, key):
        n = self.notes[key]
        o = utils.KeyValueObject(saved=False, synced=False, modified=False)
        modifydate = float(n['modifydate'])
        savedate = float(n['savedate'])

        if savedate > modifydate:
            o.saved = True
        else:
            o.modified = True

        if float(n['syncdate']) > modifydate:
            o.synced = True

        return o
Beispiel #13
0
    def set_note_pinned(self, key, pinned):
        n = self.notes[key]
        old_pinned = utils.note_pinned(n)
        if pinned != old_pinned:
            if 'systemtags' not in n:
                n['systemtags'] = []

            systemtags = n['systemtags']

            if pinned:
                # which by definition means that it was NOT pinned
                systemtags.append('pinned')

            else:
                systemtags.remove('pinned')

            n['modifydate'] = time.time()
            self.notify_observers(
                'change:note-status',
                utils.KeyValueObject(what='modifydate', key=key))
Beispiel #14
0
    def get_note_status(self, key):
        o = utils.KeyValueObject(saved=False,
                                 synced=False,
                                 modified=False,
                                 full_syncing=self.full_syncing)
        if key is None:
            return o

        n = self.notes[key]
        modifydate = float(n['modifydate'])
        savedate = float(n['savedate'])

        if savedate > modifydate:
            o.saved = True
        else:
            o.modified = True

        if float(n['syncdate']) > modifydate:
            o.synced = True

        return o
Beispiel #15
0
 def cmd_notes_list_select(self, evt):
     sidx = self.notes_list.selected_idx
     self.notify_observers('select:note', utils.KeyValueObject(sel=sidx))
Beispiel #16
0
 def handler_tags_entry(self, *args):
     self.notify_observers(
         'change:tags',
         utils.KeyValueObject(value=self.tags_entry_var.get()))
Beispiel #17
0
 def handler_search_entry(self, *args):
     self.notify_observers(
         'change:entry',
         utils.KeyValueObject(value=self.search_entry_var.get()))
Beispiel #18
0
 def handler_pinned_checkbutton(self, *args):
     self.notify_observers(
         'change:pinned',
         utils.KeyValueObject(value=self.pinned_checkbutton_var.get()))
Beispiel #19
0
    def sync_full_unthreaded(self):
        """Perform a full bi-directional sync with server.

        After this, it could be that local keys have been changed, so
        reset any views that you might have.
        """

        try:
            self.syncing_lock.acquire()

            self.full_syncing = True
            local_deletes = {}
            now = time.time()

            self.notify_observers(
                'progress:sync_full',
                utils.KeyValueObject(msg='Starting full sync.'))
            # 1. Synchronize notes when it has locally changed.
            #    In this phase, synchronized all notes from client to server.
            for ni, lk in enumerate(self.notes.keys()):
                n = self.notes[lk]
                if Note(n).need_sync_to_server:
                    result = self.update_note_to_server(n)

                    if result.error_object is None:
                        # replace n with result.note.
                        # if this was a new note, our local key is not valid anymore
                        del self.notes[lk]
                        # in either case (new or existing note), save note at assigned key
                        k = result.note.get('key')
                        # we merge the note we got back (content could be empty!)
                        n.update(result.note)
                        # and put it at the new key slot
                        self.notes[k] = n

                        # record that we just synced
                        n['syncdate'] = now

                        # whatever the case may be, k is now updated
                        self.helper_save_note(k, self.notes[k])
                        if lk != k:
                            # if lk was a different (purely local) key, should be deleted
                            local_deletes[lk] = True

                        self.notify_observers(
                            'progress:sync_full',
                            utils.KeyValueObject(
                                msg='Synced modified note %d to server.' %
                                (ni, )))

                    else:
                        key = n.get('key') or lk
                        raise SyncError(
                            "Sync step 1 error - Could not update note {0} to server: {1}"
                            .format(key, str(result.error_object)))

            # 2. Retrieves full note list from server.
            #    In phase 2 to 5, synchronized all notes from server to client.
            self.notify_observers(
                'progress:sync_full',
                utils.KeyValueObject(
                    msg=
                    'Retrieving full note list from server, could take a while.'
                ))
            self.waiting_for_simplenote = True
            nl = self.simplenote.get_note_list()
            self.waiting_for_simplenote = False
            if nl[1] == 0:
                nl = nl[0]
                self.notify_observers(
                    'progress:sync_full',
                    utils.KeyValueObject(
                        msg='Retrieved full note list from server.'))

            else:
                raise SyncError('Could not get note list from server.')

            # 3. Delete local notes not included in full note list.
            server_keys = {}
            for n in nl:
                k = n.get('key')
                server_keys[k] = True

            for lk in list(self.notes.keys()):
                if lk not in server_keys:
                    if self.notes[lk]['syncdate'] == 0:
                        # This note MUST NOT delete because it was created during phase 1 or phase 2.
                        continue

                    if self.config.notes_as_txt:
                        tfn = os.path.join(
                            self.config.txt_path,
                            utils.get_note_title_file(self.notes[lk]))
                        if os.path.isfile(tfn):
                            os.unlink(tfn)
                    del self.notes[lk]
                    local_deletes[lk] = True

            self.notify_observers(
                'progress:sync_full',
                utils.KeyValueObject(msg='Deleted note %d.' %
                                     (len(local_deletes))))

            # 4. Update local notes.
            lennl = len(nl)
            sync_from_server_errors = 0
            for ni, n in enumerate(nl):
                k = n.get('key')
                if k in self.notes:
                    # n is already exists in local.
                    if Note(n).is_newer_than(self.notes[k]):
                        # We must update local note with remote note.
                        err = 0
                        if 'content' not in n:
                            # The content field is missing.  Get all data from server.
                            self.waiting_for_simplenote = True
                            n, err = self.simplenote.get_note(k)
                            self.waiting_for_simplenote = False

                        if err == 0:
                            self.notes[k].update(n)
                            self.notes[k]['syncdate'] = now
                            self.helper_save_note(k, self.notes[k])
                            self.notify_observers(
                                'progress:sync_full',
                                utils.KeyValueObject(
                                    msg='Synced newer note %d (%d) from server.'
                                    % (ni, lennl)))

                        else:
                            logging.error(
                                'Error syncing newer note %s from server: %s' %
                                (k, err))
                            sync_from_server_errors += 1

                else:
                    # n is new note.
                    # We must save it in local.
                    err = 0
                    if 'content' not in n:
                        # The content field is missing.  Get all data from server.
                        self.waiting_for_simplenote = True
                        n, err = self.simplenote.get_note(k)
                        self.waiting_for_simplenote = False

                    if err == 0:
                        self.notes[k] = n
                        self.notes[k][
                            'savedate'] = 0  # never been written to disc
                        self.notes[k]['syncdate'] = now
                        self.helper_save_note(k, self.notes[k])
                        self.notify_observers(
                            'progress:sync_full',
                            utils.KeyValueObject(
                                msg='Synced new note %d (%d) from server.' %
                                (ni, lennl)))

                    else:
                        logging.error(
                            'Error syncing new note %s from server: %s' %
                            (k, err))
                        sync_from_server_errors += 1

            # 5. Clean up local notes.
            for dk in local_deletes.keys():
                fn = self.helper_key_to_fname(dk)
                if os.path.exists(fn):
                    os.unlink(fn)

            self.notify_observers(
                'progress:sync_full',
                utils.KeyValueObject(msg='Full sync complete.'))

            self.full_syncing = False
            return sync_from_server_errors

        finally:
            self.full_syncing = False
            self.syncing_lock.release()
Beispiel #20
0
    def sync_full(self):
        """Perform a full bi-directional sync with server.
        
        This follows the recipe in the SimpleNote 2.0 API documentation.
        After this, it could be that local keys have been changed, so
        reset any views that you might have.
        """

        local_updates = {}
        local_deletes = {}
        now = time.time()

        self.notify_observers('progress:sync_full',
                              utils.KeyValueObject(msg='Starting full sync.'))
        # 1. go through local notes, if anything changed or new, update to server
        for ni, lk in enumerate(self.notes.keys()):
            n = self.notes[lk]
            if not n.get('key') or float(n.get('modifydate')) > float(
                    n.get('syncdate')):
                uret = self.simplenote.update_note(n)
                if uret[1] == 0:
                    # replace n with uret[0]
                    # if this was a new note, our local key is not valid anymore
                    del self.notes[lk]
                    # in either case (new or existing note), save note at assigned key
                    k = uret[0].get('key')
                    # we merge the note we got back (content coud be empty!)
                    n.update(uret[0])
                    # and put it at the new key slot
                    self.notes[k] = n

                    # record that we just synced
                    uret[0]['syncdate'] = now

                    # whatever the case may be, k is now updated
                    local_updates[k] = True
                    if lk != k:
                        # if lk was a different (purely local) key, should be deleted
                        local_deletes[lk] = True

                    self.notify_observers(
                        'progress:sync_full',
                        utils.KeyValueObject(
                            msg='Synced modified note %d to server.' % (ni, )))

                else:
                    raise SyncError(
                        "Sync step 1 error - Could not update note to server")

        # 2. if remote syncnum > local syncnum, update our note; if key is new, add note to local.
        # this gets the FULL note list, even if multiple gets are required
        self.notify_observers(
            'progress:sync_full',
            utils.KeyValueObject(
                msg='Retrieving full note list from server, could take a while.'
            ))
        nl = self.simplenote.get_note_list()
        if nl[1] == 0:
            nl = nl[0]
            self.notify_observers(
                'progress:sync_full',
                utils.KeyValueObject(
                    msg='Retrieved full note list from server.'))

        else:
            raise SyncError('Could not get note list from server.')

        server_keys = {}
        lennl = len(nl)
        sync_from_server_errors = 0
        for ni, n in enumerate(nl):
            k = n.get('key')
            server_keys[k] = True
            # this works, only because in phase 1 we rewrite local keys to
            # server keys when we get an updated not back from the server
            if k in self.notes:
                # we already have this
                # check if server n has a newer syncnum than mine
                if int(n.get('syncnum')) > int(self.notes[k].get(
                        'syncnum', -1)):
                    # and the server is newer
                    ret = self.simplenote.get_note(k)
                    if ret[1] == 0:
                        self.notes[k].update(ret[0])
                        local_updates[k] = True
                        # in both cases, new or newer note, syncdate is now.
                        self.notes[k]['syncdate'] = now
                        self.notify_observers(
                            'progress:sync_full',
                            utils.KeyValueObject(
                                msg='Synced newer note %d (%d) from server.' %
                                (ni, lennl)))

                    else:
                        logging.error(
                            'Error syncing newer note %s from server: %s' %
                            (k, ret[0]))
                        sync_from_server_errors += 1

            else:
                # new note
                ret = self.simplenote.get_note(k)
                if ret[1] == 0:
                    self.notes[k] = ret[0]
                    local_updates[k] = True
                    # in both cases, new or newer note, syncdate is now.
                    self.notes[k]['syncdate'] = now
                    self.notify_observers(
                        'progress:sync_full',
                        utils.KeyValueObject(
                            msg='Synced new note %d (%d) from server.' %
                            (ni, lennl)))

                else:
                    logging.error('Error syncing new note %s from server: %s' %
                                  (k, ret[0]))
                    sync_from_server_errors += 1

        # 3. for each local note not in server index, remove.
        for lk in self.notes.keys():
            if lk not in server_keys:
                if self.config.notes_as_txt:
                    tfn = os.path.join(
                        self.config.txt_path,
                        utils.get_note_title_file(self.notes[lk]))
                    if os.path.isfile(tfn):
                        os.unlink(tfn)
                del self.notes[lk]
                local_deletes[lk] = True

        # sync done, now write changes to db_path
        for uk in local_updates.keys():
            self.helper_save_note(uk, self.notes[uk])

        for dk in local_deletes.keys():
            fn = self.helper_key_to_fname(dk)
            if os.path.exists(fn):
                os.unlink(fn)

        self.notify_observers('progress:sync_full',
                              utils.KeyValueObject(msg='Full sync complete.'))

        return sync_from_server_errors
Beispiel #21
0
    def filter_notes_regexp(self, search_string=None):
        """Return list of notes filtered with search_string,
        a regular expression, each a tuple with (local_key, note).
        """

        if search_string:
            try:
                if self.config.case_sensitive == 0:
                    sspat = re.compile(search_string, re.MULTILINE | re.I)
                else:
                    sspat = re.compile(search_string, re.MULTILINE)
            except re.error:
                sspat = None

        else:
            sspat = None

        filtered_notes = []
        # total number of notes, excluding deleted ones
        active_notes = 0
        for k in self.notes:
            n = self.notes[k]
            # we don't do anything with deleted notes (yet)
            if n.get('deleted'):
                continue

            active_notes += 1

            c = n.get('content')
            if self.config.search_tags == 1:
                t = n.get('tags')
                if sspat:
                    # this used to use a filter(), but that would by definition
                    # test all elements, whereas we can stop when the first
                    # matching element is found
                    # now I'm using this awesome trick by Alex Martelli on
                    # http://stackoverflow.com/a/2748753/532513
                    # first parameter of next is a generator
                    # next() executes one step, but due to the if, this will
                    # either be first matching element or None (second param)
                    if t and next(
                        (ti
                         for ti in t if sspat.search(ti)), None) is not None:
                        # we have to store our local key also
                        filtered_notes.append(
                            utils.KeyValueObject(key=k, note=n, tagfound=1))

                    elif sspat.search(c):
                        # we have to store our local key also
                        filtered_notes.append(
                            utils.KeyValueObject(key=k, note=n, tagfound=0))

                else:
                    # we have to store our local key also
                    filtered_notes.append(
                        utils.KeyValueObject(key=k, note=n, tagfound=0))
            else:
                if (not sspat or sspat.search(c)):
                    # we have to store our local key also
                    filtered_notes.append(
                        utils.KeyValueObject(key=k, note=n, tagfound=0))

        match_regexp = search_string if sspat else ''

        return filtered_notes, match_regexp, active_notes
Beispiel #22
0
 def cmd_root_delete(self, evt=None):
     sidx = self.notes_list.selected_idx
     self.notify_observers('delete:note', utils.KeyValueObject(sel=sidx))
Beispiel #23
0
 def cmd_lb_notes_select(self, evt):
     sidx = self.get_selected_idx()
     self.notify_observers('select:note', utils.KeyValueObject(sel=sidx))
Beispiel #24
0
    def filter_notes(self, search_string=None):
        """Return list of notes filtered with search_string, 
        a regular expression, each a tuple with (local_key, note). 
        """

        if search_string:
            try:
                if self.config.case_sensitive == 0:
                    sspat = re.compile(search_string, re.I)
                else:
                    sspat = re.compile(search_string)
            except re.error:
                sspat = None

        else:
            sspat = None

        filtered_notes = []
        for k in self.notes:
            n = self.notes[k]
            c = n.get('content')
            if self.config.search_tags == 1:
                t = n.get('tags')
                if not n.get('deleted') and sspat:
                    # this used to use a filter(), but that would by definition
                    # test all elements, whereas we can stop when the first
                    # matching element is found
                    # now I'm using this awesome trick by Alex Martelli on
                    # http://stackoverflow.com/a/2748753/532513
                    # first parameter of next is a generator
                    # next() executes one step, but due to the if, this will
                    # either be first matching element or None (second param)
                    if next((ti for ti in t if sspat.search(ti)),
                            None) is not None:
                        # we have to store our local key also
                        filtered_notes.append(
                            utils.KeyValueObject(key=k, note=n, tagfound=1))

                    elif sspat.search(c):
                        # we have to store our local key also
                        filtered_notes.append(
                            utils.KeyValueObject(key=k, note=n, tagfound=0))

                elif not n.get('deleted') and not sspat:
                    # we have to store our local key also
                    filtered_notes.append(
                        utils.KeyValueObject(key=k, note=n, tagfound=0))
            else:
                if not n.get('deleted') and (not sspat or sspat.search(c)):
                    # we have to store our local key also
                    filtered_notes.append(
                        utils.KeyValueObject(key=k, note=n, tagfound=0))

        if self.config.sort_mode == 0:
            if self.config.pinned_ontop == 0:
                # sort alphabetically on title
                filtered_notes.sort(key=lambda o: utils.get_note_title(o.note))
            else:
                filtered_notes.sort(utils.sort_by_title_pinned)

        else:
            if self.config.pinned_ontop == 0:
                # last modified on top
                filtered_notes.sort(
                    key=lambda o: -float(o.note.get('modifydate', 0)))
            else:
                filtered_notes.sort(utils.sort_by_modify_date_pinned,
                                    reverse=True)

        return filtered_notes
Beispiel #25
0
    def sync_to_server_threaded(self, wait_for_idle=True):
        """Only sync notes that have been changed / created locally since previous sync.
        
        This function is called by the housekeeping handler, so once every
        few seconds.
        
        @param wait_for_idle: Usually, last modification date has to be more
        than a few seconds ago before a sync to server is attempted. If
        wait_for_idle is set to False, no waiting is applied. Used by exit
        cleanup in controller.
        
        """

        # this many seconds of idle time (i.e. modification this long ago)
        # before we try to sync.
        if wait_for_idle:
            lastmod = 3
        else:
            lastmod = 0

        now = time.time()
        for k, n in self.notes.items():
            # if note has been modified sinc the sync, we need to sync.
            # only do so if note hasn't been touched for 3 seconds
            # and if this note isn't still in the queue to be processed by the
            # worker (this last one very important)
            modifydate = float(n.get('modifydate', -1))
            syncdate = float(n.get('syncdate', -1))
            if modifydate > syncdate and \
               now - modifydate > lastmod and \
               k not in self.threaded_syncing_keys:
                # record that we've requested a sync on this note,
                # so that we don't keep on putting stuff on the queue.
                self.threaded_syncing_keys[k] = True
                cn = copy.deepcopy(n)
                # we store the timestamp when this copy was made as the syncdate
                cn['syncdate'] = time.time()
                # put it on my queue as a sync
                o = utils.KeyValueObject(action=ACTION_SYNC_PARTIAL_TO_SERVER,
                                         key=k,
                                         note=cn)
                self.q_sync.put(o)

        # in this same call, we read out the result queue
        nsynced = 0
        nerrored = 0
        something_in_queue = True
        while something_in_queue:
            try:
                o = self.q_sync_res.get_nowait()

            except Empty:
                something_in_queue = False

            else:
                okey = o.key

                if o.error:
                    nerrored += 1

                else:
                    # o (.action, .key, .note) is something that was synced

                    # we only apply the changes if the syncdate is newer than
                    # what we already have, since the main thread could be
                    # running a full sync whilst the worker thread is putting
                    # results in the queue.
                    if float(o.note['syncdate']) > float(
                            self.notes[okey]['syncdate']):

                        if float(o.note['syncdate']) > float(
                                self.notes[okey]['modifydate']):
                            # note was synced AFTER the last modification to our local version
                            # do an in-place update of the existing note
                            # this could be with or without new content.
                            old_note = copy.deepcopy(self.notes[okey])
                            self.notes[okey].update(o.note)
                            # notify anyone (probably nvPY) that this note has been changed
                            self.notify_observers(
                                'synced:note',
                                utils.KeyValueObject(lkey=okey,
                                                     old_note=old_note))

                        else:
                            # the user has changed stuff since the version that got synced
                            # just record syncnum and version that we got from simplenote
                            # if we don't do this, merging problems start happening.
                            # VERY importantly: also store the key. It
                            # could be that we've just created the
                            # note, but that the user continued
                            # typing. We need to store the new server
                            # key, else we'll keep on sending new
                            # notes.
                            tkeys = ['syncnum', 'version', 'syncdate', 'key']
                            for tk in tkeys:
                                self.notes[okey][tk] = o.note[tk]

                        nsynced += 1
                        self.notify_observers(
                            'change:note-status',
                            utils.KeyValueObject(what='syncdate', key=okey))

                # after having handled the note that just came back,
                # we can take it from this blocker dict
                del self.threaded_syncing_keys[okey]

        return (nsynced, nerrored)
Beispiel #26
0
    def filter_notes_gstyle(self, search_string=None):

        filtered_notes = []
        # total number of notes, excluding deleted
        active_notes = 0

        if not search_string:
            for k in self.notes:
                n = self.notes[k]
                if not n.get('deleted'):
                    active_notes += 1
                    filtered_notes.append(
                        utils.KeyValueObject(key=k, note=n, tagfound=0))

            return filtered_notes, [], active_notes

        # group0: ag - not used
        # group1: t(ag)?:([^\s]+)
        # group2: multiple words in quotes
        # group3: single words
        # example result for 't:tag1 t:tag2 word1 "word2 word3" tag:tag3' ==
        # [('', 'tag1', '', ''), ('', 'tag2', '', ''), ('', '', '', 'word1'), ('', '', 'word2 word3', ''), ('ag', 'tag3', '', '')]

        groups = re.findall('t(ag)?:([^\s]+)|"([^"]+)"|([^\s]+)',
                            search_string)
        tms_pats = [[] for _ in range(3)]

        # we end up with [[tag_pats],[multi_word_pats],[single_word_pats]]
        for gi in groups:
            for mi in range(1, 4):
                if gi[mi]:
                    tms_pats[mi - 1].append(gi[mi])

        for k in self.notes:
            n = self.notes[k]

            if not n.get('deleted'):
                active_notes += 1
                c = n.get('content')

                # case insensitive mode: WARNING - SLOW!
                if not self.config.case_sensitive and c:
                    c = c.lower()

                tagmatch = self._helper_gstyle_tagmatch(tms_pats[0], n)
                # case insensitive mode: WARNING - SLOW!
                msword_pats = tms_pats[1] + tms_pats[
                    2] if self.config.case_sensitive else [
                        p.lower() for p in tms_pats[1] + tms_pats[2]
                    ]
                if tagmatch and self._helper_gstyle_mswordmatch(
                        msword_pats, c):
                    # we have a note that can go through!

                    # tagmatch == 1 if a tag was specced and found
                    # tagmatch == 2 if no tag was specced (so all notes go through)
                    tagfound = 1 if tagmatch == 1 else 0
                    # we have to store our local key also
                    filtered_notes.append(
                        utils.KeyValueObject(key=k, note=n, tagfound=tagfound))

        return filtered_notes, '|'.join(tms_pats[1] +
                                        tms_pats[2]), active_notes