class List(QDialog): """All Notes dialog""" def __init__(self, app, *args, **kwargs): QDialog.__init__(self, *args, **kwargs) self.app = app self.closed = False self.sort_order = None self.ui = Ui_List() self.ui.setupUi(self) self.setWindowIcon(get_icon()) self.notebooksModel = QStandardItemModel() self.ui.notebooksList.setModel(self.notebooksModel) self.ui.notebooksList.selection.connect(self.selection_changed) self.ui.notebooksList.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.notebooksList.customContextMenuRequested.connect(self.notebook_context_menu) self.notesModel = QStandardItemModel() self.notesModel.setHorizontalHeaderLabels( [self.tr('Title'), self.tr('Last Updated')]) self.ui.notesList.setModel(self.notesModel) self.ui.notesList.doubleClicked.connect(self.note_dblclicked) self.ui.notesList.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.notesList.customContextMenuRequested.connect(self.note_context_menu) self.ui.notesList.header().sortIndicatorChanged.connect(self.sort_order_updated) self.ui.newNotebookBtn.setIcon(QIcon.fromTheme('folder-new')) self.ui.newNotebookBtn.clicked.connect(self.new_notebook) self.ui.newNoteBtn.setIcon(QIcon.fromTheme('document-new')) self.ui.newNoteBtn.clicked.connect(self.new_note) self.ui.newNoteBtn.setShortcut(QKeySequence(self.tr('Ctrl+n'))) self.ui.newNotebookBtn.setShortcut(QKeySequence(self.tr('Ctrl+Shift+n'))) QShortcut(QKeySequence(self.tr('Ctrl+q')), self, self.close) @Slot(QItemSelection, QItemSelection) def selection_changed(self, selected, deselected): if len(selected.indexes()): self.notebook_selected(selected.indexes()[-1]) def showEvent(self, *args, **kwargs): QDialog.showEvent(self, *args, **kwargs) self._reload_notebooks_list() self.readSettings() def writeSettings(self): self.app.settings.setValue('list-geometry', self.saveGeometry()) for key, widget in self._getRestorableItems(): self.app.settings.setValue(key, widget.saveState()) def _getRestorableItems(self): return ( ('list-splitter-state', self.ui.splitter), ('list-header-state', self.ui.notesList.header()), ) def readSettings(self): geometry = self.app.settings.value('list-geometry') if geometry: self.restoreGeometry(geometry) for key, widget in self._getRestorableItems(): state = self.app.settings.value(key) if state: widget.restoreState(state) def closeEvent(self, event): self.writeSettings() event.ignore() self.closed = True self.hide() @Slot(int, Qt.SortOrder) def sort_order_updated(self, logicalIndex, order): self.sort_order = (logicalIndex, order.name) self.app.settings.setValue('list-notes-sort-order', self.sort_order) def notebook_selected(self, index): self.notesModel.setRowCount(0) item = self.notebooksModel.itemFromIndex(index) if hasattr(item, 'notebook'): notebook_id = item.notebook.id else: notebook_id = 0 notebook_filter = [notebook_id] if notebook_id > 0 else dbus.Array([], signature='i') notes = self.app.provider.find_notes( '', notebook_filter, dbus.Array([], signature='i'), 0, 2 ** 31 - 1, Note.ORDER_TITLE, -1, ) # fails with sys.maxint in 64 for note_struct in notes: note = Note.from_tuple(note_struct) self.notesModel.appendRow(QNoteItemFactory(note).make_items()) sort_order = self.sort_order if sort_order is None: sort_order = self.app.settings.value('list-notes-sort-order') if sort_order: logicalIndex, order = sort_order order = Qt.SortOrder.values[order] self.ui.notesList.sortByColumn(int(logicalIndex), order) @Slot() def note_dblclicked(self, index): item = self.notesModel.itemFromIndex(index) self.app.indicator.open(item.note) @Slot() def new_notebook(self): name, status = self._notebook_new_name(self.tr('Create new notebook')) if status: notebook_struct = self.app.provider.create_notebook(name) notebook = Notebook.from_tuple(notebook_struct) self.app.send_notify(self.tr('Notebook "%s" created!') % notebook.name) self._reload_notebooks_list(notebook.id) @Slot() def rename_notebook(self): index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) notebook = item.notebook name, status = self._notebook_new_name( self.tr('Rename notebook'), notebook.name, ) if status: notebook.name = name self.app.provider.update_notebook(notebook.struct) self.app.send_notify(self.tr('Notebook "%s" renamed!') % notebook.name) self._reload_notebooks_list(notebook.id) @Slot() def remove_notebook(self): msg = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a notebook"), self.tr("Are you sure want to delete this notebook and its notes?"), QMessageBox.Yes | QMessageBox.No ) if msg.exec_() == QMessageBox.Yes: index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) self.app.provider.delete_notebook(item.notebook.id) self.app.send_notify(self.tr('Notebook "%s" deleted!') % item.notebook.name) self._reload_notebooks_list() @Slot() def new_note(self): index = self.ui.notebooksList.currentIndex() notebook_id = NONE_ID if index.row(): item = self.notebooksModel.itemFromIndex(index) notebook_id = item.notebook.id self.app.indicator.create(notebook_id=notebook_id) @Slot() def edit_note(self): index = self.ui.notesList.currentIndex() item = self.notesModel.itemFromIndex(index) self.app.indicator.open(item.note) @Slot() def remove_note(self): index = self.ui.notesList.currentIndex() item = self.notesModel.itemFromIndex(index) msgBox = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a note"), self.tr('Are you sure want to delete note "%s"?') % item.note.title, QMessageBox.Yes | QMessageBox.No ) if msgBox.exec_() == QMessageBox.Yes: self.app.provider.delete_note(item.note.id) self.app.send_notify(self.tr('Note "%s" deleted!') % item.note.title) self.notebook_selected(self.ui.notebooksList.currentIndex()) @Slot(QPoint) def notebook_context_menu(self, pos): index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) if hasattr(item, 'notebook'): menu = QMenu(self.ui.notebooksList) menu.addAction(QIcon.fromTheme('gtk-edit'), self.tr('Rename'), self.rename_notebook) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_notebook) menu.exec_(self.ui.notebooksList.mapToGlobal(pos)) @Slot(QPoint) def note_context_menu(self, pos): menu = QMenu(self.ui.notesList) menu.addAction(QIcon.fromTheme('gtk-edit'), self.tr('Edit'), self.edit_note) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_note) menu.exec_(self.ui.notesList.mapToGlobal(pos)) def _reload_notebooks_list(self, select_notebook_id=None): self.notebooksModel.clear() root = QStandardItem(QIcon.fromTheme('user-home'), self.tr('All Notes')) self.notebooksModel.appendRow(root) selected_item = root for notebook_struct in self.app.provider.list_notebooks(): notebook = Notebook.from_tuple(notebook_struct) count = self.app.provider.get_notebook_notes_count(notebook.id) item = QNotebookItem(notebook, count) root.appendRow(item) if select_notebook_id and notebook.id == select_notebook_id: selected_item = item self.ui.notebooksList.expandAll() if selected_item: index = self.notebooksModel.indexFromItem(selected_item) self.ui.notebooksList.setCurrentIndex(index) self.notebook_selected(index) def _notebook_new_name(self, title, exclude=''): names = map(lambda nb: Notebook.from_tuple(nb).name, self.app.provider.list_notebooks()) try: names.remove(exclude) except ValueError: pass name, status = QInputDialog.getText(self, title, self.tr('Enter notebook name:'), text=exclude) while name in names and status: message = self.tr('Notebook with this name already exist. Enter notebook name') name, status = QInputDialog.getText(self, title, message) return name, status
class DialogLookup(QtGui.QDialog): def __init__(self, lookup): super().__init__() self._lookup = lookup self._model = QStandardItemModel() # (4, 4) self.initUI() self.initDB() def initUI(self): global _compatible self.result = userCancelled # create our window # define window xLoc,yLoc,xDim,yDim self.setGeometry(250, 250, 640, 480) self.setWindowTitle(translate('Rocket', "Component lookup...")) self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) searchLabel = QtGui.QLabel(translate('Rocket', "Search"), self) self._searchInput = QtGui.QLineEdit(self) self._searchInput.setFixedWidth(80) self._searchInput.textEdited.connect(self.onSearch) lookupTypeLabel = QtGui.QLabel(translate('Rocket', "Component"), self) self._lookupTypeCombo = QtGui.QComboBox(self) self._lookupTypeCombo.addItems(_compatible[self._lookup]) self._lookupTypeCombo.setCurrentText(self._lookup) self._lookupTypeCombo.currentTextChanged.connect(self.onLookupType) self._dbTable = QtGui.QTableView(self) self._dbTable.setModel(self._model) self._dbTable.setSelectionBehavior(QtGui.QTableView.SelectRows) self._dbTable.setSelectionMode(QtGui.QTableView.SingleSelection) self._dbTable.setSortingEnabled(True) self._dbTable.doubleClicked.connect(self.onTableDoubleClick) # cancel button cancelButton = QtGui.QPushButton('Cancel', self) cancelButton.clicked.connect(self.onCancel) cancelButton.setAutoDefault(True) # OK button okButton = QtGui.QPushButton('OK', self) okButton.setDefault(True) okButton.clicked.connect(self.onOk) layout = QVBoxLayout() line = QHBoxLayout() line.addWidget(searchLabel) line.addWidget(self._searchInput) line.addStretch() line.addWidget(lookupTypeLabel) line.addWidget(self._lookupTypeCombo) layout.addLayout(line) layout.addWidget(self._dbTable) line = QHBoxLayout() line.addStretch() line.addWidget(okButton) line.addWidget(cancelButton) layout.addLayout(line) self.setLayout(layout) # now make the window visible self.show() def initDB(self): self._connection = sqlite3.connect( "file:" + FreeCAD.getUserAppDataDir() + "Mod/Rocket/Resources/parts/Parts.db?mode=ro", uri=True) self._connection.row_factory = sqlite3.Row self._updateModel() def onLookupType(self, value): self._updateModel() def onSearch(self, value): rows = [] value = str(value).strip() if len(value) > 0: for column in range(self._model.columnCount()): items = self._model.findItems(value, Qt.MatchContains, column) for item in items: row = item.row() if not row in rows: rows.append(row) for row in range(self._model.rowCount()): if row in rows: self._dbTable.showRow(row) else: self._dbTable.hideRow(row) else: for row in range(self._model.rowCount()): self._dbTable.showRow(row) def onTableDoubleClick(self, selected): self.result = self._getSelected(selected.row()) self.close() def onCancel(self): self.result = {} self.close() def onOk(self): selected = self._dbTable.selectedIndexes() if len(selected) > 0: row = selected[0].row() self.result = self._getSelected(row) else: self.result = {} self.close() def _getSelectedBodyTube(self, row): try: index = int(self._model.item(row, 0).text()) cone = getBodyTube(self._connection, index) return cone except NotFoundError: _err(translate('Rocket', "Body tube not found")) except MultipleEntryError: _err(translate('Rocket', "Multiple identical entries found")) return {} def _getSelectedNose(self, row): try: index = int(self._model.item(row, 0).text()) cone = getNoseCone(self._connection, index) return cone except NotFoundError: _err(translate('Rocket', "Nose cone not found")) except MultipleEntryError: _err(translate('Rocket', "Multiple identical entries found")) return {} def _getSelectedTransition(self, row): try: index = int(self._model.item(row, 0).text()) tran = getTransition(self._connection, index) return tran except NotFoundError: _err(translate('Rocket', "Transition not found")) except MultipleEntryError: _err(translate('Rocket', "Multiple identical entries found")) return {} def _getSelected(self, row): queryType = str(self._lookupTypeCombo.currentText()) if queryType == COMPONENT_TYPE_ANY: query = self._lookup else: query = queryType if query in [ COMPONENT_TYPE_BODYTUBE, COMPONENT_TYPE_COUPLER, COMPONENT_TYPE_ENGINEBLOCK, COMPONENT_TYPE_LAUNCHLUG, COMPONENT_TYPE_CENTERINGRING, COMPONENT_TYPE_BULKHEAD ]: return self._getSelectedBodyTube(row) elif query == COMPONENT_TYPE_NOSECONE: return self._getSelectedNose(row) elif query == COMPONENT_TYPE_TRANSITION: return self._getSelectedTransition(row) # elif query == COMPONENT_TYPE_PARACHUTE: # pass # elif query == COMPONENT_TYPE_STREAMER: # pass return {} def _itemWithDimension(self, value, dim): return self._newItem(_valueWithUnits(value, dim)) def _newItem(self, text): item = QStandardItem(text) item.setEditable(False) return item def _queryBodyTube(self, queryType): rows = listBodyTubes(self._connection, queryType) self._model.setRowCount(len(rows)) if queryType == COMPONENT_TYPE_BULKHEAD: self._model.setColumnCount(7) else: self._model.setColumnCount(8) self._dbTable.hideColumn(0) # This holds index for lookups self._dbTable.setVerticalHeader(None) # Add the column headers self._model.setHorizontalHeaderItem( 1, self._newItem(translate('Rocket', "Type"))) self._model.setHorizontalHeaderItem( 2, self._newItem(translate('Rocket', "Manufacturer"))) self._model.setHorizontalHeaderItem( 3, self._newItem(translate('Rocket', "Part Number"))) self._model.setHorizontalHeaderItem( 4, self._newItem(translate('Rocket', "Description"))) self._model.setHorizontalHeaderItem( 5, self._newItem(translate('Rocket', "Outer Diameter"))) if queryType == COMPONENT_TYPE_BULKHEAD: self._model.setHorizontalHeaderItem( 6, self._newItem(translate('Rocket', "Length"))) else: self._model.setHorizontalHeaderItem( 6, self._newItem(translate('Rocket', "Inner Diameter"))) self._model.setHorizontalHeaderItem( 7, self._newItem(translate('Rocket', "Length"))) rowCount = 0 for row in rows: self._model.setItem(rowCount, 0, self._newItem(str(row["body_tube_index"]))) self._model.setItem(rowCount, 1, self._newItem(str(row["type"]))) self._model.setItem(rowCount, 2, self._newItem(str(row["manufacturer"]))) self._model.setItem(rowCount, 3, self._newItem(str(row["part_number"]))) self._model.setItem(rowCount, 4, self._newItem(str(row["description"]))) self._model.setItem( rowCount, 5, self._newItem( self._itemWithDimension(row["outer_diameter"], row["outer_diameter_units"]))) if queryType == COMPONENT_TYPE_BULKHEAD: self._model.setItem( rowCount, 6, self._newItem( self._itemWithDimension(row["length"], row["length_units"]))) else: self._model.setItem( rowCount, 6, self._newItem( self._itemWithDimension(row["inner_diameter"], row["inner_diameter_units"]))) self._model.setItem( rowCount, 7, self._newItem( self._itemWithDimension(row["length"], row["length_units"]))) rowCount += 1 def _queryNoseCone(self): rows = listNoseCones(self._connection) self._model.setRowCount(len(rows)) self._model.setColumnCount(9) self._dbTable.hideColumn(0) # This holds index for lookups self._dbTable.setVerticalHeader(None) # Add the column headers self._model.setHorizontalHeaderItem( 1, self._newItem(translate('Rocket', "Manufacturer"))) self._model.setHorizontalHeaderItem( 2, self._newItem(translate('Rocket', "Part Number"))) self._model.setHorizontalHeaderItem( 3, self._newItem(translate('Rocket', "Description"))) self._model.setHorizontalHeaderItem( 4, self._newItem(translate('Rocket', "Diameter"))) self._model.setHorizontalHeaderItem( 5, self._newItem(translate('Rocket', "Length"))) self._model.setHorizontalHeaderItem( 6, self._newItem(translate('Rocket', "Shoulder Diameter"))) self._model.setHorizontalHeaderItem( 7, self._newItem(translate('Rocket', "Shoulder Length"))) self._model.setHorizontalHeaderItem( 8, self._newItem(translate('Rocket', "Shape"))) rowCount = 0 for row in rows: self._model.setItem(rowCount, 0, self._newItem(str(row["nose_index"]))) self._model.setItem(rowCount, 1, self._newItem(str(row["manufacturer"]))) self._model.setItem(rowCount, 2, self._newItem(str(row["part_number"]))) self._model.setItem(rowCount, 3, self._newItem(str(row["description"]))) self._model.setItem( rowCount, 4, self._newItem( self._itemWithDimension(row["diameter"], row["diameter_units"]))) self._model.setItem( rowCount, 5, self._newItem( self._itemWithDimension(row["length"], row["length_units"]))) self._model.setItem( rowCount, 6, self._newItem( self._itemWithDimension(row["shoulder_diameter"], row["shoulder_diameter_units"]))) self._model.setItem( rowCount, 7, self._newItem( self._itemWithDimension(row["shoulder_length"], row["shoulder_length_units"]))) self._model.setItem(rowCount, 8, self._newItem(str(row["shape"]))) rowCount += 1 def _queryTransition(self): rows = listTransitions(self._connection) self._model.setRowCount(len(rows)) self._model.setColumnCount(12) self._dbTable.hideColumn(0) # This holds index for lookups self._dbTable.setVerticalHeader(None) # Add the column headers self._model.setHorizontalHeaderItem( 1, self._newItem(translate('Rocket', "Manufacturer"))) self._model.setHorizontalHeaderItem( 2, self._newItem(translate('Rocket', "Part Number"))) self._model.setHorizontalHeaderItem( 3, self._newItem(translate('Rocket', "Description"))) self._model.setHorizontalHeaderItem( 4, self._newItem(translate('Rocket', "Fore Diameter"))) self._model.setHorizontalHeaderItem( 5, self._newItem(translate('Rocket', "Aft Diameter"))) self._model.setHorizontalHeaderItem( 6, self._newItem(translate('Rocket', "Length"))) self._model.setHorizontalHeaderItem( 7, self._newItem(translate('Rocket', "Fore Shoulder Diameter"))) self._model.setHorizontalHeaderItem( 8, self._newItem(translate('Rocket', "Fore Shoulder Length"))) self._model.setHorizontalHeaderItem( 9, self._newItem(translate('Rocket', "Aft Shoulder Diameter"))) self._model.setHorizontalHeaderItem( 10, self._newItem(translate('Rocket', "Aft Shoulder Length"))) self._model.setHorizontalHeaderItem( 11, self._newItem(translate('Rocket', "Shape"))) rowCount = 0 for row in rows: self._model.setItem(rowCount, 0, self._newItem(str(row["transition_index"]))) self._model.setItem(rowCount, 1, self._newItem(str(row["manufacturer"]))) self._model.setItem(rowCount, 2, self._newItem(str(row["part_number"]))) self._model.setItem(rowCount, 3, self._newItem(str(row["description"]))) self._model.setItem( rowCount, 4, self._newItem( self._itemWithDimension( row["fore_outside_diameter"], row["fore_outside_diameter_units"]))) self._model.setItem( rowCount, 5, self._newItem( self._itemWithDimension( row["aft_outside_diameter"], row["aft_outside_diameter_units"]))) self._model.setItem( rowCount, 6, self._newItem( self._itemWithDimension(row["length"], row["length_units"]))) self._model.setItem( rowCount, 7, self._newItem( self._itemWithDimension( row["fore_shoulder_diameter"], row["fore_shoulder_diameter_units"]))) self._model.setItem( rowCount, 8, self._newItem( self._itemWithDimension( row["fore_shoulder_length"], row["fore_shoulder_length_units"]))) self._model.setItem( rowCount, 9, self._newItem( self._itemWithDimension( row["aft_shoulder_diameter"], row["aft_shoulder_diameter_units"]))) self._model.setItem( rowCount, 10, self._newItem( self._itemWithDimension(row["aft_shoulder_length"], row["aft_shoulder_length_units"]))) self._model.setItem(rowCount, 11, self._newItem(str(row["shape"]))) rowCount += 1 def _updateModel(self): queryType = str(self._lookupTypeCombo.currentText()) if queryType == COMPONENT_TYPE_ANY: query = self._lookup else: query = queryType if query in [ COMPONENT_TYPE_BODYTUBE, COMPONENT_TYPE_COUPLER, COMPONENT_TYPE_ENGINEBLOCK, COMPONENT_TYPE_LAUNCHLUG, COMPONENT_TYPE_CENTERINGRING, COMPONENT_TYPE_BULKHEAD ]: self._queryBodyTube(queryType) elif query == COMPONENT_TYPE_NOSECONE: self._queryNoseCone() elif query == COMPONENT_TYPE_TRANSITION: self._queryTransition() # elif query == COMPONENT_TYPE_PARACHUTE: # pass # elif query == COMPONENT_TYPE_STREAMER: # pass def update(self): # Update the SQL query pass
class List(QMainWindow): """All Notes dialog""" def __init__(self, *args, **kwargs): QMainWindow.__init__(self, *args, **kwargs) self.app = QApplication.instance() self.closed = False self.sort_order = None self._init_interface() self.app.data_changed.connect(self._reload_data) self._init_notebooks() self._init_tags() self._init_notes() def _init_interface(self): self.ui = Ui_List() self.ui.setupUi(self) self.setWindowIcon(get_icon()) self.setWindowTitle(self.tr("Everpad / All Notes")) self.ui.newNotebookBtn.setIcon(QIcon.fromTheme('folder-new')) self.ui.newNotebookBtn.clicked.connect(self.new_notebook) self.ui.newNoteBtn.setIcon(QIcon.fromTheme('document-new')) self.ui.newNoteBtn.clicked.connect(self.new_note) self.ui.newNoteBtn.setShortcut(QKeySequence(self.tr('Ctrl+n'))) self.ui.newNotebookBtn.setShortcut( QKeySequence(self.tr('Ctrl+Shift+n'))) QShortcut(QKeySequence(self.tr('Ctrl+q')), self, self.close) def _init_notebooks(self): self._current_notebook = None self.notebooksModel = QStandardItemModel() self.ui.notebooksList.setModel(self.notebooksModel) self.ui.notebooksList.selection.connect(self.selection_changed) self.ui.notebooksList.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.notebooksList.customContextMenuRequested.connect( self.notebook_context_menu) def _init_tags(self): self._current_tag = None self.tagsModel = QStandardItemModel() self.ui.tagsList.setModel(self.tagsModel) self.ui.tagsList.selection.connect(self.tag_selection_changed) self.ui.tagsList.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.tagsList.customContextMenuRequested.connect( self.tag_context_menu) def _init_notes(self): self._current_note = None self.notesModel = QStandardItemModel() self.notesModel.setHorizontalHeaderLabels( [self.tr('Title'), self.tr('Last Updated')]) self.ui.notesList.setModel(self.notesModel) self.ui.notesList.selection.connect(self.note_selection_changed) self.ui.notesList.doubleClicked.connect(self.note_dblclicked) self.ui.notesList.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.notesList.customContextMenuRequested.connect( self.note_context_menu) self.ui.notesList.header().sortIndicatorChanged.connect( self.sort_order_updated) @Slot(QItemSelection, QItemSelection) def selection_changed(self, selected, deselected): if len(selected.indexes()): self.ui.tagsList.clearSelection() self.notebook_selected(selected.indexes()[-1]) @Slot(QItemSelection, QItemSelection) def tag_selection_changed(self, selected, deselected): if len(selected.indexes()): self.ui.notebooksList.clearSelection() self.tag_selected(selected.indexes()[-1]) @Slot(QItemSelection, QItemSelection) def note_selection_changed(self, selected, deselected): if len(selected.indexes()): self.note_selected(selected.indexes()[-1]) def showEvent(self, *args, **kwargs): super(List, self).showEvent(*args, **kwargs) self._reload_data() self.readSettings() def writeSettings(self): self.app.settings.setValue('list-geometry', self.saveGeometry()) for key, widget in self._getRestorableItems(): self.app.settings.setValue(key, widget.saveState()) def _getRestorableItems(self): return ( ('list-splitter-state', self.ui.splitter), ('list-header-state', self.ui.notesList.header()), ) def readSettings(self): geometry = self.app.settings.value('list-geometry') if geometry: self.restoreGeometry(geometry) for key, widget in self._getRestorableItems(): state = self.app.settings.value(key) if state: widget.restoreState(state) def closeEvent(self, event): self.writeSettings() event.ignore() self.closed = True self.hide() @Slot(int, Qt.SortOrder) def sort_order_updated(self, logicalIndex, order): self.sort_order = (logicalIndex, order.name) self.app.settings.setValue('list-notes-sort-order', self.sort_order) def note_selected(self, index): self._current_note = index def notebook_selected(self, index): self.notesModel.setRowCount(0) item = self.notebooksModel.itemFromIndex(index) if hasattr(item, 'notebook'): notebook_id = item.notebook.id else: notebook_id = 0 self._current_notebook = notebook_id self._current_tag = SELECT_NONE notebook_filter = [notebook_id] if notebook_id > 0 else dbus.Array( [], signature='i') if hasattr( item, 'stack'): # stack selected, retrieve all underlying notebooks notebook_filter = [] for notebook_struct in self.app.provider.list_notebooks(): notebook = Notebook.from_tuple(notebook_struct) if (notebook.stack == item.stack): notebook_filter.append(notebook.id) notes = self.app.provider.find_notes( '', notebook_filter, dbus.Array([], signature='i'), 0, 2**31 - 1, Note.ORDER_TITLE, -1, ) # fails with sys.maxint in 64 for note_struct in notes: note = Note.from_tuple(note_struct) self.notesModel.appendRow(QNoteItemFactory(note).make_items()) sort_order = self.sort_order if sort_order is None: sort_order = self.app.settings.value('list-notes-sort-order') if sort_order: logicalIndex, order = sort_order order = Qt.SortOrder.values[order] self.ui.notesList.sortByColumn(int(logicalIndex), order) def tag_selected(self, index): self.notesModel.setRowCount(0) item = self.tagsModel.itemFromIndex(index) if hasattr(item, 'tag'): tag_id = item.tag.id else: tag_id = 0 self._current_notebook = SELECT_NONE self._current_tag = tag_id tag_filter = [tag_id] if tag_id > 0 else dbus.Array([], signature='i') notes = self.app.provider.find_notes( '', dbus.Array([], signature='i'), tag_filter, 0, 2**31 - 1, Note.ORDER_TITLE, -1, ) # fails with sys.maxint in 64 for note_struct in notes: note = Note.from_tuple(note_struct) self.notesModel.appendRow(QNoteItemFactory(note).make_items()) sort_order = self.sort_order if sort_order is None: sort_order = self.app.settings.value('list-notes-sort-order') if sort_order: logicalIndex, order = sort_order order = Qt.SortOrder.values[order] self.ui.notesList.sortByColumn(int(logicalIndex), order) @Slot() def note_dblclicked(self, index): item = self.notesModel.itemFromIndex(index) self.app.indicator.open(item.note) @Slot() def new_notebook(self, oldStack=''): name, status, stack = self._notebook_new_name( self.tr('Create new notebook'), '', oldStack) if status: notebook_struct = self.app.provider.create_notebook(name, stack) notebook = Notebook.from_tuple(notebook_struct) self.app.send_notify( self.tr('Notebook "%s" created!') % notebook.name) self._reload_notebooks_list(notebook.id) @Slot() def rename_notebook(self): index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) notebook = item.notebook name, status, stack = self._notebook_new_name( self.tr('Rename notebook'), notebook.name, notebook.stack) if status: notebook.name = name notebook.stack = stack self.app.provider.update_notebook(notebook.struct) self.app.send_notify( self.tr('Notebook "%s" renamed!') % notebook.name) self._reload_notebooks_list(notebook.id) @Slot() def remove_notebook(self): msg = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a notebook"), self.tr( "Are you sure want to delete this notebook and its notes?"), QMessageBox.Yes | QMessageBox.No) if msg.exec_() == QMessageBox.Yes: index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) self.app.provider.delete_notebook(item.notebook.id) self.app.send_notify( self.tr('Notebook "%s" deleted!') % item.notebook.name) self._reload_notebooks_list() @Slot() def rename_stack(self): index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) stack = item.stack name, status = self._stack_new_name( self.tr('Rename stack'), stack, ) if status: # loop notebooks and update stack str for notebook_struct in self.app.provider.list_notebooks(): notebook = Notebook.from_tuple(notebook_struct) if (notebook.stack == item.stack): notebook.stack = name self.app.provider.update_notebook(notebook.struct) self.app.send_notify(self.tr('Stack "%s" renamed!') % name) self._reload_notebooks_list(notebook.id) @Slot() def remove_stack(self): msg = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a stack"), self. tr("Are you sure want to delete this stack? Notebooks and notes are preserved." ), QMessageBox.Yes | QMessageBox.No) if msg.exec_() == QMessageBox.Yes: index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) # loop notebooks and remove stack str for notebook_struct in self.app.provider.list_notebooks(): notebook = Notebook.from_tuple(notebook_struct) if (notebook.stack == item.stack): print "Clearing one notebook from its stack." notebook.stack = '' self.app.provider.update_notebook(notebook.struct) self._reload_notebooks_list() @Slot() def remove_tag(self): msg = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a tag"), self. tr("Are you sure want to delete this tag and untag all notes tagged with it?" ), QMessageBox.Yes | QMessageBox.No) if msg.exec_() == QMessageBox.Yes: index = self.ui.tagsList.currentIndex() item = self.tagsModel.itemFromIndex(index) self.app.provider.delete_tag(item.tag.id) self.app.send_notify(self.tr('Tag "%s" deleted!') % item.tag.name) self._reload_tags_list() @Slot() def new_note(self): index = self.ui.notebooksList.currentIndex() notebook_id = NONE_ID if index.row(): item = self.notebooksModel.itemFromIndex(index) notebook_id = item.notebook.id self.app.indicator.create(notebook_id=notebook_id) @Slot() def edit_note(self): index = self.ui.notesList.currentIndex() item = self.notesModel.itemFromIndex(index) self.app.indicator.open(item.note) @Slot() def remove_note(self): index = self.ui.notesList.currentIndex() item = self.notesModel.itemFromIndex(index) msgBox = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a note"), self.tr('Are you sure want to delete note "%s"?') % item.note.title, QMessageBox.Yes | QMessageBox.No) if msgBox.exec_() == QMessageBox.Yes: self.app.provider.delete_note(item.note.id) self.app.send_notify( self.tr('Note "%s" deleted!') % item.note.title) self.notebook_selected(self.ui.notebooksList.currentIndex()) @Slot(QPoint) def notebook_context_menu(self, pos): index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) if hasattr(item, 'notebook'): menu = QMenu(self.ui.notebooksList) menu.addAction(QIcon.fromTheme('gtk-edit'), self.tr('Rename'), self.rename_notebook) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_notebook) menu.exec_(self.ui.notebooksList.mapToGlobal(pos)) if hasattr(item, 'stack'): menu = QMenu(self.ui.notebooksList) menu.addAction(QIcon.fromTheme('gtk-edit'), self.tr('Rename'), self.rename_stack) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_stack) menu.exec_(self.ui.notebooksList.mapToGlobal(pos)) @Slot(QPoint) def tag_context_menu(self, pos): index = self.ui.tagsList.currentIndex() item = self.tagsModel.itemFromIndex(index) if hasattr(item, 'tag'): menu = QMenu(self.ui.tagsList) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_tag) menu.exec_(self.ui.tagsList.mapToGlobal(pos)) @Slot(QPoint) def note_context_menu(self, pos): menu = QMenu(self.ui.notesList) menu.addAction(QIcon.fromTheme('gtk-edit'), self.tr('Edit'), self.edit_note) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_note) menu.exec_(self.ui.notesList.mapToGlobal(pos)) def _reload_data(self): self._reload_notebooks_list(self._current_notebook) self._reload_tags_list(self._current_tag) self._mark_note_selected(self._current_note) def _reload_notebooks_list(self, select_notebook_id=None): # TODO could enable selecting an already selected stack self.notebooksModel.clear() root = QStandardItem(QIcon.fromTheme('user-home'), self.tr('All Notes')) self.notebooksModel.appendRow(root) selected_item = root stacks = {} for notebook_struct in self.app.provider.list_notebooks(): notebook = Notebook.from_tuple(notebook_struct) count = self.app.provider.get_notebook_notes_count(notebook.id) item = QNotebookItem(notebook, count) if (notebook.stack == ''): root.appendRow(item) else: if (notebook.stack not in stacks.keys()): stack = QStandardItem(QIcon.fromTheme('user-home'), notebook.stack) stack.stack = notebook.stack root.appendRow(stack) stacks[notebook.stack] = stack stacks[notebook.stack].appendRow(item) if select_notebook_id and notebook.id == select_notebook_id: selected_item = item self.ui.notebooksList.expandAll() if selected_item and not select_notebook_id == SELECT_NONE: index = self.notebooksModel.indexFromItem(selected_item) self.ui.notebooksList.setCurrentIndex(index) self.notebook_selected(index) def _notebook_new_name(self, title, exclude='', oldStack=''): names = map(lambda nb: Notebook.from_tuple(nb).name, self.app.provider.list_notebooks()) try: names.remove(exclude) except ValueError: pass name, status = QInputDialog.getText(self, title, self.tr('Enter notebook name:'), text=exclude) while name in names and status: message = self.tr( 'Notebook with this name already exist. Enter notebook name') name, status = QInputDialog.getText(self, title, message) if status: stack, status = QInputDialog.getText( self, title, self.tr('Enter stack name (empty for no stack):'), text=oldStack) else: stack = oldStack return name, status, stack def _stack_new_name(self, title, value=''): name, status = QInputDialog.getText(self, title, self.tr('Enter stack name:'), text=value) return name, status def _reload_tags_list(self, select_tag_id=None): # TODO nested tags self.tagsModel.clear() tagRoot = QStandardItem(QIcon.fromTheme('user-home'), self.tr('All Tags')) self.tagsModel.appendRow(tagRoot) selected_item = tagRoot for tag_struct in self.app.provider.list_tags(): tag = Tag.from_tuple(tag_struct) count = self.app.provider.get_tag_notes_count(tag.id) item = QTagItem(tag, count) tagRoot.appendRow(item) if select_tag_id and tag.id == select_tag_id: selected_item = item self.ui.tagsList.expandAll() if selected_item and not select_tag_id == SELECT_NONE: index = self.tagsModel.indexFromItem(selected_item) self.ui.tagsList.setCurrentIndex(index) self.tag_selected(index) def _mark_note_selected(self, index): if index: self.ui.notesList.setCurrentIndex(index)
class List(QDialog): """All Notes dialog""" def __init__(self, app, *args, **kwargs): QDialog.__init__(self, *args, **kwargs) self.app = app self.closed = False self.sort_order = None self.ui = Ui_List() self.ui.setupUi(self) self.setWindowIcon(get_icon()) self.notebooksModel = QStandardItemModel() self.ui.notebooksList.setModel(self.notebooksModel) self.ui.notebooksList.selection.connect(self.selection_changed) self.ui.notebooksList.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.notebooksList.customContextMenuRequested.connect( self.notebook_context_menu) self.notesModel = QStandardItemModel() self.notesModel.setHorizontalHeaderLabels( [self.tr('Title'), self.tr('Last Updated')]) self.ui.notesList.setModel(self.notesModel) self.ui.notesList.doubleClicked.connect(self.note_dblclicked) self.ui.notesList.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.notesList.customContextMenuRequested.connect( self.note_context_menu) self.ui.notesList.header().sortIndicatorChanged.connect( self.sort_order_updated) self.ui.newNotebookBtn.setIcon(QIcon.fromTheme('folder-new')) self.ui.newNotebookBtn.clicked.connect(self.new_notebook) self.ui.newNoteBtn.setIcon(QIcon.fromTheme('document-new')) self.ui.newNoteBtn.clicked.connect(self.new_note) @Slot(QItemSelection, QItemSelection) def selection_changed(self, selected, deselected): if len(selected.indexes()): self.notebook_selected(selected.indexes()[-1]) def showEvent(self, *args, **kwargs): QDialog.showEvent(self, *args, **kwargs) self._reload_notebooks_list() self.readSettings() def writeSettings(self): self.app.settings.setValue('list-geometry', self.saveGeometry()) for key, widget in self._getRestorableItems(): self.app.settings.setValue(key, widget.saveState()) def _getRestorableItems(self): return ( ('list-splitter-state', self.ui.splitter), ('list-header-state', self.ui.notesList.header()), ) def readSettings(self): geometry = self.app.settings.value('list-geometry') if geometry: self.restoreGeometry(geometry) for key, widget in self._getRestorableItems(): state = self.app.settings.value(key) if state: widget.restoreState(state) def closeEvent(self, event): self.writeSettings() event.ignore() self.closed = True self.hide() @Slot(int, Qt.SortOrder) def sort_order_updated(self, logicalIndex, order): self.sort_order = (logicalIndex, order.name) self.app.settings.setValue('list-notes-sort-order', self.sort_order) def notebook_selected(self, index): self.notesModel.setRowCount(0) item = self.notebooksModel.itemFromIndex(index) if hasattr(item, 'notebook'): notebook_id = item.notebook.id else: notebook_id = 0 notebook_filter = [notebook_id] if notebook_id > 0 else dbus.Array( [], signature='i') notes = self.app.provider.find_notes( '', notebook_filter, dbus.Array([], signature='i'), 0, 2**31 - 1, Note.ORDER_TITLE, -1, ) # fails with sys.maxint in 64 for note_struct in notes: note = Note.from_tuple(note_struct) self.notesModel.appendRow(QNoteItemFactory(note).make_items()) sort_order = self.sort_order if sort_order is None: sort_order = self.app.settings.value('list-notes-sort-order') if sort_order: logicalIndex, order = sort_order order = Qt.SortOrder.values[order] self.ui.notesList.sortByColumn(int(logicalIndex), order) @Slot() def note_dblclicked(self, index): item = self.notesModel.itemFromIndex(index) self.app.indicator.open(item.note) @Slot() def new_notebook(self): name, status = self._notebook_new_name(self.tr('Create new notebook')) if status: notebook_struct = self.app.provider.create_notebook(name) notebook = Notebook.from_tuple(notebook_struct) self.app.send_notify( self.tr('Notebook "%s" created!') % notebook.name) self._reload_notebooks_list(notebook.id) @Slot() def rename_notebook(self): index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) notebook = item.notebook name, status = self._notebook_new_name( self.tr('Rename notebook'), notebook.name, ) if status: notebook.name = name self.app.provider.update_notebook(notebook.struct) self.app.send_notify( self.tr('Notebook "%s" renamed!') % notebook.name) self._reload_notebooks_list(notebook.id) @Slot() def remove_notebook(self): msg = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a notebook"), self.tr( "Are you sure want to delete this notebook and its notes?"), QMessageBox.Yes | QMessageBox.No) if msg.exec_() == QMessageBox.Yes: index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) self.app.provider.delete_notebook(item.notebook.id) self.app.send_notify( self.tr('Notebook "%s" deleted!') % item.notebook.name) self._reload_notebooks_list() @Slot() def new_note(self): index = self.ui.notebooksList.currentIndex() notebook_id = NONE_ID if index.row(): item = self.notebooksModel.itemFromIndex(index) notebook_id = item.notebook.id self.app.indicator.create(notebook_id=notebook_id) @Slot() def edit_note(self): index = self.ui.notesList.currentIndex() item = self.notesModel.itemFromIndex(index) self.app.indicator.open(item.note) @Slot() def remove_note(self): index = self.ui.notesList.currentIndex() item = self.notesModel.itemFromIndex(index) msgBox = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a note"), self.tr('Are you sure want to delete note "%s"?') % item.note.title, QMessageBox.Yes | QMessageBox.No) if msgBox.exec_() == QMessageBox.Yes: self.app.provider.delete_note(item.note.id) self.app.send_notify( self.tr('Note "%s" deleted!') % item.note.title) self.notebook_selected(self.ui.notebooksList.currentIndex()) @Slot(QPoint) def notebook_context_menu(self, pos): index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) if hasattr(item, 'notebook'): menu = QMenu(self.ui.notebooksList) menu.addAction(QIcon.fromTheme('gtk-edit'), self.tr('Rename'), self.rename_notebook) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_notebook) menu.exec_(self.ui.notebooksList.mapToGlobal(pos)) @Slot(QPoint) def note_context_menu(self, pos): menu = QMenu(self.ui.notesList) menu.addAction(QIcon.fromTheme('gtk-edit'), self.tr('Edit'), self.edit_note) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_note) menu.exec_(self.ui.notesList.mapToGlobal(pos)) def _reload_notebooks_list(self, select_notebook_id=None): self.notebooksModel.clear() root = QStandardItem(QIcon.fromTheme('user-home'), self.tr('All Notes')) self.notebooksModel.appendRow(root) selected_item = root for notebook_struct in self.app.provider.list_notebooks(): notebook = Notebook.from_tuple(notebook_struct) count = self.app.provider.get_notebook_notes_count(notebook.id) item = QNotebookItem(notebook, count) root.appendRow(item) if select_notebook_id and notebook.id == select_notebook_id: selected_item = item self.ui.notebooksList.expandAll() if selected_item: index = self.notebooksModel.indexFromItem(selected_item) self.ui.notebooksList.setCurrentIndex(index) self.notebook_selected(index) def _notebook_new_name(self, title, exclude=''): names = map(lambda nb: Notebook.from_tuple(nb).name, self.app.provider.list_notebooks()) try: names.remove(exclude) except ValueError: pass name, status = QInputDialog.getText(self, title, self.tr('Enter notebook name:'), text=exclude) while name in names and status: message = self.tr( 'Notebook with this name already exist. Enter notebook name') name, status = QInputDialog.getText(self, title, message) return name, status
class List(QMainWindow): """All Notes dialog""" def __init__(self, *args, **kwargs): QMainWindow.__init__(self, *args, **kwargs) self.app = QApplication.instance() self.closed = False self.sort_order = None self._init_interface() self.app.data_changed.connect(self._reload_data) self._init_notebooks() self._init_tags() self._init_notes() def _init_interface(self): self.ui = Ui_List() self.ui.setupUi(self) self.setWindowIcon(get_icon()) self.setWindowTitle(self.tr("Everpad / All Notes")) self.ui.newNotebookBtn.setIcon(QIcon.fromTheme('folder-new')) self.ui.newNotebookBtn.clicked.connect(self.new_notebook) self.ui.newNoteBtn.setIcon(QIcon.fromTheme('document-new')) self.ui.newNoteBtn.clicked.connect(self.new_note) self.ui.newNoteBtn.setShortcut(QKeySequence(self.tr('Ctrl+n'))) self.ui.newNotebookBtn.setShortcut(QKeySequence(self.tr('Ctrl+Shift+n'))) QShortcut(QKeySequence(self.tr('Ctrl+q')), self, self.close) def _init_notebooks(self): self._current_notebook = None self.notebooksModel = QStandardItemModel() self.ui.notebooksList.setModel(self.notebooksModel) self.ui.notebooksList.selection.connect(self.selection_changed) self.ui.notebooksList.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.notebooksList.customContextMenuRequested.connect(self.notebook_context_menu) def _init_tags(self): self._current_tag = None self.tagsModel = QStandardItemModel() self.ui.tagsList.setModel(self.tagsModel) self.ui.tagsList.selection.connect(self.tag_selection_changed) self.ui.tagsList.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.tagsList.customContextMenuRequested.connect(self.tag_context_menu) def _init_notes(self): self._current_note = None self.notesModel = QStandardItemModel() self.notesModel.setHorizontalHeaderLabels( [self.tr('Title'), self.tr('Last Updated')]) self.ui.notesList.setModel(self.notesModel) self.ui.notesList.selection.connect(self.note_selection_changed) self.ui.notesList.doubleClicked.connect(self.note_dblclicked) self.ui.notesList.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.notesList.customContextMenuRequested.connect(self.note_context_menu) self.ui.notesList.header().sortIndicatorChanged.connect(self.sort_order_updated) @Slot(QItemSelection, QItemSelection) def selection_changed(self, selected, deselected): if len(selected.indexes()): self.ui.tagsList.clearSelection() self.notebook_selected(selected.indexes()[-1]) @Slot(QItemSelection, QItemSelection) def tag_selection_changed(self, selected, deselected): if len(selected.indexes()): self.ui.notebooksList.clearSelection() self.tag_selected(selected.indexes()[-1]) @Slot(QItemSelection, QItemSelection) def note_selection_changed(self, selected, deselected): if len(selected.indexes()): self.note_selected(selected.indexes()[-1]) def showEvent(self, *args, **kwargs): super(List, self).showEvent(*args, **kwargs) self._reload_data() self.readSettings() def writeSettings(self): self.app.settings.setValue('list-geometry', self.saveGeometry()) for key, widget in self._getRestorableItems(): self.app.settings.setValue(key, widget.saveState()) def _getRestorableItems(self): return ( ('list-splitter-state', self.ui.splitter), ('list-header-state', self.ui.notesList.header()), ) def readSettings(self): geometry = self.app.settings.value('list-geometry') if geometry: self.restoreGeometry(geometry) for key, widget in self._getRestorableItems(): state = self.app.settings.value(key) if state: widget.restoreState(state) def closeEvent(self, event): self.writeSettings() event.ignore() self.closed = True self.hide() @Slot(int, Qt.SortOrder) def sort_order_updated(self, logicalIndex, order): self.sort_order = (logicalIndex, order.name) self.app.settings.setValue('list-notes-sort-order', self.sort_order) def note_selected(self, index): self._current_note = index def notebook_selected(self, index): self.notesModel.setRowCount(0) item = self.notebooksModel.itemFromIndex(index) if hasattr(item, 'notebook'): notebook_id = item.notebook.id else: notebook_id = 0 self._current_notebook = notebook_id self._current_tag = SELECT_NONE notebook_filter = [notebook_id] if notebook_id > 0 else dbus.Array([], signature='i') if hasattr(item, 'stack'): # stack selected, retrieve all underlying notebooks notebook_filter = [] for notebook_struct in self.app.provider.list_notebooks(): notebook = Notebook.from_tuple(notebook_struct) if(notebook.stack == item.stack): notebook_filter.append(notebook.id) notes = self.app.provider.find_notes( '', notebook_filter, dbus.Array([], signature='i'), 0, 2 ** 31 - 1, Note.ORDER_TITLE, -1, ) # fails with sys.maxint in 64 for note_struct in notes: note = Note.from_tuple(note_struct) self.notesModel.appendRow(QNoteItemFactory(note).make_items()) sort_order = self.sort_order if sort_order is None: sort_order = self.app.settings.value('list-notes-sort-order') if sort_order: logicalIndex, order = sort_order order = Qt.SortOrder.values[order] self.ui.notesList.sortByColumn(int(logicalIndex), order) def tag_selected(self, index): self.notesModel.setRowCount(0) item = self.tagsModel.itemFromIndex(index) if hasattr(item, 'tag'): tag_id = item.tag.id else: tag_id = 0 self._current_notebook = SELECT_NONE self._current_tag = tag_id tag_filter = [tag_id] if tag_id > 0 else dbus.Array([], signature='i') notes = self.app.provider.find_notes( '', dbus.Array([], signature='i'), tag_filter, 0, 2 ** 31 - 1, Note.ORDER_TITLE, -1, ) # fails with sys.maxint in 64 for note_struct in notes: note = Note.from_tuple(note_struct) self.notesModel.appendRow(QNoteItemFactory(note).make_items()) sort_order = self.sort_order if sort_order is None: sort_order = self.app.settings.value('list-notes-sort-order') if sort_order: logicalIndex, order = sort_order order = Qt.SortOrder.values[order] self.ui.notesList.sortByColumn(int(logicalIndex), order) @Slot() def note_dblclicked(self, index): item = self.notesModel.itemFromIndex(index) self.app.indicator.open(item.note) @Slot() def new_notebook(self, oldStack=''): name, status, stack = self._notebook_new_name(self.tr('Create new notebook'), '', oldStack) if status: notebook_struct = self.app.provider.create_notebook(name, stack) notebook = Notebook.from_tuple(notebook_struct) self.app.send_notify(self.tr('Notebook "%s" created!') % notebook.name) self._reload_notebooks_list(notebook.id) @Slot() def rename_notebook(self): index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) notebook = item.notebook name, status, stack = self._notebook_new_name( self.tr('Rename notebook'), notebook.name, notebook.stack ) if status: notebook.name = name notebook.stack = stack self.app.provider.update_notebook(notebook.struct) self.app.send_notify(self.tr('Notebook "%s" renamed!') % notebook.name) self._reload_notebooks_list(notebook.id) @Slot() def remove_notebook(self): msg = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a notebook"), self.tr("Are you sure want to delete this notebook and its notes?"), QMessageBox.Yes | QMessageBox.No ) if msg.exec_() == QMessageBox.Yes: index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) self.app.provider.delete_notebook(item.notebook.id) self.app.send_notify(self.tr('Notebook "%s" deleted!') % item.notebook.name) self._reload_notebooks_list() @Slot() def rename_stack(self): index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) stack = item.stack name, status = self._stack_new_name( self.tr('Rename stack'), stack, ) if status: # loop notebooks and update stack str for notebook_struct in self.app.provider.list_notebooks(): notebook = Notebook.from_tuple(notebook_struct) if(notebook.stack == item.stack): notebook.stack = name self.app.provider.update_notebook(notebook.struct) self.app.send_notify(self.tr('Stack "%s" renamed!') % name) self._reload_notebooks_list(notebook.id) @Slot() def remove_stack(self): msg = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a stack"), self.tr("Are you sure want to delete this stack? Notebooks and notes are preserved."), QMessageBox.Yes | QMessageBox.No ) if msg.exec_() == QMessageBox.Yes: index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) # loop notebooks and remove stack str for notebook_struct in self.app.provider.list_notebooks(): notebook = Notebook.from_tuple(notebook_struct) if(notebook.stack == item.stack): print "Clearing one notebook from its stack." notebook.stack = '' self.app.provider.update_notebook(notebook.struct) self._reload_notebooks_list() @Slot() def remove_tag(self): msg = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a tag"), self.tr("Are you sure want to delete this tag and untag all notes tagged with it?"), QMessageBox.Yes | QMessageBox.No ) if msg.exec_() == QMessageBox.Yes: index = self.ui.tagsList.currentIndex() item = self.tagsModel.itemFromIndex(index) self.app.provider.delete_tag(item.tag.id) self.app.send_notify(self.tr('Tag "%s" deleted!') % item.tag.name) self._reload_tags_list() @Slot() def new_note(self): index = self.ui.notebooksList.currentIndex() notebook_id = NONE_ID if index.row(): item = self.notebooksModel.itemFromIndex(index) notebook_id = item.notebook.id self.app.indicator.create(notebook_id=notebook_id) @Slot() def edit_note(self): index = self.ui.notesList.currentIndex() item = self.notesModel.itemFromIndex(index) self.app.indicator.open(item.note) @Slot() def remove_note(self): index = self.ui.notesList.currentIndex() item = self.notesModel.itemFromIndex(index) msgBox = QMessageBox( QMessageBox.Critical, self.tr("You are trying to delete a note"), self.tr('Are you sure want to delete note "%s"?') % item.note.title, QMessageBox.Yes | QMessageBox.No ) if msgBox.exec_() == QMessageBox.Yes: self.app.provider.delete_note(item.note.id) self.app.send_notify(self.tr('Note "%s" deleted!') % item.note.title) self.notebook_selected(self.ui.notebooksList.currentIndex()) @Slot(QPoint) def notebook_context_menu(self, pos): index = self.ui.notebooksList.currentIndex() item = self.notebooksModel.itemFromIndex(index) if hasattr(item, 'notebook'): menu = QMenu(self.ui.notebooksList) menu.addAction(QIcon.fromTheme('gtk-edit'), self.tr('Rename'), self.rename_notebook) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_notebook) menu.exec_(self.ui.notebooksList.mapToGlobal(pos)) if hasattr(item, 'stack'): menu = QMenu(self.ui.notebooksList) menu.addAction(QIcon.fromTheme('gtk-edit'), self.tr('Rename'), self.rename_stack) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_stack) menu.exec_(self.ui.notebooksList.mapToGlobal(pos)) @Slot(QPoint) def tag_context_menu(self, pos): index = self.ui.tagsList.currentIndex() item = self.tagsModel.itemFromIndex(index) if hasattr(item, 'tag'): menu = QMenu(self.ui.tagsList) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_tag) menu.exec_(self.ui.tagsList.mapToGlobal(pos)) @Slot(QPoint) def note_context_menu(self, pos): menu = QMenu(self.ui.notesList) menu.addAction(QIcon.fromTheme('gtk-edit'), self.tr('Edit'), self.edit_note) menu.addAction(QIcon.fromTheme('gtk-delete'), self.tr('Remove'), self.remove_note) menu.exec_(self.ui.notesList.mapToGlobal(pos)) def _reload_data(self): self._reload_notebooks_list(self._current_notebook) self._reload_tags_list(self._current_tag) self._mark_note_selected(self._current_note) def _reload_notebooks_list(self, select_notebook_id=None): # TODO could enable selecting an already selected stack self.notebooksModel.clear() root = QStandardItem(QIcon.fromTheme('user-home'), self.tr('All Notes')) self.notebooksModel.appendRow(root) selected_item = root stacks = {} for notebook_struct in self.app.provider.list_notebooks(): notebook = Notebook.from_tuple(notebook_struct) count = self.app.provider.get_notebook_notes_count(notebook.id) item = QNotebookItem(notebook, count) if(notebook.stack == ''): root.appendRow(item) else: if(notebook.stack not in stacks.keys()): stack = QStandardItem(QIcon.fromTheme('user-home'), notebook.stack) stack.stack = notebook.stack root.appendRow(stack) stacks[notebook.stack] = stack stacks[notebook.stack].appendRow(item) if select_notebook_id and notebook.id == select_notebook_id: selected_item = item self.ui.notebooksList.expandAll() if selected_item and not select_notebook_id == SELECT_NONE: index = self.notebooksModel.indexFromItem(selected_item) self.ui.notebooksList.setCurrentIndex(index) self.notebook_selected(index) def _notebook_new_name(self, title, exclude='', oldStack=''): names = map(lambda nb: Notebook.from_tuple(nb).name, self.app.provider.list_notebooks()) try: names.remove(exclude) except ValueError: pass name, status = QInputDialog.getText(self, title, self.tr('Enter notebook name:'), text=exclude) while name in names and status: message = self.tr('Notebook with this name already exist. Enter notebook name') name, status = QInputDialog.getText(self, title, message) if status: stack, status = QInputDialog.getText(self, title, self.tr('Enter stack name (empty for no stack):'), text=oldStack) else: stack = oldStack return name, status, stack def _stack_new_name(self, title, value=''): name, status = QInputDialog.getText(self, title, self.tr('Enter stack name:'), text=value) return name, status def _reload_tags_list(self, select_tag_id=None): # TODO nested tags self.tagsModel.clear() tagRoot = QStandardItem(QIcon.fromTheme('user-home'), self.tr('All Tags')) self.tagsModel.appendRow(tagRoot) selected_item = tagRoot for tag_struct in self.app.provider.list_tags(): tag = Tag.from_tuple(tag_struct) count = self.app.provider.get_tag_notes_count(tag.id) item = QTagItem(tag, count) tagRoot.appendRow(item) if select_tag_id and tag.id == select_tag_id: selected_item = item self.ui.tagsList.expandAll() if selected_item and not select_tag_id == SELECT_NONE: index = self.tagsModel.indexFromItem(selected_item) self.ui.tagsList.setCurrentIndex(index) self.tag_selected(index) def _mark_note_selected(self, index): if index: self.ui.notesList.setCurrentIndex(index)
class PostViewWidget(HorsePanel): def __init__(self, parent, order_overview_widget, find_order_slot): global configuration super(PostViewWidget, self).__init__(parent) self.set_panel_title(_("Post overview")) self.bold_font = QFont(self.font()) self.bold_font.setBold(True) self.nb_cols = 8 # Number of columns in the operation definition table self.order_overview_widget = order_overview_widget self.button = QPushButton(_("Refresh"), self) self.button.clicked.connect(self.refresh_action) self.sort_by_deadline_button = QRadioButton(_("By deadline"), self) self.sort_by_deadline_button.toggled.connect(self.sort_by_deadline) self.sort_by_size_button = QRadioButton(_("By hours left to do"), self) self.sort_by_size_button.toggled.connect(self.sort_by_size) # hlayout = QHBoxLayout() # hlayout.setObjectName("halyout") # hlayout.setContentsMargins(0,0,0,0) # hlayout.addWidget(self.sort_by_deadline_button) # hlayout.addWidget(self.sort_by_size_button) # hlayout.addWidget(self.button) # hlayout.addStretch() self.navbar = NavBar(self, [(self.sort_by_deadline_button, None), (self.sort_by_size_button, None), (self.button, None), (_("Find"), find_order_slot)]) self.navbar.buttons[3].setObjectName("specialMenuButton") self.vlayout = QVBoxLayout(self) self.vlayout.setObjectName("Vlayout") self.vlayout.addWidget( TitleWidget(_("Posts Overview"), self, self.navbar)) self._table_model = QStandardItemModel(1, self.nb_cols, self) self.table_view = QTableView(None) self.table_view.setModel(self._table_model) self.table_view.selectionModel().currentChanged.connect( self.operation_selected) self.table_view.verticalHeader().hide() self.table_view.horizontalHeader().hide() self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) # This forces Qt to expand layout once I fill data in # FIXME dirty but I really don't get why setting # the mini width to something smaller (that happens at # startup, on first refresh) doesn't work self.table_view.setMinimumWidth(1) self.table_view.setMaximumWidth(1) self.post_view_scene = PostViewScene(self, order_overview_widget) self.post_view_scene_view = QGraphicsView(self) self.post_view_scene_view.setScene(self.post_view_scene) self.post_view_scene_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.splitter = QSplitter(Qt.Horizontal) self.splitter.addWidget( SubFrame(_("Posts"), self.table_view, self.splitter)) self.splitter.addWidget( SubFrame(_("Workload"), self.post_view_scene_view, self.splitter)) # self.splitter.setStretchFactor(0,1) self.splitter.setStretchFactor(1, 1) self.vlayout.addWidget(self.splitter) # hlayout = QHBoxLayout() # hlayout.addWidget(SubFrame(_("Posts"),self.table_view,self)) # hlayout.addWidget(SubFrame(_("Workload"),self.post_view_scene_view,self)) # hlayout.setStretch(1,1) # self.vlayout.addLayout(hlayout) self.vlayout.setStretch(0, 0) self.vlayout.setStretch(1, 1) self.setLayout(self.vlayout) self.timer = QTimer(self) self.timer.timeout.connect(self.slidePostsScene) self.current_view_y = 0 def _data_load(self): global dao all_operations = dao.operation_dao.load_all_operations_ready_for_production( ) operation_definitions = dao.operation_definition_dao.all_direct_frozen( ) return operation_definitions, all_operations def _reset_operation_definitions(self, operations): self._table_model.setColumnCount(1) self._table_model.setRowCount(len(operations)) # BUG This should be refreshed on reload() too row = col = 0 first_active = None for opdef in operations: if opdef.operation_definition_id in self.post_view_scene.drawn_operations_data: # currently total planned time t = self.post_view_scene.drawn_operations_data[ opdef.operation_definition_id] ndx = self._table_model.index(row, col) if not first_active: first_active = ndx self._table_model.setData( ndx, u"{} {}".format(opdef.description, t), Qt.DisplayRole) # self._table_model.setData(ndx,self.bold_font,Qt.FontRole) self._table_model.setData(self._table_model.index(row, col), opdef.operation_definition_id, Qt.UserRole) row += 1 else: pass # self._table_model.setData(self._table_model.index(row,col),opdef.description,Qt.DisplayRole) # = col + 1 # if col == self.nb_cols: # col = 0 # row += 1 self._table_model.setRowCount(row) # self.table_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) # self.vlayout.setStretch(0,0) # self.vlayout.setStretch(1,10) # self.vlayout.setStretch(2,10000) # height = 0 # for c in range(self.table_view.model().rowCount()): # height += self.table_view.rowHeight(c) + 1 # +1 for cell border # self.table_view.setMinimumHeight(height) # self.table_view.setMaximumHeight(height) for i in range(self.nb_cols): self.table_view.resizeColumnToContents(i) self.table_view.setMaximumWidth(self.table_view.columnWidth(0)) self.table_view.setMinimumWidth(self.table_view.columnWidth(0)) self.table_view.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) self.table_view.update() self.splitter.update() return first_active def slide_to_operation(self, opdef_id): if opdef_id in self.post_view_scene.posts_offsets: self.slide_target_opdef_id = opdef_id # mainlog.debug("Target y = {}".format(self.post_view_scene.posts_offsets[self.slide_target_opdef])) self.timer.start(20) @Slot() def slidePostsScene(self): if self.slide_target_opdef_id is None: return # self.post_view_scene_view self.post_view_scene.set_cursor_on( self.slide_target_opdef_id ) # This done here also aviod some screen trashing v = self.post_view_scene_view.verticalScrollBar().value() # mainlog.debug( "slidePostsScene : {}".format(v)) r = self.post_view_scene.posts_offsets[self.slide_target_opdef_id] target_y = r.y() + r.height() / 2 delta = (target_y - self.current_view_y) * 0.4 self.current_view_y = self.current_view_y + delta self.post_view_scene_view.centerOn(0, self.current_view_y) # mainlog.debug( "slidePostsScene : {} / {}".format(target_y, self.current_view_y)) if self.post_view_scene_view.verticalScrollBar().value() == v: # Close enough => stop moving # FIXME not correct because we must stop when the view stops moving, not when the goal we set for centerOn is reached self.timer.stop() @Slot(QModelIndex, QModelIndex) def operation_selected(self, ndx_cur, ndx_old): if ndx_cur.isValid(): opdef = self._table_model.data(ndx_cur, Qt.UserRole) if opdef: self.slide_to_operation( self._table_model.data(ndx_cur, Qt.UserRole)) @Slot() def refresh_action(self): # FIXME reload operations as well operation_definitions, all_operations = self._data_load() # mainlog.debug("reload") if self.sort_by_deadline_button.isChecked(): self.post_view_scene.reload(self, operation_definitions, all_operations, 1) elif self.sort_by_size_button.isChecked(): self.post_view_scene.reload(self, operation_definitions, all_operations, 2) else: self.post_view_scene.reload(self, operation_definitions, all_operations, 0) # mainlog.debug("reset") first_active = self._reset_operation_definitions(operation_definitions) # self.table_view.selectionModel().currentChanged.connect(self.operation_selected) if first_active: self.table_view.setCurrentIndex(first_active) # mainlog.debug("done reset") @Slot(bool) def sort_by_deadline(self, checked): if checked: self.refresh_action() @Slot(bool) def sort_by_size(self, checked): if checked: self.refresh_action() order_part_double_clicked = Signal(int) # Callback that will be called by HooverBar def set_on_order_part(self, order_part_id): self.order_part_double_clicked.emit(order_part_id)