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
=== modified file 'data/manual/Plugins/BookmarksBar.txt'
--- data/manual/Plugins/BookmarksBar.txt 2015-09-24 09:50:39 +0000
+++ data/manual/Plugins/BookmarksBar.txt 2016-09-28 12:26:36 +0000
@@ -11,6 +11,7 @@
11===== Plugin options =====11===== Plugin options =====
12The 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.12The 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.
13The 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. 13The 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.
14It is possible to set the maximum number of bookmarks in the interval from 5 to 20.
1415
15===== Basic operations =====16===== Basic operations =====
16To show/hide the bar with bookmarks press **Bookmarks** button in the toolbar or press **<F4>** on keyboard.17To show/hide the bar with bookmarks press **Bookmarks** button in the toolbar or press **<F4>** on keyboard.
@@ -24,7 +25,7 @@
24**Remove All** to delete all bookmarks from the bar,25**Remove All** to delete all bookmarks from the bar,
25**Open in New Window** to open the bookmark in a new window,26**Open in New Window** to open the bookmark in a new window,
26**Copy** to mark the bookmark for following "Paste",27**Copy** to mark the bookmark for following "Paste",
27**Paste** to transfer the marked bookmark to the new position,28**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,
28**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),29**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),
29**Back to Original Name** to return the bookmark to its default name. This option will appear only if the bookmark is renamed,30**Back to Original Name** to return the bookmark to its default name. This option will appear only if the bookmark is renamed,
30**Set to Current Page** to change the bookmark into a bookmark of the currently opened page.31**Set to Current Page** to change the bookmark into a bookmark of the currently opened page.
@@ -36,6 +37,6 @@
36===== Restrictions =====37===== Restrictions =====
37Only 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.38Only 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.
38No duplicate bookmarks are allowed in the bar, though there can be different bookmarks with identical names.39No duplicate bookmarks are allowed in the bar, though there can be different bookmarks with identical names.
39The number of bookmarks is limited to 15.40
4041
4142
4243
=== modified file 'tests/bookmarksbar.py'
--- tests/bookmarksbar.py 2015-09-24 12:33:11 +0000
+++ tests/bookmarksbar.py 2016-09-28 12:26:36 +0000
@@ -1,225 +1,287 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
22
3# Copyright 2015 Pavel_M <plprgt@gmail.com>.3# Copyright 2015-2016 Pavel_M <plprgt@gmail.com>,
4# This is the test for BookmarksBar plugin.4# released under the GNU GPL version 3.
5# BookmarksBar is the plugin for Zim program5
6# by Jaap Karssenberg <jaap.karssenberg@gmail.com>.6# This is the test for BookmarksBar plugin.
77# BookmarksBar is the plugin for Zim program
88# by Jaap Karssenberg <jaap.karssenberg@gmail.com>.
9import tests9
10import gtk10
1111import tests
12from zim.notebook import Path12import gtk
13from zim.plugins.bookmarksbar import *13
14from zim.config import ConfigDict14from zim.notebook import Path
15from zim.gui.clipboard import Clipboard15from zim.plugins.bookmarksbar import *
1616from zim.config import ConfigDict
17import logging17from zim.gui.clipboard import Clipboard
18logger = logging.getLogger('zim.plugins.bookmarksbar')18
1919import logging
2020logger = logging.getLogger('zim.plugins.bookmarksbar')
21class TestBookmarksBar(tests.TestCase):21
2222
23 def setUp(self):23class TestBookmarksBar(tests.TestCase):
24 self.notebook = tests.new_notebook()24
25 self.index = self.notebook.index25 @classmethod
2626 def setUpClass(cls):
27 def runTest(self):27 cls.notebook = tests.new_notebook()
28 '''There is one long test.'''28 cls.index = cls.notebook.index
2929 cls.ui = MockUI()
30 ui = MockUI()30 cls.ui.notebook = cls.notebook
31 ui.notebook = self.notebook31 cls.ui.page = Path('Test:foo')
32 ui.page = Path('Test:foo')32
33 uistate = ConfigDict()33
34 self.assertTrue(self.notebook.get_page(ui.page).exists())34 def setUp(self):
3535 self.PATHS = ('Parent:Daughter:Granddaughter',
36 PATHS = ('Parent:Daughter:Granddaughter',36 'Test:tags', 'Test:foo', 'Books')
37 'Test:tags', 'Test:foo', 'Books')37 self.LEN_PATHS = len(self.PATHS)
38 LEN_PATHS = len(PATHS)38 self.PATHS_NAMES = {self.PATHS[0]:'name 1', self.PATHS[1]:'name 2', self.PATHS[2]:'name 3'}
39 PATHS_NAMES = {PATHS[0]:'name 1', PATHS[1]:'name 2', PATHS[2]:'name 3'}39
4040 self.uistate = ConfigDict()
41 # Check correctness of reading uistate.41 self.uistate.setdefault('bookmarks', [])
42 uistate.setdefault('bookmarks', [])42 self.uistate.setdefault('bookmarks_names', {})
43 uistate.setdefault('bookmarks_names', {})43 self.uistate.setdefault('show_full_page_name', True)
4444
45 uistate['bookmarks'] = list(PATHS)45
46 uistate['bookmarks_names'] = dict(PATHS_NAMES)46 def testGeneral(self):
47 Bar = BookmarkBar(ui, uistate, get_page_func = lambda: '')47 '''Test general functions: add, delete bookmarks.'''
48 self.assertTrue(Bar.paths == list(PATHS))48
49 self.assertTrue(Bar.paths_names == PATHS_NAMES)49 self.assertTrue(self.notebook.get_page(self.ui.page).exists())
5050
51 uistate['bookmarks'] = []51 Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
52 uistate['bookmarks_names'] = {}52 Bar.max_bookmarks = 15 # set maximum number of bookmarks
53 Bar = BookmarkBar(ui, uistate, get_page_func = lambda: '')53
54 self.assertTrue(Bar.paths == [])54 # Add paths to the beginning of the bar.
55 self.assertTrue(Bar.paths_names == {})55 for i, path in enumerate(self.PATHS):
5656 Bar._add_new(path, add_bookmarks_to_beginning = True)
57 # Add paths to the beginning of the bar.57 self.assertEqual(len(Bar.paths), i + 1)
58 for i, path in enumerate(PATHS):58 self.assertTrue(Bar.paths == list(reversed(self.PATHS)))
59 Bar._add_new(path, add_bookmarks_to_beginning = True)59
60 self.assertTrue(len(Bar.paths) == i + 1)60 # Add paths to the end of the bar.
61 self.assertTrue(Bar.paths == list(reversed(PATHS)))61 Bar.paths = []
6262 for i, path in enumerate(self.PATHS):
63 # Add paths to the end of the bar.63 Bar._add_new(path, add_bookmarks_to_beginning = False)
64 Bar.paths = []64 self.assertEqual(len(Bar.paths), i + 1)
65 for i, path in enumerate(PATHS):65 self.assertEqual(Bar.paths, list(self.PATHS))
66 Bar._add_new(path, add_bookmarks_to_beginning = False)66
67 self.assertTrue(len(Bar.paths) == i + 1)67 # Check that the same path can't be added to the bar.
68 self.assertTrue(Bar.paths == list(PATHS))68 Bar._add_new(self.PATHS[0])
6969 Bar._add_new(self.PATHS[1])
70 # Check that the same path can't be added to the bar.70 self.assertEqual(Bar.paths, list(self.PATHS))
71 Bar._add_new(PATHS[0])71
72 Bar._add_new(PATHS[1])72 # Delete paths from the bar.
73 self.assertTrue(Bar.paths == list(PATHS))73 for i, button in enumerate(Bar.container.get_children()[2:]):
7474 path = button.zim_path
75 # Delete paths from the bar.75 self.assertTrue(path in Bar.paths)
76 for i, button in enumerate(Bar.container.get_children()[2:]):76 Bar.delete(button.zim_path)
77 path = button.zim_path77 self.assertEqual(len(Bar.paths), self.LEN_PATHS - i - 1)
78 self.assertTrue(path in Bar.paths)78 self.assertTrue(path not in Bar.paths)
79 Bar.delete(button.zim_path)79 self.assertEqual(Bar.paths, [])
80 self.assertTrue(len(Bar.paths) == LEN_PATHS - i - 1)80
81 self.assertTrue(path not in Bar.paths)81 # Delete all bookmarks from the bar.
82 self.assertTrue(Bar.paths == [])82 Bar.delete_all()
8383 self.assertEqual(Bar.paths, [])
84 # Check short page names.84
85 uistate['show_full_page_name'] = False85
86 for path in PATHS:86 def testDeletePages(self):
87 Bar._add_new(path)87 '''Check deleting a bookmark after deleting a page in the notebook.'''
88 self.assertTrue(Bar.paths == list(PATHS))88
89 for i, button in enumerate(Bar.container.get_children()[2:]):89 notebook = tests.new_notebook()
90 self.assertTrue(PATHS[i] == button.zim_path)90 ui = MockUI()
91 self.assertTrue(Path(PATHS[i]).basename == button.get_label())91 ui.notebook = notebook
92 uistate['show_full_page_name'] = True92 self.uistate['bookmarks'] = list(self.PATHS)
9393
94 # Delete all bookmarks from the bar.94 Bar = BookmarkBar(ui, self.uistate, get_page_func = lambda: '')
95 Bar.delete_all()95 for i, path in enumerate(self.PATHS):
96 self.assertTrue(Bar.paths == [])96 self.assertTrue(path in Bar.paths)
9797 notebook.delete_page(Path(path))
98 # Check restriction of max bookmarks in the bar.98 self.assertTrue(path not in Bar.paths)
99 pagelist = set(self.index.list_pages(None))99 self.assertEqual(len(Bar.paths), self.LEN_PATHS - i - 1)
100 _enhanced_pagelist = set()100 self.assertEqual(Bar.paths, [])
101 for page in pagelist:101
102 _enhanced_pagelist.update( set(self.index.list_pages(page)) )102
103 if len(_enhanced_pagelist) > MAX_BOOKMARKS:103 def testFunctions(self):
104 break104 '''Test bookmark functions: changing, reordering, ranaming.'''
105 pagelist.update(_enhanced_pagelist)105
106 self.assertTrue(len(pagelist) > MAX_BOOKMARKS)106 Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
107 pagelist = list(pagelist)107 Bar.max_bookmarks = 15 # set maximum number of bookmarks
108 for page in pagelist:108
109 Bar._add_new(page.name)109 # Check changing a bookmark.
110 self.assertTrue(len(Bar.paths) == MAX_BOOKMARKS)110 for i, path in enumerate(self.PATHS):
111 self.assertTrue(Bar.paths == [a.name for a in pagelist[:MAX_BOOKMARKS]])111 Bar._add_new(path, add_bookmarks_to_beginning = False)
112 Bar.delete_all()112
113113 self.assertTrue('Test' not in Bar.paths)
114 # Check 'save' option in preferences.114 self.assertTrue('Books' in Bar.paths)
115 for i, path in enumerate(PATHS):115 Bar.change_bookmark('Books', 'Books')
116 Bar.on_preferences_changed({'save':False, 'add_bookmarks_to_beginning':False})116 self.assertEqual(Bar.paths, list(self.PATHS))
117 Bar._add_new(path)117 Bar.change_bookmark('Books', 'Test')
118 self.assertTrue(uistate['bookmarks'] == [])118 self.assertTrue('Test' in Bar.paths)
119 Bar.on_preferences_changed({'save':True, 'add_bookmarks_to_beginning':False})119 self.assertTrue('Books' not in Bar.paths)
120 self.assertTrue(uistate['bookmarks'] == list(PATHS[:i+1]))120 _result = [a if a != 'Books' else 'Test' for a in self.PATHS]
121 self.assertTrue(uistate['bookmarks'] == list(PATHS))121 self.assertEqual(Bar.paths, _result)
122122
123 # Check changing a bookmark.123 Bar.change_bookmark('Test', 'Books')
124 self.assertTrue('Test' not in Bar.paths)124 self.assertEqual(Bar.paths, list(self.PATHS))
125 self.assertTrue('Books' in Bar.paths)125
126 Bar.change_bookmark('Books', 'Books')126 # Check reordering bookmarks.
127 self.assertTrue(Bar.paths == list(PATHS))127 new_paths = ('1','2','3','4','5')
128 _b_paths = [a for a in Bar.paths if a != 'Books']128
129 Bar.change_bookmark('Books', 'Test')129 Bar.paths = list(new_paths)
130 self.assertTrue('Test' in Bar.paths)130 Bar.move_bookmark(new_paths[2], new_paths[2], 'left')
131 self.assertTrue('Books' not in Bar.paths)131 self.assertEqual(Bar.paths, list(new_paths))
132 _e_paths = [a for a in Bar.paths if a != 'Test']132 Bar.move_bookmark(new_paths[3], new_paths[3], 'right')
133 self.assertTrue(_b_paths == _e_paths)133 self.assertEqual(Bar.paths, list(new_paths))
134134 Bar.move_bookmark('3', '1', 'left')
135 Bar.change_bookmark('Test', 'Books')135 self.assertEqual(Bar.paths, ['3','1','2','4','5'])
136 self.assertTrue(Bar.paths == list(PATHS))136 Bar.move_bookmark('5', '1', 'left')
137137 self.assertEqual(Bar.paths, ['3','5','1','2','4'])
138 # Check deleting a bookmark after deleting a page in the notebook.138 Bar.move_bookmark('5', '1', 'right')
139 self.assertTrue(len(Bar.paths) == LEN_PATHS)139 self.assertEqual(Bar.paths, ['3','1','5','2','4'])
140 for i, path in enumerate(PATHS):140 Bar.move_bookmark('3', '4', 'right')
141 self.assertTrue(path in Bar.paths)141 self.assertEqual(Bar.paths, ['1','5','2','4','3'])
142 self.notebook.delete_page(Path(path))142 Bar.move_bookmark('5', '4', '-')
143 self.assertTrue(path not in Bar.paths)143 self.assertEqual(Bar.paths, ['1','5','2','4','3'])
144 self.assertTrue(len(Bar.paths) == LEN_PATHS - i - 1)144
145 self.assertTrue(Bar.paths == [])145 # Check rename_bookmark and save options.
146146 preferences_changed = lambda save: Bar.on_preferences_changed({'save': save,
147 # Check reordering bookmarks.147 'add_bookmarks_to_beginning': False,
148 PATHS_2 = ('1','2','3','4','5')148 'max_bookmarks': 15})
149 PATHS_NAMES_2 = {PATHS_2[0]:'11', PATHS_2[1]:'22', PATHS_2[2]:'33'}149
150150 new_path_names = {new_paths[0]:'11', new_paths[1]:'22', new_paths[2]:'33'}
151 Bar.paths = list(PATHS_2)151 Bar.paths = list(new_paths)
152 Bar.move_bookmark(PATHS_2[2], PATHS_2[2], 'left')152 preferences_changed(True)
153 self.assertTrue(Bar.paths == list(PATHS_2))153 Bar._reload_bar()
154 Bar.move_bookmark(PATHS_2[3], PATHS_2[3], 'right')154
155 self.assertTrue(Bar.paths == list(PATHS_2))155 def rename_check(label, path, paths_names, path_names_uistate):
156 Bar.move_bookmark('3', '1', 'left')156 self.assertEqual(button.get_label(), label)
157 self.assertTrue(Bar.paths == ['3','1','2','4','5'])157 self.assertEqual(button.zim_path, path)
158 Bar.move_bookmark('5', '1', 'left')158 self.assertEqual(Bar.paths_names, paths_names)
159 self.assertTrue(Bar.paths == ['3','5','1','2','4'])159 self.assertEqual(self.uistate['bookmarks_names'], path_names_uistate)
160 Bar.move_bookmark('5', '1', 'right')160
161 self.assertTrue(Bar.paths == ['3','1','5','2','4'])161 button = gtk.Button(label = new_paths[0], use_underline = False)
162 Bar.move_bookmark('3', '4', 'right')162 button.zim_path = new_paths[0]
163 self.assertTrue(Bar.paths == ['1','5','2','4','3'])163 rename_check(new_paths[0], new_paths[0], {}, {})
164 Bar.move_bookmark('5', '4', '-')164
165 self.assertTrue(Bar.paths == ['1','5','2','4','3'])165 Clipboard.set_text('new name')
166166 Bar.rename_bookmark(button)
167 # CHECK RENAMING167 rename_check('new name', new_paths[0], {new_paths[0]:'new name'}, {new_paths[0]:'new name'})
168 # Check rename_bookmark and save options.168 preferences_changed(False)
169 Bar.paths = list(PATHS_2)169 rename_check('new name', new_paths[0], {new_paths[0]:'new name'}, {})
170 button = gtk.Button(label = PATHS_2[0], use_underline = False)170 preferences_changed(True)
171 button.zim_path = PATHS_2[0]171 rename_check('new name', new_paths[0], {new_paths[0]:'new name'}, {new_paths[0]:'new name'})
172 Bar.on_preferences_changed({'save':True, 'add_bookmarks_to_beginning':False})172 Bar.rename_bookmark(button)
173 Bar._reload_bar()173 rename_check(new_paths[0], new_paths[0], {}, {})
174174
175 def rename_check(label, path, paths_names, path_names_uistate):175 # Check delete with renaming.
176 self.assertTrue(button.get_label() == label)176 preferences_changed(True)
177 self.assertTrue(button.zim_path == path)177 paths_names_copy = dict(new_path_names)
178 self.assertTrue(Bar.paths_names == paths_names)178 Bar.paths_names = dict(new_path_names)
179 self.assertTrue(uistate['bookmarks_names'] == path_names_uistate)179 for key in new_path_names:
180180 Bar.delete(key)
181 rename_check(PATHS_2[0], PATHS_2[0], {}, {})181 del paths_names_copy[key]
182 Clipboard.set_text('new name')182 self.assertEqual(Bar.paths_names, paths_names_copy)
183 Bar.rename_bookmark(button)183 self.assertEqual(self.uistate['bookmarks_names'], Bar.paths_names)
184 rename_check('new name', PATHS_2[0], {PATHS_2[0]:'new name'}, {PATHS_2[0]:'new name'})184
185 Bar.on_preferences_changed({'save':False, 'add_bookmarks_to_beginning':False})185 # Check delete all with renaming.
186 rename_check('new name', PATHS_2[0], {PATHS_2[0]:'new name'}, {})186 Bar.paths_names = dict(new_path_names)
187 Bar.on_preferences_changed({'save':True, 'add_bookmarks_to_beginning':False})187 Bar.delete_all()
188 rename_check('new name', PATHS_2[0], {PATHS_2[0]:'new name'}, {PATHS_2[0]:'new name'})188 self.assertEqual(Bar.paths_names, {})
189 Bar.rename_bookmark(button)189 self.assertEqual(self.uistate['bookmarks_names'], {})
190 rename_check(PATHS_2[0], PATHS_2[0], {}, {})190
191191 # Check change bookmark with renaming.
192 # Check delete with renaming.192 new_path_names = {new_paths[0]:'11', new_paths[1]:'22', new_paths[2]:'33'}
193 Bar.on_preferences_changed({'save':True, 'add_bookmarks_to_beginning':False})193
194 paths_names_copy = dict(PATHS_NAMES_2)194 Bar.paths = list(new_paths)
195 Bar.paths_names = dict(PATHS_NAMES_2)195 Bar.paths_names = dict(new_path_names)
196 for key in PATHS_NAMES_2:196 paths_names_copy = dict(new_path_names)
197 Bar.delete(key)197 _name = paths_names_copy.pop(new_paths[0])
198 del paths_names_copy[key]198 paths_names_copy['new path'] = _name
199 self.assertTrue(Bar.paths_names == paths_names_copy)199 Bar.change_bookmark(new_paths[0], 'new path')
200 self.assertTrue(uistate['bookmarks_names'] == Bar.paths_names)200 self.assertEqual(Bar.paths_names, paths_names_copy)
201201 self.assertEqual(Bar.paths, ['new path'] + list(new_paths[1:]))
202 # Check delete all with renaming.202
203 Bar.paths_names = dict(PATHS_NAMES_2)203
204 Bar.delete_all()204 def testPreferences(self):
205 self.assertTrue(Bar.paths_names == {})205 '''Check preferences: full/short page names, save option,
206 self.assertTrue(uistate['bookmarks_names'] == {})206 max number of bookmarks.'''
207207
208 # Check change bookmark with renaming.208 # Check short page names.
209 Bar.paths = list(PATHS_2)209 Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
210 Bar.paths_names = dict(PATHS_NAMES_2)210 self.uistate['show_full_page_name'] = False
211 paths_names_copy = dict(PATHS_NAMES_2)211 for path in self.PATHS:
212 paths_names_copy.pop(PATHS_2[0], None)212 Bar._add_new(path)
213 Bar.change_bookmark(PATHS_2[0], 'new path')213 self.assertEqual(Bar.paths, list(self.PATHS))
214 self.assertTrue(Bar.paths_names == paths_names_copy)214 for i, button in enumerate(Bar.container.get_children()[2:]):
215 self.assertTrue(Bar.paths == ['new path'] + list(PATHS_2[1:]))215 self.assertEqual(self.PATHS[i], button.zim_path)
216216 self.assertEqual(Path(self.PATHS[i]).basename, button.get_label())
217 # Check that paths and paths_names didn't change in the process.217
218 self.assertTrue(PATHS_2 == ('1','2','3','4','5'))218 # Show full page names.
219 self.assertTrue(PATHS_NAMES_2 == {PATHS_2[0]:'11', PATHS_2[1]:'22', PATHS_2[2]:'33'})219 Bar.toggle_show_full_page_name()
220220 self.assertEqual(Bar.paths, list(self.PATHS))
221221 for i, button in enumerate(Bar.container.get_children()[2:]):
222class MockUI(tests.MockObject):222 self.assertEqual(self.PATHS[i], button.zim_path)
223 page = None223 self.assertEqual(self.PATHS[i], button.get_label())
224 notebook = None224
225225 # Check save option.
226 self.uistate['bookmarks'] = list(self.PATHS)
227 self.uistate['bookmarks_names'] = dict(self.PATHS_NAMES)
228 Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
229 self.assertEqual(Bar.paths, list(self.PATHS))
230 self.assertEqual(Bar.paths_names, self.PATHS_NAMES)
231
232 self.uistate['bookmarks'] = []
233 self.uistate['bookmarks_names'] = {}
234 Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
235 self.assertEqual(Bar.paths, [])
236 self.assertEqual(Bar.paths_names, {})
237
238 # Get pages to check max number of bookmarks.
239 pagelist = set(self.index.list_pages(None))
240 _enhanced_pagelist = set()
241 for page in pagelist:
242 _enhanced_pagelist.update( set(self.index.list_pages(page)) )
243 if len(_enhanced_pagelist) > 20:
244 break
245 pagelist.update(_enhanced_pagelist)
246 pagelist = [a.name for a in pagelist if a.exists()]
247 self.assertTrue(len(pagelist) > 20)
248
249 def preferences_changed(save, max_b):
250 Bar.on_preferences_changed({
251 'save': save,
252 'add_bookmarks_to_beginning': False,
253 'max_bookmarks': max_b})
254
255 # Check that more than max bookmarks can be loaded at start.
256 self.uistate['bookmarks'] = pagelist
257 Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
258 self.assertEqual(pagelist, Bar.paths)
259 preferences_changed(True, 5)
260 self.assertEqual(pagelist, Bar.paths)
261 self.assertEqual(pagelist, self.uistate['bookmarks'])
262
263 # Set maximum number of bookmarks.
264 self.uistate['bookmarks'] = []
265 Bar = BookmarkBar(self.ui, self.uistate, get_page_func = lambda: '')
266 for max_bookmarks in (5, 10, 15, 20):
267 preferences_changed(False, max_bookmarks)
268 for page in pagelist:
269 Bar._add_new(page)
270 self.assertEqual(len(Bar.paths), max_bookmarks)
271 self.assertEqual(Bar.paths, pagelist[:max_bookmarks])
272 Bar.delete_all()
273
274 # Check 'save' option in preferences.
275 for i, path in enumerate(self.PATHS):
276 preferences_changed(False, 15)
277 Bar._add_new(path)
278 self.assertEqual(self.uistate['bookmarks'], [])
279 preferences_changed(True, 15)
280 self.assertEqual(self.uistate['bookmarks'], list(self.PATHS[:i+1]))
281 self.assertEqual(self.uistate['bookmarks'], list(self.PATHS))
282
283
284class MockUI(tests.MockObject):
285 page = None
286 notebook = None
287
226288
=== modified file 'zim/plugins/bookmarksbar.py'
--- zim/plugins/bookmarksbar.py 2015-10-08 18:31:40 +0000
+++ zim/plugins/bookmarksbar.py 2016-09-28 12:26:36 +0000
@@ -1,6 +1,7 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
22
3# Copyright 2015 Pavel_M <plprgt@gmail.com>.3# Copyright 2015-2016 Pavel_M <plprgt@gmail.com>,
4# released under the GNU GPL version 3.
4# This plugin is for Zim program by Jaap Karssenberg <jaap.karssenberg@gmail.com>.5# This plugin is for Zim program by Jaap Karssenberg <jaap.karssenberg@gmail.com>.
5#6#
6# This plugin uses an icon from Tango Desktop Project (http://tango.freedesktop.org/)7# This plugin uses an icon from Tango Desktop Project (http://tango.freedesktop.org/)
@@ -21,9 +22,6 @@
21import logging22import logging
22logger = logging.getLogger('zim.plugins.bookmarksbar')23logger = logging.getLogger('zim.plugins.bookmarksbar')
2324
24# Constant for max number of bookmarks in the bar.
25MAX_BOOKMARKS = 15
26
27# Keyboard shortcut constants.25# Keyboard shortcut constants.
28BM_TOGGLE_BAR_KEY ='F4'26BM_TOGGLE_BAR_KEY ='F4'
29BM_ADD_BOOKMARK_KEY ='<alt>1'27BM_ADD_BOOKMARK_KEY ='<alt>1'
@@ -40,6 +38,7 @@
4038
41 plugin_preferences = (39 plugin_preferences = (
42 # key, type, label, default40 # key, type, label, default
41 ('max_bookmarks', 'int', _('Maximum number of bookmarks'), 15, (5, 20)), # T: plugin preference
43 ('save', 'bool', _('Save bookmarks'), True), # T: preferences option42 ('save', 'bool', _('Save bookmarks'), True), # T: preferences option
44 ('add_bookmarks_to_beginning', 'bool', _('Add new bookmarks to the beginning of the bar'), False), # T: preferences option43 ('add_bookmarks_to_beginning', 'bool', _('Add new bookmarks to the beginning of the bar'), False), # T: preferences option
45 )44 )
@@ -70,7 +69,7 @@
70 def __init__(self, plugin, window):69 def __init__(self, plugin, window):
71 WindowExtension.__init__(self, plugin, window)70 WindowExtension.__init__(self, plugin, window)
72 self.widget = BookmarkBar(self.window.ui, self.uistate,71 self.widget = BookmarkBar(self.window.ui, self.uistate,
73 self.window.pageview.get_page)72 self.window.pageview.get_page)
74 self.widget.show_all()73 self.widget.show_all()
7574
76 # Add a new option to the Index popup menu.75 # Add a new option to the Index popup menu.
@@ -149,10 +148,12 @@
149 self.uistate = uistate148 self.uistate = uistate
150 self.save_flag = False # if True save bookmarks in config149 self.save_flag = False # if True save bookmarks in config
151 self.add_bookmarks_to_beginning = False # add new bookmarks to the end of the bar150 self.add_bookmarks_to_beginning = False # add new bookmarks to the end of the bar
151 self.max_bookmarks = False # maximum number of bookmarks
152 self._get_page = get_page_func # function to get current page152 self._get_page = get_page_func # function to get current page
153153
154 # Create button to add new bookmarks.154 # Create button to add new bookmarks.
155 self.plus_button = IconsButton(gtk.STOCK_ADD, gtk.STOCK_REMOVE, relief = False)155 self.plus_button = IconsButton(gtk.STOCK_ADD, gtk.STOCK_REMOVE, relief = False)
156 self.plus_button.set_tooltip_text(_('Add bookmark/Show settings'))
156 self.plus_button.connect('clicked', lambda o: self.add_new_page())157 self.plus_button.connect('clicked', lambda o: self.add_new_page())
157 self.plus_button.connect('button-release-event', self.do_plus_button_popup_menu)158 self.plus_button.connect('button-release-event', self.do_plus_button_popup_menu)
158 self.pack_start(self.plus_button, expand = False)159 self.pack_start(self.plus_button, expand = False)
@@ -164,7 +165,7 @@
164 # Toggle between full/short page names.165 # Toggle between full/short page names.
165 self.uistate.setdefault('show_full_page_name', False)166 self.uistate.setdefault('show_full_page_name', False)
166167
167 # Save path to use later in Cut/Paste menu.168 # Save path to use later in Copy/Paste menu.
168 self._saved_bookmark = None169 self._saved_bookmark = None
169170
170 self.paths = [] # list of bookmarks as string objects171 self.paths = [] # list of bookmarks as string objects
@@ -173,7 +174,8 @@
173 # Add pages from config to the bar.174 # Add pages from config to the bar.
174 for path in self.uistate['bookmarks']:175 for path in self.uistate['bookmarks']:
175 page = self.ui.notebook.get_page(Path(path))176 page = self.ui.notebook.get_page(Path(path))
176 self.add_new_page(page, reload_bar = False)177 if page.exists() and (page.name not in self.paths):
178 self.paths.append(page.name)
177179
178 self.paths_names = {} # dict of changed names of bookmarks180 self.paths_names = {} # dict of changed names of bookmarks
179 self.uistate.setdefault('bookmarks_names', {})181 self.uistate.setdefault('bookmarks_names', {})
@@ -189,46 +191,46 @@
189 except:191 except:
190 logger.error('BookmarksBar: Error while loading path_names.')192 logger.error('BookmarksBar: Error while loading path_names.')
191193
192 self._reload_bar()194 # Look for new pages to mark corresponding bookmarks in the bar.
195 self.connectto(self.ui, 'open-page', self.on_open_page)
193196
194 # Delete a bookmark if a page is deleted.197 # Delete a bookmark if a page is deleted.
195 self.connectto(self.ui.notebook.index, 'page-deleted',198 self.connectto(self.ui.notebook.index, 'page-deleted',
196 lambda obj, path: self.delete(path.name))199 lambda obj, path: self.delete(path.name))
197200
198 def add_new_page(self, page = None, reload_bar = True):201 def on_open_page(self, ui, page, path):
202 '''If a page is present as a bookmark than select it.'''
203 pagename = page.name
204 for button in self.container.get_children()[2:]:
205 if button.zim_path == pagename:
206 button.set_active(True)
207 else:
208 button.set_active(False)
209
210 def add_new_page(self, page = None):
199 '''211 '''
200 Add new page as bookmark to the bar.212 Add new page as bookmark to the bar.
201 :param page: L{Page}, if None takes currently opened page,213 :param page: L{Page}, if None takes currently opened page,
202 :reload_bar: if True reload the bar.
203 '''214 '''
204 if not page:215 if not page:
205 page = self._get_page()216 page = self._get_page()
206217
207 if page.exists():218 if page.exists():
208 return self._add_new(page.name, self.add_bookmarks_to_beginning, reload_bar)219 return self._add_new(page.name, self.add_bookmarks_to_beginning)
209220
210 def _add_new(self, path, add_bookmarks_to_beginning = False, reload_bar = True):221 def _add_new(self, path, add_bookmarks_to_beginning = False):
211 '''Add bookmark to the bar.222 '''Add bookmark to the bar.
212 :param path: path as a string object223 :param path: path as a string object
213 :param add_bookmarks_to_beginning: bool,224 :param add_bookmarks_to_beginning: bool,
214 add new bookmarks to the beginning of the bar,225 add new bookmarks to the beginning of the bar,
215 :reload_bar: if True reload the bar.
216 '''226 '''
217 if path in self.paths:227 if path in self.paths:
218 logger.debug('BookmarksBar: path is already in the bar.')228 logger.debug('BookmarksBar: path is already in the bar.')
219229 self.plus_button.blink()
220 # Temporary change icon for plus_button to show
221 # that bookmark is already in the bar.
222 def _change_icon():
223 '''Function to be called only once.'''
224 self.plus_button.change_state()
225 return False
226 self.plus_button.change_state()
227 gobject.timeout_add(300, _change_icon)
228 return False230 return False
229231
230 # Limit max number of bookmarks.232 # Limit max number of bookmarks.
231 if len(self.paths) >= MAX_BOOKMARKS:233 if self.max_bookmarks and (len(self.paths) >= self.max_bookmarks):
232 logger.debug('BookmarksBar: max number of bookmarks is achieved.')234 logger.debug('BookmarksBar: max number of bookmarks is achieved.')
233 return False235 return False
234236
@@ -238,7 +240,7 @@
238 else:240 else:
239 self.paths.append(path)241 self.paths.append(path)
240242
241 if reload_bar: self._reload_bar()243 self._reload_bar()
242244
243 def delete(self, path):245 def delete(self, path):
244 '''246 '''
@@ -284,8 +286,13 @@
284286
285 if new_path and (new_path not in self.paths) and (new_path != old_path):287 if new_path and (new_path not in self.paths) and (new_path != old_path):
286 self.paths[self.paths.index(old_path)] = new_path288 self.paths[self.paths.index(old_path)] = new_path
287 self.paths_names.pop(old_path, None)289 name = self.paths_names.pop(old_path, None)
290 if name:
291 self.paths_names[new_path] = name
292
288 self._reload_bar()293 self._reload_bar()
294 else:
295 self.plus_button.blink()
289296
290 def move_bookmark(self, first, second, direction):297 def move_bookmark(self, first, second, direction):
291 '''298 '''
@@ -350,7 +357,7 @@
350 def do_bookmarks_popup_menu(self, button, event):357 def do_bookmarks_popup_menu(self, button, event):
351 '''Handler for button-release-event, triggers popup menu for bookmarks.'''358 '''Handler for button-release-event, triggers popup menu for bookmarks.'''
352 if event.button != 3:359 if event.button != 3:
353 return False360 return False
354361
355 path = button.zim_path362 path = button.zim_path
356363
@@ -371,13 +378,12 @@
371 (_('Remove'), lambda o: self.delete(path)), # T: menu item378 (_('Remove'), lambda o: self.delete(path)), # T: menu item
372 (_('Remove All'), lambda o: self.delete_all(True)), # T: menu item379 (_('Remove All'), lambda o: self.delete_all(True)), # T: menu item
373 ('separator', ''),380 ('separator', ''),
374 (_('Open in New Window'), lambda o: self.ui.open_new_window(Path(path))), # T: menu item
375 ('separator', ''),
376 ('gtk-copy', lambda o: set_save_bookmark(path)),381 ('gtk-copy', lambda o: set_save_bookmark(path)),
377 ('gtk-paste', lambda o: self.move_bookmark(self._saved_bookmark, path, direction)),382 ('gtk-paste', lambda o: self.move_bookmark(self._saved_bookmark, path, direction)),
378 ('separator', ''),383 ('separator', ''),
384 (_('Open in New Window'), lambda o: self.ui.open_new_window(Path(path))), # T: menu item
385 ('separator', ''),
379 (rename_button_text, lambda o: self.rename_bookmark(button)),386 (rename_button_text, lambda o: self.rename_bookmark(button)),
380 ('separator', ''),
381 (_('Set to Current Page'), lambda o: self.change_bookmark(path)) ) # T: menu item387 (_('Set to Current Page'), lambda o: self.change_bookmark(path)) ) # T: menu item
382388
383 for name, func in main_menu_items:389 for name, func in main_menu_items:
@@ -412,6 +418,10 @@
412 self.uistate['bookmarks'] = []418 self.uistate['bookmarks'] = []
413 self.uistate['bookmarks_names'] = {}419 self.uistate['bookmarks_names'] = {}
414420
421 if self.max_bookmarks != preferences['max_bookmarks']:
422 self.max_bookmarks = preferences['max_bookmarks']
423 self._reload_bar() # to update plus_button
424
415 def _get_short_page_name(self, name):425 def _get_short_page_name(self, name):
416 '''426 '''
417 Function to return short name for the page.427 Function to return short name for the page.
@@ -430,6 +440,12 @@
430 for button in self.container.get_children()[2:]:440 for button in self.container.get_children()[2:]:
431 self.container.remove(button)441 self.container.remove(button)
432442
443 page = self._get_page()
444 if page:
445 pagename = page.name
446 else:
447 pagename = None
448
433 for path in self.paths:449 for path in self.paths:
434 if path in self.paths_names:450 if path in self.paths_names:
435 name = self.paths_names[path]451 name = self.paths_names[path]
@@ -437,16 +453,19 @@
437 name = self._get_short_page_name(path)453 name = self._get_short_page_name(path)
438 else:454 else:
439 name = path455 name = path
440 button = gtk.Button(label = name, use_underline = False)456 button = gtk.ToggleButton(label = name, use_underline = False)
441 button.set_tooltip_text(path)457 button.set_tooltip_text(path)
442 button.zim_path = path458 button.zim_path = path
459 if path == pagename:
460 button.set_active(True)
461
443 button.connect('clicked', self.on_bookmark_clicked)462 button.connect('clicked', self.on_bookmark_clicked)
444 button.connect('button-release-event', self.do_bookmarks_popup_menu)463 button.connect('button-release-event', self.do_bookmarks_popup_menu)
445 button.show()464 button.show()
446 self.container.add(button)465 self.container.add(button)
447466
448 # 'Disable' plus_button if max bookmarks is reached.467 # 'Disable' plus_button if max bookmarks is reached.
449 if len(self.paths) >= MAX_BOOKMARKS:468 if self.max_bookmarks and (len(self.paths) >= self.max_bookmarks):
450 self.plus_button.change_state(False)469 self.plus_button.change_state(False)
451 else:470 else:
452 self.plus_button.change_state(True)471 self.plus_button.change_state(True)
@@ -501,3 +520,13 @@
501 self._enabled_state = not self._enabled_state520 self._enabled_state = not self._enabled_state
502 self.show_all()521 self.show_all()
503522
523 def blink(self):
524 '''Quickly change an icon to show
525 that bookmark can't be added/changed.'''
526
527 def change_icon():
528 '''Function to be called only once.'''
529 self.change_state()
530 return False
531 self.change_state()
532 gobject.timeout_add(300, change_icon)