lollms-webui/tools/LiteSQLViewer/LiteSQLViewer.py

274 lines
9.4 KiB
Python
Raw Normal View History

2024-11-04 00:22:50 +00:00
import sys
2024-12-19 12:48:57 +00:00
from PyQt5.QtCore import QSortFilterProxyModel, Qt
2024-11-04 00:22:50 +00:00
from PyQt5.QtSql import QSqlDatabase, QSqlTableModel
2024-12-19 12:48:57 +00:00
from PyQt5.QtWidgets import (QApplication, QDialog, QFileDialog, QFormLayout,
QHBoxLayout, QHeaderView, QLabel, QLineEdit,
QListWidget, QMainWindow, QMessageBox,
QPushButton, QSplitter, QTableView, QVBoxLayout,
QWidget)
2024-11-04 00:22:50 +00:00
class AddRecordDialog(QDialog):
def __init__(self, columns, parent=None):
super().__init__(parent)
self.setWindowTitle("Add Record")
self.setGeometry(100, 100, 300, 200)
self.layout = QFormLayout(self)
self.line_edits = {}
for column in columns:
if column.lower() != "id": # Exclude the ID field
line_edit = QLineEdit(self)
self.layout.addRow(QLabel(column), line_edit)
self.line_edits[column] = line_edit
self.submit_button = QPushButton("Submit", self)
self.submit_button.clicked.connect(self.accept)
self.layout.addRow(self.submit_button)
def get_values(self):
2024-12-19 12:48:57 +00:00
return {
column: line_edit.text() for column, line_edit in self.line_edits.items()
}
2024-11-04 00:22:50 +00:00
class LiteSQLViewer(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("LiteSQL Viewer")
self.setGeometry(100, 100, 800, 600)
2024-12-19 12:48:57 +00:00
self.setStyleSheet(
"""
2024-11-04 00:22:50 +00:00
QMainWindow {
background-color: #f0f0f0;
}
QPushButton {
background-color: #4CAF50;
color: white;
border: none;
padding: 8px 16px;
text-align: center;
text-decoration: none;
font-size: 14px;
margin: 4px 2px;
border-radius: 4px;
}
QPushButton:hover {
background-color: #45a049;
}
QLineEdit {
padding: 8px;
margin: 4px 2px;
border: 1px solid #ccc;
border-radius: 4px;
}
QTableView {
border: 1px solid #ddd;
gridline-color: #ddd;
}
QHeaderView::section {
background-color: #f2f2f2;
padding: 4px;
border: 1px solid #ddd;
font-weight: bold;
}
QListWidget {
width: 200px;
background-color: #ffffff;
border: 1px solid #ddd;
}
2024-12-19 12:48:57 +00:00
"""
)
2024-11-04 00:22:50 +00:00
self.db = QSqlDatabase.addDatabase("QSQLITE")
self.model = None
self.setup_ui()
def setup_ui(self):
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QHBoxLayout()
# Splitter for left sidebar and main view
self.splitter = QSplitter(Qt.Horizontal)
layout.addWidget(self.splitter)
# Left sidebar for tables
self.table_list = QListWidget()
self.table_list.itemClicked.connect(self.load_table_from_list)
self.splitter.addWidget(self.table_list)
# Main layout
main_widget = QWidget()
main_layout = QVBoxLayout(main_widget)
# Buttons
button_layout = QHBoxLayout()
self.open_button = QPushButton("Open Database", self)
self.open_button.clicked.connect(self.open_database)
self.commit_button = QPushButton("Commit Changes", self)
self.commit_button.clicked.connect(self.commit_changes)
self.add_button = QPushButton("Add Record", self)
self.add_button.clicked.connect(self.add_record)
self.edit_button = QPushButton("Edit Record", self)
self.edit_button.clicked.connect(self.edit_record)
self.delete_button = QPushButton("Delete Record", self)
self.delete_button.clicked.connect(self.delete_record)
self.scroll_button = QPushButton("Scroll to Bottom", self)
2024-12-19 12:48:57 +00:00
self.scroll_button.clicked.connect(
self.scroll_to_bottom
) # Connect to scroll method
2024-11-04 00:22:50 +00:00
button_layout.addWidget(self.open_button)
button_layout.addWidget(self.commit_button)
button_layout.addWidget(self.add_button)
button_layout.addWidget(self.edit_button)
button_layout.addWidget(self.delete_button)
button_layout.addWidget(self.scroll_button) # Add scroll button to layout
main_layout.addLayout(button_layout)
# Search bar
self.search_bar = QLineEdit(self)
self.search_bar.setPlaceholderText("Search...")
self.search_bar.textChanged.connect(self.filter_table)
main_layout.addWidget(self.search_bar)
# Table view
self.table_view = QTableView()
2024-12-19 12:48:57 +00:00
self.table_view.horizontalHeader().setSectionResizeMode(
QHeaderView.ResizeToContents
)
self.table_view.verticalHeader().setSectionResizeMode(
QHeaderView.ResizeToContents
)
2024-11-04 00:22:50 +00:00
main_layout.addWidget(self.table_view)
self.splitter.addWidget(main_widget)
self.splitter.setSizes([150, 650]) # Set default sizes for the splitter
central_widget.setLayout(layout)
def open_database(self):
2024-12-19 12:48:57 +00:00
file_name, _ = QFileDialog.getOpenFileName(
self,
"Open Database",
"",
"SQLite Database Files (*.db *.sqlite);;All Files (*)",
)
2024-11-04 00:22:50 +00:00
if file_name:
self.db.setDatabaseName(file_name)
if not self.db.open():
QMessageBox.critical(self, "Error", "Could not open database")
return
self.load_tables()
def load_tables(self):
self.table_list.clear()
tables = self.db.tables()
if not tables:
QMessageBox.warning(self, "Warning", "No tables found in the database")
return
self.table_list.addItems(tables)
def load_table_from_list(self, item):
table_name = item.text()
self.model = QSqlTableModel(self, self.db)
self.model.setTable(table_name)
self.model.setEditStrategy(QSqlTableModel.OnFieldChange)
self.model.select()
self.proxy_model = QSortFilterProxyModel(self)
self.proxy_model.setSourceModel(self.model)
self.proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.proxy_model.setFilterKeyColumn(-1) # Search all columns
self.table_view.setModel(self.proxy_model)
def filter_table(self, text):
self.proxy_model.setFilterFixedString(text)
def add_record(self):
if not self.model:
QMessageBox.warning(self, "Warning", "No table selected")
return
2024-12-19 12:48:57 +00:00
2024-11-04 00:22:50 +00:00
# Get the column names, excluding the ID field
2024-12-19 12:48:57 +00:00
columns = [
self.model.record().fieldName(i)
for i in range(self.model.record().count())
if self.model.record().fieldName(i).lower() != "id"
]
2024-11-04 00:22:50 +00:00
# Create and show the dialog
dialog = AddRecordDialog(columns, self)
if dialog.exec_() == QDialog.Accepted:
values = dialog.get_values()
self.insert_record(values)
def insert_record(self, values):
if not self.model:
return
2024-12-19 12:48:57 +00:00
2024-11-04 00:22:50 +00:00
row = self.model.rowCount()
self.model.insertRow(row)
2024-12-19 12:48:57 +00:00
2024-11-04 00:22:50 +00:00
for column, value in values.items():
2024-12-19 12:48:57 +00:00
self.model.setData(
self.model.index(row, self.model.fieldIndex(column)), value
)
2024-11-04 00:22:50 +00:00
def edit_record(self):
if not self.model:
QMessageBox.warning(self, "Warning", "No table selected")
return
indexes = self.table_view.selectionModel().selectedRows()
if len(indexes) != 1:
QMessageBox.warning(self, "Warning", "Please select a single row to edit")
return
source_index = self.proxy_model.mapToSource(indexes[0])
self.table_view.edit(indexes[0])
def delete_record(self):
if not self.model:
QMessageBox.warning(self, "Warning", "No table selected")
return
indexes = self.table_view.selectionModel().selectedRows()
if not indexes:
QMessageBox.warning(self, "Warning", "Please select row(s) to delete")
return
2024-12-19 12:48:57 +00:00
confirm = QMessageBox.question(
self,
"Confirm Deletion",
f"Are you sure you want to delete {len(indexes)} row(s)?",
QMessageBox.Yes | QMessageBox.No,
)
2024-11-04 00:22:50 +00:00
if confirm == QMessageBox.Yes:
for index in sorted(indexes, reverse=True):
source_index = self.proxy_model.mapToSource(index)
self.model.removeRow(source_index.row())
self.model.select()
def commit_changes(self):
if self.model:
if self.model.submitAll():
2024-12-19 12:48:57 +00:00
QMessageBox.information(
self, "Success", "Changes committed successfully."
)
2024-11-04 00:22:50 +00:00
else:
2024-12-19 12:48:57 +00:00
QMessageBox.critical(
self,
"Error",
"Failed to commit changes: " + self.model.lastError().text(),
)
2024-11-04 00:22:50 +00:00
def scroll_to_bottom(self):
if self.model and self.model.rowCount() > 0:
self.table_view.scrollToBottom() # Scroll to the bottom of the table view
2024-12-19 12:48:57 +00:00
if __name__ == "__main__":
2024-11-04 00:22:50 +00:00
app = QApplication(sys.argv)
window = LiteSQLViewer()
window.show()
sys.exit(app.exec_())