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