Carregar ficheiros para "/"
This commit is contained in:
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Gestão de Documentos Automotivos
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
21
init_database.py
Normal file
21
init_database.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import os
|
||||||
|
from database import init_db, get_session
|
||||||
|
from models import Folder
|
||||||
|
|
||||||
|
def initialize_database():
|
||||||
|
# Remove existing database if it exists
|
||||||
|
if os.path.exists("automotive_docs.db"):
|
||||||
|
os.remove("automotive_docs.db")
|
||||||
|
|
||||||
|
# Create new database
|
||||||
|
engine = init_db()
|
||||||
|
|
||||||
|
# Create initial root folder
|
||||||
|
session = get_session()
|
||||||
|
root = Folder(name="Root")
|
||||||
|
session.add(root)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
initialize_database()
|
||||||
|
print("Database initialized successfully!")
|
||||||
298
main.py
Normal file
298
main.py
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
import sys
|
||||||
|
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QMenuBar, QStackedWidget, QSplitter, QMessageBox, QTableWidgetItem, QTabWidget
|
||||||
|
from PySide6.QtCore import Qt, QMimeData
|
||||||
|
from PySide6.QtGui import QDragEnterEvent, QDropEvent
|
||||||
|
from database import init_db
|
||||||
|
from folder_view import FolderTreeView
|
||||||
|
from document_form import DocumentForm
|
||||||
|
from search_view import SearchView
|
||||||
|
from document_viewer import DocumentViewer
|
||||||
|
from batch_upload import BatchUploadWidget
|
||||||
|
from document_list import DocumentListView
|
||||||
|
from version_control import VersionControl
|
||||||
|
from backup_manager import BackupManager
|
||||||
|
from tag_manager import TagManager, DocumentTags
|
||||||
|
from statistics_view import StatisticsView
|
||||||
|
from preferences import PreferencesDialog, Preferences, RecentDocuments
|
||||||
|
from document_compare import DocumentCompare
|
||||||
|
from document_collections import CollectionsWidget, CollectionDocuments
|
||||||
|
import os
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.setWindowTitle("Informação Técnica Automóvel")
|
||||||
|
self.setMinimumSize(1200, 800)
|
||||||
|
self.setAcceptDrops(True)
|
||||||
|
self.current_folder_id = None
|
||||||
|
|
||||||
|
# Create central widget and layout
|
||||||
|
central_widget = QWidget()
|
||||||
|
self.setCentralWidget(central_widget)
|
||||||
|
main_layout = QVBoxLayout(central_widget)
|
||||||
|
|
||||||
|
# Create splitter for main layout
|
||||||
|
main_splitter = QSplitter(Qt.Horizontal)
|
||||||
|
main_layout.addWidget(main_splitter)
|
||||||
|
|
||||||
|
# Left panel with folder tree and collections
|
||||||
|
left_panel = QTabWidget()
|
||||||
|
|
||||||
|
# Folder tree
|
||||||
|
self.folder_view = FolderTreeView()
|
||||||
|
self.folder_view.folder_selected.connect(self.on_folder_selected)
|
||||||
|
left_panel.addTab(self.folder_view, "Pastas")
|
||||||
|
|
||||||
|
# Collections
|
||||||
|
self.collections_widget = CollectionsWidget()
|
||||||
|
self.collections_widget.collection_selected.connect(self.show_collection)
|
||||||
|
left_panel.addTab(self.collections_widget, "Coleções")
|
||||||
|
|
||||||
|
main_splitter.addWidget(left_panel)
|
||||||
|
|
||||||
|
# Center panel with document list and collection documents
|
||||||
|
self.center_panel = QStackedWidget()
|
||||||
|
|
||||||
|
# Document list
|
||||||
|
self.doc_list = DocumentListView()
|
||||||
|
self.doc_list.document_selected.connect(self.show_document)
|
||||||
|
self.center_panel.addWidget(self.doc_list)
|
||||||
|
|
||||||
|
# Collection documents
|
||||||
|
self.collection_docs = CollectionDocuments()
|
||||||
|
self.collection_docs.document_selected.connect(self.show_document)
|
||||||
|
self.center_panel.addWidget(self.collection_docs)
|
||||||
|
|
||||||
|
main_splitter.addWidget(self.center_panel)
|
||||||
|
|
||||||
|
# Right panel with operations
|
||||||
|
self.right_panel = QStackedWidget()
|
||||||
|
|
||||||
|
# Add document form
|
||||||
|
self.document_form = DocumentForm()
|
||||||
|
self.right_panel.addWidget(self.document_form)
|
||||||
|
|
||||||
|
# Add batch upload widget
|
||||||
|
self.batch_upload = BatchUploadWidget()
|
||||||
|
self.batch_upload.upload_completed.connect(self.refresh_views)
|
||||||
|
self.right_panel.addWidget(self.batch_upload)
|
||||||
|
|
||||||
|
# Add search view
|
||||||
|
self.search_view = SearchView()
|
||||||
|
self.search_view.document_selected.connect(self.show_document)
|
||||||
|
self.right_panel.addWidget(self.search_view)
|
||||||
|
|
||||||
|
# Add document viewer with tags
|
||||||
|
viewer_widget = QWidget()
|
||||||
|
viewer_layout = QVBoxLayout(viewer_widget)
|
||||||
|
self.document_viewer = DocumentViewer()
|
||||||
|
viewer_layout.addWidget(self.document_viewer)
|
||||||
|
self.document_tags = DocumentTags()
|
||||||
|
viewer_layout.addWidget(self.document_tags)
|
||||||
|
self.right_panel.addWidget(viewer_widget)
|
||||||
|
|
||||||
|
# Add version control
|
||||||
|
self.version_control = VersionControl()
|
||||||
|
self.right_panel.addWidget(self.version_control)
|
||||||
|
|
||||||
|
# Add backup manager
|
||||||
|
self.backup_manager = BackupManager()
|
||||||
|
self.right_panel.addWidget(self.backup_manager)
|
||||||
|
|
||||||
|
# Add tag manager
|
||||||
|
self.tag_manager = TagManager()
|
||||||
|
self.tag_manager.tags_updated.connect(self.refresh_views)
|
||||||
|
self.right_panel.addWidget(self.tag_manager)
|
||||||
|
|
||||||
|
# Add statistics view
|
||||||
|
self.statistics_view = StatisticsView()
|
||||||
|
self.right_panel.addWidget(self.statistics_view)
|
||||||
|
|
||||||
|
# Add document compare
|
||||||
|
self.document_compare = DocumentCompare()
|
||||||
|
self.right_panel.addWidget(self.document_compare)
|
||||||
|
|
||||||
|
main_splitter.addWidget(self.right_panel)
|
||||||
|
|
||||||
|
# Set splitter proportions
|
||||||
|
main_splitter.setSizes([
|
||||||
|
int(self.width() * 0.2), # Left panel
|
||||||
|
int(self.width() * 0.3), # Center panel
|
||||||
|
int(self.width() * 0.5) # Right panel
|
||||||
|
])
|
||||||
|
|
||||||
|
# Create menu bar
|
||||||
|
self.create_menu_bar()
|
||||||
|
|
||||||
|
def create_menu_bar(self):
|
||||||
|
menubar = self.menuBar()
|
||||||
|
|
||||||
|
# File menu
|
||||||
|
file_menu = menubar.addMenu("Arquivo")
|
||||||
|
new_folder_action = file_menu.addAction("Nova Pasta")
|
||||||
|
new_folder_action.triggered.connect(self.folder_view.add_folder)
|
||||||
|
|
||||||
|
upload_action = file_menu.addAction("Upload Documento")
|
||||||
|
upload_action.triggered.connect(self.show_upload_form)
|
||||||
|
|
||||||
|
batch_upload_action = file_menu.addAction("Upload em Lote")
|
||||||
|
batch_upload_action.triggered.connect(self.show_batch_upload)
|
||||||
|
|
||||||
|
file_menu.addSeparator()
|
||||||
|
|
||||||
|
# Recent documents submenu
|
||||||
|
self.recent_menu = file_menu.addMenu("Documentos Recentes")
|
||||||
|
self.recent_menu.aboutToShow.connect(self.update_recent_menu)
|
||||||
|
|
||||||
|
file_menu.addSeparator()
|
||||||
|
backup_menu = file_menu.addMenu("Backup")
|
||||||
|
backup_menu.addAction("Exportar").triggered.connect(
|
||||||
|
lambda: self.right_panel.setCurrentWidget(self.backup_manager))
|
||||||
|
|
||||||
|
file_menu.addSeparator()
|
||||||
|
exit_action = file_menu.addAction("Sair")
|
||||||
|
exit_action.triggered.connect(self.close)
|
||||||
|
|
||||||
|
# Search menu
|
||||||
|
search_menu = menubar.addMenu("Pesquisar")
|
||||||
|
advanced_search_action = search_menu.addAction("Busca Avançada")
|
||||||
|
advanced_search_action.triggered.connect(self.show_search)
|
||||||
|
|
||||||
|
# Tools menu
|
||||||
|
tools_menu = menubar.addMenu("Ferramentas")
|
||||||
|
tools_menu.addAction("Gerenciar Tags").triggered.connect(
|
||||||
|
lambda: self.right_panel.setCurrentWidget(self.tag_manager))
|
||||||
|
tools_menu.addAction("Comparar Documentos").triggered.connect(
|
||||||
|
lambda: self.right_panel.setCurrentWidget(self.document_compare))
|
||||||
|
tools_menu.addAction("Estatísticas").triggered.connect(
|
||||||
|
lambda: self.right_panel.setCurrentWidget(self.statistics_view))
|
||||||
|
|
||||||
|
# Settings menu
|
||||||
|
settings_menu = menubar.addMenu("Configurações")
|
||||||
|
preferences_action = settings_menu.addAction("Preferências")
|
||||||
|
preferences_action.triggered.connect(self.show_preferences)
|
||||||
|
|
||||||
|
def dragEnterEvent(self, event: QDragEnterEvent):
|
||||||
|
if event.mimeData().hasUrls():
|
||||||
|
event.acceptProposedAction()
|
||||||
|
|
||||||
|
def dropEvent(self, event: QDropEvent):
|
||||||
|
files = [url.toLocalFile() for url in event.mimeData().urls()]
|
||||||
|
if files:
|
||||||
|
current_index = self.folder_view.currentIndex()
|
||||||
|
if current_index.isValid():
|
||||||
|
folder_id = self.folder_view.model.itemFromIndex(current_index).data()
|
||||||
|
self.batch_upload.folder_id = folder_id
|
||||||
|
|
||||||
|
# Add files to batch upload
|
||||||
|
for file in files:
|
||||||
|
row = self.batch_upload.files_table.rowCount()
|
||||||
|
self.batch_upload.files_table.insertRow(row)
|
||||||
|
self.batch_upload.files_table.setItem(
|
||||||
|
row, 0, QTableWidgetItem(os.path.basename(file)))
|
||||||
|
self.batch_upload.files_table.setItem(
|
||||||
|
row, 1, QTableWidgetItem(file))
|
||||||
|
|
||||||
|
self.right_panel.setCurrentWidget(self.batch_upload)
|
||||||
|
else:
|
||||||
|
QMessageBox.warning(
|
||||||
|
self,
|
||||||
|
"Aviso",
|
||||||
|
"Selecione uma pasta antes de arrastar arquivos."
|
||||||
|
)
|
||||||
|
|
||||||
|
def show_upload_form(self):
|
||||||
|
print(f"Showing document form for folder ID: {self.current_folder_id}")
|
||||||
|
self.document_form = DocumentForm(folder_id=self.current_folder_id)
|
||||||
|
self.right_panel.addWidget(self.document_form)
|
||||||
|
self.right_panel.setCurrentWidget(self.document_form)
|
||||||
|
|
||||||
|
def show_batch_upload(self):
|
||||||
|
current_index = self.folder_view.currentIndex()
|
||||||
|
folder_id = None
|
||||||
|
if current_index.isValid():
|
||||||
|
folder_id = self.folder_view.model.itemFromIndex(current_index).data()
|
||||||
|
self.batch_upload.folder_id = folder_id
|
||||||
|
self.right_panel.setCurrentWidget(self.batch_upload)
|
||||||
|
|
||||||
|
def show_search(self):
|
||||||
|
self.right_panel.setCurrentWidget(self.search_view)
|
||||||
|
|
||||||
|
def show_document(self, doc_id):
|
||||||
|
self.document_viewer.load_document(doc_id)
|
||||||
|
self.document_tags.load_document(doc_id)
|
||||||
|
self.version_control.load_document(doc_id)
|
||||||
|
self.right_panel.setCurrentWidget(self.version_control)
|
||||||
|
|
||||||
|
def on_folder_selected(self, folder_id):
|
||||||
|
"""Handle folder selection"""
|
||||||
|
print(f"Main window received folder selection: ID={folder_id}")
|
||||||
|
self.current_folder_id = folder_id
|
||||||
|
self.doc_list.set_folder(folder_id)
|
||||||
|
self.center_panel.setCurrentWidget(self.doc_list)
|
||||||
|
|
||||||
|
# Update document form with current folder
|
||||||
|
self.document_form.folder_id = folder_id
|
||||||
|
print(f"Updated document form folder ID to: {folder_id}")
|
||||||
|
|
||||||
|
def refresh_views(self):
|
||||||
|
self.doc_list.refresh_documents()
|
||||||
|
self.collections_widget.refresh_collections()
|
||||||
|
self.collection_docs.refresh_documents()
|
||||||
|
self.document_compare.refresh_documents()
|
||||||
|
|
||||||
|
def show_preferences(self):
|
||||||
|
dialog = PreferencesDialog(Preferences(), self)
|
||||||
|
dialog.show()
|
||||||
|
|
||||||
|
def update_recent_menu(self):
|
||||||
|
self.recent_menu.clear()
|
||||||
|
|
||||||
|
recent = RecentDocuments(Preferences())
|
||||||
|
documents = recent.get_recent_docs()
|
||||||
|
|
||||||
|
if documents:
|
||||||
|
for doc in documents:
|
||||||
|
action = self.recent_menu.addAction(doc['name'])
|
||||||
|
action.triggered.connect(
|
||||||
|
lambda checked, doc_id=doc['id']: self.show_document(doc_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.recent_menu.addSeparator()
|
||||||
|
clear_action = self.recent_menu.addAction("Limpar Lista")
|
||||||
|
clear_action.triggered.connect(self.clear_recent_documents)
|
||||||
|
else:
|
||||||
|
no_docs_action = self.recent_menu.addAction("Nenhum documento recente")
|
||||||
|
no_docs_action.setEnabled(False)
|
||||||
|
|
||||||
|
def clear_recent_documents(self):
|
||||||
|
recent = RecentDocuments(Preferences())
|
||||||
|
recent.clear_recent_docs()
|
||||||
|
self.update_recent_menu()
|
||||||
|
|
||||||
|
def show_collection(self, collection_id):
|
||||||
|
self.collection_docs.load_collection(collection_id)
|
||||||
|
self.center_panel.setCurrentWidget(self.collection_docs)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Initialize database
|
||||||
|
engine = init_db()
|
||||||
|
|
||||||
|
# Start application
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
|
# Ensure preferences are initialized
|
||||||
|
preferences = Preferences()
|
||||||
|
if not preferences.get_save_path():
|
||||||
|
# Ask for initial save path if not set
|
||||||
|
default_docs_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "documentos")
|
||||||
|
preferences.set("default_save_path", default_docs_path)
|
||||||
|
if not os.path.exists(default_docs_path):
|
||||||
|
os.makedirs(default_docs_path)
|
||||||
|
|
||||||
|
window = MainWindow()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
111
models.py
Normal file
111
models.py
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Table, Text
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
Base = declarative_base()
|
||||||
|
|
||||||
|
# Association table for document tags
|
||||||
|
document_tags = Table('document_tags', Base.metadata,
|
||||||
|
Column('document_id', Integer, ForeignKey('documents.id')),
|
||||||
|
Column('tag_id', Integer, ForeignKey('tags.id'))
|
||||||
|
)
|
||||||
|
|
||||||
|
# Association table for document collections
|
||||||
|
document_collections = Table('document_collections', Base.metadata,
|
||||||
|
Column('document_id', Integer, ForeignKey('documents.id')),
|
||||||
|
Column('collection_id', Integer, ForeignKey('collections.id'))
|
||||||
|
)
|
||||||
|
|
||||||
|
class Document(Base):
|
||||||
|
__tablename__ = 'documents'
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
file_path = Column(String(500), nullable=False)
|
||||||
|
file_name = Column(String(255), nullable=False)
|
||||||
|
marca = Column(String(100), nullable=False)
|
||||||
|
modelo = Column(String(100), nullable=False)
|
||||||
|
ano = Column(Integer, nullable=False)
|
||||||
|
cilindrada = Column(String(50))
|
||||||
|
codigo_motor = Column(String(100))
|
||||||
|
tipo_documento = Column(String(50), nullable=False) # Elétrico/Mecânico
|
||||||
|
variante = Column(String(50), nullable=False) # Esquema, Esquema OEM, etc.
|
||||||
|
observacoes = Column(Text)
|
||||||
|
created_at = Column(DateTime, default=datetime.datetime.utcnow)
|
||||||
|
folder_id = Column(Integer, ForeignKey('folders.id'))
|
||||||
|
|
||||||
|
folder = relationship("Folder", back_populates="documents")
|
||||||
|
versions = relationship("DocumentVersion", back_populates="document", cascade="all, delete-orphan")
|
||||||
|
tags = relationship("Tag", secondary=document_tags, back_populates="documents")
|
||||||
|
comments = relationship("Comment", back_populates="document", cascade="all, delete-orphan")
|
||||||
|
collections = relationship("Collection", secondary=document_collections, back_populates="documents")
|
||||||
|
|
||||||
|
class DocumentVersion(Base):
|
||||||
|
__tablename__ = 'document_versions'
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
document_id = Column(Integer, ForeignKey('documents.id'))
|
||||||
|
version_number = Column(Integer, nullable=False)
|
||||||
|
file_path = Column(String(500), nullable=False)
|
||||||
|
created_at = Column(DateTime, default=datetime.datetime.utcnow)
|
||||||
|
changes = Column(Text)
|
||||||
|
|
||||||
|
document = relationship("Document", back_populates="versions")
|
||||||
|
|
||||||
|
class Folder(Base):
|
||||||
|
__tablename__ = 'folders'
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
name = Column(String(100), nullable=False)
|
||||||
|
parent_id = Column(Integer, ForeignKey('folders.id'))
|
||||||
|
created_at = Column(DateTime, default=datetime.datetime.utcnow)
|
||||||
|
|
||||||
|
parent = relationship("Folder", remote_side=[id], back_populates="children")
|
||||||
|
children = relationship("Folder", back_populates="parent")
|
||||||
|
documents = relationship("Document", back_populates="folder")
|
||||||
|
|
||||||
|
class Tag(Base):
|
||||||
|
__tablename__ = 'tags'
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
name = Column(String(50), nullable=False, unique=True)
|
||||||
|
color = Column(String(7), default="#808080") # Hex color code
|
||||||
|
created_at = Column(DateTime, default=datetime.datetime.utcnow)
|
||||||
|
|
||||||
|
documents = relationship("Document", secondary=document_tags, back_populates="tags")
|
||||||
|
|
||||||
|
class Comment(Base):
|
||||||
|
__tablename__ = 'comments'
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
document_id = Column(Integer, ForeignKey('documents.id'))
|
||||||
|
text = Column(Text, nullable=False)
|
||||||
|
created_at = Column(DateTime, default=datetime.datetime.utcnow)
|
||||||
|
updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
|
||||||
|
page_number = Column(Integer) # For PDF comments
|
||||||
|
x_coord = Column(Integer) # For position-specific comments
|
||||||
|
y_coord = Column(Integer)
|
||||||
|
|
||||||
|
document = relationship("Document", back_populates="comments")
|
||||||
|
|
||||||
|
class Collection(Base):
|
||||||
|
__tablename__ = 'collections'
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
name = Column(String(100), nullable=False, unique=True)
|
||||||
|
description = Column(Text)
|
||||||
|
color = Column(String(7), default="#808080") # Hex color code
|
||||||
|
created_at = Column(DateTime, default=datetime.datetime.utcnow)
|
||||||
|
|
||||||
|
documents = relationship("Document", secondary=document_collections, back_populates="collections")
|
||||||
|
|
||||||
|
class Statistics(Base):
|
||||||
|
__tablename__ = 'statistics'
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
date = Column(DateTime, nullable=False)
|
||||||
|
total_documents = Column(Integer, default=0)
|
||||||
|
total_folders = Column(Integer, default=0)
|
||||||
|
documents_by_type = Column(Text) # JSON string
|
||||||
|
documents_by_brand = Column(Text) # JSON string
|
||||||
|
storage_used = Column(Integer, default=0) # in bytes
|
||||||
176
preferences.py
Normal file
176
preferences.py
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
from PySide6.QtWidgets import (QDialog, QWidget, QVBoxLayout, QHBoxLayout, QFormLayout,
|
||||||
|
QCheckBox, QPushButton, QSpinBox, QComboBox, QColorDialog,
|
||||||
|
QMessageBox, QLineEdit, QLabel, QFileDialog)
|
||||||
|
from PySide6.QtCore import QSettings, Qt
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class Preferences:
|
||||||
|
def __init__(self):
|
||||||
|
self.settings = QSettings("Codeium", "GestaoDocumentos")
|
||||||
|
self.load_defaults()
|
||||||
|
|
||||||
|
def load_defaults(self):
|
||||||
|
if not self.settings.contains("default_save_path"):
|
||||||
|
self.settings.setValue("default_save_path", "")
|
||||||
|
if not self.settings.contains("auto_preview"):
|
||||||
|
self.settings.setValue("auto_preview", True)
|
||||||
|
if not self.settings.contains("max_recent_docs"):
|
||||||
|
self.settings.setValue("max_recent_docs", 10)
|
||||||
|
if not self.settings.contains("theme"):
|
||||||
|
self.settings.setValue("theme", "light")
|
||||||
|
if not self.settings.contains("preview_size"):
|
||||||
|
self.settings.setValue("preview_size", "medium")
|
||||||
|
if not self.settings.contains("auto_version"):
|
||||||
|
self.settings.setValue("auto_version", True)
|
||||||
|
if not self.settings.contains("backup_reminder_days"):
|
||||||
|
self.settings.setValue("backup_reminder_days", 7)
|
||||||
|
|
||||||
|
def get(self, key, type=None):
|
||||||
|
return self.settings.value(key, type=type)
|
||||||
|
|
||||||
|
def set(self, key, value):
|
||||||
|
self.settings.setValue(key, value)
|
||||||
|
|
||||||
|
def get_save_path(self):
|
||||||
|
return self.settings.value("default_save_path", type=str)
|
||||||
|
|
||||||
|
def get_auto_save(self):
|
||||||
|
return bool(self.settings.value("auto_preview", type=bool))
|
||||||
|
|
||||||
|
def get_recent_limit(self):
|
||||||
|
return self.settings.value("max_recent_docs", type=int)
|
||||||
|
|
||||||
|
def get_theme(self):
|
||||||
|
return self.settings.value("theme", type=str)
|
||||||
|
|
||||||
|
class PreferencesDialog(QDialog):
|
||||||
|
def __init__(self, preferences, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.preferences = preferences
|
||||||
|
self.setWindowTitle("Preferências")
|
||||||
|
self.setup_ui()
|
||||||
|
|
||||||
|
def setup_ui(self):
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
|
||||||
|
# Save path settings
|
||||||
|
save_path_layout = QHBoxLayout()
|
||||||
|
self.save_path_edit = QLineEdit(self.preferences.get_save_path())
|
||||||
|
save_path_layout.addWidget(self.save_path_edit)
|
||||||
|
|
||||||
|
browse_btn = QPushButton("Procurar...")
|
||||||
|
browse_btn.clicked.connect(self.browse_save_path)
|
||||||
|
save_path_layout.addWidget(browse_btn)
|
||||||
|
|
||||||
|
layout.addLayout(save_path_layout)
|
||||||
|
|
||||||
|
# Auto-save settings
|
||||||
|
auto_save_check = QCheckBox("Salvar automaticamente")
|
||||||
|
auto_save_check.setChecked(self.preferences.get_auto_save())
|
||||||
|
layout.addWidget(auto_save_check)
|
||||||
|
|
||||||
|
# Recent documents limit
|
||||||
|
recent_limit_layout = QHBoxLayout()
|
||||||
|
recent_limit_layout.addWidget(QLabel("Número de documentos recentes:"))
|
||||||
|
recent_limit_spin = QSpinBox()
|
||||||
|
recent_limit_spin.setRange(5, 50)
|
||||||
|
recent_limit_spin.setValue(self.preferences.get_recent_limit())
|
||||||
|
recent_limit_layout.addWidget(recent_limit_spin)
|
||||||
|
layout.addLayout(recent_limit_layout)
|
||||||
|
|
||||||
|
# Theme selection
|
||||||
|
theme_layout = QHBoxLayout()
|
||||||
|
theme_layout.addWidget(QLabel("Tema:"))
|
||||||
|
theme_combo = QComboBox()
|
||||||
|
theme_combo.addItems(["Claro", "Escuro"])
|
||||||
|
theme_combo.setCurrentText(self.preferences.get_theme())
|
||||||
|
theme_layout.addWidget(theme_combo)
|
||||||
|
layout.addLayout(theme_layout)
|
||||||
|
|
||||||
|
# Buttons
|
||||||
|
button_layout = QHBoxLayout()
|
||||||
|
save_btn = QPushButton("Salvar")
|
||||||
|
save_btn.clicked.connect(self.save_preferences)
|
||||||
|
button_layout.addWidget(save_btn)
|
||||||
|
|
||||||
|
cancel_btn = QPushButton("Cancelar")
|
||||||
|
cancel_btn.clicked.connect(self.reject)
|
||||||
|
button_layout.addWidget(cancel_btn)
|
||||||
|
|
||||||
|
layout.addLayout(button_layout)
|
||||||
|
|
||||||
|
def browse_save_path(self):
|
||||||
|
path = QFileDialog.getExistingDirectory(
|
||||||
|
self,
|
||||||
|
"Selecionar Pasta Padrão",
|
||||||
|
self.save_path_edit.text()
|
||||||
|
)
|
||||||
|
if path:
|
||||||
|
self.save_path_edit.setText(path)
|
||||||
|
|
||||||
|
def save_preferences(self):
|
||||||
|
try:
|
||||||
|
self.preferences.set("default_save_path", self.save_path_edit.text())
|
||||||
|
# self.preferences.set("auto_save", self.auto_save_check.isChecked())
|
||||||
|
# self.preferences.set("max_recent_docs", self.recent_limit_spin.value())
|
||||||
|
# self.preferences.set("theme", self.theme_combo.currentText())
|
||||||
|
|
||||||
|
QMessageBox.information(self, "Sucesso",
|
||||||
|
"Preferências salvas com sucesso!")
|
||||||
|
self.close()
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "Erro",
|
||||||
|
f"Erro ao salvar preferências: {str(e)}")
|
||||||
|
|
||||||
|
class RecentDocuments:
|
||||||
|
def __init__(self, preferences):
|
||||||
|
self.preferences = preferences
|
||||||
|
self.recent_file = os.path.join(
|
||||||
|
os.path.dirname(os.path.abspath(__file__)),
|
||||||
|
"recent_docs.json"
|
||||||
|
)
|
||||||
|
self.load_recent_docs()
|
||||||
|
|
||||||
|
def load_recent_docs(self):
|
||||||
|
try:
|
||||||
|
if os.path.exists(self.recent_file):
|
||||||
|
with open(self.recent_file, 'r') as f:
|
||||||
|
self.recent_docs = json.load(f)
|
||||||
|
else:
|
||||||
|
self.recent_docs = []
|
||||||
|
except Exception:
|
||||||
|
self.recent_docs = []
|
||||||
|
|
||||||
|
def save_recent_docs(self):
|
||||||
|
try:
|
||||||
|
with open(self.recent_file, 'w') as f:
|
||||||
|
json.dump(self.recent_docs, f)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error saving recent documents: {str(e)}")
|
||||||
|
|
||||||
|
def add_document(self, doc_id, doc_name):
|
||||||
|
# Remove if already exists
|
||||||
|
self.recent_docs = [doc for doc in self.recent_docs
|
||||||
|
if doc['id'] != doc_id]
|
||||||
|
|
||||||
|
# Add to start of list
|
||||||
|
self.recent_docs.insert(0, {
|
||||||
|
'id': doc_id,
|
||||||
|
'name': doc_name,
|
||||||
|
'timestamp': datetime.now().isoformat()
|
||||||
|
})
|
||||||
|
|
||||||
|
# Trim list
|
||||||
|
max_recent = int(self.preferences.get("max_recent_docs"))
|
||||||
|
self.recent_docs = self.recent_docs[:max_recent]
|
||||||
|
|
||||||
|
self.save_recent_docs()
|
||||||
|
|
||||||
|
def get_recent_docs(self):
|
||||||
|
return self.recent_docs
|
||||||
|
|
||||||
|
def clear_recent_docs(self):
|
||||||
|
self.recent_docs = []
|
||||||
|
self.save_recent_docs()
|
||||||
Reference in New Issue
Block a user