Compare commits

..

2 Commits

4 changed files with 155 additions and 33 deletions

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="books">
<xs:complexType>
<xs:sequence>
<xs:element name="book" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title"> <!-- Book title-->
<xs:simpleType>
<!-- Allow for a string 2-100 characters long -->
<xs:restriction base="xs:string">
<xs:minLength value="2" />
<xs:maxLength value="100" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="description" type="xs:string" /> <!-- Description -->
<xs:element name="year_published"> <!-- Year published -->
<xs:simpleType>
<xs:restriction base="xs:gYear" />
</xs:simpleType>
</xs:element>
<xs:element name="isbn"> <!-- ISBN -->
<xs:simpleType>
<!-- Strictly limit to either 10 or 13 digits -->
<xs:restriction base="xs:string">
<xs:pattern value="\d{10}" />
<xs:pattern value="\d{13}" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="categories"> <!-- Categories list -->
<xs:complexType>
<xs:sequence>
<xs:element name="category" type="xs:string" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -1,40 +1,66 @@
from PySide6.QtGui import QGuiApplication, QAction from PySide6.QtWidgets import (
from PySide6.QtQml import QQmlApplicationEngine QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QTextEdit, QPushButton, QComboBox, QFormLayout
from PySide6 import QtWidgets, QtCore )
from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel from models.book import Book, BookStatusEnum
from models.book_overview import BooksOverview
class BookEditor(QDialog): class BookEditor(QDialog):
def __init__(self, book_overview: BooksOverview, parent=None): def __init__(self, book: Book, parent=None):
super().__init__(parent) super().__init__(parent)
self.setWindowTitle("Edit a book") self.book = book
self.setWindowTitle("Edit Book")
self.setMinimumSize(400, 300) self.setMinimumSize(400, 300)
# Create layout # Create main layout
layout = QVBoxLayout(self) layout = QVBoxLayout(self)
data_mode_layout = QHBoxLayout() # Form layout for book fields
form_layout = QFormLayout()
self.data_mode_label = QLabel("Data mode:") # Title field
data_mode_layout.addWidget(self.data_mode_label) self.title_input = QLineEdit(self.book.title)
form_layout.addRow("Title:", self.title_input)
# Description field
self.description_input = QTextEdit(self.book.description)
form_layout.addRow("Description:", self.description_input)
# Year published field
self.year_input = QLineEdit(self.book.year_published)
form_layout.addRow("Year Published:", self.year_input)
# ISBN field
self.isbn_input = QLineEdit(self.book.isbn)
form_layout.addRow("ISBN:", self.isbn_input)
# Status dropdown
self.status_input = QComboBox()
self.status_input.addItems([status.value for status in BookStatusEnum])
self.status_input.setCurrentText(self.book.status.value)
form_layout.addRow("Status:", self.status_input)
layout.addLayout(form_layout)
# Buttons # Buttons
button_layout = QtWidgets.QHBoxLayout() button_layout = QHBoxLayout()
self.save_button = QtWidgets.QPushButton("Save") self.save_button = QPushButton("Save")
self.save_button.clicked.connect(self.save_book) self.save_button.clicked.connect(self.save_book)
button_layout.addWidget(self.save_button) button_layout.addWidget(self.save_button)
self.cancel_button = QtWidgets.QPushButton("Discard") self.cancel_button = QPushButton("Discard")
self.cancel_button.clicked.connect(self.reject) self.cancel_button.clicked.connect(self.reject)
button_layout.addWidget(self.cancel_button) button_layout.addWidget(self.cancel_button)
layout.addLayout(button_layout) layout.addLayout(button_layout)
def save_book(self): def save_book(self):
pass # Update book object with input values
self.book.title = self.title_input.text()
self.book.description = self.description_input.toPlainText()
self.book.year_published = self.year_input.text()
self.book.isbn = self.isbn_input.text()
self.book.status = BookStatusEnum(self.status_input.currentText())
# Accept the dialog and close
self.accept()

View File

