1'''library_main_dialog.py - The library dialog window.''' 2 3import os 4from gi.repository import Gdk, Gtk 5 6from mcomix.preferences import prefs 7from mcomix import i18n 8from mcomix import tools 9from mcomix import log 10from mcomix import file_chooser_library_dialog 11from mcomix import status 12from mcomix.library import backend as library_backend 13from mcomix.library import book_area as library_book_area 14from mcomix.library import collection_area as library_collection_area 15from mcomix.library import control_area as library_control_area 16from mcomix.library import add_progress_dialog as library_add_progress_dialog 17 18_dialog = None 19# The "All books" collection is not a real collection stored in the library, 20# but is represented by this ID in the library's TreeModels. 21_COLLECTION_ALL = -1 22 23class _LibraryDialog(Gtk.Window): 24 25 '''The library window. Automatically creates and uses a new 26 library_backend.LibraryBackend when opened. 27 ''' 28 29 def __init__(self, window, file_handler): 30 super(_LibraryDialog, self).__init__(type=Gtk.WindowType.TOPLEVEL) 31 32 self._window = window 33 34 self.resize(prefs['lib window width'], prefs['lib window height']) 35 self.set_title(_('Library')) 36 self.connect('delete_event', self.close) 37 self.connect('key-press-event', self._key_press_event) 38 39 self.filter_string = None 40 self._file_handler = file_handler 41 self._statusbar = Gtk.Statusbar() 42 self.backend = library_backend.LibraryBackend() 43 self.book_area = library_book_area._BookArea(self) 44 self.control_area = library_control_area._ControlArea(self) 45 self.collection_area = library_collection_area._CollectionArea(self) 46 47 self.backend.watchlist.new_files_found += self._new_files_found 48 49 table = Gtk.Table(n_rows=2, n_columns=2, homogeneous=False) 50 table.attach(self.collection_area, 0, 1, 0, 1, Gtk.AttachOptions.FILL, 51 Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL) 52 table.attach(self.book_area, 1, 2, 0, 1, Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL, 53 Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL) 54 table.attach(self.control_area, 0, 2, 1, 2, Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL, 55 Gtk.AttachOptions.FILL) 56 57 if prefs['show statusbar']: 58 table.attach(self._statusbar, 0, 2, 2, 3, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL) 59 60 self.add(table) 61 self.show_all() 62 self.present() 63 64 def open_book(self, books, keep_library_open=False): 65 '''Open the book with ID <book>.''' 66 67 paths = [ self.backend.get_book_path(book) for book in books ] 68 69 if not keep_library_open: 70 self.hide() 71 72 self._window.present() 73 74 if len(paths) > 1: 75 self._file_handler.open_file(paths) 76 elif len(paths) == 1: 77 self._file_handler.open_file(paths[0]) 78 79 def scan_for_new_files(self): 80 ''' Start scanning for new files from the watch list. ''' 81 82 if len(self.backend.watchlist.get_watchlist()) > 0: 83 self.set_status_message(_('Scanning for new books...')) 84 self.backend.watchlist.scan_for_new_files() 85 86 def _new_files_found(self, filelist, watchentry): 87 ''' Called after the scan for new files finished. ''' 88 89 if len(filelist) > 0: 90 if watchentry.collection.id is not None: 91 collection_name = watchentry.collection.name 92 else: 93 collection_name = None 94 95 self.add_books(filelist, collection_name) 96 97 if len(filelist) == 1: 98 message = _('Added new book "%(bookname)s" ' 99 'from directory "%(directory)s".') 100 else: 101 message = _('Added %(count)d new books ' 102 'from directory "%(directory)s".') 103 104 self.set_status_message(message % { 105 'directory': watchentry.directory, 106 'count': len(filelist), 107 'bookname': os.path.basename(filelist[0]), 108 }) 109 else: 110 self.set_status_message( 111 _('No new books found in directory "%s".') % watchentry.directory) 112 113 def get_status_bar(self): 114 ''' Returns the window's status bar. ''' 115 return self._statusbar 116 117 def set_status_message(self, message): 118 '''Set a specific message on the statusbar, replacing whatever was 119 there earlier. 120 ''' 121 self._statusbar.pop(0) 122 self._statusbar.push( 123 0, 124 ' ' * status.Statusbar.SPACING + '%s' % i18n.to_unicode(message)) 125 126 def close(self, *args): 127 '''Close the library and do required cleanup tasks.''' 128 prefs['lib window width'], prefs['lib window height'] = self.get_size() 129 self.backend.watchlist.new_files_found -= self._new_files_found 130 self.book_area.stop_update() 131 self.book_area.close() 132 file_chooser_library_dialog.close_library_filechooser_dialog() 133 _close_dialog() 134 135 def add_books(self, paths, collection_name=None): 136 '''Add the books at <paths> to the library. If <collection_name> 137 is not None, it is the name of a (new or existing) collection the 138 books should be put in. 139 ''' 140 if collection_name is None: 141 collection_id = self.collection_area.get_current_collection() 142 else: 143 collection = self.backend.get_collection_by_name(collection_name) 144 145 if collection is None: # Collection by that name doesn't exist. 146 self.backend.add_collection(collection_name) 147 collection = self.backend.get_collection_by_name( 148 collection_name) 149 150 collection_id = collection.id 151 152 library_add_progress_dialog._AddLibraryProgressDialog(self, self._window, paths, collection_id) 153 154 if collection_id is not None: 155 prefs['last library collection'] = collection_id 156 157 def _key_press_event(self, widget, event, *args): 158 ''' Handle key press events for closing the library on Escape press. ''' 159 160 if event.keyval == Gdk.KEY_Escape: 161 self.hide() 162 163 164def open_dialog(action, window): 165 ''' Shows the library window. If sqlite is not available, this method 166 does nothing and returns False. Otherwise, True is returned. ''' 167 global _dialog 168 169 if _dialog is None: 170 171 if library_backend.sqlite3 is None: 172 text = _('! python need sqlite support to use the library.') 173 window.osd.show(text) 174 log.error(text) 175 return False 176 177 else: 178 _dialog = _LibraryDialog(window, window.filehandler) 179 180 else: 181 _dialog.present() 182 183 if prefs['scan for new books on library startup']: 184 _dialog.scan_for_new_files() 185 186 return True 187 188 189def _close_dialog(*args): 190 global _dialog 191 192 if _dialog is not None: 193 _dialog.destroy() 194 _dialog = None 195 tools.garbage_collect() 196 197# vim: expandtab:sw=4:ts=4 198