Carregar ficheiros para "/"
This commit is contained in:
296
backup_manager.py
Normal file
296
backup_manager.py
Normal file
@ -0,0 +1,296 @@
|
||||
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
|
||||
QProgressDialog, QFileDialog, QMessageBox)
|
||||
from PySide6.QtCore import Qt
|
||||
from database import get_session
|
||||
from models import Document, DocumentVersion, Folder, Tag
|
||||
import os
|
||||
import json
|
||||
import shutil
|
||||
import zipfile
|
||||
from datetime import datetime
|
||||
|
||||
class BackupManager(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setup_ui()
|
||||
|
||||
def setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Export button
|
||||
self.export_btn = QPushButton("Exportar Documentos")
|
||||
self.export_btn.clicked.connect(self.export_documents)
|
||||
layout.addWidget(self.export_btn)
|
||||
|
||||
# Import button
|
||||
self.import_btn = QPushButton("Importar Documentos")
|
||||
self.import_btn.clicked.connect(self.import_documents)
|
||||
layout.addWidget(self.import_btn)
|
||||
|
||||
def export_documents(self):
|
||||
export_dir = QFileDialog.getExistingDirectory(
|
||||
self,
|
||||
"Selecionar Pasta para Exportação"
|
||||
)
|
||||
|
||||
if not export_dir:
|
||||
return
|
||||
|
||||
try:
|
||||
session = get_session()
|
||||
|
||||
# Create export directory structure
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
export_path = os.path.join(export_dir, f"doc_export_{timestamp}")
|
||||
os.makedirs(export_path)
|
||||
|
||||
# Create progress dialog
|
||||
documents = session.query(Document).all()
|
||||
progress = QProgressDialog(
|
||||
"Exportando documentos...",
|
||||
"Cancelar",
|
||||
0,
|
||||
len(documents),
|
||||
self
|
||||
)
|
||||
progress.setWindowModality(Qt.WindowModal)
|
||||
|
||||
# Export metadata
|
||||
metadata = {
|
||||
'documents': [],
|
||||
'folders': [],
|
||||
'tags': []
|
||||
}
|
||||
|
||||
# Export documents and their versions
|
||||
for i, doc in enumerate(documents):
|
||||
if progress.wasCanceled():
|
||||
break
|
||||
|
||||
# Create document directory
|
||||
doc_dir = os.path.join(export_path, f"doc_{doc.id}")
|
||||
os.makedirs(doc_dir)
|
||||
|
||||
# Copy main document
|
||||
if os.path.exists(doc.file_path):
|
||||
shutil.copy2(doc.file_path,
|
||||
os.path.join(doc_dir, os.path.basename(doc.file_path)))
|
||||
|
||||
# Copy versions
|
||||
versions_dir = os.path.join(doc_dir, "versions")
|
||||
os.makedirs(versions_dir)
|
||||
for version in doc.versions:
|
||||
if os.path.exists(version.file_path):
|
||||
shutil.copy2(
|
||||
version.file_path,
|
||||
os.path.join(versions_dir, os.path.basename(version.file_path))
|
||||
)
|
||||
|
||||
# Add document metadata
|
||||
doc_data = {
|
||||
'id': doc.id,
|
||||
'file_name': doc.file_name,
|
||||
'marca': doc.marca,
|
||||
'modelo': doc.modelo,
|
||||
'ano': doc.ano,
|
||||
'cilindrada': doc.cilindrada,
|
||||
'codigo_motor': doc.codigo_motor,
|
||||
'tipo_documento': doc.tipo_documento,
|
||||
'variante': doc.variante,
|
||||
'observacoes': doc.observacoes,
|
||||
'folder_id': doc.folder_id,
|
||||
'tags': [tag.name for tag in doc.tags],
|
||||
'versions': [{
|
||||
'version_number': v.version_number,
|
||||
'file_name': os.path.basename(v.file_path),
|
||||
'changes': v.changes,
|
||||
'created_at': v.created_at.isoformat()
|
||||
} for v in doc.versions]
|
||||
}
|
||||
metadata['documents'].append(doc_data)
|
||||
|
||||
progress.setValue(i + 1)
|
||||
|
||||
# Export folders
|
||||
folders = session.query(Folder).all()
|
||||
for folder in folders:
|
||||
folder_data = {
|
||||
'id': folder.id,
|
||||
'name': folder.name,
|
||||
'parent_id': folder.parent_id
|
||||
}
|
||||
metadata['folders'].append(folder_data)
|
||||
|
||||
# Export tags
|
||||
tags = session.query(Tag).all()
|
||||
for tag in tags:
|
||||
tag_data = {
|
||||
'name': tag.name,
|
||||
'color': tag.color
|
||||
}
|
||||
metadata['tags'].append(tag_data)
|
||||
|
||||
# Save metadata
|
||||
with open(os.path.join(export_path, 'metadata.json'), 'w',
|
||||
encoding='utf-8') as f:
|
||||
json.dump(metadata, f, ensure_ascii=False, indent=2)
|
||||
|
||||
# Create ZIP archive
|
||||
zip_path = f"{export_path}.zip"
|
||||
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
||||
for root, _, files in os.walk(export_path):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
arcname = os.path.relpath(file_path, export_path)
|
||||
zipf.write(file_path, arcname)
|
||||
|
||||
# Clean up temporary directory
|
||||
shutil.rmtree(export_path)
|
||||
|
||||
QMessageBox.information(
|
||||
self,
|
||||
"Sucesso",
|
||||
f"Exportação concluída com sucesso!\nArquivo: {zip_path}"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro durante a exportação: {str(e)}")
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def import_documents(self):
|
||||
zip_path, _ = QFileDialog.getOpenFileName(
|
||||
self,
|
||||
"Selecionar Arquivo de Importação",
|
||||
"",
|
||||
"Arquivos ZIP (*.zip)"
|
||||
)
|
||||
|
||||
if not zip_path:
|
||||
return
|
||||
|
||||
try:
|
||||
session = get_session()
|
||||
|
||||
# Create temporary directory for extraction
|
||||
temp_dir = os.path.join(os.path.dirname(zip_path), "temp_import")
|
||||
os.makedirs(temp_dir, exist_ok=True)
|
||||
|
||||
# Extract ZIP file
|
||||
with zipfile.ZipFile(zip_path, 'r') as zipf:
|
||||
zipf.extractall(temp_dir)
|
||||
|
||||
# Read metadata
|
||||
with open(os.path.join(temp_dir, 'metadata.json'), 'r',
|
||||
encoding='utf-8') as f:
|
||||
metadata = json.load(f)
|
||||
|
||||
# Import tags
|
||||
for tag_data in metadata['tags']:
|
||||
if not session.query(Tag)\
|
||||
.filter(Tag.name == tag_data['name']).first():
|
||||
tag = Tag(
|
||||
name=tag_data['name'],
|
||||
color=tag_data['color']
|
||||
)
|
||||
session.add(tag)
|
||||
|
||||
# Import folders
|
||||
for folder_data in metadata['folders']:
|
||||
if not session.query(Folder)\
|
||||
.filter(Folder.id == folder_data['id']).first():
|
||||
folder = Folder(
|
||||
id=folder_data['id'],
|
||||
name=folder_data['name'],
|
||||
parent_id=folder_data['parent_id']
|
||||
)
|
||||
session.add(folder)
|
||||
|
||||
# Create progress dialog
|
||||
progress = QProgressDialog(
|
||||
"Importando documentos...",
|
||||
"Cancelar",
|
||||
0,
|
||||
len(metadata['documents']),
|
||||
self
|
||||
)
|
||||
progress.setWindowModality(Qt.WindowModal)
|
||||
|
||||
# Import documents
|
||||
for i, doc_data in enumerate(metadata['documents']):
|
||||
if progress.wasCanceled():
|
||||
break
|
||||
|
||||
# Check if document already exists
|
||||
existing_doc = session.query(Document)\
|
||||
.filter(Document.file_name == doc_data['file_name'])\
|
||||
.filter(Document.folder_id == doc_data['folder_id'])\
|
||||
.first()
|
||||
|
||||
if not existing_doc:
|
||||
# Copy document file
|
||||
doc_dir = os.path.join(temp_dir, f"doc_{doc_data['id']}")
|
||||
original_file = os.path.join(doc_dir, doc_data['file_name'])
|
||||
|
||||
if os.path.exists(original_file):
|
||||
# Create new document
|
||||
new_doc = Document(
|
||||
file_name=doc_data['file_name'],
|
||||
file_path=original_file,
|
||||
marca=doc_data['marca'],
|
||||
modelo=doc_data['modelo'],
|
||||
ano=doc_data['ano'],
|
||||
cilindrada=doc_data['cilindrada'],
|
||||
codigo_motor=doc_data['codigo_motor'],
|
||||
tipo_documento=doc_data['tipo_documento'],
|
||||
variante=doc_data['variante'],
|
||||
observacoes=doc_data['observacoes'],
|
||||
folder_id=doc_data['folder_id']
|
||||
)
|
||||
|
||||
# Add tags
|
||||
for tag_name in doc_data['tags']:
|
||||
tag = session.query(Tag)\
|
||||
.filter(Tag.name == tag_name).first()
|
||||
if tag:
|
||||
new_doc.tags.append(tag)
|
||||
|
||||
session.add(new_doc)
|
||||
session.flush() # Get new_doc.id
|
||||
|
||||
# Import versions
|
||||
versions_dir = os.path.join(doc_dir, "versions")
|
||||
if os.path.exists(versions_dir):
|
||||
for version_data in doc_data['versions']:
|
||||
version_file = os.path.join(
|
||||
versions_dir,
|
||||
version_data['file_name']
|
||||
)
|
||||
if os.path.exists(version_file):
|
||||
new_version = DocumentVersion(
|
||||
document_id=new_doc.id,
|
||||
version_number=version_data['version_number'],
|
||||
file_path=version_file,
|
||||
changes=version_data['changes'],
|
||||
created_at=datetime.fromisoformat(
|
||||
version_data['created_at'])
|
||||
)
|
||||
session.add(new_version)
|
||||
|
||||
progress.setValue(i + 1)
|
||||
|
||||
session.commit()
|
||||
|
||||
# Clean up
|
||||
shutil.rmtree(temp_dir)
|
||||
|
||||
QMessageBox.information(self, "Sucesso",
|
||||
"Importação concluída com sucesso!")
|
||||
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro durante a importação: {str(e)}")
|
||||
finally:
|
||||
session.close()
|
||||
144
batch_upload.py
Normal file
144
batch_upload.py
Normal file
@ -0,0 +1,144 @@
|
||||
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
|
||||
QTableWidget, QTableWidgetItem, QHeaderView,
|
||||
QFileDialog, QMessageBox, QProgressDialog)
|
||||
from PySide6.QtCore import Qt, Signal
|
||||
import os
|
||||
from database import get_session
|
||||
from models import Document
|
||||
from document_form import DocumentForm
|
||||
|
||||
class BatchUploadWidget(QWidget):
|
||||
upload_completed = Signal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.files_to_upload = []
|
||||
self.folder_id = None
|
||||
self.setup_ui()
|
||||
|
||||
def setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Buttons
|
||||
button_layout = QHBoxLayout()
|
||||
self.add_files_btn = QPushButton("Adicionar Arquivos")
|
||||
self.add_files_btn.clicked.connect(self.add_files)
|
||||
self.remove_files_btn = QPushButton("Remover Selecionados")
|
||||
self.remove_files_btn.clicked.connect(self.remove_selected_files)
|
||||
self.upload_all_btn = QPushButton("Upload em Lote")
|
||||
self.upload_all_btn.clicked.connect(self.upload_all)
|
||||
|
||||
button_layout.addWidget(self.add_files_btn)
|
||||
button_layout.addWidget(self.remove_files_btn)
|
||||
button_layout.addWidget(self.upload_all_btn)
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
# Files table
|
||||
self.files_table = QTableWidget()
|
||||
self.files_table.setColumnCount(2)
|
||||
self.files_table.setHorizontalHeaderLabels(["Nome do Arquivo", "Caminho"])
|
||||
self.files_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||
layout.addWidget(self.files_table)
|
||||
|
||||
# Create document form for metadata
|
||||
self.doc_form = DocumentForm()
|
||||
layout.addWidget(self.doc_form)
|
||||
|
||||
def add_files(self):
|
||||
files, _ = QFileDialog.getOpenFileNames(
|
||||
self,
|
||||
"Selecionar Arquivos",
|
||||
"",
|
||||
"Todos os Arquivos (*);;PDF (*.pdf);;Imagens (*.png *.jpg);;Documentos (*.doc *.docx)"
|
||||
)
|
||||
|
||||
for file_path in files:
|
||||
if file_path not in [self.files_table.item(row, 1).text()
|
||||
for row in range(self.files_table.rowCount())]:
|
||||
row = self.files_table.rowCount()
|
||||
self.files_table.insertRow(row)
|
||||
self.files_table.setItem(row, 0, QTableWidgetItem(os.path.basename(file_path)))
|
||||
self.files_table.setItem(row, 1, QTableWidgetItem(file_path))
|
||||
|
||||
def remove_selected_files(self):
|
||||
rows = set(item.row() for item in self.files_table.selectedItems())
|
||||
for row in sorted(rows, reverse=True):
|
||||
self.files_table.removeRow(row)
|
||||
|
||||
def upload_all(self):
|
||||
if not self.validate_form():
|
||||
return
|
||||
|
||||
progress = QProgressDialog(
|
||||
"Fazendo upload dos arquivos...",
|
||||
"Cancelar",
|
||||
0,
|
||||
self.files_table.rowCount(),
|
||||
self
|
||||
)
|
||||
progress.setWindowModality(Qt.WindowModal)
|
||||
|
||||
try:
|
||||
session = get_session()
|
||||
|
||||
for row in range(self.files_table.rowCount()):
|
||||
if progress.wasCanceled():
|
||||
break
|
||||
|
||||
file_path = self.files_table.item(row, 1).text()
|
||||
|
||||
# Create new document with metadata
|
||||
new_doc = Document(
|
||||
file_path=file_path,
|
||||
file_name=os.path.basename(file_path),
|
||||
marca=self.doc_form.marca_edit.text(),
|
||||
modelo=self.doc_form.modelo_edit.text(),
|
||||
ano=self.doc_form.ano_spin.value(),
|
||||
cilindrada=self.doc_form.cilindrada_edit.text(),
|
||||
codigo_motor=self.doc_form.codigo_motor_edit.text(),
|
||||
tipo_documento=self.doc_form.tipo_combo.currentText(),
|
||||
variante=self.doc_form.variante_combo.currentText(),
|
||||
observacoes=self.doc_form.observacoes_edit.toPlainText(),
|
||||
folder_id=self.folder_id
|
||||
)
|
||||
|
||||
session.add(new_doc)
|
||||
progress.setValue(row + 1)
|
||||
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
QMessageBox.information(self, "Sucesso",
|
||||
"Upload em lote concluído com sucesso!")
|
||||
self.clear_form()
|
||||
self.upload_completed.emit()
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro durante o upload em lote: {str(e)}")
|
||||
session.rollback()
|
||||
session.close()
|
||||
|
||||
progress.close()
|
||||
|
||||
def validate_form(self):
|
||||
if self.files_table.rowCount() == 0:
|
||||
QMessageBox.warning(self, "Validação",
|
||||
"Adicione pelo menos um arquivo.")
|
||||
return False
|
||||
|
||||
if not self.doc_form.marca_edit.text():
|
||||
QMessageBox.warning(self, "Validação",
|
||||
"Por favor, preencha a marca.")
|
||||
return False
|
||||
|
||||
if not self.doc_form.modelo_edit.text():
|
||||
QMessageBox.warning(self, "Validação",
|
||||
"Por favor, preencha o modelo.")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def clear_form(self):
|
||||
self.files_table.setRowCount(0)
|
||||
self.doc_form.clear_form()
|
||||
205
comments.py
Normal file
205
comments.py
Normal file
@ -0,0 +1,205 @@
|
||||
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
|
||||
QTextEdit, QListWidget, QListWidgetItem,
|
||||
QLabel, QMenu, QMessageBox, QDialog)
|
||||
from PySide6.QtCore import Qt, Signal, QPoint
|
||||
from PySide6.QtGui import QAction
|
||||
from database import get_session
|
||||
from models import Comment, Document
|
||||
from datetime import datetime
|
||||
|
||||
class CommentWidget(QWidget):
|
||||
comment_updated = Signal()
|
||||
|
||||
def __init__(self, comment, parent=None):
|
||||
super().__init__(parent)
|
||||
self.comment = comment
|
||||
self.setup_ui()
|
||||
|
||||
def setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(5, 5, 5, 5)
|
||||
|
||||
# Header with timestamp and options
|
||||
header_layout = QHBoxLayout()
|
||||
|
||||
timestamp = QLabel(self.comment.created_at.strftime("%d/%m/%Y %H:%M"))
|
||||
timestamp.setStyleSheet("color: gray; font-size: 10px;")
|
||||
header_layout.addWidget(timestamp)
|
||||
|
||||
if self.comment.updated_at and self.comment.updated_at != self.comment.created_at:
|
||||
edited_label = QLabel("(editado)")
|
||||
edited_label.setStyleSheet("color: gray; font-size: 10px;")
|
||||
header_layout.addWidget(edited_label)
|
||||
|
||||
header_layout.addStretch()
|
||||
|
||||
# Options button
|
||||
options_btn = QPushButton("...")
|
||||
options_btn.setFixedWidth(30)
|
||||
options_btn.clicked.connect(self.show_options)
|
||||
header_layout.addWidget(options_btn)
|
||||
|
||||
layout.addLayout(header_layout)
|
||||
|
||||
# Comment text
|
||||
text_label = QLabel(self.comment.text)
|
||||
text_label.setWordWrap(True)
|
||||
layout.addWidget(text_label)
|
||||
|
||||
# Location info if available
|
||||
if self.comment.page_number:
|
||||
location = f"Página {self.comment.page_number}"
|
||||
if self.comment.x_coord and self.comment.y_coord:
|
||||
location += f" (x: {self.comment.x_coord}, y: {self.comment.y_coord})"
|
||||
|
||||
location_label = QLabel(location)
|
||||
location_label.setStyleSheet("color: gray; font-style: italic; font-size: 10px;")
|
||||
layout.addWidget(location_label)
|
||||
|
||||
def show_options(self):
|
||||
menu = QMenu(self)
|
||||
|
||||
edit_action = QAction("Editar", self)
|
||||
edit_action.triggered.connect(self.edit_comment)
|
||||
menu.addAction(edit_action)
|
||||
|
||||
delete_action = QAction("Excluir", self)
|
||||
delete_action.triggered.connect(self.delete_comment)
|
||||
menu.addAction(delete_action)
|
||||
|
||||
# Show menu at button position
|
||||
button = self.sender()
|
||||
pos = button.mapToGlobal(QPoint(0, button.height()))
|
||||
menu.exec_(pos)
|
||||
|
||||
def edit_comment(self):
|
||||
dialog = CommentDialog(self.comment.text, self)
|
||||
if dialog.exec_():
|
||||
try:
|
||||
session = get_session()
|
||||
comment = session.query(Comment).get(self.comment.id)
|
||||
comment.text = dialog.comment_text()
|
||||
comment.updated_at = datetime.utcnow()
|
||||
session.commit()
|
||||
self.comment_updated.emit()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro ao editar comentário: {str(e)}")
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def delete_comment(self):
|
||||
reply = QMessageBox.question(
|
||||
self,
|
||||
"Confirmar Exclusão",
|
||||
"Tem certeza que deseja excluir este comentário?",
|
||||
QMessageBox.Yes | QMessageBox.No
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
try:
|
||||
session = get_session()
|
||||
comment = session.query(Comment).get(self.comment.id)
|
||||
session.delete(comment)
|
||||
session.commit()
|
||||
self.comment_updated.emit()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro ao excluir comentário: {str(e)}")
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
class CommentsList(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.current_document = None
|
||||
self.setup_ui()
|
||||
|
||||
def setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Header
|
||||
header_layout = QHBoxLayout()
|
||||
header_layout.addWidget(QLabel("Comentários"))
|
||||
|
||||
self.add_comment_btn = QPushButton("Novo Comentário")
|
||||
self.add_comment_btn.clicked.connect(self.add_comment)
|
||||
header_layout.addWidget(self.add_comment_btn)
|
||||
|
||||
layout.addLayout(header_layout)
|
||||
|
||||
# Comments list
|
||||
self.comments_list = QListWidget()
|
||||
layout.addWidget(self.comments_list)
|
||||
|
||||
def load_document(self, doc_id):
|
||||
self.current_document = doc_id
|
||||
self.refresh_comments()
|
||||
|
||||
def refresh_comments(self):
|
||||
self.comments_list.clear()
|
||||
|
||||
if self.current_document:
|
||||
session = get_session()
|
||||
document = session.query(Document).get(self.current_document)
|
||||
|
||||
for comment in document.comments:
|
||||
item = QListWidgetItem()
|
||||
widget = CommentWidget(comment)
|
||||
widget.comment_updated.connect(self.refresh_comments)
|
||||
|
||||
item.setSizeHint(widget.sizeHint())
|
||||
self.comments_list.addItem(item)
|
||||
self.comments_list.setItemWidget(item, widget)
|
||||
|
||||
session.close()
|
||||
|
||||
def add_comment(self):
|
||||
if not self.current_document:
|
||||
return
|
||||
|
||||
dialog = CommentDialog(parent=self)
|
||||
if dialog.exec_():
|
||||
try:
|
||||
session = get_session()
|
||||
comment = Comment(
|
||||
document_id=self.current_document,
|
||||
text=dialog.comment_text()
|
||||
)
|
||||
session.add(comment)
|
||||
session.commit()
|
||||
self.refresh_comments()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro ao adicionar comentário: {str(e)}")
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
class CommentDialog(QDialog):
|
||||
def __init__(self, initial_text="", parent=None):
|
||||
super().__init__(parent)
|
||||
self.initial_text = initial_text
|
||||
self.setup_ui()
|
||||
|
||||
def setup_ui(self):
|
||||
self.setWindowTitle("Comentário")
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
self.text_edit = QTextEdit()
|
||||
self.text_edit.setPlainText(self.initial_text)
|
||||
layout.addWidget(self.text_edit)
|
||||
|
||||
buttons_layout = QHBoxLayout()
|
||||
|
||||
cancel_btn = QPushButton("Cancelar")
|
||||
cancel_btn.clicked.connect(self.reject)
|
||||
buttons_layout.addWidget(cancel_btn)
|
||||
|
||||
save_btn = QPushButton("Salvar")
|
||||
save_btn.clicked.connect(self.accept)
|
||||
buttons_layout.addWidget(save_btn)
|
||||
|
||||
layout.addLayout(buttons_layout)
|
||||
|
||||
def comment_text(self):
|
||||
return self.text_edit.toPlainText()
|
||||
23
database.py
Normal file
23
database.py
Normal file
@ -0,0 +1,23 @@
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from models import Base
|
||||
import os
|
||||
|
||||
# Get the absolute path to the database file
|
||||
DATABASE_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "automotive_docs.db")
|
||||
DATABASE_URL = f"sqlite:///{DATABASE_FILE}"
|
||||
|
||||
def init_db():
|
||||
# Create new engine
|
||||
engine = create_engine(DATABASE_URL)
|
||||
|
||||
# Create tables if they don't exist
|
||||
if not os.path.exists(DATABASE_FILE):
|
||||
Base.metadata.create_all(engine)
|
||||
|
||||
return engine
|
||||
|
||||
def get_session():
|
||||
engine = create_engine(DATABASE_URL)
|
||||
Session = sessionmaker(bind=engine)
|
||||
return Session()
|
||||
373
document_collections.py
Normal file
373
document_collections.py
Normal file
@ -0,0 +1,373 @@
|
||||
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
|
||||
QListWidget, QListWidgetItem, QInputDialog,
|
||||
QMessageBox, QMenu, QDialog, QLabel, QLineEdit,
|
||||
QTextEdit, QComboBox)
|
||||
from PySide6.QtCore import Qt, Signal
|
||||
from PySide6.QtGui import QAction, QColor, QIcon
|
||||
from database import get_session
|
||||
from models import Collection, Document
|
||||
import json
|
||||
|
||||
class CollectionDialog(QDialog):
|
||||
def __init__(self, collection=None, parent=None):
|
||||
super().__init__(parent)
|
||||
self.collection = collection
|
||||
self.setup_ui()
|
||||
|
||||
def setup_ui(self):
|
||||
self.setWindowTitle("Coleção")
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Name
|
||||
name_layout = QHBoxLayout()
|
||||
name_layout.addWidget(QLabel("Nome:"))
|
||||
self.name_edit = QLineEdit()
|
||||
if self.collection:
|
||||
self.name_edit.setText(self.collection.name)
|
||||
name_layout.addWidget(self.name_edit)
|
||||
layout.addLayout(name_layout)
|
||||
|
||||
# Description
|
||||
layout.addWidget(QLabel("Descrição:"))
|
||||
self.desc_edit = QTextEdit()
|
||||
if self.collection:
|
||||
self.desc_edit.setText(self.collection.description)
|
||||
layout.addWidget(self.desc_edit)
|
||||
|
||||
# Color
|
||||
color_layout = QHBoxLayout()
|
||||
color_layout.addWidget(QLabel("Cor:"))
|
||||
self.color_combo = QComboBox()
|
||||
colors = ["#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF"]
|
||||
for color in colors:
|
||||
self.color_combo.addItem("")
|
||||
self.color_combo.setItemData(
|
||||
self.color_combo.count() - 1,
|
||||
QColor(color),
|
||||
Qt.BackgroundRole
|
||||
)
|
||||
if self.collection:
|
||||
index = colors.index(self.collection.color)
|
||||
self.color_combo.setCurrentIndex(index)
|
||||
color_layout.addWidget(self.color_combo)
|
||||
layout.addLayout(color_layout)
|
||||
|
||||
# Buttons
|
||||
button_layout = QHBoxLayout()
|
||||
|
||||
cancel_btn = QPushButton("Cancelar")
|
||||
cancel_btn.clicked.connect(self.reject)
|
||||
button_layout.addWidget(cancel_btn)
|
||||
|
||||
save_btn = QPushButton("Salvar")
|
||||
save_btn.clicked.connect(self.accept)
|
||||
button_layout.addWidget(save_btn)
|
||||
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
def get_data(self):
|
||||
return {
|
||||
'name': self.name_edit.text(),
|
||||
'description': self.desc_edit.toPlainText(),
|
||||
'color': self.color_combo.itemData(
|
||||
self.color_combo.currentIndex(),
|
||||
Qt.BackgroundRole
|
||||
).name()
|
||||
}
|
||||
|
||||
class CollectionsWidget(QWidget):
|
||||
collection_selected = Signal(int) # collection_id
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setup_ui()
|
||||
|
||||
def setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Toolbar
|
||||
toolbar = QHBoxLayout()
|
||||
|
||||
new_btn = QPushButton("Nova Coleção")
|
||||
new_btn.clicked.connect(self.add_collection)
|
||||
toolbar.addWidget(new_btn)
|
||||
|
||||
toolbar.addStretch()
|
||||
|
||||
layout.addLayout(toolbar)
|
||||
|
||||
# Collections list
|
||||
self.collections_list = QListWidget()
|
||||
self.collections_list.itemClicked.connect(self.on_collection_clicked)
|
||||
self.collections_list.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.collections_list.customContextMenuRequested.connect(
|
||||
self.show_context_menu)
|
||||
layout.addWidget(self.collections_list)
|
||||
|
||||
self.refresh_collections()
|
||||
|
||||
def refresh_collections(self):
|
||||
self.collections_list.clear()
|
||||
|
||||
try:
|
||||
session = get_session()
|
||||
collections = session.query(Collection).all()
|
||||
|
||||
for collection in collections:
|
||||
item = QListWidgetItem(collection.name)
|
||||
item.setData(Qt.UserRole, collection.id)
|
||||
item.setBackground(QColor(collection.color))
|
||||
|
||||
# Add document count
|
||||
doc_count = len(collection.documents)
|
||||
item.setToolTip(
|
||||
f"{collection.description}\n\n"
|
||||
f"Documentos: {doc_count}"
|
||||
)
|
||||
|
||||
self.collections_list.addItem(item)
|
||||
|
||||
session.close()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro ao carregar coleções: {str(e)}")
|
||||
|
||||
def add_collection(self):
|
||||
dialog = CollectionDialog(parent=self)
|
||||
if dialog.exec_():
|
||||
try:
|
||||
session = get_session()
|
||||
|
||||
data = dialog.get_data()
|
||||
collection = Collection(
|
||||
name=data['name'],
|
||||
description=data['description'],
|
||||
color=data['color']
|
||||
)
|
||||
session.add(collection)
|
||||
session.commit()
|
||||
|
||||
self.refresh_collections()
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro ao criar coleção: {str(e)}")
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def edit_collection(self, collection_id):
|
||||
try:
|
||||
session = get_session()
|
||||
collection = session.query(Collection).get(collection_id)
|
||||
|
||||
if collection:
|
||||
dialog = CollectionDialog(collection, self)
|
||||
if dialog.exec_():
|
||||
data = dialog.get_data()
|
||||
collection.name = data['name']
|
||||
collection.description = data['description']
|
||||
collection.color = data['color']
|
||||
session.commit()
|
||||
|
||||
self.refresh_collections()
|
||||
|
||||
session.close()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro ao editar coleção: {str(e)}")
|
||||
|
||||
def delete_collection(self, collection_id):
|
||||
reply = QMessageBox.question(
|
||||
self,
|
||||
"Confirmar Exclusão",
|
||||
"Tem certeza que deseja excluir esta coleção?",
|
||||
QMessageBox.Yes | QMessageBox.No
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
try:
|
||||
session = get_session()
|
||||
collection = session.query(Collection).get(collection_id)
|
||||
|
||||
if collection:
|
||||
session.delete(collection)
|
||||
session.commit()
|
||||
|
||||
self.refresh_collections()
|
||||
|
||||
session.close()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro ao excluir coleção: {str(e)}")
|
||||
|
||||
def on_collection_clicked(self, item):
|
||||
collection_id = item.data(Qt.UserRole)
|
||||
self.collection_selected.emit(collection_id)
|
||||
|
||||
def show_context_menu(self, position):
|
||||
item = self.collections_list.itemAt(position)
|
||||
if not item:
|
||||
return
|
||||
|
||||
collection_id = item.data(Qt.UserRole)
|
||||
|
||||
menu = QMenu()
|
||||
edit_action = menu.addAction("Editar")
|
||||
edit_action.triggered.connect(
|
||||
lambda: self.edit_collection(collection_id))
|
||||
|
||||
delete_action = menu.addAction("Excluir")
|
||||
delete_action.triggered.connect(
|
||||
lambda: self.delete_collection(collection_id))
|
||||
|
||||
menu.exec_(self.collections_list.mapToGlobal(position))
|
||||
|
||||
class CollectionDocuments(QWidget):
|
||||
document_selected = Signal(int) # document_id
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.current_collection = None
|
||||
self.setup_ui()
|
||||
|
||||
def setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Header
|
||||
header_layout = QHBoxLayout()
|
||||
|
||||
self.collection_label = QLabel()
|
||||
header_layout.addWidget(self.collection_label)
|
||||
|
||||
self.add_doc_btn = QPushButton("Adicionar Documento")
|
||||
self.add_doc_btn.clicked.connect(self.add_document)
|
||||
header_layout.addWidget(self.add_doc_btn)
|
||||
|
||||
layout.addLayout(header_layout)
|
||||
|
||||
# Documents list
|
||||
self.documents_list = QListWidget()
|
||||
self.documents_list.itemClicked.connect(self.on_document_clicked)
|
||||
self.documents_list.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.documents_list.customContextMenuRequested.connect(
|
||||
self.show_context_menu)
|
||||
layout.addWidget(self.documents_list)
|
||||
|
||||
def load_collection(self, collection_id):
|
||||
self.current_collection = collection_id
|
||||
self.refresh_documents()
|
||||
|
||||
def refresh_documents(self):
|
||||
self.documents_list.clear()
|
||||
|
||||
if not self.current_collection:
|
||||
return
|
||||
|
||||
try:
|
||||
session = get_session()
|
||||
collection = session.query(Collection).get(self.current_collection)
|
||||
|
||||
if collection:
|
||||
self.collection_label.setText(
|
||||
f"Coleção: {collection.name}"
|
||||
)
|
||||
|
||||
for doc in collection.documents:
|
||||
item = QListWidgetItem(doc.file_name)
|
||||
item.setData(Qt.UserRole, doc.id)
|
||||
item.setToolTip(
|
||||
f"Marca: {doc.marca}\n"
|
||||
f"Modelo: {doc.modelo}\n"
|
||||
f"Ano: {doc.ano}"
|
||||
)
|
||||
self.documents_list.addItem(item)
|
||||
|
||||
session.close()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro ao carregar documentos: {str(e)}")
|
||||
|
||||
def add_document(self):
|
||||
if not self.current_collection:
|
||||
return
|
||||
|
||||
try:
|
||||
session = get_session()
|
||||
|
||||
# Get documents not in collection
|
||||
collection = session.query(Collection).get(self.current_collection)
|
||||
all_docs = session.query(Document).all()
|
||||
collection_doc_ids = [doc.id for doc in collection.documents]
|
||||
available_docs = [doc for doc in all_docs
|
||||
if doc.id not in collection_doc_ids]
|
||||
|
||||
if not available_docs:
|
||||
QMessageBox.information(
|
||||
self,
|
||||
"Aviso",
|
||||
"Não há documentos disponíveis para adicionar."
|
||||
)
|
||||
return
|
||||
|
||||
# Show document selection dialog
|
||||
doc_names = [f"{doc.file_name} ({doc.marca} {doc.modelo})"
|
||||
for doc in available_docs]
|
||||
name, ok = QInputDialog.getItem(
|
||||
self,
|
||||
"Adicionar Documento",
|
||||
"Selecione um documento:",
|
||||
doc_names,
|
||||
0,
|
||||
False
|
||||
)
|
||||
|
||||
if ok and name:
|
||||
index = doc_names.index(name)
|
||||
doc = available_docs[index]
|
||||
collection.documents.append(doc)
|
||||
session.commit()
|
||||
|
||||
self.refresh_documents()
|
||||
|
||||
session.close()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro ao adicionar documento: {str(e)}")
|
||||
|
||||
def remove_document(self, doc_id):
|
||||
if not self.current_collection:
|
||||
return
|
||||
|
||||
try:
|
||||
session = get_session()
|
||||
collection = session.query(Collection).get(self.current_collection)
|
||||
document = session.query(Document).get(doc_id)
|
||||
|
||||
if collection and document:
|
||||
collection.documents.remove(document)
|
||||
session.commit()
|
||||
|
||||
self.refresh_documents()
|
||||
|
||||
session.close()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erro",
|
||||
f"Erro ao remover documento: {str(e)}")
|
||||
|
||||
def on_document_clicked(self, item):
|
||||
doc_id = item.data(Qt.UserRole)
|
||||
self.document_selected.emit(doc_id)
|
||||
|
||||
def show_context_menu(self, position):
|
||||
item = self.documents_list.itemAt(position)
|
||||
if not item:
|
||||
return
|
||||
|
||||
doc_id = item.data(Qt.UserRole)
|
||||
|
||||
menu = QMenu()
|
||||
remove_action = menu.addAction("Remover da Coleção")
|
||||
remove_action.triggered.connect(
|
||||
lambda: self.remove_document(doc_id))
|
||||
|
||||
menu.exec_(self.documents_list.mapToGlobal(position))
|
||||
Reference in New Issue
Block a user