@ -1,27 +1,32 @@
from PySide6.QtGui import QGuiApplication, QAction, Qt from PySide6.QtGui import QGuiApplication, QAction, Qt
from PySide6.QtQml import QQmlApplicationEngine from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtWidgets import QHBoxLayout, QVBoxLayout, QLabel, QWidget, QMenu, QSizePolicy, QLayout from PySide6.QtWidgets import QHBoxLayout, QVBoxLayout, QLabel, QWidget, QMenu, QSizePolicy, QLayout, QMessageBox
from PySide6.QtCore import qDebug from PySide6.QtCore import qDebug
from ui.book_editor.book_editor import BookEditor from ui.book_editor.book_editor import BookEditor
from models.book import BookStatusEnum from models.book import BookStatusEnum, Book
from models.book_overview import BooksOverview from models.book_overview import BooksOverview
from utils.database import DatabaseManager
STATUS_TO_COLOR_MAP = { STATUS_TO_COLOR_MAP = {
BookStatusEnum.available: "#3c702e", BookStatusEnum.available: "#3c702e",
BookStatusEnum.borrowed: "#702525", BookStatusEnum.borrowed: "#702525",
BookStatusEnum.reserved: "#bc7613" BookStatusEnum.reserved: "#bc7613"
} }
class BookCard(QWidget): class BookCard(QWidget):
def __init__(self, book_overview: BooksOverview): def __init__(self, book_overview: BooksOverview):
super().__init__() super().__init__()
self.book_overview = book_overview self.book_overview = book_overview
self.setAttribute(Qt.WidgetAttribute.WA_Hover, True) # Enable hover events self.setAttribute(Qt.WidgetAttribute.WA_Hover,
self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True) # Enable styling for background True) # Enable hover events
# Enable styling for background
self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True)
# Set initial stylesheet with hover behavior # Set initial stylesheet with hover behavior
self.setStyleSheet(""" self.setStyleSheet("""
@ -33,7 +38,8 @@ class BookCard(QWidget):
# Layout setup # Layout setup
layout = QHBoxLayout(self) layout = QHBoxLayout(self)
layout.setSizeConstraint(QLayout.SizeConstraint.SetMinimumSize) layout.setSizeConstraint(QLayout.SizeConstraint.SetMinimumSize)
self.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed) self.setSizePolicy(QSizePolicy.Policy.Preferred,
QSizePolicy.Policy.Fixed)
layout.setContentsMargins(10, 10, 10, 10) layout.setContentsMargins(10, 10, 10, 10)
layout.setSpacing(10) layout.setSpacing(10)
@ -54,7 +60,8 @@ class BookCard(QWidget):
layout.addLayout(right_side) layout.addLayout(right_side)
status_label = QLabel(str(book_overview.status.value.capitalize())) status_label = QLabel(str(book_overview.status.value.capitalize()))
status_label.setStyleSheet(f"color: {STATUS_TO_COLOR_MAP[book_overview.status]}; font-size: 20px; font-weight: bold;") status_label.setStyleSheet(f"color: {
STATUS_TO_COLOR_MAP[book_overview.status]}; font-size: 20px; font-weight: bold;")
status_label.setAlignment(Qt.AlignmentFlag.AlignRight) status_label.setAlignment(Qt.AlignmentFlag.AlignRight)
right_side.addWidget(status_label) right_side.addWidget(status_label)
@ -87,12 +94,26 @@ class BookCard(QWidget):
action_mark_returned = context_menu.addAction("Mark as Returned") action_mark_returned = context_menu.addAction("Mark as Returned")
if self.book_overview.status == BookStatusEnum.reserved: if self.book_overview.status == BookStatusEnum.reserved:
action_remove_reservation = context_menu.addAction("Remove reservation") action_remove_reservation = context_menu.addAction(
"Remove reservation")
action = context_menu.exec_(self.mapToGlobal(event.pos())) action = context_menu.exec_(self.mapToGlobal(event.pos()))
if action == action_edit_book: if action == action_edit_book:
BookEditor(self.book_overview).exec() with DatabaseManager.get_session() as session:
book_id = self.book_overview.id
book = session.query(Book).filter(
Book.id == book_id).one_or_none()
if book:
BookEditor(book).exec()
else:
QMessageBox.critical(self,
"Error",
"The book you requested could not be found. Try again later",
QMessageBox.StandardButton.Ok,
QMessageBox.StandardButton.NoButton)
elif action == action_edit_author: elif action == action_edit_author:
print("Edit Author selected") print("Edit Author selected")
elif action == action_mark_returned: elif action == action_mark_returned:

View File

@ -56,10 +56,35 @@ class LibraryWindow(QtWidgets.QMainWindow):
# File menu # File menu
file_menu = menu_bar.addMenu("File") file_menu = menu_bar.addMenu("File")
import_action = QAction("Import books", self) # New submenu
import_action.triggered.connect(self.import_data) new_submenu = QtWidgets.QMenu(self)
file_menu.addAction(import_action) new_submenu.setTitle("New")
file_menu.addMenu(new_submenu)
# New book action
new_book_action = QAction("New book", self)
new_book_action.triggered.connect(self.new_book)
new_submenu.addAction(new_book_action)
# New book action
new_member_action = QAction("New member", self)
new_member_action.triggered.connect(self.new_member)
new_submenu.addAction(new_member_action)
# Import submenu
import_submenu = QtWidgets.QMenu(self)
import_submenu.setTitle("Import")
file_menu.addMenu(import_submenu)
import_books_action = QAction("Import books", self)
import_books_action.triggered.connect(self.import_data)
import_submenu.addAction(import_books_action)
import_members_action = QAction("Import members", self)
import_members_action.triggered.connect(self.import_data)
import_submenu.addAction(import_members_action)
# Export action
export_action = QAction("Export overview", self) export_action = QAction("Export overview", self)
export_action.triggered.connect(self.export_data) export_action.triggered.connect(self.export_data)
file_menu.addAction(export_action) file_menu.addAction(export_action)
@ -92,8 +117,11 @@ class LibraryWindow(QtWidgets.QMainWindow):
if dialog.exec() == QtWidgets.QDialog.Accepted: if dialog.exec() == QtWidgets.QDialog.Accepted:
print("Settings were saved.") print("Settings were saved.")
def open_file(self): def new_book(self):
QtWidgets.QMessageBox.information(self, "Open File", "Open an existing file.") pass
def new_member(self):
pass
def import_data(self): def import_data(self):
pass pass