import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk import src.utils as utils import src.models as models from src.ui.entry_list import EntryList from src.ui.book_entries import BookEntries from src.ui.cover_entry import CoverEntry import src.book_store as book_store import src.book_files as book_files import src.str_format as str_format class BookForm(Gtk.Window): def __init__(self, parent_window, resources, library, conn, init_progress, on_book_saved, book = None): Gtk.Window.__init__(self) self._book = book self._library = library self._conn = conn self._on_book_saved = on_book_saved title = 'Modifier un livre' if book else 'Ajouter un livre' utils.configure_dialog(self, parent_window, title, height=800) scrolled_window = Gtk.ScrolledWindow() self.set_child(scrolled_window) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=20) scrolled_window.set_child(box) utils.set_margin(box, 20) # Cover and form cover_and_form = Gtk.Box(spacing=20) box.append(cover_and_form) cover_path = f'{library}/{book['id']}/cover.png' if book else None self._cover_entry = CoverEntry(parent_window, resources, cover_path) cover_and_form.append(self._cover_entry) top_form = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=20) cover_and_form.append(top_form) # Title and subtitle self._title, self._subtitle = double_entry(top_form, 'Titre') self._title.set_hexpand(True) # Year, lang and progress year_lang_progress = Gtk.Box(spacing=10) top_form.append(year_lang_progress) self._year = labeled_entry(year_lang_progress, 'Année') self._lang = dropdown(year_lang_progress, 'Langue', models.langs) self._progress = dropdown(year_lang_progress, 'Progrès', models.all_progress, init_progress) # Authors, genres authors_genres = Gtk.Box(spacing=10) box.append(authors_genres) self._authors = EntryList('Auteurs') authors_genres.append(self._authors) self._genres = EntryList('Genres') authors_genres.append(self._genres) # Summary summary_box = label_box(box, 'Résumé') self._summary = Gtk.TextView() self._summary.set_wrap_mode(Gtk.WrapMode.WORD) self._summary.set_top_margin(10) self._summary.set_right_margin(10) self._summary.set_bottom_margin(10) self._summary.set_left_margin(10) summary_box.append(self._summary) # Books self._book_entries = BookEntries(self) box.append(self._book_entries) # Init values if book: book_id = book['id'] data = book['data'] update_entry(self._title, data['title']) if 'subtitle' in data: update_entry(self._subtitle, data['subtitle']) if 'year' in data: update_entry(self._year, str(data['year'])) if 'lang' in data: self._lang.set_selected(models.langs.index(data['lang'])) for author in data['authors']: self._authors.add_entry(author) for genre in data['genres']: self._genres.add_entry(genre) self._summary.get_buffer().set_text(data['summary']) for path in book_files.get(self._library, book_id): self._book_entries.add_book(path) else: self._authors.add_entry('') self._genres.add_entry('') # Button validate = Gtk.Button(label='Modifier' if book else 'Ajouter') validate.connect('clicked', lambda _: self._on_validate()) box.append(validate) def _on_validate(self): data = {} data['title'] = self._title.get_text() data['subtitle'] = self._subtitle.get_text() match safe_string_to_int(self._year.get_text()): case None: pass case n: data['year'] = n data['lang'] = self._lang.get_selected_item().get_string() data['progress'] = self._progress.get_selected_item().get_string() data['authors'] = non_empty(self._authors.get_entry_texts()) data['genres'] = non_empty(self._genres.get_entry_texts()) data['summary'] = str_format.cleanup_text(text_view_text(self._summary), data['lang']) cover = self._cover_entry.get_image() books = self._book_entries.get_books() book_id = book_store.store(self._library, self._conn, data, cover, books, self._book) if book_id: self.close() self._on_book_saved(book_id, data) def non_empty(xs): return [x.strip() for x in xs if x.strip()] def safe_string_to_int(n): try: return int(n) except ValueError: return None def double_entry(parent, label): box = label_box(parent, label) entry1 = Gtk.Entry() entry2 = Gtk.Entry() box.append(entry1) box.append(entry2) return entry1, entry2 def labeled_entry(parent, label): box = label_box(parent, label) entry = Gtk.Entry() box.append(entry) return entry def dropdown(parent, label, values, selected = None): box = label_box(parent, label) dropdown = Gtk.DropDown.new_from_strings(values) box.append(dropdown) if selected: dropdown.set_selected(values.index(selected)) return dropdown def label_box(parent, label): box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) box.append(utils.label(label)) parent.append(box) return box def text_view_text(text_view): buffer = text_view.get_buffer() start, end = buffer.get_bounds() return buffer.get_text(start, end, False) def update_entry(entry, text): entry.set_buffer(Gtk.EntryBuffer.new(text, len(text)))