1'''library_control_area.py - The window in the library that contains buttons 2and displays info.''' 3 4import os 5from gi.repository import Gtk 6from gi.repository import GLib 7from gi.repository import Pango 8 9from mcomix import i18n 10from mcomix import labels 11from mcomix.library.watchlist import WatchListDialog 12 13# The "All books" collection is not a real collection stored in the library, 14# but is represented by this ID in the library's TreeModels. 15_COLLECTION_ALL = -1 16 17 18class _ControlArea(Gtk.HBox): 19 20 '''The _ControlArea is the bottom area of the library window where 21 information is displayed and controls such as buttons reside. 22 ''' 23 24 def __init__(self, library): 25 super(_ControlArea, self).__init__(homogeneous=False, spacing=12) 26 27 self._library = library 28 self.set_border_width(10) 29 30 borderbox = Gtk.Frame() 31 borderbox.set_shadow_type(Gtk.ShadowType.ETCHED_IN) 32 borderbox.set_size_request(350, -1) 33 34 insidebox = Gtk.EventBox() 35 insidebox.set_border_width(1) 36 insidebox.set_state(Gtk.StateType.ACTIVE) 37 38 infobox = Gtk.VBox(homogeneous=False, spacing=5) 39 infobox.set_border_width(10) 40 self.pack_start(borderbox, True, True, 0) 41 borderbox.add(insidebox) 42 insidebox.add(infobox) 43 44 self._namelabel = labels.BoldLabel() 45 self._namelabel.set_alignment(0, 0.5) 46 self._namelabel.set_selectable(True) 47 self._namelabel.set_ellipsize(Pango.EllipsizeMode.MIDDLE) 48 infobox.pack_start(self._namelabel, False, False, 0) 49 50 self._filelabel = Gtk.Label() 51 self._filelabel.set_ellipsize(Pango.EllipsizeMode.MIDDLE) 52 self._filelabel.set_alignment(0, 0.5) 53 infobox.pack_start(self._filelabel, False, False, 0) 54 55 self._dirlabel = Gtk.Label() 56 self._dirlabel.set_ellipsize(Pango.EllipsizeMode.MIDDLE) 57 self._dirlabel.set_alignment(0, 0.5) 58 self._dirlabel.set_selectable(True) 59 infobox.pack_start(self._dirlabel, False, False, 0) 60 61 vbox = Gtk.VBox(homogeneous=False, spacing=10) 62 vbox.set_size_request(350, -1) 63 self.pack_start(vbox, False, False, 0) 64 65 # First line of controls, containing the search box 66 hbox = Gtk.HBox(homogeneous=False) 67 vbox.pack_start(hbox, True, True, 0) 68 69 label = Gtk.Label(label=_('_Search:')) 70 label.set_use_underline(True) 71 hbox.pack_start(label, False, False, 0) 72 search_entry = Gtk.Entry() 73 search_entry.connect('activate', self._filter_books) 74 search_entry.set_tooltip_text( 75 _('Display only those books that have the specified text string ' 76 'in their full path. The search is not case sensitive.')) 77 hbox.pack_start(search_entry, True, True, 6) 78 label.set_mnemonic_widget(search_entry) 79 80 # Last line of controls, containing buttons like 'Open' 81 hbox = Gtk.HBox(homogeneous=False, spacing=10) 82 vbox.pack_end(hbox, True, True, 0) 83 84 watchlist_button = Gtk.Button(label=_('_Watch list'), use_underline=True) 85 watchlist_button.set_always_show_image(True) 86 watchlist_button.set_image(Gtk.Image.new_from_stock(Gtk.STOCK_FIND, Gtk.IconSize.BUTTON)) 87 watchlist_button.set_image_position(Gtk.PositionType.LEFT) 88 watchlist_button.connect('clicked', 89 lambda *args: WatchListDialog(self._library)) 90 watchlist_button.set_tooltip_text( 91 _('Open the watchlist management dialog.')) 92 hbox.pack_start(watchlist_button, True, True, 0) 93 94 self._open_button = Gtk.Button(label=_('_Open list'), use_underline=True) 95 self._open_button.set_always_show_image(True) 96 self._open_button.set_image(Gtk.Image.new_from_stock(Gtk.STOCK_OPEN, Gtk.IconSize.BUTTON)) 97 self._open_button.set_image_position(Gtk.PositionType.LEFT) 98 self._open_button.connect('clicked', 99 self._library.book_area.open_selected_book) 100 self._open_button.set_tooltip_text(_('Open the selected book.')) 101 self._open_button.set_sensitive(False) 102 hbox.pack_end(self._open_button, True, True, 0) 103 104 def update_info(self, selected): 105 '''Update the info box using the currently <selected> books from 106 the _BookArea. 107 ''' 108 109 if selected: 110 book_id = self._library.book_area.get_book_at_path(selected[0]) 111 book = self._library.backend.get_book_by_id(book_id) 112 else: 113 book = None 114 115 if book: 116 name = book.name 117 dir_path = os.path.dirname(book.path) 118 pages = book.pages 119 size = book.size 120 last_page = book.get_last_read_page() 121 last_date = book.get_last_read_date() 122 else: 123 name = dir_path = pages = size = last_page = last_date = None 124 125 if len(selected) > 0: 126 self._open_button.set_sensitive(True) 127 else: 128 self._open_button.set_sensitive(False) 129 130 if name is not None: 131 self._namelabel.set_text(i18n.to_unicode(name)) 132 self._namelabel.set_tooltip_text(i18n.to_unicode(name)) 133 else: 134 self._namelabel.set_text('') 135 self._namelabel.set_has_tooltip(False) 136 137 infotext = [] 138 139 if last_page is not None and pages is not None and last_page != pages: 140 infotext.append('%s %d/%d' % (_('Page'), last_page, pages)) 141 elif pages is not None: 142 infotext.append(_('%d pages') % pages) 143 144 if size is not None: 145 infotext.append('%.1f MiB' % (size / 1048576.0)) 146 147 if (pages is not None and last_page is not None and 148 last_date is not None and last_page == pages): 149 infotext.append(_('Finished reading on %(date)s, %(time)s') % { 150 'date': last_date.strftime('%x'), 151 'time': last_date.strftime('%X'), 152 }) 153 154 self._filelabel.set_text(', '.join(infotext)) 155 156 if dir_path is not None: 157 self._dirlabel.set_text(i18n.to_unicode(dir_path)) 158 else: 159 self._dirlabel.set_text('') 160 161 def _filter_books(self, entry, *args): 162 '''Display only the books in the current collection whose paths 163 contain the string in the Gtk.Entry. The string is not 164 case-sensitive. 165 ''' 166 self._library.filter_string = entry.get_text() 167 if not self._library.filter_string: 168 self._library.filter_string = None 169 collection = self._library.collection_area.get_current_collection() 170 GLib.idle_add(self._library.book_area.display_covers, collection) 171 172# vim: expandtab:sw=4:ts=4 173