Buckets:
| import sys | |
| import requests | |
| import json | |
| from PyQt6.QtWidgets import * | |
| from PyQt6.QtCore import * | |
| from PyQt6.QtGui import * | |
| from canvas import DrawingCanvas | |
| API_URL = "http://localhost:5000/api" | |
| class RichTextEditor(QWidget): | |
| def __init__(self): | |
| super().__init__() | |
| self.layout = QVBoxLayout(self) | |
| # Barre d'outils de formatage | |
| self.toolbar = QHBoxLayout() | |
| # Police | |
| self.font_combo = QFontComboBox() | |
| self.font_combo.currentFontChanged.connect(self.change_font) | |
| self.toolbar.addWidget(self.font_combo) | |
| # Taille | |
| self.size_spin = QSpinBox() | |
| self.size_spin.setRange(8, 72) | |
| self.size_spin.setValue(11) | |
| self.size_spin.valueChanged.connect(self.change_size) | |
| self.toolbar.addWidget(self.size_spin) | |
| # Séparateur | |
| line = QFrame() | |
| line.setFrameShape(QFrame.Shape.VLine) | |
| line.setFrameShadow(QFrame.Shadow.Sunken) | |
| self.toolbar.addWidget(line) | |
| # Boutons de style | |
| self.bold_btn = QPushButton("B") | |
| self.bold_btn.setCheckable(True) | |
| self.bold_btn.clicked.connect(self.toggle_bold) | |
| self.toolbar.addWidget(self.bold_btn) | |
| self.italic_btn = QPushButton("I") | |
| self.italic_btn.setCheckable(True) | |
| self.italic_btn.clicked.connect(self.toggle_italic) | |
| self.toolbar.addWidget(self.italic_btn) | |
| self.underline_btn = QPushButton("U") | |
| self.underline_btn.setCheckable(True) | |
| self.underline_btn.clicked.connect(self.toggle_underline) | |
| self.toolbar.addWidget(self.underline_btn) | |
| self.toolbar.addStretch() | |
| self.layout.addLayout(self.toolbar) | |
| # Éditeur HTML | |
| self.editor = QTextEdit() | |
| self.editor.setAcceptRichText(True) | |
| self.layout.addWidget(self.editor) | |
| self.current_page_id = None | |
| def change_font(self, font): | |
| self.editor.setCurrentFont(font) | |
| def change_size(self, size): | |
| self.editor.setFontPointSize(size) | |
| def toggle_bold(self): | |
| self.editor.setFontWeight( | |
| QFont.Weight.Bold if self.bold_btn.isChecked() else QFont.Weight.Normal | |
| ) | |
| def toggle_italic(self): | |
| self.editor.setFontItalic(self.italic_btn.isChecked()) | |
| def toggle_underline(self): | |
| self.editor.setFontUnderline(self.underline_btn.isChecked()) | |
| def set_content(self, html_content): | |
| self.editor.setHtml(html_content if html_content else "") | |
| def get_content(self): | |
| return self.editor.toHtml() | |
| def clear(self): | |
| self.editor.clear() | |
| class OneNoteClone(QMainWindow): | |
| def __init__(self): | |
| super().__init__() | |
| self.setWindowTitle("OneNote Clone") | |
| self.setGeometry(100, 100, 1400, 900) | |
| # Widget central | |
| self.central_widget = QWidget() | |
| self.setCentralWidget(self.central_widget) | |
| self.layout = QHBoxLayout(self.central_widget) | |
| # Panneau de navigation | |
| self.nav_panel = QSplitter(Qt.Orientation.Horizontal) | |
| self.notebook_list = QListWidget() | |
| self.notebook_list.setMaximumWidth(200) | |
| self.notebook_list.itemClicked.connect(self.load_sections) | |
| self.nav_panel.addWidget(self.create_panel("📒 Notebooks", self.notebook_list, self.add_notebook)) | |
| self.section_list = QListWidget() | |
| self.section_list.setMaximumWidth(200) | |
| self.section_list.itemClicked.connect(self.load_pages) | |
| self.nav_panel.addWidget(self.create_panel("📑 Sections", self.section_list, self.add_section)) | |
| self.page_list = QListWidget() | |
| self.page_list.setMaximumWidth(250) | |
| self.page_list.itemClicked.connect(self.load_page_content) | |
| self.nav_panel.addWidget(self.create_panel("📄 Pages", self.page_list, self.add_page)) | |
| self.layout.addWidget(self.nav_panel, 1) | |
| # Zone d'édition avec onglets | |
| self.editor_container = QWidget() | |
| self.editor_layout = QVBoxLayout(self.editor_container) | |
| self.page_title = QLineEdit() | |
| self.page_title.setPlaceholderText("Titre de la page") | |
| self.page_title.setStyleSheet("font-size: 24px; border: none; padding: 10px; background: transparent;") | |
| self.editor_layout.addWidget(self.page_title) | |
| self.tabs = QTabWidget() | |
| self.text_editor = RichTextEditor() | |
| self.canvas = DrawingCanvas() | |
| self.tabs.addTab(self.text_editor, "Texte") | |
| self.tabs.addTab(self.canvas, "Dessin") | |
| self.editor_layout.addWidget(self.tabs) | |
| self.save_btn = QPushButton("💾 Sauvegarder") | |
| self.save_btn.clicked.connect(self.save_page) | |
| self.editor_layout.addWidget(self.save_btn) | |
| self.layout.addWidget(self.editor_container, 3) | |
| self.status_bar = QStatusBar() | |
| self.setStatusBar(self.status_bar) | |
| self.current_notebook_id = None | |
| self.current_section_id = None | |
| self.current_page_id = None | |
| self.load_notebooks() | |
| self.auto_save_timer = QTimer() | |
| self.auto_save_timer.timeout.connect(self.auto_save) | |
| self.auto_save_timer.start(30000) | |
| def create_panel(self, title, list_widget, add_callback): | |
| panel = QWidget() | |
| layout = QVBoxLayout(panel) | |
| header = QLabel(title) | |
| header.setStyleSheet("font-weight: bold; font-size: 14px; padding: 5px;") | |
| layout.addWidget(header) | |
| layout.addWidget(list_widget) | |
| add_btn = QPushButton("+ Ajouter") | |
| add_btn.clicked.connect(add_callback) | |
| layout.addWidget(add_btn) | |
| return panel | |
| def load_notebooks(self): | |
| self.notebook_list.clear() | |
| try: | |
| response = requests.get(f"{API_URL}/notebooks") | |
| for nb in response.json(): | |
| item = QListWidgetItem(nb['name']) | |
| item.setData(Qt.ItemDataRole.UserRole, nb['id']) | |
| item.setBackground(QColor(nb['color'])) | |
| self.notebook_list.addItem(item) | |
| except Exception as e: | |
| self.status_bar.showMessage(f"Erreur: {str(e)}") | |
| def add_notebook(self): | |
| name, ok = QInputDialog.getText(self, "Nouveau Notebook", "Nom:") | |
| if ok and name: | |
| color = QColorDialog.getColor() | |
| try: | |
| requests.post(f"{API_URL}/notebooks", json={ | |
| 'name': name, | |
| 'color': color.name() if color.isValid() else '#7719AA' | |
| }) | |
| self.load_notebooks() | |
| except Exception as e: | |
| QMessageBox.critical(self, "Erreur", str(e)) | |
| def load_sections(self, item): | |
| self.current_notebook_id = item.data(Qt.ItemDataRole.UserRole) | |
| self.section_list.clear() | |
| self.page_list.clear() | |
| self.current_page_id = None | |
| try: | |
| response = requests.get(f"{API_URL}/notebooks/{self.current_notebook_id}/sections") | |
| for sec in response.json(): | |
| item = QListWidgetItem(sec['name']) | |
| item.setData(Qt.ItemDataRole.UserRole, sec['id']) | |
| self.section_list.addItem(item) | |
| except Exception as e: | |
| self.status_bar.showMessage(f"Erreur: {str(e)}") | |
| def add_section(self): | |
| if not self.current_notebook_id: | |
| QMessageBox.warning(self, "Attention", "Sélectionnez d'abord un notebook") | |
| return | |
| name, ok = QInputDialog.getText(self, "Nouvelle Section", "Nom:") | |
| if ok and name: | |
| try: | |
| requests.post(f"{API_URL}/notebooks/{self.current_notebook_id}/sections", json={'name': name}) | |
| self.load_sections(self.notebook_list.currentItem()) | |
| except Exception as e: | |
| QMessageBox.critical(self, "Erreur", str(e)) | |
| def load_pages(self, item): | |
| self.current_section_id = item.data(Qt.ItemDataRole.UserRole) | |
| self.page_list.clear() | |
| try: | |
| response = requests.get(f"{API_URL}/sections/{self.current_section_id}/pages") | |
| for page in response.json(): | |
| item = QListWidgetItem(f"{page['title']}\n{page['updated_at'][:10]}") | |
| item.setData(Qt.ItemDataRole.UserRole, page['id']) | |
| self.page_list.addItem(item) | |
| except Exception as e: | |
| self.status_bar.showMessage(f"Erreur: {str(e)}") | |
| def add_page(self): | |
| if not self.current_section_id: | |
| QMessageBox.warning(self, "Attention", "Sélectionnez d'abord une section") | |
| return | |
| title, ok = QInputDialog.getText(self, "Nouvelle Page", "Titre:") | |
| if ok: | |
| try: | |
| requests.post(f"{API_URL}/sections/{self.current_section_id}/pages", json={'title': title}) | |
| self.load_pages(self.section_list.currentItem()) | |
| except Exception as e: | |
| QMessageBox.critical(self, "Erreur", str(e)) | |
| def load_page_content(self, item): | |
| self.current_page_id = item.data(Qt.ItemDataRole.UserRole) | |
| try: | |
| response = requests.get(f"{API_URL}/pages/{self.current_page_id}") | |
| page = response.json() | |
| self.page_title.setText(page['title']) | |
| self.text_editor.set_content(page['content']) | |
| self.canvas.set_data(page.get('drawing_data', '[]')) | |
| except Exception as e: | |
| self.status_bar.showMessage(f"Erreur: {str(e)}") | |
| def save_page(self): | |
| if not self.current_page_id: | |
| return | |
| try: | |
| requests.put(f"{API_URL}/pages/{self.current_page_id}", json={ | |
| 'title': self.page_title.text(), | |
| 'content': self.text_editor.get_content(), | |
| 'drawing_data': self.canvas.get_data() | |
| }) | |
| self.status_bar.showMessage("Sauvegardé!", 2000) | |
| if self.section_list.currentItem(): | |
| self.load_pages(self.section_list.currentItem()) | |
| except Exception as e: | |
| self.status_bar.showMessage(f"Erreur: {str(e)}") | |
| def auto_save(self): | |
| if self.current_page_id and self.page_title.text(): | |
| self.save_page() | |
| def main(): | |
| app = QApplication(sys.argv) | |
| app.setStyle('Fusion') | |
| app.setStyleSheet(""" | |
| QMainWindow { background-color: #1e1e1e; } | |
| QWidget { background-color: #2d2d2d; color: #ffffff; } | |
| QListWidget { background-color: #252526; border: none; padding: 5px; } | |
| QListWidget::item { padding: 8px; border-radius: 4px; } | |
| QListWidget::item:selected { background-color: #094771; } | |
| QPushButton { background-color: #0e639c; border: none; padding: 8px; border-radius: 4px; color: white; } | |
| QPushButton:hover { background-color: #1177bb; } | |
| QTextEdit { background-color: #1e1e1e; border: 1px solid #3c3c3c; } | |
| QLineEdit { background-color: transparent; border-bottom: 1px solid #3c3c3c; color: white; } | |
| """) | |
| window = OneNoteClone() | |
| window.show() | |
| sys.exit(app.exec()) | |
| if __name__ == '__main__': | |
| main() | |
Xet Storage Details
- Size:
- 11.3 kB
- Xet hash:
- f45122fc60268fdafe33209150db0926c902f00a64dcaeaf1a044732aada63aa
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.