Zim

Merge lp:~plprgt/zim/bookmarksbar-update into lp:~jaap.karssenberg/zim/pyzim

Proposed by Pl
Status: Merged
Merged at revision: 851
Proposed branch: lp:~plprgt/zim/bookmarksbar-update
Merge into: lp:~jaap.karssenberg/zim/pyzim
Diff against target: 790 lines (+351/-259)
3 files modified
data/manual/Plugins/BookmarksBar.txt (+3/-2)
tests/bookmarksbar.py (+287/-225)
zim/plugins/bookmarksbar.py (+61/-32)
To merge this branch: bzr merge lp:~plprgt/zim/bookmarksbar-update
Reviewer Review Type Date Requested Status
Jaap Karssenberg Pending
Review via email: mp+307016@code.launchpad.net

Description of the change

A small update to the BookmarksBar plugin.
The main changes:
- A new option to change maximum number of bookmarks is available from the plugin settings.
- If a bookmark has a special name it will not be changed after setting this bookmark to another page.
- If an open page has a corresponding bookmark it will be selected in the bar.
- Tests for the plugin are updated.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/manual/Plugins/BookmarksBar.txt'
2--- data/manual/Plugins/BookmarksBar.txt 2015-09-24 09:50:39 +0000
3+++ data/manual/Plugins/BookmarksBar.txt 2016-09-28 12:26:36 +0000
4@@ -11,6 +11,7 @@
5 ===== Plugin options =====
6 The option **Save bookmarks** allows to save and load bookmarks and their names between different sessions. If it is unchecked all bookmarks will be automatically deleted after closing the program.
7 The option **Add new bookmarks to the beginning of the bar** allows to choose the place where new bookmarks will be added. If checked all new bookmarks will be added to the beginning of the bar, if unchecked bookmarks will be added to the end of the bar.
8+It is possible to set the maximum number of bookmarks in the interval from 5 to 20.
9
10 ===== Basic operations =====
11 To show/hide the bar with bookmarks press **Bookmarks** button in the toolbar or press **<F4>** on keyboard.
12@@ -24,7 +25,7 @@
13 **Remove All** to delete all bookmarks from the bar,
14 **Open in New Window** to open the bookmark in a new window,
15 **Copy** to mark the bookmark for following "Paste",
16-**Paste** to transfer the marked bookmark to the new position,
17+**Paste** to transfer the marked bookmark to the new position. The position will be determined by coordinates of the mouse click which was made to invoke the popup menu,
18 **Set New Name** to set a new name to the bookmark. The name is taken from the clipboard (if the name is too long, the plugin will take only first 25 symbols),
19 **Back to Original Name** to return the bookmark to its default name. This option will appear only if the bookmark is renamed,
20 **Set to Current Page** to change the bookmark into a bookmark of the currently opened page.
21@@ -36,6 +37,6 @@
22 ===== Restrictions =====
23 Only existing pages (which have content or have sub-pages) can be added as bookmarks. If a page is deleted from the notebook its bookmark also will be deleted.
24 No duplicate bookmarks are allowed in the bar, though there can be different bookmarks with identical names.
25-The number of bookmarks is limited to 15.
26+
27
28
29
30=== modified file 'tests/bookmarksbar.py'
31--- tests/bookmarksbar.py 2015-09-24 12:33:11 +0000
32+++ tests/bookmarksbar.py 2016-09-28 12:26:36 +0000
33@@ -1,225 +1,287 @@
34-# -*- coding: utf-8 -*-
35-
36-# Copyright 2015 Pavel_M <plprgt@gmail.com>.
37-# This is the test for BookmarksBar plugin.
38-# BookmarksBar is the plugin for Zim program
39-# by Jaap Karssenberg <jaap.karssenberg@gmail.com>.
40-
41-
42-import tests
43-import gtk
44-
45-from zim.notebook import Path
46-from zim.plugins.bookmarksbar import *
47-from zim.config import ConfigDict
48-from zim.gui.clipboard import Clipboard
49-
50-import logging
51-logger = logging.getLogger('zim.plugins.bookmarksbar')
52-
53-
54-class TestBookmarksBar(tests.TestCase):
55-
56- def setUp(self):
57- self.notebook = tests.new_notebook()
58- self.index = self.notebook.index
59-
60- def runTest(self):
61- '''There is one long test.'''
62-
63- ui = MockUI()
64- ui.notebook = self.notebook
65- ui.page = Path('Test:foo')
66- uistate = ConfigDict()
67- self.assertTrue(self.notebook.get_page(ui.page).exists())
68-
69- PATHS = ('Parent:Daughter:Granddaughter',
70- 'Test:tags', 'Test:foo', 'Books')
71- LEN_PATHS = len(PATHS)
72- PATHS_NAMES = {PATHS[0]:'name 1', PATHS[1]:'name 2', PATHS[2]:'name 3'}
73-
74- # Check correctness of reading uistate.
75- uistate.setdefault('bookmarks', [])
76- uistate.setdefault('bookmarks_names', {})
77-
78- uistate['bookmarks'] = list(PATHS)
79- uistate['bookmarks_names'] = dict(PATHS_NAMES)
80- Bar = BookmarkBar(ui, uistate, get_page_func = lambda: '')
81- self.assertTrue(Bar.paths == list(PATHS))
82- self.assertTrue(Bar.paths_names == PATHS_NAMES)
83-
84- uistate['bookmarks'] = []
85- uistate['bookmarks_names'] = {}
86- Bar = BookmarkBar(ui, uistate, get_page_func = lambda: '')
87- self.assertTrue(Bar.paths == [])
88- self.assertTrue(Bar.paths_names == {})
89-
90- # Add paths to the beginning of the bar.
91- for i, path in enumerate(PATHS):
92- Bar._add_new(path, add_bookmarks_to_beginning = True)
93- self.assertTrue(len(Bar.paths) == i + 1)
94- self.assertTrue(Bar.paths == list(reversed(PATHS)))
95-
96- # Add paths to the end of the bar.
97- Bar.paths = []
98- for i, path in enumerate(PATHS):
99- Bar._add_new(path, add_bookmarks_to_beginning = False)
100- self.assertTrue(len(Bar.paths) == i + 1)
101- self.assertTrue(Bar.paths == list(PATHS))
102-
103- # Check that the same path can't be added to the bar.
104- Bar._add_new(PATHS[0])
105- Bar._add_new(PATHS[1])
106- self.assertTrue(Bar.paths == list(PATHS))
107-
108- # Delete paths from the bar.
109- for i, button in enumerate(Bar.container.get_children()[2:]):
110- path = button.zim_path
111- self.assertTrue(path in Bar.paths)
112- Bar.delete(button.zim_path)
113- self.assertTrue(len(Bar.paths) == LEN_PATHS - i - 1)
114- self.assertTrue(path not in Bar.paths)
115- self.assertTrue(Bar.paths == [])
116-
117- # Check short page names.
118- uistate['show_full_page_name'] = False
119- for path in PATHS:
120- Bar._add_new(path)
121- self.assertTrue(Bar.paths == list(PATHS))
122- for i, button in enumerate(Bar.container.get_children()[2:]):
123- self.assertTrue(PATHS[i] == button.zim_path)
124- self.assertTrue(Path(PATHS[i]).basename == button.get_label())
125- uistate['show_full_page_name'] = True
126-
127- # Delete all bookmarks from the bar.
128- Bar.delete_all()
129- self.assertTrue(Bar.paths == [])
130-
131- # Check restriction of max bookmarks in the bar.
132- pagelist = set(self.index.list_pages(None))
133- _enhanced_pagelist = set()
134- for page in pagelist:
135- _enhanced_pagelist.update( set(self.index.list_pages(page)) )
136- if len(_enhanced_pagelist) > MAX_BOOKMARKS:
137- break
138- pagelist.update(_enhanced_pagelist)
139- self.assertTrue(len(pagelist) > MAX_BOOKMARKS)
140- pagelist = list(pagelist)
141- for page in pagelist:
142- Bar._add_new(page.name)
143- self.assertTrue(len(Bar.paths) == MAX_BOOKMARKS)
144- self.assertTrue(Bar.paths == [a.name for a in pagelist[:MAX_BOOKMARKS]])
145- Bar.delete_all()
146-
147- # Check 'save' option in preferences.
148- for i, path in enumerate(PATHS):
149- Bar.on_preferences_changed({'save':False, 'add_bookmarks_to_beginning':False})
150- Bar._add_new(path)
151- self.assertTrue(uistate['bookmarks'] == [])
152- Bar.on_preferences_changed({'save':True, 'add_bookmarks_to_beginning':False})
153- self.assertTrue(uistate['bookmarks'] == list(PATHS[:i+1]))
154- self.assertTrue(uistate['bookmarks'] == list(PATHS))
155-
156- # Check changing a bookmark.
157- self.assertTrue('Test' not in Bar.paths)
158- self.assertTrue('Books' in Bar.paths)
159- Bar.change_bookmark('Books', 'Books')
160- self.assertTrue(Bar.paths == list(PATHS))
161- _b_paths = [a for a in Bar.paths if a != 'Books']
162- Bar.change_bookmark('Books', 'Test')
163- self.assertTrue('Test' in Bar.paths)
164- self.assertTrue('Books' not in Bar.paths)
165- _e_paths = [a for a in Bar.paths if a != 'Test']
166- self.assertTrue(_b_paths == _e_paths)
167-
168- Bar.change_bookmark('Test', 'Books')
169- self.assertTrue(Bar.paths == list(PATHS))
170-
171- # Check deleting a bookmark after deleting a page in the notebook.
172- self.assertTrue(len(Bar.paths) == LEN_PATHS)
173- for i, path in enumerate(PATHS):
174- self.assertTrue(path in Bar.paths)
175- self.notebook.delete_page(Path(path))
176- self.assertTrue(path not in Bar.paths)
177- self.assertTrue(len(Bar.paths) == LEN_PATHS - i - 1)
178- self.assertTrue(Bar.paths == [])
179-
180- # Check reordering bookmarks.
181- PATHS_2 = ('1','2','3','4','5')
182- PATHS_NAMES_2 = {PATHS_2[0]:'11', PATHS_2[1]:'22', PATHS_2[2]:'33'}
183-
184- Bar.paths = list(PATHS_2)
185- Bar.move_bookmark(PATHS_2[2], PATHS_2[2], 'left')
186- self.assertTrue(Bar.paths == list(PATHS_2))
187- Bar.move_bookmark(PATHS_2[3], PATHS_2[3], 'right')
188- self.assertTrue(Bar.paths == list(PATHS_2))
189- Bar.move_bookmark('3', '1', 'left')
190- self.assertTrue(Bar.paths == ['3','1','2','4','5'])
191- Bar.move_bookmark('5', '1', 'left')
192- self.assertTrue(Bar.paths == ['3','5','1','2','4'])
193- Bar.move_bookmark('5', '1', 'right')
194- self.assertTrue(Bar.paths == ['3','1','5','2','4'])
195- Bar.move_bookmark('3', '4', 'right')
196- self.assertTrue(Bar.paths == ['1','5','2','4','3'])
197- Bar.move_bookmark('5', '4', '-')
198- self.assertTrue(Bar.paths == ['1','5','2','4','3'])
199-
200- # CHECK RENAMING
201- # Check rename_bookmark and save options.
202- Bar.paths = list(PATHS_2)
203- button = gtk.Button(label = PATHS_2[0], use_underline = False)
204- button.zim_path = PATHS_2[0]
205- Bar.on_preferences_changed({'save':True, 'add_bookmarks_to_beginning':False})
206- Bar._reload_bar()
207-
208- def rename_check(label, path, paths_names, path_names_uistate):
209- self.assertTrue(button.get_label() == label)
210- self.assertTrue(button.zim_path == path)
211- self.assertTrue(Bar.paths_names == paths_names)
212- self.assertTrue(uistate['bookmarks_names'] == path_names_uistate)
213-
214- rename_check(PATHS_2[0], PATHS_2[0], {}, {})
215- Clipboard.set_text('new name')
216- Bar.rename_bookmark(button)
217- rename_check('new name', PATHS_2[0], {PATHS_2[0]:'new name'}, {PATHS_2[0]:'new name'})
218- Bar.on_preferences_changed({'save':False, 'add_bookmarks_to_beginning':False})
219- rename_check('new name', PATHS_2[0], {PATHS_2[0]:'new name'}, {})
220- Bar.on_preferences_changed({'save':True, 'add_bookmarks_to_beginning':False})
221- rename_check('new name', PATHS_2[0], {PATHS_2[0]:'new name'}, {PATHS_2[0]:'new name'})
222- Bar.rename_bookmark(button)
223- rename_check(PATHS_2[0], PATHS_2[0], {}, {})
224-
225- # Check delete with renaming.
226- Bar.on_preferences_changed({'save':True, 'add_bookmarks_to_beginning':False})
227- paths_names_copy = dict(PATHS_NAMES_2)
228- Bar.paths_names = dict(PATHS_NAMES_2)
229- for key in PATHS_NAMES_2:
230- Bar.delete(key)
231- del paths_names_copy[key]
232- self.assertTrue(Bar.paths_names == paths_names_copy)
233- self.assertTrue(uistate['bookmarks_names'] == Bar.paths_names)
234-
235- # Check delete all with renaming.
236- Bar.paths_names = dict(PATHS_NAMES_2)
237- Bar.delete_all()
238- self.assertTrue(Bar.paths_names == {})
239- self.assertTrue(uistate['bookmarks_names'] == {})
240-
241- # Check change bookmark with renaming.
242- Bar.paths = list(PATHS_2)
243- Bar.paths_names = dict(PATHS_NAMES_2)
244- paths_names_copy = dict(PATHS_NAMES_2)
245- paths_names_copy.pop(PATHS_2[0], None)
246- Bar.change_bookmark(PATHS_2[0], 'new path')
247- self.assertTrue(Bar.paths_names == paths_names_copy)
248- self.assertTrue(Bar.paths == ['new path'] + list(PATHS_2[1:]))
249-
250- # Check that paths and paths_names didn't change in the process.
251- self.assertTrue(PATHS_2 == ('1','2','3','4','5'))
252- self.assertTrue(PATHS_NAMES_2 == {PATHS_2[0]:'11', PATHS_2[1]:'22', PATHS_2[2]:'33'})
253-
254-
255-class MockUI(tests.MockObject):
256- page = None
257- notebook = None
258-
259+# -*- coding: utf-8 -*-
260+
261+# Copyright 2015-2016 Pavel_M <plprgt@gmail.com>,
262+# released under the GNU GPL version 3.
263+
264+# This is the test for BookmarksBar plugin.
265+# BookmarksBar is the plugin for Zim program
266+# by Jaap Karssenberg <jaap.karssenberg@gmail.com>.
267+
268+
269+import tests
270+import gtk
271+
272+from zim.notebook import Path
273+from zim.plugins.bookmarksbar import *
274+from zim.config import ConfigDict
275+from zim.gui.clipboard import Clipboard
276+
277+import logging
278+logger = logging.getLogger('zim.plugins.bookmarksbar')
279+
280+
281+class TestBookmarksBar(tests.TestCase):
282+
283+ @classmethod
284+ def setUpClass(cls):
285+ cls.notebook = tests.new_notebook()
286+ cls.index = cls.notebook.index
287+ cls.ui = MockUI()
288+ cls.ui.notebook = cls.notebook
289+ cls.ui.page = Path('Test:foo')
290+
291+
292+ def setUp(self):
293+ self.PATHS = ('Parent:Daughter:Granddaughter',
294+ 'Test:tags', 'Test:foo', 'Books')
295+ self.LEN_PATHS = len(self.PATHS)
296+ self.PATHS_NAMES = {self.PATHS[0]:'name 1', self.PATHS[1]:'name 2', self.PATHS[2]:'name 3'}
297+
298+ self.uistate = ConfigDict()
299+ self.uistate.setdefault('bookmarks', [])
300+ self.uistate.setdefault('bookmarks_names', {})
301+ self.uistate.setdefault('show_full_page_name', True)
302+
303+
304+ def testGeneral(self):
305+ '''Test general functions: add, delete bookmarks.'''
306+
307+ self.assertTrue(self.notebook.get_page(self.ui.page).exists())
308+
309+ Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
310+ Bar.max_bookmarks = 15 # set maximum number of bookmarks
311+
312+ # Add paths to the beginning of the bar.
313+ for i, path in enumerate(self.PATHS):
314+ Bar._add_new(path, add_bookmarks_to_beginning = True)
315+ self.assertEqual(len(Bar.paths), i + 1)
316+ self.assertTrue(Bar.paths == list(reversed(self.PATHS)))
317+
318+ # Add paths to the end of the bar.
319+ Bar.paths = []
320+ for i, path in enumerate(self.PATHS):
321+ Bar._add_new(path, add_bookmarks_to_beginning = False)
322+ self.assertEqual(len(Bar.paths), i + 1)
323+ self.assertEqual(Bar.paths, list(self.PATHS))
324+
325+ # Check that the same path can't be added to the bar.
326+ Bar._add_new(self.PATHS[0])
327+ Bar._add_new(self.PATHS[1])
328+ self.assertEqual(Bar.paths, list(self.PATHS))
329+
330+ # Delete paths from the bar.
331+ for i, button in enumerate(Bar.container.get_children()[2:]):
332+ path = button.zim_path
333+ self.assertTrue(path in Bar.paths)
334+ Bar.delete(button.zim_path)
335+ self.assertEqual(len(Bar.paths), self.LEN_PATHS - i - 1)
336+ self.assertTrue(path not in Bar.paths)
337+ self.assertEqual(Bar.paths, [])
338+
339+ # Delete all bookmarks from the bar.
340+ Bar.delete_all()
341+ self.assertEqual(Bar.paths, [])
342+
343+
344+ def testDeletePages(self):
345+ '''Check deleting a bookmark after deleting a page in the notebook.'''
346+
347+ notebook = tests.new_notebook()
348+ ui = MockUI()
349+ ui.notebook = notebook
350+ self.uistate['bookmarks'] = list(self.PATHS)
351+
352+ Bar = BookmarkBar(ui, self.uistate, get_page_func = lambda: '')
353+ for i, path in enumerate(self.PATHS):
354+ self.assertTrue(path in Bar.paths)
355+ notebook.delete_page(Path(path))
356+ self.assertTrue(path not in Bar.paths)
357+ self.assertEqual(len(Bar.paths), self.LEN_PATHS - i - 1)
358+ self.assertEqual(Bar.paths, [])
359+
360+
361+ def testFunctions(self):
362+ '''Test bookmark functions: changing, reordering, ranaming.'''
363+
364+ Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
365+ Bar.max_bookmarks = 15 # set maximum number of bookmarks
366+
367+ # Check changing a bookmark.
368+ for i, path in enumerate(self.PATHS):
369+ Bar._add_new(path, add_bookmarks_to_beginning = False)
370+
371+ self.assertTrue('Test' not in Bar.paths)
372+ self.assertTrue('Books' in Bar.paths)
373+ Bar.change_bookmark('Books', 'Books')
374+ self.assertEqual(Bar.paths, list(self.PATHS))
375+ Bar.change_bookmark('Books', 'Test')
376+ self.assertTrue('Test' in Bar.paths)
377+ self.assertTrue('Books' not in Bar.paths)
378+ _result = [a if a != 'Books' else 'Test' for a in self.PATHS]
379+ self.assertEqual(Bar.paths, _result)
380+
381+ Bar.change_bookmark('Test', 'Books')
382+ self.assertEqual(Bar.paths, list(self.PATHS))
383+
384+ # Check reordering bookmarks.
385+ new_paths = ('1','2','3','4','5')
386+
387+ Bar.paths = list(new_paths)
388+ Bar.move_bookmark(new_paths[2], new_paths[2], 'left')
389+ self.assertEqual(Bar.paths, list(new_paths))
390+ Bar.move_bookmark(new_paths[3], new_paths[3], 'right')
391+ self.assertEqual(Bar.paths, list(new_paths))
392+ Bar.move_bookmark('3', '1', 'left')
393+ self.assertEqual(Bar.paths, ['3','1','2','4','5'])
394+ Bar.move_bookmark('5', '1', 'left')
395+ self.assertEqual(Bar.paths, ['3','5','1','2','4'])
396+ Bar.move_bookmark('5', '1', 'right')
397+ self.assertEqual(Bar.paths, ['3','1','5','2','4'])
398+ Bar.move_bookmark('3', '4', 'right')
399+ self.assertEqual(Bar.paths, ['1','5','2','4','3'])
400+ Bar.move_bookmark('5', '4', '-')
401+ self.assertEqual(Bar.paths, ['1','5','2','4','3'])
402+
403+ # Check rename_bookmark and save options.
404+ preferences_changed = lambda save: Bar.on_preferences_changed({'save': save,
405+ 'add_bookmarks_to_beginning': False,
406+ 'max_bookmarks': 15})
407+
408+ new_path_names = {new_paths[0]:'11', new_paths[1]:'22', new_paths[2]:'33'}
409+ Bar.paths = list(new_paths)
410+ preferences_changed(True)
411+ Bar._reload_bar()
412+
413+ def rename_check(label, path, paths_names, path_names_uistate):
414+ self.assertEqual(button.get_label(), label)
415+ self.assertEqual(button.zim_path, path)
416+ self.assertEqual(Bar.paths_names, paths_names)
417+ self.assertEqual(self.uistate['bookmarks_names'], path_names_uistate)
418+
419+ button = gtk.Button(label = new_paths[0], use_underline = False)
420+ button.zim_path = new_paths[0]
421+ rename_check(new_paths[0], new_paths[0], {}, {})
422+
423+ Clipboard.set_text('new name')
424+ Bar.rename_bookmark(button)
425+ rename_check('new name', new_paths[0], {new_paths[0]:'new name'}, {new_paths[0]:'new name'})
426+ preferences_changed(False)
427+ rename_check('new name', new_paths[0], {new_paths[0]:'new name'}, {})
428+ preferences_changed(True)
429+ rename_check('new name', new_paths[0], {new_paths[0]:'new name'}, {new_paths[0]:'new name'})
430+ Bar.rename_bookmark(button)
431+ rename_check(new_paths[0], new_paths[0], {}, {})
432+
433+ # Check delete with renaming.
434+ preferences_changed(True)
435+ paths_names_copy = dict(new_path_names)
436+ Bar.paths_names = dict(new_path_names)
437+ for key in new_path_names:
438+ Bar.delete(key)
439+ del paths_names_copy[key]
440+ self.assertEqual(Bar.paths_names, paths_names_copy)
441+ self.assertEqual(self.uistate['bookmarks_names'], Bar.paths_names)
442+
443+ # Check delete all with renaming.
444+ Bar.paths_names = dict(new_path_names)
445+ Bar.delete_all()
446+ self.assertEqual(Bar.paths_names, {})
447+ self.assertEqual(self.uistate['bookmarks_names'], {})
448+
449+ # Check change bookmark with renaming.
450+ new_path_names = {new_paths[0]:'11', new_paths[1]:'22', new_paths[2]:'33'}
451+
452+ Bar.paths = list(new_paths)
453+ Bar.paths_names = dict(new_path_names)
454+ paths_names_copy = dict(new_path_names)
455+ _name = paths_names_copy.pop(new_paths[0])
456+ paths_names_copy['new path'] = _name
457+ Bar.change_bookmark(new_paths[0], 'new path')
458+ self.assertEqual(Bar.paths_names, paths_names_copy)
459+ self.assertEqual(Bar.paths, ['new path'] + list(new_paths[1:]))
460+
461+
462+ def testPreferences(self):
463+ '''Check preferences: full/short page names, save option,
464+ max number of bookmarks.'''
465+
466+ # Check short page names.
467+ Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
468+ self.uistate['show_full_page_name'] = False
469+ for path in self.PATHS:
470+ Bar._add_new(path)
471+ self.assertEqual(Bar.paths, list(self.PATHS))
472+ for i, button in enumerate(Bar.container.get_children()[2:]):
473+ self.assertEqual(self.PATHS[i], button.zim_path)
474+ self.assertEqual(Path(self.PATHS[i]).basename, button.get_label())
475+
476+ # Show full page names.
477+ Bar.toggle_show_full_page_name()
478+ self.assertEqual(Bar.paths, list(self.PATHS))
479+ for i, button in enumerate(Bar.container.get_children()[2:]):
480+ self.assertEqual(self.PATHS[i], button.zim_path)
481+ self.assertEqual(self.PATHS[i], button.get_label())
482+
483+ # Check save option.
484+ self.uistate['bookmarks'] = list(self.PATHS)
485+ self.uistate['bookmarks_names'] = dict(self.PATHS_NAMES)
486+ Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
487+ self.assertEqual(Bar.paths, list(self.PATHS))
488+ self.assertEqual(Bar.paths_names, self.PATHS_NAMES)
489+
490+ self.uistate['bookmarks'] = []
491+ self.uistate['bookmarks_names'] = {}
492+ Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
493+ self.assertEqual(Bar.paths, [])
494+ self.assertEqual(Bar.paths_names, {})
495+
496+ # Get pages to check max number of bookmarks.
497+ pagelist = set(self.index.list_pages(None))
498+ _enhanced_pagelist = set()
499+ for page in pagelist:
500+ _enhanced_pagelist.update( set(self.index.list_pages(page)) )
501+ if len(_enhanced_pagelist) > 20:
502+ break
503+ pagelist.update(_enhanced_pagelist)
504+ pagelist = [a.name for a in pagelist if a.exists()]
505+ self.assertTrue(len(pagelist) > 20)
506+
507+ def preferences_changed(save, max_b):
508+ Bar.on_preferences_changed({
509+ 'save': save,
510+ 'add_bookmarks_to_beginning': False,
511+ 'max_bookmarks': max_b})
512+
513+ # Check that more than max bookmarks can be loaded at start.
514+ self.uistate['bookmarks'] = pagelist
515+ Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
516+ self.assertEqual(pagelist, Bar.paths)
517+ preferences_changed(True, 5)
518+ self.assertEqual(pagelist, Bar.paths)
519+ self.assertEqual(pagelist, self.uistate['bookmarks'])
520+
521+ # Set maximum number of bookmarks.
522+ self.uistate['bookmarks'] = []
523+ Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
524+ for max_bookmarks in (5, 10, 15, 20):
525+ preferences_changed(False, max_bookmarks)
526+ for page in pagelist:
527+ Bar._add_new(page)
528+ self.assertEqual(len(Bar.paths), max_bookmarks)
529+ self.assertEqual(Bar.paths, pagelist[:max_bookmarks])
530+ Bar.delete_all()
531+
532+ # Check 'save' option in preferences.
533+ for i, path in enumerate(self.PATHS):
534+ preferences_changed(False, 15)
535+ Bar._add_new(path)
536+ self.assertEqual(self.uistate['bookmarks'], [])
537+ preferences_changed(True, 15)
538+ self.assertEqual(self.uistate['bookmarks'], list(self.PATHS[:i+1]))
539+ self.assertEqual(self.uistate['bookmarks'], list(self.PATHS))
540+
541+
542+class MockUI(tests.MockObject):
543+ page = None
544+ notebook = None
545+
546
547=== modified file 'zim/plugins/bookmarksbar.py'
548--- zim/plugins/bookmarksbar.py 2015-10-08 18:31:40 +0000
549+++ zim/plugins/bookmarksbar.py 2016-09-28 12:26:36 +0000
550@@ -1,6 +1,7 @@
551 # -*- coding: utf-8 -*-
552
553-# Copyright 2015 Pavel_M <plprgt@gmail.com>.
554+# Copyright 2015-2016 Pavel_M <plprgt@gmail.com>,
555+# released under the GNU GPL version 3.
556 # This plugin is for Zim program by Jaap Karssenberg <jaap.karssenberg@gmail.com>.
557 #
558 # This plugin uses an icon from Tango Desktop Project (http://tango.freedesktop.org/)
559@@ -21,9 +22,6 @@
560 import logging
561 logger = logging.getLogger('zim.plugins.bookmarksbar')
562
563-# Constant for max number of bookmarks in the bar.
564-MAX_BOOKMARKS = 15
565-
566 # Keyboard shortcut constants.
567 BM_TOGGLE_BAR_KEY ='F4'
568 BM_ADD_BOOKMARK_KEY ='<alt>1'
569@@ -40,6 +38,7 @@
570
571 plugin_preferences = (
572 # key, type, label, default
573+ ('max_bookmarks', 'int', _('Maximum number of bookmarks'), 15, (5, 20)), # T: plugin preference
574 ('save', 'bool', _('Save bookmarks'), True), # T: preferences option
575 ('add_bookmarks_to_beginning', 'bool', _('Add new bookmarks to the beginning of the bar'), False), # T: preferences option
576 )
577@@ -70,7 +69,7 @@
578 def __init__(self, plugin, window):
579 WindowExtension.__init__(self, plugin, window)
580 self.widget = BookmarkBar(self.window.ui, self.uistate,
581- self.window.pageview.get_page)
582+ self.window.pageview.get_page)
583 self.widget.show_all()
584
585 # Add a new option to the Index popup menu.
586@@ -149,10 +148,12 @@
587 self.uistate = uistate
588 self.save_flag = False # if True save bookmarks in config
589 self.add_bookmarks_to_beginning = False # add new bookmarks to the end of the bar
590+ self.max_bookmarks = False # maximum number of bookmarks
591 self._get_page = get_page_func # function to get current page
592
593 # Create button to add new bookmarks.
594 self.plus_button = IconsButton(gtk.STOCK_ADD, gtk.STOCK_REMOVE, relief = False)
595+ self.plus_button.set_tooltip_text(_('Add bookmark/Show settings'))
596 self.plus_button.connect('clicked', lambda o: self.add_new_page())
597 self.plus_button.connect('button-release-event', self.do_plus_button_popup_menu)
598 self.pack_start(self.plus_button, expand = False)
599@@ -164,7 +165,7 @@
600 # Toggle between full/short page names.
601 self.uistate.setdefault('show_full_page_name', False)
602
603- # Save path to use later in Cut/Paste menu.
604+ # Save path to use later in Copy/Paste menu.
605 self._saved_bookmark = None
606
607 self.paths = [] # list of bookmarks as string objects
608@@ -173,7 +174,8 @@
609 # Add pages from config to the bar.
610 for path in self.uistate['bookmarks']:
611 page = self.ui.notebook.get_page(Path(path))
612- self.add_new_page(page, reload_bar = False)
613+ if page.exists() and (page.name not in self.paths):
614+ self.paths.append(page.name)
615
616 self.paths_names = {} # dict of changed names of bookmarks
617 self.uistate.setdefault('bookmarks_names', {})
618@@ -189,46 +191,46 @@
619 except:
620 logger.error('BookmarksBar: Error while loading path_names.')
621
622- self._reload_bar()
623+ # Look for new pages to mark corresponding bookmarks in the bar.
624+ self.connectto(self.ui, 'open-page', self.on_open_page)
625
626 # Delete a bookmark if a page is deleted.
627 self.connectto(self.ui.notebook.index, 'page-deleted',
628 lambda obj, path: self.delete(path.name))
629
630- def add_new_page(self, page = None, reload_bar = True):
631+ def on_open_page(self, ui, page, path):
632+ '''If a page is present as a bookmark than select it.'''
633+ pagename = page.name
634+ for button in self.container.get_children()[2:]:
635+ if button.zim_path == pagename:
636+ button.set_active(True)
637+ else:
638+ button.set_active(False)
639+
640+ def add_new_page(self, page = None):
641 '''
642 Add new page as bookmark to the bar.
643 :param page: L{Page}, if None takes currently opened page,
644- :reload_bar: if True reload the bar.
645 '''
646 if not page:
647 page = self._get_page()
648
649 if page.exists():
650- return self._add_new(page.name, self.add_bookmarks_to_beginning, reload_bar)
651-
652- def _add_new(self, path, add_bookmarks_to_beginning = False, reload_bar = True):
653+ return self._add_new(page.name, self.add_bookmarks_to_beginning)
654+
655+ def _add_new(self, path, add_bookmarks_to_beginning = False):
656 '''Add bookmark to the bar.
657 :param path: path as a string object
658 :param add_bookmarks_to_beginning: bool,
659 add new bookmarks to the beginning of the bar,
660- :reload_bar: if True reload the bar.
661 '''
662 if path in self.paths:
663 logger.debug('BookmarksBar: path is already in the bar.')
664-
665- # Temporary change icon for plus_button to show
666- # that bookmark is already in the bar.
667- def _change_icon():
668- '''Function to be called only once.'''
669- self.plus_button.change_state()
670- return False
671- self.plus_button.change_state()
672- gobject.timeout_add(300, _change_icon)
673+ self.plus_button.blink()
674 return False
675
676 # Limit max number of bookmarks.
677- if len(self.paths) >= MAX_BOOKMARKS:
678+ if self.max_bookmarks and (len(self.paths) >= self.max_bookmarks):
679 logger.debug('BookmarksBar: max number of bookmarks is achieved.')
680 return False
681
682@@ -238,7 +240,7 @@
683 else:
684 self.paths.append(path)
685
686- if reload_bar: self._reload_bar()
687+ self._reload_bar()
688
689 def delete(self, path):
690 '''
691@@ -284,8 +286,13 @@
692
693 if new_path and (new_path not in self.paths) and (new_path != old_path):
694 self.paths[self.paths.index(old_path)] = new_path
695- self.paths_names.pop(old_path, None)
696+ name = self.paths_names.pop(old_path, None)
697+ if name:
698+ self.paths_names[new_path] = name
699+
700 self._reload_bar()
701+ else:
702+ self.plus_button.blink()
703
704 def move_bookmark(self, first, second, direction):
705 '''
706@@ -350,7 +357,7 @@
707 def do_bookmarks_popup_menu(self, button, event):
708 '''Handler for button-release-event, triggers popup menu for bookmarks.'''
709 if event.button != 3:
710- return False
711+ return False
712
713 path = button.zim_path
714
715@@ -371,13 +378,12 @@
716 (_('Remove'), lambda o: self.delete(path)), # T: menu item
717 (_('Remove All'), lambda o: self.delete_all(True)), # T: menu item
718 ('separator', ''),
719- (_('Open in New Window'), lambda o: self.ui.open_new_window(Path(path))), # T: menu item
720- ('separator', ''),
721 ('gtk-copy', lambda o: set_save_bookmark(path)),
722 ('gtk-paste', lambda o: self.move_bookmark(self._saved_bookmark, path, direction)),
723 ('separator', ''),
724+ (_('Open in New Window'), lambda o: self.ui.open_new_window(Path(path))), # T: menu item
725+ ('separator', ''),
726 (rename_button_text, lambda o: self.rename_bookmark(button)),
727- ('separator', ''),
728 (_('Set to Current Page'), lambda o: self.change_bookmark(path)) ) # T: menu item
729
730 for name, func in main_menu_items:
731@@ -412,6 +418,10 @@
732 self.uistate['bookmarks'] = []
733 self.uistate['bookmarks_names'] = {}
734
735+ if self.max_bookmarks != preferences['max_bookmarks']:
736+ self.max_bookmarks = preferences['max_bookmarks']
737+ self._reload_bar() # to update plus_button
738+
739 def _get_short_page_name(self, name):
740 '''
741 Function to return short name for the page.
742@@ -430,6 +440,12 @@
743 for button in self.container.get_children()[2:]:
744 self.container.remove(button)
745
746+ page = self._get_page()
747+ if page:
748+ pagename = page.name
749+ else:
750+ pagename = None
751+
752 for path in self.paths:
753 if path in self.paths_names:
754 name = self.paths_names[path]
755@@ -437,16 +453,19 @@
756 name = self._get_short_page_name(path)
757 else:
758 name = path
759- button = gtk.Button(label = name, use_underline = False)
760+ button = gtk.ToggleButton(label = name, use_underline = False)
761 button.set_tooltip_text(path)
762 button.zim_path = path
763+ if path == pagename:
764+ button.set_active(True)
765+
766 button.connect('clicked', self.on_bookmark_clicked)
767 button.connect('button-release-event', self.do_bookmarks_popup_menu)
768 button.show()
769 self.container.add(button)
770
771 # 'Disable' plus_button if max bookmarks is reached.
772- if len(self.paths) >= MAX_BOOKMARKS:
773+ if self.max_bookmarks and (len(self.paths) >= self.max_bookmarks):
774 self.plus_button.change_state(False)
775 else:
776 self.plus_button.change_state(True)
777@@ -501,3 +520,13 @@
778 self._enabled_state = not self._enabled_state
779 self.show_all()
780
781+ def blink(self):
782+ '''Quickly change an icon to show
783+ that bookmark can't be added/changed.'''
784+
785+ def change_icon():
786+ '''Function to be called only once.'''
787+ self.change_state()
788+ return False
789+ self.change_state()
790+ gobject.timeout_add(300, change_icon)