# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: shainer-20110401120804-ql6dkvl3ji684tgk # target_branch: http://bazaar.launchpad.net/~jaap.karssenberg/zim\ # /pyzim/ # testament_sha1: e5a656bf58ff8abe5884bfb77a0f05b870a43182 # timestamp: 2011-04-01 14:08:41 +0200 # base_revision_id: pardus@cpan.org-20110329225441-c1s4ru3d0pycvnec # # Begin patch === modified file 'zim/index.py' --- zim/index.py 2011-02-19 16:27:44 +0000 +++ zim/index.py 2011-04-01 12:08:04 +0000 @@ -43,7 +43,7 @@ import logging import zim -from zim.notebook import Path, Link, PageNameError +from zim.notebook import Path, Page, Link, PageNameError logger = logging.getLogger('zim.index') @@ -63,6 +63,7 @@ basename TEXT, parent INTEGER DEFAULT '0', hascontent BOOLEAN, + indexposition INTEGER DEFAULT '1', haschildren BOOLEAN, type INTEGER, ctime TIMESTAMP, @@ -466,6 +467,8 @@ Returns the final IndexPath. Path is created as a palceholder which has neither content or children. ''' + sorting = NaturalIndexSorting() + with self.db_commit: cursor = self.db.cursor() names = path.parts @@ -473,13 +476,36 @@ indexpath = [ROOT_ID] inserted = [] # newly inserted paths lastparent = None # last parent that already existed + + # FIXME: the Home page doesn't seem to pick a coherent indexposition, so I need + # to fix this manually. Don't know if it's really necessary + if self.n_list_pages(lastparent) == 1: + for p in self.list_pages(lastparent): + if p.basename == "Home": + cursor.execute('update pages set indexposition=?', (1,)) + for i in range(len(names)): p = self.lookup_path(Path(names[:i+1])) + if p is None: haschildren = i < (len(names) - 1) + page = Page(path, False) + + # Finds position in index for this new pages and updates the other positions + position = sorting.find_new_position(self.list_pages(lastparent), page) + ppid = ROOT_ID + if lastparent is not None: + ppid = lastparent.id + + # The iteration must go backwards otherwise the update won't be correct + for nextpos in range(self.n_list_pages(lastparent), position-1, -1): + cursor.execute( + 'update pages set indexposition=? where parent=? and indexposition=?', + (nextpos+1, ppid, nextpos)) + cursor.execute( - 'insert into pages(basename, parent, hascontent, haschildren) values (?, ?, ?, ?)', - (names[i], parentid, False, haschildren)) + 'insert into pages(basename, parent, hascontent, haschildren, indexposition) values (?, ?, ?, ?, ?)', + (names[i], parentid, False, haschildren, position)) parentid = cursor.lastrowid indexpath.append(parentid) inserted.append( @@ -746,7 +772,23 @@ (haschildren, path.id) ) else: # Delete - delete.append(path) + delete.append(path) + cursor = self.db.cursor() + + # Finds position for the path to be deleted and updates the pages with + # a bigger position index + ppid = path.parent.id + cursor.execute( + 'select * from pages where basename==? ', + (path.basename,)) + for record in cursor: + position = record['indexposition'] + + for nextpos in range(position, self.n_list_pages(path.parent)+1): + self.db.execute( + 'update pages set indexposition=? where parent=? and indexposition=?', + (nextpos-1, ppid, nextpos)) + self.db.execute('delete from pages where id=?', (path.id,)) self.lookup_data(path) # refresh @@ -827,7 +869,7 @@ def _walk(self, path, indexpath): # Here path always is an IndexPath cursor = self.db.cursor() - cursor.execute('select * from pages where parent == ? order by lower(basename)', (path.id,)) + cursor.execute('select * from pages where parent == ? order by indexposition', (path.id,)) # FIXME, this lower is not utf8 proof for row in cursor: name = path.name+':'+row['basename'] @@ -987,7 +1029,7 @@ if not parentid is None: cursor = self.db.cursor() - cursor.execute('select * from pages where parent==? order by lower(basename)', (parentid,)) + cursor.execute('select * from pages where parent==? order by indexposition', (parentid,)) # FIXME, this lower is not utf8 proof for row in cursor: yield IndexPath( @@ -1014,7 +1056,7 @@ if not parentid is None: cursor = self.db.cursor() - cursor.execute('select * from pages where parent==? order by lower(basename) limit ? offset ?', (parentid, limit, offset)) + cursor.execute('select * from pages where parent==? order by indexposition limit ? offset ?', (parentid, limit, offset)) # FIXME, this lower is not utf8 proof for row in cursor: yield IndexPath( @@ -1202,6 +1244,76 @@ # Need to register classes defining gobject signals gobject.type_register(Index) +class IndexSorting: + + def find_new_position(self, pagegen, pagenew): + '''Given the page list pagegen and the new page, returns the new + index position for the page, starting from one''' + + i = 1 + for page in pagegen: + if self.compareTo(page.basename, pagenew.basename) > 0: + break + i += 1 + + return i + + def compareTo(self, pagename1, pagename2): + '''This method must be implemented in child classes (which define the desired sorting) + to return a positive integer if page1 comes after page2 in the sorting + a negative integer is page1 comes first + and zero if they're equal (optional, that will never be the case)''' + raise NotImplementedError + +class NaturalIndexSorting(IndexSorting): + def compareTo(self, pagename1, pagename2): + t1 = self.naturalTuple(pagename1) + t2 = self.naturalTuple(pagename2) + + if len(t1) > len(t2): + return 1 + elif len(t1) < len(t2): + return -1 + + for i in range(len(t1)): + part1 = t1[i] + part2 = t2[i] + + if part1.isdigit() and part2.isdigit(): + n1 = int(part1) + n2 = int(part2) + + if n1 > n2: + return 1 + elif n1 < n2: + return -1 + + else: + if part1 > part2: + return 1 + elif part1 < part2: + return -1 + + return 0 + + def naturalTuple(self, s): + formatList = [] + temp = "" + isChar = True + + for c in s: + if (c.isalpha() and isChar) or (not c.isalpha() and not isChar): + if len(temp) > 0: + formatList.append(temp) + + isChar = not isChar + temp = c + elif (c.isalpha() and not isChar) or (not c.isalpha() and isChar): + temp += c + + formatList.append(temp) + return tuple(formatList) + class PropertiesDict(object): '''Wrapper for access to the meta table with properties''' # Begin bundle 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