1 //
2 // C++ Implementation: bookmarks dialog
3 //
4 // Description:
5 //      Allows to set or go to bookmarks
6 //
7 // Author: Vadim Lopatin <vadim.lopatin@coolreader.org>, (C) 2008
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 // bmkdlg.cpp
12 
13 #include <cri18n.h>
14 #include "bmkdlg.h"
15 #include "mainwnd.h"
16 
17 
CRBookmarkMenuItem(CRMenu * menu,int shortcut,CRBookmark * bookmark,int page)18 CRBookmarkMenuItem::CRBookmarkMenuItem( CRMenu * menu, int shortcut, CRBookmark * bookmark, int page )
19 : CRMenuItem(menu, shortcut, lString16(_("Empty slot")), LVImageSourceRef(), LVFontRef() ), _bookmark( bookmark ), _page(page)
20 {
21 
22 }
23 
Draw(LVDrawBuf & buf,lvRect & rc,CRRectSkinRef skin,CRRectSkinRef valueSkin,bool selected)24 void CRBookmarkMenuItem::Draw( LVDrawBuf & buf, lvRect & rc, CRRectSkinRef skin, CRRectSkinRef valueSkin, bool selected )
25 {
26     _itemDirty = false;
27     if ( !_bookmark ) {
28         CRMenuItem::Draw( buf, rc, skin, valueSkin, selected );
29         return;
30     }
31     lvRect itemBorders = skin->getBorderWidths();
32     skin->draw( buf, rc );
33     buf.SetTextColor( 0x000000 );
34     buf.SetBackgroundColor( 0xFFFFFF );
35     int imgWidth = 0;
36     int hh = rc.bottom - rc.top - itemBorders.top - itemBorders.bottom;
37     if ( !_image.isNull() ) {
38         int w = _image->GetWidth();
39         int h = _image->GetHeight();
40         buf.Draw( _image, rc.left + hh/2-w/2 + itemBorders.left, rc.top + hh/2 - h/2 + itemBorders.top, w, h );
41         imgWidth = w + 8;
42     }
43     lvRect textRect = rc;
44     textRect.left += imgWidth;
45     lvRect posRect = textRect;
46     lString16 text = _bookmark->getPosText();
47     if ( !text.empty() ) {
48         posRect.bottom = posRect.top + skin->getFont()->getHeight() + itemBorders.top + itemBorders.bottom;
49         textRect.top = posRect.bottom - itemBorders.bottom;
50     }
51     lString16 postext(_("Page $1 ($2%)"));
52     postext.replaceIntParam(1, _page+1);
53     postext.replaceParam(2, lString16::itoa( _bookmark->getPercent()/100 ) << "." << fmt::decimal(_bookmark->getPercent()%100));
54     postext << "  " << _bookmark->getTitleText();
55     skin->drawText( buf, posRect, postext );
56     if ( !text.empty() )
57         valueSkin->drawText( buf, textRect, text );
58 }
59 
setMode(bool goToMode)60 void CRBookmarkMenu::setMode( bool goToMode )
61 {
62     //if ( _goToMode==goToMode )
63     //    return;
64     CRLog::trace("CRBookmarkMenu::setMode");
65     int k, f;
66 #ifdef CR_POCKETBOOK
67 	lString16 selKeyName = getCommandKeyName( MCMD_SELECT );
68 #else
69     lString16 selKeyName = getItemNumberKeysName();
70 #endif
71     lString16 modeKeyName = getCommandKeyName( MCMD_NEXT_MODE );
72     bool hasModeSwitch = !modeKeyName.empty();
73     _goToMode = goToMode;
74     if ( _goToMode ) {
75         _caption = lString16(_("Go to bookmark"));
76         _label = _caption;
77         _statusText = lString16(
78                 hasModeSwitch
79                 ? _("Short press $1 - go to bookmark,\n$2 - switch to SET mode")
80                 : _("Short press $1 - go to bookmark,\nlong press - set bookmark")
81                 );
82     } else {
83         _caption = lString16(_("Set bookmark"));
84         _label = _caption;
85         _statusText = lString16(
86                 hasModeSwitch
87                 ? _("$1 - set bookmark,\n$2 - switch to GO mode")
88                 : _("Short press $1 - set bookmark,\nlong press - go to bookmark")
89                 );
90     }
91     _statusText.replaceParam(1, selKeyName);
92     _statusText.replaceParam(2, modeKeyName);
93     setDirty();
94 }
95 
96 /// returns index of selected item, -1 if no item selected
getSelectedItemIndex()97 int CRBookmarkMenu::getSelectedItemIndex()
98 {
99     CRFileHistRecord * bookmarks = _docview->getCurrentFileHistRecord();
100     int curPage = _docview->getCurPage();
101     int n = bookmarks->getLastShortcutBookmark()+1;
102     for ( int i=1; i<=n; i++ ) {
103         CRBookmark * bm = bookmarks->getShortcutBookmark(i);
104         int page = 0;
105         if ( bm ) {
106             ldomXPointer p = _docview->getDocument()->createXPointer( bm->getStartPos() );
107             if ( !p.isNull() ) {
108                 /// get page number by bookmark
109                 page = _docview->getBookmarkPage( p );
110                 /// get bookmark position text
111                 if ( page>0 && page==curPage )
112                     return i-1;
113             }
114         }
115     }
116     return -1;
117 }
118 
119 #ifdef CR_POCKETBOOK
120 #include "cr3pocketbook.h"
121 #include "inkview.h"
122 
123 static CRBookmarkMenu *bmkDialog = NULL;
124 
125 static imenu _contextMenu[] = {
126 	{ITEM_ACTIVE, DCMD_BOOKMARK_SAVE_N, NULL, NULL},
127 	{ITEM_ACTIVE, DCMD_BOOKMARK_GO_N, NULL, NULL},
128 	{ITEM_ACTIVE, PB_CMD_BOOKMARK_REMOVE, NULL, NULL},
129 	{ 0, 0, NULL, NULL }
130 };
131 
handle_contextMenu(int index)132 static void handle_contextMenu(int index)
133 {
134 	CRLog::trace("CRBookmarkMenu handle_contextMenu(%d)", index);
135 	bmkDialog->handleContextMenu(index);
136 }
137 
getDefaultSelectionIndex()138 int CRBookmarkMenu::getDefaultSelectionIndex()
139 {
140 	if ( _goToMode )
141 		return -1;
142     CRFileHistRecord * bookmarks = _docview->getCurrentFileHistRecord();
143     for ( int i=0; i<_items.length(); i++ ) {
144         CRBookmark * bm = bookmarks->getShortcutBookmark(i);
145         if ( bm == NULL)
146 			return i;
147     }
148     return -1;
149 }
150 
showContextMenu()151 void CRBookmarkMenu::showContextMenu()
152 {
153 	CRBookmarkMenuItem *item = static_cast<CRBookmarkMenuItem *>(_items[_selectedItem]);
154 	CRMenuSkinRef skin = getSkin();
155 	CRRectSkinRef separatorSkin = skin->getSeparatorSkin();
156     int separatorHeight = 0;
157     if ( !separatorSkin.isNull() )
158         separatorHeight = separatorSkin->getMinSize().y;
159 
160     lvRect clientRect;
161     getClientRect(clientRect);
162     lvPoint itemSize = getMaxItemSize();
163 	_contextMenu[2].type = item->getBookmark() ? ITEM_ACTIVE : ITEM_INACTIVE;
164         int y = clientRect.top + (itemSize.y + separatorHeight) * (_selectedItem - _topItem) +
165 			((itemSize.y + separatorHeight)/4);
166 	if (_contextMenu[0].text == NULL) {
167 		_contextMenu[0].text = (char *)_("Set bookmark");
168 		_contextMenu[1].text = (char *)_("Go to bookmark");
169 		_contextMenu[2].text = (char *)_("Delete bookmark");
170 	}
171 	OpenMenu(_contextMenu,
172 		_goToMode ? DCMD_BOOKMARK_GO_N : DCMD_BOOKMARK_SAVE_N,
173 		ScreenWidth()/4,
174 		y,
175 		handle_contextMenu);
176 }
177 
handleContextMenu(int index)178 void CRBookmarkMenu::handleContextMenu(int index)
179 {
180 	_wm->postCommand(index, 0);
181 	_wm->processPostedEvents();
182 }
183 
184 #endif
185 
186 #define MIN_BOOKMARK_ITEMS 32
CRBookmarkMenu(CRGUIWindowManager * wm,LVDocView * docview,int numItems,lvRect & rc,bool goToMode)187 CRBookmarkMenu::CRBookmarkMenu(CRGUIWindowManager * wm, LVDocView * docview, int numItems, lvRect & rc, bool goToMode)
188     : CRFullScreenMenu( wm, MCMD_BOOKMARK_LIST, lString16(_("Bookmarks")), numItems, rc )
189     , _docview(docview)
190 {
191     CRFileHistRecord * bookmarks = docview->getCurrentFileHistRecord();
192     CRGUIAcceleratorTableRef acc = _wm->getAccTables().get("bookmarks");
193     if ( acc.isNull() )
194         acc = _wm->getAccTables().get("menu");
195     setAccelerators( acc );
196     setSkinName(lString16("#bookmarks"));
197     int mc = getSkin()->getMinItemCount();
198     if ( _pageItems < mc )
199         _pageItems = mc;
200     int n = bookmarks->getLastShortcutBookmark()+1;
201     n = (n + _pageItems - 1) / _pageItems * _pageItems;
202     int minitems = (MIN_BOOKMARK_ITEMS + _pageItems - 1) / _pageItems * _pageItems;
203     if ( n<minitems )
204         n = minitems;
205     for ( int i=1; i<=n; i++ ) {
206         CRBookmark * bm = bookmarks->getShortcutBookmark(i);
207         int page = 0;
208         if ( bm ) {
209             ldomXPointer p = docview->getDocument()->createXPointer( bm->getStartPos() );
210             if ( !p.isNull() ) {
211                 /// get page number by bookmark
212                 page = docview->getBookmarkPage( p );
213                 /// get bookmark position text
214                 if ( page<0 )
215                     bm = NULL;
216             }
217         }
218         CRBookmarkMenuItem * item = new CRBookmarkMenuItem( this, i, bm, page );
219         addItem( item );
220     }
221     setMode( goToMode );
222 #ifdef CR_POCKETBOOK
223     bmkDialog = this;
224 #endif
225 }
226 
227 /// returns true if command is processed
onCommand(int command,int params)228 bool CRBookmarkMenu::onCommand( int command, int params )
229 {
230     if ( command>=MCMD_SELECT_1 && command<=MCMD_SELECT_9 ) {
231         int index = command - MCMD_SELECT_1 + 1;
232         if ( index >=1 && index <= _pageItems ) {
233             index += _topItem;
234             int cmd = _goToMode ? DCMD_BOOKMARK_GO_N : DCMD_BOOKMARK_SAVE_N;
235             closeMenu( cmd, index );
236             return true;
237         }
238     } else if ( command>=MCMD_SELECT_1_LONG && command<=MCMD_SELECT_9_LONG ) {
239         int index = command - MCMD_SELECT_1_LONG + 1;
240         if ( index >=1 && index <= _pageItems ) {
241             index += _topItem;
242             int cmd = _goToMode ? DCMD_BOOKMARK_SAVE_N : DCMD_BOOKMARK_GO_N;
243             closeMenu( cmd, index );
244             return true;
245         }
246     } else if ( command==MCMD_NEXT_MODE || command==MCMD_PREV_MODE ) {
247         setMode( !_goToMode );
248         return true;
249     } else if (command == MCMD_SELECT) {
250 		if (_selectedItem >= 0)
251 			closeMenu( _goToMode ? DCMD_BOOKMARK_GO_N : DCMD_BOOKMARK_SAVE_N, _selectedItem + 1 );
252 		return true;
253 	} else if (command == MCMD_SELECT_LONG) {
254 #ifdef CR_POCKETBOOK
255 		if (_selectedItem >= 0)
256 			showContextMenu();
257 #else
258 		if (_selectedItem >= 0)
259 			closeMenu( _goToMode ? DCMD_BOOKMARK_SAVE_N : DCMD_BOOKMARK_GO_N, _selectedItem + 1 );
260 #endif
261 		return true;
262 	} else if (command == MCMD_PREV_PAGE) {
263 		if (_topItem == 0) {
264 			closeMenu(0);
265 			return true;
266 		}
267 	}
268 #ifdef CR_POCKETBOOK
269 	 else if (command == DCMD_BOOKMARK_SAVE_N || command == DCMD_BOOKMARK_GO_N) {
270 		 closeMenu( command, _selectedItem + 1 );
271 		 return true;
272 	 } else if (command == PB_CMD_BOOKMARK_REMOVE && _selectedItem >= 0) {
273 		 CRBookmarkMenuItem *item = static_cast<CRBookmarkMenuItem *>(_items[_selectedItem]);
274 		 CRBookmark *bm = item->getBookmark();
275 		 if (bm && _docview->removeBookmark(bm)) {
276 			 item->setBookmark(NULL);
277 			 setDirty();
278 		 }
279 		 return true;
280 	 }
281 #endif
282     return CRMenu::onCommand(command, params);
283     //closeMenu( 0 );
284     //return true;
285 }
286 
287 #ifdef CR_POCKETBOOK
288 static CRCitesMenu *citesDialog = NULL;
289 
290 static imenu _cites_contextMenu[] = {
291         {ITEM_ACTIVE, DCMD_BOOKMARK_GO_N, NULL, NULL},
292         {ITEM_ACTIVE, PB_CMD_BOOKMARK_REMOVE, NULL, NULL},
293         { 0, 0, NULL, NULL }
294 };
295 
handle_citesContextMenu(int index)296 static void handle_citesContextMenu(int index)
297 {
298     citesDialog->handleContextMenu(index);
299 }
300 
showContextMenu()301 void CRCitesMenu::showContextMenu()
302 {
303     CRBookmarkMenuItem *item = static_cast<CRBookmarkMenuItem *>(_items[_selectedItem]);
304     if (item->getBookmark() == NULL)
305         return;
306     CRMenuSkinRef skin = getSkin();
307     CRRectSkinRef separatorSkin = skin->getSeparatorSkin();
308     int separatorHeight = 0;
309     if ( !separatorSkin.isNull() )
310         separatorHeight = separatorSkin->getMinSize().y;
311     lvRect clientRect;
312     getClientRect(clientRect);
313     lvPoint itemSize = getMaxItemSize();
314     int y = clientRect.top + (itemSize.y + separatorHeight) * (_selectedItem - _topItem) +
315                         ((itemSize.y + separatorHeight)/4);
316     if (_cites_contextMenu[0].text == NULL) {
317         _cites_contextMenu[0].text = (char *)_("Go to citation");
318         _cites_contextMenu[1].text = (char *)_("Delete citation");
319     }
320     OpenMenu(_cites_contextMenu, DCMD_BOOKMARK_GO_N, ScreenWidth()/4, y,
321                 handle_citesContextMenu);
322 }
323 
handleContextMenu(int index)324 void CRCitesMenu::handleContextMenu(int index)
325 {
326     _wm->postCommand(index, 0);
327     _wm->processPostedEvents();
328 }
329 #endif
330 
CRCitesMenu(CRGUIWindowManager * wm,LVDocView * docview,int numItems,lvRect & rc)331 CRCitesMenu::CRCitesMenu(CRGUIWindowManager * wm, LVDocView * docview, int numItems, lvRect & rc)
332     : CRFullScreenMenu( wm, MCMD_CITES_LIST, lString16(_("Citations")), numItems, rc )
333     , _docview(docview)
334 {
335     CRGUIAcceleratorTableRef acc = _wm->getAccTables().get("bookmarks");
336     if ( acc.isNull() )
337         acc = _wm->getAccTables().get("menu");
338     setAccelerators( acc );
339     setSkinName(lString16("#bookmarks"));
340     int mc = getSkin()->getMinItemCount();
341     if ( _pageItems < mc )
342         _pageItems = mc;
343     CRFileHistRecord * rec = docview->getCurrentFileHistRecord();
344     LVPtrVector < CRBookmark > &bookmarks = rec->getBookmarks();
345     for ( int i=0; i < bookmarks.length(); i++ ) {
346         CRBookmark * bmk = bookmarks[i];
347         if (!bmk || ((bmk->getType() != bmkt_comment && bmk->getType() != bmkt_correction)))
348             continue;
349         ldomXPointer p = docview->getDocument()->createXPointer( bmk->getStartPos() );
350         if ( p.isNull() )
351             continue;
352         int page = docview->getBookmarkPage( p );
353         /// get bookmark position text
354         if ( page<0 )
355             continue;
356         CRBookmarkMenuItem * item = new CRBookmarkMenuItem( this, i, bmk, page );
357         addItem( item );
358     }
359 #ifdef CR_POCKETBOOK
360     citesDialog = this;
361 #endif
362     if (_items.length() == 0)
363         createDefaultItem();
364 }
365 
366 /// returns true if command is processed
onCommand(int command,int params)367 bool CRCitesMenu::onCommand( int command, int params )
368 {
369     if ( command>=MCMD_SELECT_1 && command<=MCMD_SELECT_9 ) {
370         int index = command - MCMD_SELECT_1 + 1;
371         if ( index >=1 && index <= _pageItems ) {
372             index += _topItem;
373             goToCitePage( index - 1);
374             return true;
375         }
376     } else if (command == MCMD_SELECT) {
377         if (_selectedItem >= 0)
378             goToCitePage(_selectedItem );
379         return true;
380     } else if (command == MCMD_SELECT_LONG) {
381 #ifdef CR_POCKETBOOK
382         if (_selectedItem >= 0)
383             showContextMenu();
384 #endif
385         return true;
386     } else if (command == MCMD_PREV_PAGE) {
387         if (_topItem == 0) {
388             closeMenu(0);
389             return true;
390         }
391     }
392 #ifdef CR_POCKETBOOK
393     else if (command == DCMD_BOOKMARK_GO_N) {
394         goToCitePage( _selectedItem );
395         return true;
396     } else if (command == PB_CMD_BOOKMARK_REMOVE && _selectedItem >= 0) {
397         CRBookmarkMenuItem *item = static_cast<CRBookmarkMenuItem *>(_items[_selectedItem]);
398         CRBookmark *bm = item->getBookmark();
399         if (bm && _docview->removeBookmark(bm)) {
400             item = static_cast<CRBookmarkMenuItem *>(_items.remove(_selectedItem));
401             delete item;
402             if (_selectedItem >= _items.length()) {
403                 _selectedItem = _items.length() -1;
404                 if (_selectedItem < 0) {
405                     createDefaultItem();
406                     _selectedItem = 0;
407                 }
408             }
409             setDirty();
410             _pageUpdate = true;
411         }
412         return true;
413     }
414 #endif
415     return CRMenu::onCommand(command, params);
416 }
417 
goToCitePage(int selecteditem)418 void CRCitesMenu::goToCitePage(int selecteditem)
419 {
420     if (selecteditem >= 0 && selecteditem < _items.length()) {
421         CRBookmarkMenuItem *item = static_cast<CRBookmarkMenuItem *>(_items[_selectedItem]);
422         if (item->getBookmark() == NULL)
423             closeMenu(MCMD_CITE);
424         else
425             closeMenu( DCMD_GO_PAGE, item->getPage() );
426     }
427 }
428 
getSelectedItemIndex()429 int CRCitesMenu::getSelectedItemIndex()
430 {
431     CRFileHistRecord * bookmarks = _docview->getCurrentFileHistRecord();
432     int curPage = _docview->getCurPage();
433     for (int i = 0; i < _items.length(); i++) {
434         CRBookmarkMenuItem *item = static_cast<CRBookmarkMenuItem *>(_items[i]);
435         if (item->getPage() == curPage)
436             return i;
437     }
438     return -1;
439 }
440 
createDefaultItem()441 void CRCitesMenu::createDefaultItem()
442 {
443     CRBookmarkMenuItem * item = new CRBookmarkMenuItem( this, 0, NULL, 0 );
444     item->setLabel(lString16(_("Cite selection dialog")));
445     addItem( item );
446 }
447