Compare commits
	
		
			2 Commits
		
	
	
		
			0b960cbae6
			...
			50227b9a2b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 50227b9a2b | |||
| 48d1a28783 | 
							
								
								
									
										47
									
								
								src/book_import_scheme.xsd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/book_import_scheme.xsd
									
									
									
									
									
										Normal 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>
 | 
			
		||||
@ -1,40 +1,66 @@
 | 
			
		||||
from PySide6.QtGui import QGuiApplication, QAction
 | 
			
		||||
from PySide6.QtQml import QQmlApplicationEngine
 | 
			
		||||
from PySide6 import QtWidgets, QtCore
 | 
			
		||||
from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel
 | 
			
		||||
 | 
			
		||||
from models.book_overview import BooksOverview
 | 
			
		||||
from PySide6.QtWidgets import (
 | 
			
		||||
    QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QTextEdit, QPushButton, QComboBox, QFormLayout
 | 
			
		||||
)
 | 
			
		||||
from models.book import Book, BookStatusEnum
 | 
			
		||||
 | 
			
		||||
class BookEditor(QDialog):
 | 
			
		||||
    def __init__(self, book_overview: BooksOverview, parent=None):
 | 
			
		||||
    def __init__(self, book: Book, parent=None):
 | 
			
		||||
        super().__init__(parent)
 | 
			
		||||
 | 
			
		||||
        self.setWindowTitle("Edit a book")
 | 
			
		||||
        self.book = book
 | 
			
		||||
        self.setWindowTitle("Edit Book")
 | 
			
		||||
        self.setMinimumSize(400, 300)
 | 
			
		||||
 | 
			
		||||
        # Create layout
 | 
			
		||||
        # Create main layout
 | 
			
		||||
        layout = QVBoxLayout(self)
 | 
			
		||||
 | 
			
		||||
        data_mode_layout = QHBoxLayout()
 | 
			
		||||
        # Form layout for book fields
 | 
			
		||||
        form_layout = QFormLayout()
 | 
			
		||||
 | 
			
		||||
        self.data_mode_label = QLabel("Data mode:")
 | 
			
		||||
        data_mode_layout.addWidget(self.data_mode_label)
 | 
			
		||||
        # Title field
 | 
			
		||||
        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
 | 
			
		||||
        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)
 | 
			
		||||
        button_layout.addWidget(self.save_button)
 | 
			
		||||
 | 
			
		||||
        self.cancel_button = QtWidgets.QPushButton("Discard")
 | 
			
		||||
        self.cancel_button = QPushButton("Discard")
 | 
			
		||||
        self.cancel_button.clicked.connect(self.reject)
 | 
			
		||||
        button_layout.addWidget(self.cancel_button)
 | 
			
		||||
 | 
			
		||||
        layout.addLayout(button_layout)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    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()
 | 
			
		||||
 | 
			
		||||
@ -1,27 +1,32 @@
 | 
			
		||||
from PySide6.QtGui import QGuiApplication, QAction, Qt
 | 
			
		||||
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 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 utils.database import DatabaseManager
 | 
			
		||||
 | 
			
		||||
STATUS_TO_COLOR_MAP = {
 | 
			
		||||
    BookStatusEnum.available: "#3c702e",
 | 
			
		||||
    BookStatusEnum.borrowed: "#702525",
 | 
			
		||||
    BookStatusEnum.reserved: "#bc7613"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BookCard(QWidget):
 | 
			
		||||
    def __init__(self, book_overview: BooksOverview):
 | 
			
		||||
        super().__init__()
 | 
			
		||||
 | 
			
		||||
        self.book_overview = book_overview
 | 
			
		||||
 | 
			
		||||
        self.setAttribute(Qt.WidgetAttribute.WA_Hover, True)  # Enable hover events
 | 
			
		||||
        self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True)  # Enable styling for background
 | 
			
		||||
        self.setAttribute(Qt.WidgetAttribute.WA_Hover,
 | 
			
		||||
                          True)  # Enable hover events
 | 
			
		||||
        # Enable styling for background
 | 
			
		||||
        self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True)
 | 
			
		||||
 | 
			
		||||
        # Set initial stylesheet with hover behavior
 | 
			
		||||
        self.setStyleSheet("""
 | 
			
		||||
@ -33,7 +38,8 @@ class BookCard(QWidget):
 | 
			
		||||
        # Layout setup
 | 
			
		||||
        layout = QHBoxLayout(self)
 | 
			
		||||
        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.setSpacing(10)
 | 
			
		||||
@ -54,7 +60,8 @@ class BookCard(QWidget):
 | 
			
		||||
        layout.addLayout(right_side)
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
 | 
			
		||||
        right_side.addWidget(status_label)
 | 
			
		||||
@ -87,12 +94,26 @@ class BookCard(QWidget):
 | 
			
		||||
            action_mark_returned = context_menu.addAction("Mark as Returned")
 | 
			
		||||
 | 
			
		||||
        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()))
 | 
			
		||||
 | 
			
		||||
        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:
 | 
			
		||||
            print("Edit Author selected")
 | 
			
		||||
        elif action == action_mark_returned:
 | 
			
		||||
 | 
			
		||||
@ -56,10 +56,35 @@ class LibraryWindow(QtWidgets.QMainWindow):
 | 
			
		||||
        # File menu
 | 
			
		||||
        file_menu = menu_bar.addMenu("File")
 | 
			
		||||
 | 
			
		||||
        import_action = QAction("Import books", self)
 | 
			
		||||
        import_action.triggered.connect(self.import_data)
 | 
			
		||||
        file_menu.addAction(import_action)
 | 
			
		||||
        # New submenu
 | 
			
		||||
        new_submenu = QtWidgets.QMenu(self)
 | 
			
		||||
        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.triggered.connect(self.export_data)
 | 
			
		||||
        file_menu.addAction(export_action)
 | 
			
		||||
@ -92,8 +117,11 @@ class LibraryWindow(QtWidgets.QMainWindow):
 | 
			
		||||
        if dialog.exec() == QtWidgets.QDialog.Accepted:
 | 
			
		||||
            print("Settings were saved.")
 | 
			
		||||
 | 
			
		||||
    def open_file(self):
 | 
			
		||||
        QtWidgets.QMessageBox.information(self, "Open File", "Open an existing file.")
 | 
			
		||||
    def new_book(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def new_member(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def import_data(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user