From 2e9bf5028373d5fac9921ee8b3e87b5fceaca080 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 18 Oct 2024 15:59:24 +0100 Subject: [PATCH] - Tidy up and spliting of ui to seperate file --- DBEditor/DBEditor.py | 705 +++++-------------------- DBEditor/database_operations.py | 114 ---- DBEditor/db_editor.py | 19 - DBEditor/encounter_operations.py | 12 - DBEditor/event_system.py | 59 +++ DBEditor/evolution_operations.py | 12 - DBEditor/main.py | 9 - DBEditor/patch_operations.py | 12 - DBEditor/pokemon_db_ui.py | 585 ++++++++++++++++++++ DBEditor/pokemon_details_operations.py | 8 - DBEditor/pokemon_list_operations.py | 13 - DBEditor/ui_components.py | 8 - 12 files changed, 781 insertions(+), 775 deletions(-) delete mode 100644 DBEditor/database_operations.py delete mode 100644 DBEditor/db_editor.py delete mode 100644 DBEditor/encounter_operations.py create mode 100644 DBEditor/event_system.py delete mode 100644 DBEditor/evolution_operations.py delete mode 100644 DBEditor/main.py delete mode 100644 DBEditor/patch_operations.py create mode 100644 DBEditor/pokemon_db_ui.py delete mode 100644 DBEditor/pokemon_details_operations.py delete mode 100644 DBEditor/pokemon_list_operations.py delete mode 100644 DBEditor/ui_components.py diff --git a/DBEditor/DBEditor.py b/DBEditor/DBEditor.py index 06f906c..f3ecce2 100644 --- a/DBEditor/DBEditor.py +++ b/DBEditor/DBEditor.py @@ -1,7 +1,8 @@ import sys from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QListWidget, QLineEdit, QLabel, QCheckBox, QPushButton, QFormLayout, QListWidgetItem, QSplitter, QTreeWidget, - QTreeWidgetItem, QDialog, QDialogButtonBox, QComboBox, QMessageBox, QSpinBox, QMenu) + QTreeWidgetItem, QDialog, QDialogButtonBox, QComboBox, QMessageBox, QSpinBox, QMenu, QTabWidget, + QTextEdit) from PyQt6.QtCore import Qt, QSize from PyQt6.QtGui import QPixmap, QFontMetrics, QColor, QAction import sqlite3 @@ -12,54 +13,10 @@ import os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # Now try to import +from pokemon_db_ui import PokemonUI from DataGatherers.update_location_information import process_pokemon_for_location_data from DataGatherers.cache_manager import CacheManager - -class EvolutionEditDialog(QDialog): - def __init__(self, parent=None, from_pfic=None, to_pfic=None, method=None): - super().__init__(parent) - self.setWindowTitle("Edit Evolution") - self.setModal(True) - - layout = QVBoxLayout(self) - - self.from_combo = QComboBox() - self.to_combo = QComboBox() - self.method_edit = QLineEdit(method) - - layout.addWidget(QLabel("From Pokémon:")) - layout.addWidget(self.from_combo) - layout.addWidget(QLabel("To Pokémon:")) - layout.addWidget(self.to_combo) - layout.addWidget(QLabel("Evolution Method:")) - layout.addWidget(self.method_edit) - - self.button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) - self.button_box.accepted.connect(self.accept) - self.button_box.rejected.connect(self.reject) - layout.addWidget(self.button_box) - - self.delete_button = QPushButton("Delete Evolution") - self.delete_button.clicked.connect(self.delete_evolution) - layout.addWidget(self.delete_button) - - self.populate_combos(from_pfic, to_pfic) - - def populate_combos(self, from_pfic, to_pfic): - cursor = self.parent().cursor - cursor.execute('SELECT PFIC, name, form_name FROM pokemon_forms ORDER BY name, form_name') - for pfic, name, form_name in cursor.fetchall(): - display_name = f"{name} ({form_name})" if form_name else name - self.from_combo.addItem(display_name, pfic) - self.to_combo.addItem(display_name, pfic) - - if from_pfic: - self.from_combo.setCurrentIndex(self.from_combo.findData(from_pfic)) - if to_pfic: - self.to_combo.setCurrentIndex(self.to_combo.findData(to_pfic)) - - def delete_evolution(self): - self.done(2) # Use a custom return code for delete action +from event_system import event_system def parse_pfic(pfic): parts = pfic.split('-') @@ -71,14 +28,21 @@ class DBEditor(QMainWindow): self.setWindowTitle("Pokémon Database Editor") self.setGeometry(100, 100, 1000, 600) - self.conn = sqlite3.connect(':memory:') # Use in-memory database for runtime + event_system.add_listener('get_pokemon_data', self.load_pokemon_details) + event_system.add_listener('save_changes', self.save_changes) + event_system.add_listener('add_new_encounter', self.add_new_encounter) + event_system.add_listener('get_pokemon_list', self.send_pokemon_list) + event_system.add_listener('get_home_storable', self.get_home_storable) + event_system.add_listener('get_evolution_chain', self.get_evolution_chain) + event_system.add_listener('get_evolution_parent', self.get_evolution_parent) + + self.conn = sqlite3.connect(':memory:', check_same_thread=False) # Use in-memory database for runtime self.cursor = self.conn.cursor() self.init_database() self.patches = self.load_and_apply_patches() self.encounter_cache = {} # Add this line self.init_ui() - #self.load_pokemon_list() # Make sure this is called after init_ui def init_database(self): # Create or open the file-based database @@ -369,124 +333,26 @@ class DBEditor(QMainWindow): with open('patches.json', 'w') as f: json.dump(self.patches, f) - def init_ui(self): - central_widget = QWidget() - self.setCentralWidget(central_widget) - main_layout = QHBoxLayout(central_widget) - - # Left side: Search and List - left_layout = QVBoxLayout() - search_layout = QHBoxLayout() - self.search_bar = QLineEdit() - self.search_bar.setPlaceholderText("Search Pokémon...") - self.search_bar.textChanged.connect(self.filter_pokemon_list) - search_layout.addWidget(self.search_bar) - - left_layout.addLayout(search_layout) - - self.pokemon_list = QListWidget() - self.pokemon_list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) - self.pokemon_list.customContextMenuRequested.connect(self.show_pokemon_context_menu) - self.pokemon_list.currentItemChanged.connect(self.load_pokemon_details) - left_layout.addWidget(self.pokemon_list) - - # Move the checkbox here, after the pokemon_list - self.highlight_no_encounters = QCheckBox("Highlight Pokémon without encounters") - self.highlight_no_encounters.stateChanged.connect(self.toggle_highlight_mode) - left_layout.addWidget(self.highlight_no_encounters) - - # Add the new checkbox for filtering Home-storable Pokémon - self.filter_home_storable = QCheckBox("Show only Home-storable Pokémon") - self.filter_home_storable.stateChanged.connect(self.filter_pokemon_list) - left_layout.addWidget(self.filter_home_storable) - - # Right side: Edit panel - right_layout = QHBoxLayout() - - # Left side of right panel: Text information - text_layout = QVBoxLayout() - self.edit_form = QFormLayout() - self.name_label = QLabel() - self.form_name_label = QLabel() - self.national_dex_label = QLabel() - self.generation_label = QLabel() - self.home_checkbox = QCheckBox("Available in Home") - self.is_baby_form_checkbox = QCheckBox("Is Baby Form") + def load_pokemon_details(self, pfic): + self.cursor.execute(''' + SELECT pf.name, pf.form_name, pf.national_dex, pf.generation, ps.storable_in_home + FROM pokemon_forms pf + LEFT JOIN pokemon_storage ps ON pf.PFIC = ps.PFIC + WHERE pf.PFIC = ? + ''', (pfic,)) - self.edit_form.addRow("Name:", self.name_label) - self.edit_form.addRow("Form:", self.form_name_label) - self.edit_form.addRow("National Dex:", self.national_dex_label) - self.edit_form.addRow("Generation:", self.generation_label) - self.edit_form.addRow(self.home_checkbox) - self.edit_form.addRow(self.is_baby_form_checkbox) - - text_layout.addLayout(self.edit_form) - - # Evolution chain tree - self.evolution_tree = QTreeWidget() - self.evolution_tree.setHeaderLabels(["Pokémon", "Evolution Method"]) - self.evolution_tree.setColumnWidth(0, 200) - text_layout.addWidget(self.evolution_tree) - - # Add Locations tree - self.locations_tree = QTreeWidget() - self.locations_tree.setHeaderLabels(["Game/Location", "Details"]) - self.locations_tree.setColumnWidth(0, 200) - self.locations_tree.itemDoubleClicked.connect(self.edit_encounter) - text_layout.addWidget(QLabel("Locations:")) - text_layout.addWidget(self.locations_tree) - - # Add New Encounter button - self.add_encounter_button = QPushButton("Add New Encounter") - self.add_encounter_button.clicked.connect(self.add_new_encounter) - text_layout.addWidget(self.add_encounter_button) - - # Move buttons to the bottom - text_layout.addStretch(1) - - self.save_button = QPushButton("Save Changes") - self.save_button.clicked.connect(self.save_changes) - text_layout.addWidget(self.save_button) - - self.export_button = QPushButton("Export Database") - self.export_button.clicked.connect(self.export_database) - text_layout.addWidget(self.export_button) - - # Add New Evolution button - self.add_evolution_button = QPushButton("Add New Evolution") - self.add_evolution_button.clicked.connect(self.add_new_evolution) - text_layout.addWidget(self.add_evolution_button) - - # Right side of right panel: Image - image_layout = QVBoxLayout() - self.image_label = QLabel() - self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter) - self.image_label.setFixedSize(200, 200) - image_layout.addWidget(self.image_label) - image_layout.addStretch(1) - - right_layout.addLayout(text_layout) - right_layout.addLayout(image_layout) - - main_layout.addLayout(left_layout, 1) - main_layout.addLayout(right_layout, 1) - - self.load_pokemon_list() - - def adjust_list_width(self): - max_width = 0 - font_metrics = QFontMetrics(self.pokemon_list.font()) - for i in range(self.pokemon_list.count()): - item_width = font_metrics.horizontalAdvance(self.pokemon_list.item(i).text()) - max_width = max(max_width, item_width) - - # Add some padding to the width - list_width = max_width + 50 - self.pokemon_list.setFixedWidth(list_width) - self.search_bar.setFixedWidth(list_width) - - def load_pokemon_list(self): - self.pokemon_list.clear() + return self.cursor.fetchone() + + def save_changes(self, data): + # Your existing code to save changes + pass + + def add_new_encounter(self, data): + # Your existing code to add a new encounter + pass + + def send_pokemon_list(self, callback): + # Fetch pokemon list from database self.cursor.execute(''' SELECT pf.PFIC, pf.name, pf.form_name, pf.national_dex FROM pokemon_forms pf @@ -495,82 +361,23 @@ class DBEditor(QMainWindow): # Sort the pokemon_data based on PFIC pokemon_data.sort(key=lambda x: parse_pfic(x[0])) + callback(pokemon_data) - for pfic, name, form_name, national_dex in pokemon_data: - display_name = f"{national_dex:04d} - {name}" - if form_name: - display_name += f" ({form_name})" - item = QListWidgetItem(display_name) - item.setData(Qt.ItemDataRole.UserRole, pfic) - self.pokemon_list.addItem(item) - - self.update_encounter_cache() - self.update_pokemon_list_highlights() - self.adjust_list_width() - self.filter_pokemon_list() - - def filter_pokemon_list(self): - search_text = self.search_bar.text().lower() - show_only_home_storable = self.filter_home_storable.isChecked() - - for i in range(self.pokemon_list.count()): - item = self.pokemon_list.item(i) - pfic = item.data(Qt.ItemDataRole.UserRole) - - # Check if the item matches the search text - text_match = search_text in item.text().lower() - - # Check if the item is storable in Home (if the filter is active) - home_storable = True - if show_only_home_storable: - self.cursor.execute('SELECT storable_in_home FROM pokemon_storage WHERE PFIC = ?', (pfic,)) - result = self.cursor.fetchone() - home_storable = result[0] if result else False - - # Show the item only if it matches both filters - item.setHidden(not (text_match and home_storable)) - - self.update_pokemon_list_highlights() - - def load_pokemon_details(self, current, previous): - if not current: - return - - pfic = current.data(Qt.ItemDataRole.UserRole) - self.cursor.execute(''' - SELECT pf.name, pf.form_name, pf.national_dex, pf.generation, ps.storable_in_home, pf.is_baby_form - FROM pokemon_forms pf - LEFT JOIN pokemon_storage ps ON pf.PFIC = ps.PFIC - WHERE pf.PFIC = ? - ''', (pfic,)) - pokemon_data = self.cursor.fetchone() - - if pokemon_data: - name, form_name, national_dex, generation, storable_in_home, is_baby_form = pokemon_data - self.name_label.setText(name) - self.form_name_label.setText(form_name if form_name else "") - self.national_dex_label.setText(str(national_dex)) - self.generation_label.setText(str(generation)) - self.home_checkbox.setChecked(bool(storable_in_home)) - self.is_baby_form_checkbox.setChecked(bool(is_baby_form)) - self.home_checkbox.stateChanged.connect(self.update_home_storable) - - # Load and display the image - image_path = f"images-new/{pfic}.png" - if os.path.exists(image_path): - pixmap = QPixmap(image_path) - self.image_label.setPixmap(pixmap.scaled(200, 200, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) - else: - self.image_label.setText("Image not found") - - # Load and display evolution chain - self.load_evolution_chain(pfic) + def init_ui(self): + # Create a central widget for the main window + central_widget = QWidget() + self.setCentralWidget(central_widget) + main_layout = QVBoxLayout(central_widget) - # Load and display encounter locations - self.load_encounter_locations(pfic) + # Create the PokemonUI as a child widget + self.pokemon_ui = PokemonUI(self) + main_layout.addWidget(self.pokemon_ui) - self.current_pfic = pfic - self.add_evolution_button.setEnabled(True) # Enable the button when a Pokémon is selected + def get_home_storable(self, pfic): + self.cursor.execute('SELECT storable_in_home FROM pokemon_storage WHERE PFIC = ?', (pfic,)) + result = self.cursor.fetchone() + home_storable = result[0] if result else False + return home_storable def update_home_storable(self): if hasattr(self, 'current_pfic'): @@ -584,55 +391,55 @@ class DBEditor(QMainWindow): if not parent: return # Don't edit the root item - from_pfic = parent.data(0, Qt.ItemDataRole.UserRole) - to_pfic = item.data(0, Qt.ItemDataRole.UserRole) - method = item.text(1) + #from_pfic = parent.data(0, Qt.ItemDataRole.UserRole) + #to_pfic = item.data(0, Qt.ItemDataRole.UserRole) + #method = item.text(1) - dialog = EvolutionEditDialog(self, from_pfic, to_pfic, method) - result = dialog.exec() + #dialog = EvolutionEditDialog(self, from_pfic, to_pfic, method) + #result = dialog.exec() - if result == QDialog.DialogCode.Accepted: - new_from_pfic = dialog.from_combo.currentData() - new_to_pfic = dialog.to_combo.currentData() - new_method = dialog.method_edit.text() + #if result == QDialog.DialogCode.Accepted: + # new_from_pfic = dialog.from_combo.currentData() + # new_to_pfic = dialog.to_combo.currentData() + # new_method = dialog.method_edit.text() # Update the in-memory database - self.cursor.execute(''' - UPDATE evolution_chains - SET from_pfic = ?, to_pfic = ?, method = ? - WHERE from_pfic = ? AND to_pfic = ? - ''', (new_from_pfic, new_to_pfic, new_method, from_pfic, to_pfic)) - - # Create or update the patch - patch_key = f"evolution_{from_pfic}_{to_pfic}" - self.patches[patch_key] = { - 'action': 'update', - 'new_from_pfic': new_from_pfic, - 'new_to_pfic': new_to_pfic, - 'new_method': new_method - } - self.save_patches() + # self.cursor.execute(''' + # UPDATE evolution_chains + # SET from_pfic = ?, to_pfic = ?, method = ? + # WHERE from_pfic = ? AND to_pfic = ? + # ''', (new_from_pfic, new_to_pfic, new_method, from_pfic, to_pfic)) + + # # Create or update the patch + # patch_key = f"evolution_{from_pfic}_{to_pfic}" + # self.patches[patch_key] = { + # 'action': 'update', + # 'new_from_pfic': new_from_pfic, + # 'new_to_pfic': new_to_pfic, + # 'new_method': new_method + # } + # self.save_patches() # Refresh the evolution chain display - self.load_evolution_chain(self.current_pfic) - - elif result == 2: # Delete action - confirm = QMessageBox.question(self, "Confirm Deletion", "Are you sure you want to delete this evolution?", - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) - if confirm == QMessageBox.StandardButton.Yes: - # Delete from the in-memory database - self.cursor.execute(''' - DELETE FROM evolution_chains - WHERE from_pfic = ? AND to_pfic = ? - ''', (from_pfic, to_pfic)) + # self.load_evolution_chain(self.current_pfic) + + #elif result == 2: # Delete action + # confirm = QMessageBox.question(self, "Confirm Deletion", "Are you sure you want to delete this evolution?", + # QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + # if confirm == QMessageBox.StandardButton.Yes: + # # Delete from the in-memory database + # self.cursor.execute(''' + # DELETE FROM evolution_chains + # WHERE from_pfic = ? AND to_pfic = ? + # ''', (from_pfic, to_pfic)) # Create a delete patch - patch_key = f"evolution_{from_pfic}_{to_pfic}" - self.patches[patch_key] = {'action': 'delete'} - self.save_patches() + # patch_key = f"evolution_{from_pfic}_{to_pfic}" + # self.patches[patch_key] = {'action': 'delete'} + # self.save_patches() # Refresh the evolution chain display - self.load_evolution_chain(self.current_pfic) + # self.load_evolution_chain(self.current_pfic) def get_evolution_chain(self, pfic): def follow_chain(start_pfic, visited=None): @@ -670,100 +477,15 @@ class DBEditor(QMainWindow): return chain return follow_chain(pfic) - - def load_evolution_chain(self, pfic): - self.evolution_tree.clear() - evolution_chain = self.get_evolution_chain(pfic) - - # Create a dictionary to store tree items - tree_items = {} - - # First pass: create all tree items - for current_pfic, name, form_name, method in evolution_chain: - display_name = f"{name} ({form_name})" if form_name else name - item = QTreeWidgetItem([display_name, method if method else ""]) - item.setData(0, Qt.ItemDataRole.UserRole, current_pfic) - tree_items[current_pfic] = item - - if current_pfic == pfic: - item.setBackground(0, QColor(255, 255, 0, 100)) # Highlight selected Pokémon - - # Second pass: build the tree structure - root = None - for current_pfic, name, form_name, method in evolution_chain: - item = tree_items[current_pfic] - - # Find the parent of this item - self.cursor.execute('SELECT from_pfic FROM evolution_chains WHERE to_pfic = ?', (current_pfic,)) - parent_pfic = self.cursor.fetchone() - - if parent_pfic: - parent_item = tree_items.get(parent_pfic[0]) - if parent_item: - parent_item.addChild(item) - elif not root: - root = item - self.evolution_tree.addTopLevelItem(root) - - # Expand the entire tree - self.evolution_tree.expandAll() - - # Scroll to and select the current Pokémon - current_item = tree_items[pfic] - self.evolution_tree.scrollToItem(current_item) - self.evolution_tree.setCurrentItem(current_item) - - # Connect double-click signal - self.evolution_tree.itemDoubleClicked.connect(self.edit_evolution) - - def save_changes(self): - if hasattr(self, 'current_pfic'): - storable_in_home = self.home_checkbox.isChecked() - self.patches[self.current_pfic] = {'storable_in_home': storable_in_home} - - with open('patches.json', 'w') as f: - json.dump(self.patches, f) - - def export_database(self): - export_conn = sqlite3.connect('pokemon_forms_production.db') - self.conn.backup(export_conn) - export_conn.close() + + def get_evolution_parent(self, pfic): + self.cursor.execute('SELECT from_pfic FROM evolution_chains WHERE to_pfic = ?', (pfic,)) + return self.cursor.fetchone() def closeEvent(self, event): self.conn.close() event.accept() - def add_new_evolution(self): - if not hasattr(self, 'current_pfic'): - return - - dialog = EvolutionEditDialog(self, self.current_pfic, None, "") - result = dialog.exec() - - if result == QDialog.DialogCode.Accepted: - new_from_pfic = dialog.from_combo.currentData() - new_to_pfic = dialog.to_combo.currentData() - new_method = dialog.method_edit.text() - - # Update the in-memory database - self.cursor.execute(''' - INSERT INTO evolution_chains (from_pfic, to_pfic, method) - VALUES (?, ?, ?) - ''', (new_from_pfic, new_to_pfic, new_method)) - - # Create a new patch - patch_key = f"evolution_{new_from_pfic}_{new_to_pfic}" - self.patches[patch_key] = { - 'action': 'add', - 'from_pfic': new_from_pfic, - 'to_pfic': new_to_pfic, - 'method': new_method - } - self.save_patches() - - # Refresh the evolution chain display - self.load_evolution_chain(self.current_pfic) - def load_encounter_locations(self, pfic): self.locations_tree.clear() self.cursor.execute(''' @@ -817,185 +539,6 @@ class DBEditor(QMainWindow): # After updating the locations tree self.update_pokemon_list_highlights() - def edit_encounter(self, item, column): - if item.parent() is None: # This is a game item, not a location item - return - - game = item.parent().text(0) - location = item.text(0) - - dialog = QDialog(self) - dialog.setWindowTitle("Edit Encounter") - layout = QFormLayout(dialog) - - game_edit = QLineEdit(game) - location_edit = QLineEdit(location) - day_edit = QLineEdit() - time_edit = QLineEdit() - dual_slot_edit = QLineEdit() - static_encounter_check = QCheckBox("Static Encounter") - static_encounter_count_edit = QSpinBox() - extra_text_edit = QLineEdit() - stars_edit = QLineEdit() - fishing_check = QCheckBox("Fishing") - rods_edit = QLineEdit() - - layout.addRow("Game:", game_edit) - layout.addRow("Location:", location_edit) - layout.addRow("Day:", day_edit) - layout.addRow("Time:", time_edit) - layout.addRow("Dual Slot:", dual_slot_edit) - layout.addRow("Static Encounter:", static_encounter_check) - layout.addRow("Static Encounter Count:", static_encounter_count_edit) - layout.addRow("Extra Text:", extra_text_edit) - layout.addRow("Stars:", stars_edit) - layout.addRow("Fishing:", fishing_check) - layout.addRow("Rods:", rods_edit) - - exclusive_group_combo = QComboBox() - exclusive_group_combo.addItem("None", None) - self.cursor.execute('SELECT id, group_name FROM exclusive_encounter_groups') - for group_id, group_name in self.cursor.fetchall(): - exclusive_group_combo.addItem(group_name, group_id) - - layout.addRow("Exclusive Group:", exclusive_group_combo) - - # Fetch current values - self.cursor.execute(''' - SELECT day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, fishing, rods, exclusive_group_id - FROM encounters - WHERE pfic = ? AND game = ? AND location = ? - ''', (self.current_pfic, game, location)) - current_values = self.cursor.fetchone() - - if current_values: - day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, fishing, rods, exclusive_group_id = current_values - day_edit.setText(day or "") - time_edit.setText(time or "") - dual_slot_edit.setText(dual_slot or "") - static_encounter_check.setChecked(bool(static_encounter)) - static_encounter_count_edit.setValue(static_encounter_count or 0) - extra_text_edit.setText(extra_text or "") - stars_edit.setText(stars or "") - fishing_check.setChecked(bool(fishing)) - rods_edit.setText(rods or "") - index = exclusive_group_combo.findData(exclusive_group_id) - if index >= 0: - exclusive_group_combo.setCurrentIndex(index) - - buttons = QDialogButtonBox( - QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, - Qt.Orientation.Horizontal, dialog) - buttons.accepted.connect(dialog.accept) - buttons.rejected.connect(dialog.reject) - layout.addRow(buttons) - - if dialog.exec() == QDialog.DialogCode.Accepted: - new_game = game_edit.text() - new_location = location_edit.text() - new_day = day_edit.text() or None - new_time = time_edit.text() or None - new_dual_slot = dual_slot_edit.text() or None - new_static_encounter = static_encounter_check.isChecked() - new_static_encounter_count = static_encounter_count_edit.value() - new_extra_text = extra_text_edit.text() or None - new_stars = stars_edit.text() or None - new_fishing = fishing_check.isChecked() - new_rods = rods_edit.text() or None - new_exclusive_group_id = exclusive_group_combo.currentData() - - # Update the database - self.cursor.execute(''' - UPDATE encounters - SET game = ?, location = ?, day = ?, time = ?, dual_slot = ?, - static_encounter = ?, static_encounter_count = ?, extra_text = ?, - stars = ?, fishing = ?, rods = ?, exclusive_group_id = ? - WHERE pfic = ? AND game = ? AND location = ? - ''', (new_game, new_location, new_day, new_time, new_dual_slot, - new_static_encounter, new_static_encounter_count, new_extra_text, - new_stars, new_fishing, new_rods, new_exclusive_group_id, - self.current_pfic, game, location)) - self.conn.commit() - - # Update the cache if all encounters for this Pokémon were deleted - if not self.check_pokemon_has_encounters(self.current_pfic): - self.encounter_cache[self.current_pfic] = False - - # Refresh the locations tree - self.load_encounter_locations(self.current_pfic) - - def add_new_encounter(self): - dialog = QDialog(self) - dialog.setWindowTitle("Add New Encounter") - layout = QFormLayout(dialog) - - game_edit = QLineEdit() - location_edit = QLineEdit() - day_edit = QLineEdit() - time_edit = QLineEdit() - dual_slot_edit = QLineEdit() - static_encounter_check = QCheckBox("Static Encounter") - static_encounter_count_edit = QSpinBox() - extra_text_edit = QLineEdit() - stars_edit = QLineEdit() - fishing_check = QCheckBox("Fishing") - rods_edit = QLineEdit() - - layout.addRow("Game:", game_edit) - layout.addRow("Location:", location_edit) - layout.addRow("Day:", day_edit) - layout.addRow("Time:", time_edit) - layout.addRow("Dual Slot:", dual_slot_edit) - layout.addRow("Static Encounter:", static_encounter_check) - layout.addRow("Static Encounter Count:", static_encounter_count_edit) - layout.addRow("Extra Text:", extra_text_edit) - layout.addRow("Stars:", stars_edit) - layout.addRow("Fishing:", fishing_check) - layout.addRow("Rods:", rods_edit) - - exclusive_group_combo = QComboBox() - exclusive_group_combo.addItem("None", None) - self.cursor.execute('SELECT id, group_name FROM exclusive_encounter_groups') - for group_id, group_name in self.cursor.fetchall(): - exclusive_group_combo.addItem(group_name, group_id) - - layout.addRow("Exclusive Group:", exclusive_group_combo) - - buttons = QDialogButtonBox( - QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, - Qt.Orientation.Horizontal, dialog) - buttons.accepted.connect(dialog.accept) - buttons.rejected.connect(dialog.reject) - layout.addRow(buttons) - - if dialog.exec() == QDialog.DialogCode.Accepted: - game = game_edit.text() - location = location_edit.text() - day = day_edit.text() or None - time = time_edit.text() or None - dual_slot = dual_slot_edit.text() or None - static_encounter = static_encounter_check.isChecked() - static_encounter_count = static_encounter_count_edit.value() - extra_text = extra_text_edit.text() or None - stars = stars_edit.text() or None - fishing = fishing_check.isChecked() - rods = rods_edit.text() or None - exclusive_group_id = exclusive_group_combo.currentData() - - # Insert new encounter into the database - self.cursor.execute(''' - INSERT INTO encounters - (pfic, game, location, day, time, dual_slot, static_encounter, static_encounter_count, extra_text, stars, fishing, rods, exclusive_group_id) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ''', (self.current_pfic, game, location, day, time, dual_slot, static_encounter, static_encounter_count, extra_text, stars, fishing, rods, exclusive_group_id)) - self.conn.commit() - - # Update the cache - self.encounter_cache[self.current_pfic] = True - - # Refresh the locations tree - self.load_encounter_locations(self.current_pfic) - # Add this as a class attribute in the DBEditor class game_generations = { "Red": 1, "Blue": 1, "Yellow": 1, @@ -1011,24 +554,6 @@ class DBEditor(QMainWindow): "Pokémon Go": 0, "Pokémon Home": 0 } - def toggle_highlight_mode(self): - self.update_pokemon_list_highlights() - - def update_pokemon_list_highlights(self): - highlight_mode = self.highlight_no_encounters.isChecked() - for i in range(self.pokemon_list.count()): - item = self.pokemon_list.item(i) - pfic = item.data(Qt.ItemDataRole.UserRole) - - if highlight_mode: - has_encounters = self.encounter_cache.get(pfic, False) - if not has_encounters: - item.setData(Qt.ItemDataRole.BackgroundRole, QColor(255, 200, 200)) # Light red background - else: - item.setData(Qt.ItemDataRole.BackgroundRole, None) # White background - else: - item.setData(Qt.ItemDataRole.BackgroundRole, None) # White background - def update_encounter_cache(self): self.cursor.execute(''' SELECT DISTINCT pfic @@ -1036,10 +561,10 @@ class DBEditor(QMainWindow): ''') pokemon_with_encounters = set(row[0] for row in self.cursor.fetchall()) - for i in range(self.pokemon_list.count()): - item = self.pokemon_list.item(i) - pfic = item.data(Qt.ItemDataRole.UserRole) - self.encounter_cache[pfic] = pfic in pokemon_with_encounters + #for i in range(self.pokemon_list.count()): + # item = self.pokemon_list.item(i) + # pfic = item.data(Qt.ItemDataRole.UserRole) + # self.encounter_cache[pfic] = pfic in pokemon_with_encounters def check_pokemon_has_encounters(self, pfic): return self.encounter_cache.get(pfic, False) @@ -1180,6 +705,50 @@ class DBEditor(QMainWindow): print(f"Refreshed encounters for {name} {form if form else ''}") + def gather_pokemon_forms(self): + self.progress_text.clear() # Clear previous progress text + self.progress_text.append("Starting to gather Pokémon forms...") + # Implement the logic to gather Pokémon forms + # Update progress as you go, for example: + self.progress_text.append("Processed 100 Pokémon...") + self.progress_text.append("Processed 200 Pokémon...") + # ... + self.progress_text.append("Finished gathering Pokémon forms.") + + def gather_home_storage_info(self): + self.progress_text.clear() + self.progress_text.append("Starting to gather Home storage information...") + # Implement the logic + # ... + + def gather_evolution_info(self): + self.progress_text.clear() + self.progress_text.append("Starting to gather evolution information...") + # Implement the logic + # ... + + def gather_encounter_info(self): + self.progress_text.clear() + self.progress_text.append("Starting to gather encounter information...") + # Implement the logic + # ... + + def reinitialize_database(self): + reply = QMessageBox.question(self, 'Confirm Action', + 'Are you sure you want to clear and reinitialize the database? This action cannot be undone.', + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No) + if reply == QMessageBox.StandardButton.Yes: + self.progress_text.clear() + self.progress_text.append("Starting database reinitialization...") + # Implement the logic to clear and reinitialize the database + self.conn.close() + os.remove('pokemon_forms.db') # Remove the existing database file + self.conn = sqlite3.connect('pokemon_forms.db') + self.cursor = self.conn.cursor() + self.init_database() # Reinitialize the database structure + self.progress_text.append("Database reinitialized successfully.") + QMessageBox.information(self, 'Database Reinitialized', 'The database has been cleared and reinitialized.') + if __name__ == '__main__': app = QApplication(sys.argv) editor = DBEditor() diff --git a/DBEditor/database_operations.py b/DBEditor/database_operations.py deleted file mode 100644 index 547c6e1..0000000 --- a/DBEditor/database_operations.py +++ /dev/null @@ -1,114 +0,0 @@ -import sqlite3 - -class DatabaseOperations: - def init_database(self): - # Create or open the file-based database - disk_conn = sqlite3.connect('pokemon_forms.db') - disk_cursor = disk_conn.cursor() - - # Create tables in the file-based database - self.create_pokemon_forms_table(disk_cursor) - self.create_pokemon_storage_table(disk_cursor) - self.create_evolution_chains_table(disk_cursor) - self.create_exclusive_encounter_groups_table(disk_cursor) - self.create_encounters_table(disk_cursor) - - # Commit changes to the file-based database - disk_conn.commit() - - # Copy the file-based database to the in-memory database - disk_conn.backup(self.conn) - - # Close the file-based database connection - disk_conn.close() - - # Create tables in the in-memory database (in case they weren't copied) - self.create_pokemon_forms_table(self.cursor) - self.create_pokemon_storage_table(self.cursor) - self.create_evolution_chains_table(self.cursor) - self.create_exclusive_encounter_groups_table(self.cursor) - self.create_encounters_table(self.cursor) - - # Commit changes to the in-memory database - self.conn.commit() - - def create_pokemon_forms_table(self, cursor): - cursor.execute(''' - CREATE TABLE IF NOT EXISTS pokemon_forms ( - PFIC TEXT PRIMARY KEY, - name TEXT NOT NULL, - form_name TEXT, - national_dex INTEGER NOT NULL, - generation INTEGER NOT NULL - ) - ''') - - def create_pokemon_storage_table(self, cursor): - cursor.execute(''' - CREATE TABLE IF NOT EXISTS pokemon_storage ( - PFIC TEXT PRIMARY KEY, - storable_in_home BOOLEAN NOT NULL, - FOREIGN KEY (PFIC) REFERENCES pokemon_forms (PFIC) - ) - ''') - - def create_evolution_chains_table(self, cursor): - cursor.execute(''' - CREATE TABLE IF NOT EXISTS evolution_chains ( - from_pfic TEXT, - to_pfic TEXT, - method TEXT, - PRIMARY KEY (from_pfic, to_pfic), - FOREIGN KEY (from_pfic) REFERENCES pokemon_forms (PFIC), - FOREIGN KEY (to_pfic) REFERENCES pokemon_forms (PFIC) - ) - ''') - - def create_exclusive_encounter_groups_table(self, cursor): - cursor.execute(''' - CREATE TABLE IF NOT EXISTS exclusive_encounter_groups ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - group_name TEXT NOT NULL, - description TEXT - ) - ''') - - def create_encounters_table(self, cursor): - # First, check if the table exists - cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='encounters'") - table_exists = cursor.fetchone() is not None - - if not table_exists: - # If the table doesn't exist, create it with all columns - cursor.execute(''' - CREATE TABLE encounters ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - pfic TEXT, - game TEXT, - location TEXT, - day TEXT, - time TEXT, - dual_slot TEXT, - static_encounter BOOLEAN, - static_encounter_count INTEGER, - extra_text TEXT, - stars TEXT, - fishing BOOLEAN, - rods TEXT, - exclusive_group_id INTEGER, - FOREIGN KEY (pfic) REFERENCES pokemon_forms (PFIC), - FOREIGN KEY (exclusive_group_id) REFERENCES exclusive_encounter_groups (id) - ) - ''') - else: - # If the table exists, check if the exclusive_group_id column exists - cursor.execute("PRAGMA table_info(encounters)") - columns = [column[1] for column in cursor.fetchall()] - - if 'exclusive_group_id' not in columns: - # If the column doesn't exist, add it - cursor.execute(''' - ALTER TABLE encounters - ADD COLUMN exclusive_group_id INTEGER - REFERENCES exclusive_encounter_groups (id) - ''') \ No newline at end of file diff --git a/DBEditor/db_editor.py b/DBEditor/db_editor.py deleted file mode 100644 index 9f98040..0000000 --- a/DBEditor/db_editor.py +++ /dev/null @@ -1,19 +0,0 @@ -from PyQt6.QtWidgets import QMainWindow -from database_operations import DatabaseOperations -from ui_components import UIComponents -from pokemon_list_operations import PokemonListOperations -from pokemon_details_operations import PokemonDetailsOperations -from evolution_operations import EvolutionOperations -from encounter_operations import EncounterOperations -from patch_operations import PatchOperations - -class DBEditor(QMainWindow, DatabaseOperations, UIComponents, PokemonListOperations, - PokemonDetailsOperations, EvolutionOperations, EncounterOperations, PatchOperations): - def __init__(self): - super().__init__() - self.setWindowTitle("Pokémon Database Editor") - self.setGeometry(100, 100, 1000, 600) - - self.init_database() - self.init_ui() - self.load_pokemon_list() \ No newline at end of file diff --git a/DBEditor/encounter_operations.py b/DBEditor/encounter_operations.py deleted file mode 100644 index 4dccba6..0000000 --- a/DBEditor/encounter_operations.py +++ /dev/null @@ -1,12 +0,0 @@ -from PyQt6.QtWidgets import QTreeWidgetItem - -class EncounterOperations: - def load_encounter_locations(self, pfic): - print("") - # Encounter locations loading code - - def add_new_encounter(self): - print("") - # New encounter addition code - - # Other encounter-related methods \ No newline at end of file diff --git a/DBEditor/event_system.py b/DBEditor/event_system.py new file mode 100644 index 0000000..da891db --- /dev/null +++ b/DBEditor/event_system.py @@ -0,0 +1,59 @@ +from threading import Event, Lock +from collections import defaultdict +from queue import Queue, Empty +import threading + +class EventSystem: + def __init__(self): + self.listeners = defaultdict(list) + self.event_queue = Queue() + self.lock = Lock() + self._stop_event = Event() + self.event_thread = threading.Thread(target=self._process_events) + self.event_thread.start() + + def add_listener(self, event_type, callback): + with self.lock: + self.listeners[event_type].append(callback) + + def remove_listener(self, event_type, callback): + with self.lock: + self.listeners[event_type].remove(callback) + + def emit(self, event_type, data=None, callback=None): + self.event_queue.put((event_type, data, callback)) + + def emit_sync(self, event_type, data=None): + results = [] + with self.lock: + for listener in self.listeners[event_type]: + result = listener(data) + results.append(result) + return results + + def call_sync(self, event_type, data=None): + with self.lock: + if event_type in self.listeners and self.listeners[event_type]: + # Call only the first registered listener + return self.listeners[event_type][0](data) + return None + + def _process_events(self): + while not self._stop_event.is_set(): + try: + event_type, data, callback = self.event_queue.get(timeout=0.1) + results = [] + with self.lock: + for listener in self.listeners[event_type]: + result = listener(data) + results.append(result) + if callback: + callback(results) + except Empty: + pass + + def stop(self): + self._stop_event.set() + self.event_thread.join() + +event_system = EventSystem() diff --git a/DBEditor/evolution_operations.py b/DBEditor/evolution_operations.py deleted file mode 100644 index 5ad824d..0000000 --- a/DBEditor/evolution_operations.py +++ /dev/null @@ -1,12 +0,0 @@ -from PyQt6.QtWidgets import QTreeWidgetItem - -class EvolutionOperations: - def load_evolution_chain(self, pfic): - print("") - # Evolution chain loading code - - def edit_evolution(self, item, column): - print("") - # Evolution editing code - - # Other evolution-related methods \ No newline at end of file diff --git a/DBEditor/main.py b/DBEditor/main.py deleted file mode 100644 index 9cad14d..0000000 --- a/DBEditor/main.py +++ /dev/null @@ -1,9 +0,0 @@ -import sys -from PyQt6.QtWidgets import QApplication -from db_editor import DBEditor - -if __name__ == '__main__': - app = QApplication(sys.argv) - editor = DBEditor() - editor.show() - sys.exit(app.exec()) \ No newline at end of file diff --git a/DBEditor/patch_operations.py b/DBEditor/patch_operations.py deleted file mode 100644 index 9d26a40..0000000 --- a/DBEditor/patch_operations.py +++ /dev/null @@ -1,12 +0,0 @@ -import json - -class PatchOperations: - def load_and_apply_patches(self): - print("") - # Patch loading and applying code - - def save_patches(self): - print("") - # Patch saving code - - # Other patch-related methods \ No newline at end of file diff --git a/DBEditor/pokemon_db_ui.py b/DBEditor/pokemon_db_ui.py new file mode 100644 index 0000000..3208cca --- /dev/null +++ b/DBEditor/pokemon_db_ui.py @@ -0,0 +1,585 @@ +import json +import os +import sqlite3 +from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QListWidget, QLineEdit, + QLabel, QCheckBox, QPushButton, QFormLayout, QListWidgetItem, QSplitter, QTreeWidget, + QTreeWidgetItem, QDialog, QDialogButtonBox, QComboBox, QMessageBox, QSpinBox, QMenu, QTabWidget, + QTextEdit) +from PyQt6.QtCore import Qt, QSize +from PyQt6.QtGui import QPixmap, QFontMetrics, QColor, QAction + +from event_system import event_system + +class EvolutionEditDialog(QDialog): + def __init__(self, parent=None, from_pfic=None, to_pfic=None, method=None): + super().__init__(parent) + self.setWindowTitle("Edit Evolution") + self.setModal(True) + + layout = QVBoxLayout(self) + + self.from_combo = QComboBox() + self.to_combo = QComboBox() + self.method_edit = QLineEdit(method) + + layout.addWidget(QLabel("From Pokémon:")) + layout.addWidget(self.from_combo) + layout.addWidget(QLabel("To Pokémon:")) + layout.addWidget(self.to_combo) + layout.addWidget(QLabel("Evolution Method:")) + layout.addWidget(self.method_edit) + + self.button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.delete_button = QPushButton("Delete Evolution") + self.delete_button.clicked.connect(self.delete_evolution) + layout.addWidget(self.delete_button) + + self.populate_combos(from_pfic, to_pfic) + + def populate_combos(self, from_pfic, to_pfic): + cursor = self.parent().cursor + cursor.execute('SELECT PFIC, name, form_name FROM pokemon_forms ORDER BY name, form_name') + for pfic, name, form_name in cursor.fetchall(): + display_name = f"{name} ({form_name})" if form_name else name + self.from_combo.addItem(display_name, pfic) + self.to_combo.addItem(display_name, pfic) + + if from_pfic: + self.from_combo.setCurrentIndex(self.from_combo.findData(from_pfic)) + if to_pfic: + self.to_combo.setCurrentIndex(self.to_combo.findData(to_pfic)) + + def delete_evolution(self): + self.done(2) # Use a custom return code for delete action + +class PokemonUI(QWidget): # Change from QMainWindow to QWidget + def __init__(self, parent=None): + super().__init__(parent) + self.init_ui() + self.request_pokemon_list() + + def init_ui(self): + main_layout = QVBoxLayout(self) # Use self directly instead of a central widget + + # Create a tab widget + self.tab_widget = QTabWidget() + main_layout.addWidget(self.tab_widget) + + # Main tab (existing content) + main_tab = QWidget() + main_tab_layout = QHBoxLayout(main_tab) + self.tab_widget.addTab(main_tab, "Main") + + # Left side: Search and List + left_layout = QVBoxLayout() + search_layout = QHBoxLayout() + self.search_bar = QLineEdit() + self.search_bar.setPlaceholderText("Search Pokémon...") + self.search_bar.textChanged.connect(self.filter_pokemon_list) + search_layout.addWidget(self.search_bar) + + left_layout.addLayout(search_layout) + + self.pokemon_list = QListWidget() + self.pokemon_list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) + #self.pokemon_list.customContextMenuRequested.connect(self.show_pokemon_context_menu) + self.pokemon_list.currentItemChanged.connect(self.on_pokemon_selected) + left_layout.addWidget(self.pokemon_list) + + # Move the checkbox here, after the pokemon_list + self.highlight_no_encounters = QCheckBox("Highlight Pokémon without encounters") + self.highlight_no_encounters.stateChanged.connect(self.toggle_highlight_mode) + left_layout.addWidget(self.highlight_no_encounters) + + # Add the new checkbox for filtering Home-storable Pokémon + self.filter_home_storable = QCheckBox("Show only Home-storable Pokémon") + self.filter_home_storable.stateChanged.connect(self.filter_pokemon_list) + left_layout.addWidget(self.filter_home_storable) + + main_tab_layout.addLayout(left_layout, 1) + + # Right side: Edit panel + right_layout = QHBoxLayout() + + # Left side of right panel: Text information + text_layout = QVBoxLayout() + self.edit_form = QFormLayout() + self.name_label = QLabel() + self.form_name_label = QLabel() + self.national_dex_label = QLabel() + self.generation_label = QLabel() + self.home_checkbox = QCheckBox("Available in Home") + self.is_baby_form_checkbox = QCheckBox("Is Baby Form") + + self.edit_form.addRow("Name:", self.name_label) + self.edit_form.addRow("Form:", self.form_name_label) + self.edit_form.addRow("National Dex:", self.national_dex_label) + self.edit_form.addRow("Generation:", self.generation_label) + self.edit_form.addRow(self.home_checkbox) + self.edit_form.addRow(self.is_baby_form_checkbox) + + text_layout.addLayout(self.edit_form) + + # Evolution chain tree + self.evolution_tree = QTreeWidget() + self.evolution_tree.setHeaderLabels(["Pokémon", "Evolution Method"]) + self.evolution_tree.setColumnWidth(0, 200) + text_layout.addWidget(self.evolution_tree) + + # Add Locations tree + self.locations_tree = QTreeWidget() + self.locations_tree.setHeaderLabels(["Game/Location", "Details"]) + self.locations_tree.setColumnWidth(0, 200) + self.locations_tree.itemDoubleClicked.connect(self.edit_encounter) + text_layout.addWidget(QLabel("Locations:")) + text_layout.addWidget(self.locations_tree) + + # Add New Encounter button + self.add_encounter_button = QPushButton("Add New Encounter") + self.add_encounter_button.clicked.connect(self.add_new_encounter) + text_layout.addWidget(self.add_encounter_button) + + # Move buttons to the bottom + text_layout.addStretch(1) + + self.save_button = QPushButton("Save Changes") + self.save_button.clicked.connect(self.save_changes) + text_layout.addWidget(self.save_button) + + self.export_button = QPushButton("Export Database") + self.export_button.clicked.connect(self.export_database) + text_layout.addWidget(self.export_button) + + # Add New Evolution button + self.add_evolution_button = QPushButton("Add New Evolution") + self.add_evolution_button.clicked.connect(self.add_new_evolution) + text_layout.addWidget(self.add_evolution_button) + + # Right side of right panel: Image + image_layout = QVBoxLayout() + self.image_label = QLabel() + self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.image_label.setFixedSize(200, 200) + image_layout.addWidget(self.image_label) + image_layout.addStretch(1) + + right_layout.addLayout(text_layout) + right_layout.addLayout(image_layout) + + main_tab_layout.addLayout(right_layout, 1) + + # Database Operations tab + db_tab = QWidget() + db_tab_layout = QVBoxLayout(db_tab) + self.tab_widget.addTab(db_tab, "Database Operations") + + # Add buttons to the Database Operations tab + gather_forms_btn = QPushButton("Gather Pokémon Forms") + #gather_forms_btn.clicked.connect(self.gather_pokemon_forms) + db_tab_layout.addWidget(gather_forms_btn) + + gather_home_btn = QPushButton("Gather Home Storage Info") + #gather_home_btn.clicked.connect(self.gather_home_storage_info) + db_tab_layout.addWidget(gather_home_btn) + + gather_evolutions_btn = QPushButton("Gather Evolution Information") + #gather_evolutions_btn.clicked.connect(self.gather_evolution_info) + db_tab_layout.addWidget(gather_evolutions_btn) + + gather_encounters_btn = QPushButton("Gather Encounter Information") + #gather_encounters_btn.clicked.connect(self.gather_encounter_info) + db_tab_layout.addWidget(gather_encounters_btn) + + # Add QTextEdit for progress reporting + self.progress_text = QTextEdit() + self.progress_text.setReadOnly(True) + self.progress_text.setMinimumHeight(200) # Set a minimum height + db_tab_layout.addWidget(self.progress_text) + + db_tab_layout.addStretch(1) # Add stretch to separate the last button + + reinit_db_btn = QPushButton("Clear and Reinitialize Database") + #reinit_db_btn.clicked.connect(self.reinitialize_database) + db_tab_layout.addWidget(reinit_db_btn) + + def on_pokemon_selected(self, item): + pfic = item.data(Qt.ItemDataRole.UserRole) + pokemon_data = event_system.emit_sync('get_pokemon_data', data=pfic) + + if pokemon_data: + name, form_name, national_dex, generation, storable_in_home = pokemon_data[0] + self.name_label.setText(name) + self.form_name_label.setText(form_name if form_name else "") + self.national_dex_label.setText(str(national_dex)) + self.generation_label.setText(str(generation)) + self.home_checkbox.setChecked(bool(storable_in_home)) + #self.home_checkbox.stateChanged.connect(self.update_home_storable) + self.is_baby_form_checkbox.setChecked(bool(False)) + + # Load and display the image + image_path = f"images-new/{pfic}.png" + if os.path.exists(image_path): + pixmap = QPixmap(image_path) + self.image_label.setPixmap(pixmap.scaled(200, 200, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) + else: + self.image_label.setText("Image not found") + + # Load and display evolution chain + self.load_evolution_chain(pfic) + + # Load and display encounter locations + #self.load_encounter_locations(pfic) + + self.current_pfic = pfic + self.add_evolution_button.setEnabled(True) # Enable the button when a Pokémon is selected + + def load_evolution_chain(self, pfic): + self.evolution_tree.clear() + + evolution_chain = event_system.emit_sync('get_evolution_chain', data=pfic)[0] + + # Create a dictionary to store tree items + tree_items = {} + + # First pass: create all tree items + for current_pfic, name, form_name, method in evolution_chain: + display_name = f"{name} ({form_name})" if form_name else name + item = QTreeWidgetItem([display_name, method if method else ""]) + item.setData(0, Qt.ItemDataRole.UserRole, current_pfic) + tree_items[current_pfic] = item + + if current_pfic == pfic: + item.setBackground(0, QColor(255, 255, 0, 100)) # Highlight selected Pokémon + + # Second pass: build the tree structure + root = None + for current_pfic, name, form_name, method in evolution_chain: + item = tree_items[current_pfic] + + # Find the parent of this item + parent_pfic = event_system.emit_sync('get_evolution_parent', data=current_pfic)[0] + + if parent_pfic: + parent_item = tree_items.get(parent_pfic[0]) + if parent_item: + parent_item.addChild(item) + elif not root: + root = item + self.evolution_tree.addTopLevelItem(root) + + # Expand the entire tree + self.evolution_tree.expandAll() + + # Scroll to and select the current Pokémon + current_item = tree_items[pfic] + self.evolution_tree.scrollToItem(current_item) + self.evolution_tree.setCurrentItem(current_item) + + # Connect double-click signal + #self.evolution_tree.itemDoubleClicked.connect(self.edit_evolution) + + def on_save_button_clicked(self): + # Gather data from UI elements + data = { + 'name': self.name_input.text(), + 'form': self.form_input.text(), + # ... other fields ... + } + event_system.emit('save_changes', data) + + def request_pokemon_list(self): + event_system.emit('get_pokemon_list', self.update_pokemon_list) + + def update_pokemon_list(self, pokemon_data): + self.pokemon_list.clear() + + for pfic, name, form_name, national_dex in pokemon_data: + display_name = f"{national_dex:04d} - {name}" + if form_name: + display_name += f" ({form_name})" + item = QListWidgetItem(display_name) + item.setData(Qt.ItemDataRole.UserRole, pfic) + self.pokemon_list.addItem(item) + + #self.update_encounter_cache() + self.update_pokemon_list_highlights() + self.adjust_list_width() + self.filter_pokemon_list() + + def adjust_list_width(self): + max_width = 0 + font_metrics = QFontMetrics(self.pokemon_list.font()) + for i in range(self.pokemon_list.count()): + item_width = font_metrics.horizontalAdvance(self.pokemon_list.item(i).text()) + max_width = max(max_width, item_width) + + # Add some padding to the width + list_width = max_width + 50 + self.pokemon_list.setFixedWidth(list_width) + self.search_bar.setFixedWidth(list_width) + + def filter_pokemon_list(self): + search_text = self.search_bar.text().lower() + show_only_home_storable = self.filter_home_storable.isChecked() + + for i in range(self.pokemon_list.count()): + item = self.pokemon_list.item(i) + pfic = item.data(Qt.ItemDataRole.UserRole) + + # Check if the item matches the search text + text_match = search_text in item.text().lower() + + # Check if the item is storable in Home (if the filter is active) + home_storable = True + if show_only_home_storable: + home_storable = event_system.call_sync('get_home_storable', pfic) + # Show the item only if it matches both filters + item.setHidden(not (text_match and home_storable)) + + self.update_pokemon_list_highlights() + + def toggle_highlight_mode(self): + self.update_pokemon_list_highlights() + + def update_pokemon_list_highlights(self): + highlight_mode = self.highlight_no_encounters.isChecked() + for i in range(self.pokemon_list.count()): + item = self.pokemon_list.item(i) + pfic = item.data(Qt.ItemDataRole.UserRole) + + if highlight_mode: + has_encounters = self.encounter_cache.get(pfic, False) + if not has_encounters: + item.setData(Qt.ItemDataRole.BackgroundRole, QColor(255, 200, 200)) # Light red background + else: + item.setData(Qt.ItemDataRole.BackgroundRole, None) # White background + else: + item.setData(Qt.ItemDataRole.BackgroundRole, None) # White background + + + def edit_encounter(self, item, column): + if item.parent() is None: # This is a game item, not a location item + return + + game = item.parent().text(0) + location = item.text(0) + + dialog = QDialog(self) + dialog.setWindowTitle("Edit Encounter") + layout = QFormLayout(dialog) + + game_edit = QLineEdit(game) + location_edit = QLineEdit(location) + day_edit = QLineEdit() + time_edit = QLineEdit() + dual_slot_edit = QLineEdit() + static_encounter_check = QCheckBox("Static Encounter") + static_encounter_count_edit = QSpinBox() + extra_text_edit = QLineEdit() + stars_edit = QLineEdit() + fishing_check = QCheckBox("Fishing") + rods_edit = QLineEdit() + + layout.addRow("Game:", game_edit) + layout.addRow("Location:", location_edit) + layout.addRow("Day:", day_edit) + layout.addRow("Time:", time_edit) + layout.addRow("Dual Slot:", dual_slot_edit) + layout.addRow("Static Encounter:", static_encounter_check) + layout.addRow("Static Encounter Count:", static_encounter_count_edit) + layout.addRow("Extra Text:", extra_text_edit) + layout.addRow("Stars:", stars_edit) + layout.addRow("Fishing:", fishing_check) + layout.addRow("Rods:", rods_edit) + + exclusive_group_combo = QComboBox() + exclusive_group_combo.addItem("None", None) + self.cursor.execute('SELECT id, group_name FROM exclusive_encounter_groups') + for group_id, group_name in self.cursor.fetchall(): + exclusive_group_combo.addItem(group_name, group_id) + + layout.addRow("Exclusive Group:", exclusive_group_combo) + + # Fetch current values + self.cursor.execute(''' + SELECT day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, fishing, rods, exclusive_group_id + FROM encounters + WHERE pfic = ? AND game = ? AND location = ? + ''', (self.current_pfic, game, location)) + current_values = self.cursor.fetchone() + + if current_values: + day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, fishing, rods, exclusive_group_id = current_values + day_edit.setText(day or "") + time_edit.setText(time or "") + dual_slot_edit.setText(dual_slot or "") + static_encounter_check.setChecked(bool(static_encounter)) + static_encounter_count_edit.setValue(static_encounter_count or 0) + extra_text_edit.setText(extra_text or "") + stars_edit.setText(stars or "") + fishing_check.setChecked(bool(fishing)) + rods_edit.setText(rods or "") + index = exclusive_group_combo.findData(exclusive_group_id) + if index >= 0: + exclusive_group_combo.setCurrentIndex(index) + + buttons = QDialogButtonBox( + QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, + Qt.Orientation.Horizontal, dialog) + buttons.accepted.connect(dialog.accept) + buttons.rejected.connect(dialog.reject) + layout.addRow(buttons) + + if dialog.exec() == QDialog.DialogCode.Accepted: + new_game = game_edit.text() + new_location = location_edit.text() + new_day = day_edit.text() or None + new_time = time_edit.text() or None + new_dual_slot = dual_slot_edit.text() or None + new_static_encounter = static_encounter_check.isChecked() + new_static_encounter_count = static_encounter_count_edit.value() + new_extra_text = extra_text_edit.text() or None + new_stars = stars_edit.text() or None + new_fishing = fishing_check.isChecked() + new_rods = rods_edit.text() or None + new_exclusive_group_id = exclusive_group_combo.currentData() + + # Update the database + self.cursor.execute(''' + UPDATE encounters + SET game = ?, location = ?, day = ?, time = ?, dual_slot = ?, + static_encounter = ?, static_encounter_count = ?, extra_text = ?, + stars = ?, fishing = ?, rods = ?, exclusive_group_id = ? + WHERE pfic = ? AND game = ? AND location = ? + ''', (new_game, new_location, new_day, new_time, new_dual_slot, + new_static_encounter, new_static_encounter_count, new_extra_text, + new_stars, new_fishing, new_rods, new_exclusive_group_id, + self.current_pfic, game, location)) + self.conn.commit() + + # Update the cache if all encounters for this Pokémon were deleted + if not self.check_pokemon_has_encounters(self.current_pfic): + self.encounter_cache[self.current_pfic] = False + + # Refresh the locations tree + self.load_encounter_locations(self.current_pfic) + + def add_new_encounter(self): + dialog = QDialog(self) + dialog.setWindowTitle("Add New Encounter") + layout = QFormLayout(dialog) + + game_edit = QLineEdit() + location_edit = QLineEdit() + day_edit = QLineEdit() + time_edit = QLineEdit() + dual_slot_edit = QLineEdit() + static_encounter_check = QCheckBox("Static Encounter") + static_encounter_count_edit = QSpinBox() + extra_text_edit = QLineEdit() + stars_edit = QLineEdit() + fishing_check = QCheckBox("Fishing") + rods_edit = QLineEdit() + + layout.addRow("Game:", game_edit) + layout.addRow("Location:", location_edit) + layout.addRow("Day:", day_edit) + layout.addRow("Time:", time_edit) + layout.addRow("Dual Slot:", dual_slot_edit) + layout.addRow("Static Encounter:", static_encounter_check) + layout.addRow("Static Encounter Count:", static_encounter_count_edit) + layout.addRow("Extra Text:", extra_text_edit) + layout.addRow("Stars:", stars_edit) + layout.addRow("Fishing:", fishing_check) + layout.addRow("Rods:", rods_edit) + + exclusive_group_combo = QComboBox() + exclusive_group_combo.addItem("None", None) + self.cursor.execute('SELECT id, group_name FROM exclusive_encounter_groups') + for group_id, group_name in self.cursor.fetchall(): + exclusive_group_combo.addItem(group_name, group_id) + + layout.addRow("Exclusive Group:", exclusive_group_combo) + + buttons = QDialogButtonBox( + QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, + Qt.Orientation.Horizontal, dialog) + buttons.accepted.connect(dialog.accept) + buttons.rejected.connect(dialog.reject) + layout.addRow(buttons) + + if dialog.exec() == QDialog.DialogCode.Accepted: + game = game_edit.text() + location = location_edit.text() + day = day_edit.text() or None + time = time_edit.text() or None + dual_slot = dual_slot_edit.text() or None + static_encounter = static_encounter_check.isChecked() + static_encounter_count = static_encounter_count_edit.value() + extra_text = extra_text_edit.text() or None + stars = stars_edit.text() or None + fishing = fishing_check.isChecked() + rods = rods_edit.text() or None + exclusive_group_id = exclusive_group_combo.currentData() + + # Insert new encounter into the database + self.cursor.execute(''' + INSERT INTO encounters + (pfic, game, location, day, time, dual_slot, static_encounter, static_encounter_count, extra_text, stars, fishing, rods, exclusive_group_id) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ''', (self.current_pfic, game, location, day, time, dual_slot, static_encounter, static_encounter_count, extra_text, stars, fishing, rods, exclusive_group_id)) + self.conn.commit() + + # Update the cache + self.encounter_cache[self.current_pfic] = True + + # Refresh the locations tree + self.load_encounter_locations(self.current_pfic) + + def save_changes(self): + if hasattr(self, 'current_pfic'): + storable_in_home = self.home_checkbox.isChecked() + self.patches[self.current_pfic] = {'storable_in_home': storable_in_home} + + with open('patches.json', 'w') as f: + json.dump(self.patches, f) + + def export_database(self): + export_conn = sqlite3.connect('pokemon_forms_production.db') + self.conn.backup(export_conn) + export_conn.close() + + def add_new_evolution(self): + if not hasattr(self, 'current_pfic'): + return + + dialog = EvolutionEditDialog(self, self.current_pfic, None, "") + result = dialog.exec() + + if result == QDialog.DialogCode.Accepted: + new_from_pfic = dialog.from_combo.currentData() + new_to_pfic = dialog.to_combo.currentData() + new_method = dialog.method_edit.text() + + # Update the in-memory database + self.cursor.execute(''' + INSERT INTO evolution_chains (from_pfic, to_pfic, method) + VALUES (?, ?, ?) + ''', (new_from_pfic, new_to_pfic, new_method)) + + # Create a new patch + patch_key = f"evolution_{new_from_pfic}_{new_to_pfic}" + self.patches[patch_key] = { + 'action': 'add', + 'from_pfic': new_from_pfic, + 'to_pfic': new_to_pfic, + 'method': new_method + } + self.save_patches() + + # Refresh the evolution chain display + self.load_evolution_chain(self.current_pfic) \ No newline at end of file diff --git a/DBEditor/pokemon_details_operations.py b/DBEditor/pokemon_details_operations.py deleted file mode 100644 index 17e93d4..0000000 --- a/DBEditor/pokemon_details_operations.py +++ /dev/null @@ -1,8 +0,0 @@ -from PyQt6.QtGui import QPixmap - -class PokemonDetailsOperations: - def load_pokemon_details(self, current, previous): - print("") - # Pokémon details loading code - - # Other Pokémon details-related methods \ No newline at end of file diff --git a/DBEditor/pokemon_list_operations.py b/DBEditor/pokemon_list_operations.py deleted file mode 100644 index 8d51a5f..0000000 --- a/DBEditor/pokemon_list_operations.py +++ /dev/null @@ -1,13 +0,0 @@ -from PyQt6.QtWidgets import QListWidgetItem -from PyQt6.QtCore import Qt - -class PokemonListOperations: - def load_pokemon_list(self): - print("") - # Pokémon list loading code - - def filter_pokemon_list(self): - print("") - # Filtering code - - # Other Pokémon list-related methods \ No newline at end of file diff --git a/DBEditor/ui_components.py b/DBEditor/ui_components.py deleted file mode 100644 index f71ac49..0000000 --- a/DBEditor/ui_components.py +++ /dev/null @@ -1,8 +0,0 @@ -from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QSplitter - -class UIComponents: - def init_ui(self): - print("") - # UI setup code - - # Methods for creating and setting up UI components \ No newline at end of file