Exemplo n.º 1
0
    def save_document(self) -> bool:
        if not self.document:
            return False

        text = self.buffer.get_text(self.buffer.get_start_iter(),
                                    self.buffer.get_end_iter(), True).strip()

        # New document has id == -1
        # No need to save new empty documents
        if self.document.document_id == -1 and len(text) == 0:
            # storage.delete(self.document.document_id)
            return False

        if self.document.title in ('', 'Nameless'):
            try:
                self.document.title = text.partition('\n')[0].lstrip(
                    ' #') or "Nameless"
            except TypeError:
                pass

        # Save new document to get ID before continue
        if self.document.document_id == -1:
            self.document.document_id = storage.add(self.document)

        if storage.update(self.document.document_id, {
                "content": text,
                'title': self.document.title
        }):
            self.document.content = text
            Logger.debug('Document %s saved', self.document.document_id)
            return True
Exemplo n.º 2
0
    def rename_folder(self, folder: Folder, title: str) -> bool:
        """Renames folder with given `folder` to `title`.
        """
        if title == '..':
            return False

        query = f"UPDATE folders SET title=? WHERE path=? AND title=?"

        try:
            self.conn.execute(query, (
                title,
                folder.path,
                folder.title,
            ))
            self.conn.commit()

            # Store old path
            old_path = folder.absolute_path
            # Set new title to get the new path
            folder.title = title
            new_path = folder.absolute_path

            self.move_folders(old_path, new_path)
            self.move_documents(old_path, new_path)

        except Exception as e:
            Logger.error(e)
            return False

        return True
Exemplo n.º 3
0
    def move_folder(self, folder: Folder, path: str = '/') -> bool:
        """Moves folder to the given `path`.

        Returns True if folder was moved successfully.
        """
        query = 'UPDATE folders SET path=? WHERE path=? AND title=?'

        try:
            self.conn.execute(query, (path, folder.path, folder.title))
            self.conn.commit()

            # Store old path
            old_path = folder.absolute_path
            # Set new title to get the new path
            folder.path = path
            new_path = folder.absolute_path

            self.move_folders(old_path, new_path)
            self.move_documents(old_path, new_path)

        except Exception as e:
            Logger.error(e)
            return False

        return True
Exemplo n.º 4
0
    def on_preview(self, sender, event):
        if not self.is_document_editing:
            Logger.debug('Not in edit mode')
            return

        doc = self.document_grid.selected_document or self.editor.document

        if not doc:
            return

        if not self.preview:
            # create preview window
            text = doc.content if doc else None
            self.preview = Preview(parent=self, text=text)
            # connect signal handlers
            self.editor.scrolled.get_vscrollbar().connect(
                'value-changed', self.scroll_preview)
            self.editor.buffer.connect('changed', self.preview.buffer_changed)
            self.editor.connect('document-load', self.preview.show_preview)
            self.editor.connect('document-close', self.preview.show_empty_page)
            self.preview.connect('destroy', self.on_preview_close)
            self.preview.show_all()
        else:
            self.preview.present()

        if doc:
            self.preview.show_preview(self)
Exemplo n.º 5
0
    def on_document_rename_activated(self,
                                     sender: Gtk.Widget = None,
                                     event=None) -> None:
        """Rename currently selected document.
        Show rename dialog and update document's title
        if user puts new one in the entry.

        :param sender:
        :param event:
        :return:
        """
        doc = self.document_grid.selected_document
        if doc:
            popover = RenameDialog(doc.title)
            response = popover.run()
            try:
                if response == Gtk.ResponseType.APPLY:
                    new_title = popover.entry.get_text()

                    if storage.update(doc_id=doc._id,
                                      data={'title': new_title}):
                        self.document_grid.reload_items()
            except Exception as e:
                Logger.debug(e)
            finally:
                popover.destroy()
Exemplo n.º 6
0
    def update(self, doc_id: int, data: dict) -> bool:
        """Updates document with given `doc_id` with given `data`.

        `data` can contain any of the following keys:
        - title
        - content
        - archived
        - tags
        - path
        - encrypted

        However, if you need to move document to another folder, you should use :func:`move` method.
        """
        fields = {field: value for field, value in data.items()}

        query = f"UPDATE documents SET {','.join(f'{key}=?' for key in fields.keys())}, modified=? WHERE id=?"

        try:
            self.conn.execute(
                query,
                tuple(fields.values()) + (
                    datetime.now(),
                    doc_id,
                ))
            self.conn.commit()
        except Exception as e:
            Logger.error(e)
            return False

        return True
Exemplo n.º 7
0
 def document_activate(self, doc_id):
     Logger.info(f'Document {doc_id} activated')
     editor = self.screens.get_child_by_name('editor-grid')
     editor.load_document(doc_id)
     editor.connect('update-document-stats', self.update_document_stats)
     self.screens.set_visible_child_name('editor-grid')
     self.header.toggle_document_mode()
     self.header.update_title(title=editor.document.title)
     self.settings.set_int('last-document-id', doc_id)
Exemplo n.º 8
0
    def save_document(self) -> bool:
        if not self.document:
            return False

        text = self.buffer.get_text(self.buffer.get_start_iter(),
                                    self.buffer.get_end_iter(), True)
        if storage.update(self.document._id, {"content": text}):
            self.document.content = text
            Logger.debug('Document %s saved', self.document._id)
            return True
Exemplo n.º 9
0
 def count_all(self, path: str = '/', with_archived: bool = False) -> int:
     """Counts all documents and folders in the given path.
     
     If `with_archived` is True then archived documents and folders will be counted too.
     """
     folders = self.count_folders(path, with_archived)
     documents = self.count_documents(path, with_archived)
     Logger.debug(
         f'{folders} folders + {documents} documents found in {path}')
     return folders + documents
Exemplo n.º 10
0
    def delete(self, doc_id: int) -> bool:
        query = f"DELETE FROM documents WHERE id=?"

        try:
            self.conn.execute(query, (doc_id, ))
            self.conn.commit()
        except Exception as e:
            Logger.error(e)
            return False

        return True
Exemplo n.º 11
0
    def count_folders(self,
                      path: str = '/',
                      with_archived: bool = False) -> int:
        """Counts folders in the given path.

        If `with_archived` is True then archived folders will be counted too. Not yet implemented.
        """
        query = 'SELECT COUNT (1) AS count FROM folders WHERE path=?'
        cursor = self.conn.cursor().execute(query, (path, ))
        row = cursor.fetchone()
        Logger.debug(f'{row[0]} folders found in {path}')
        return row[0]
Exemplo n.º 12
0
    def save(self, document: Document) -> bool:
        query = "UPDATE documents SET title=?, content=?, archived=?, modified=? WHERE id=?"

        try:
            self.conn.execute(query, (document.title, document.content,
                                      document.archived, datetime.now()))
            self.conn.commit()
        except Exception as e:
            Logger.error(e)
            return False

        return True
Exemplo n.º 13
0
    def on_document_item_activated(self, sender: Gtk.Widget, path: Gtk.TreePath) -> None:
        """Activate currently selected document in grid and open it in editor.

        :param sender:
        :param path:
        :return:
        """
        model_iter = self.document_grid.model.get_iter(path)
        doc_id = self.document_grid.model.get_value(model_iter, 3)
        Logger.debug('Activated Document.Id %s', doc_id)

        self.document_activate(doc_id)
Exemplo n.º 14
0
    def update(self, doc_id: int, data: dict) -> bool:
        fields = {field: value for field, value in data.items()}

        query = f"UPDATE documents SET {','.join(f'{key}=?' for key in fields.keys())} WHERE id=?"

        try:
            self.conn.execute(query, tuple(fields.values()) + (doc_id, ))
            self.conn.commit()
        except Exception as e:
            Logger.error(e)
            return False

        return True
Exemplo n.º 15
0
    def delete_folders(self, path: str) -> bool:
        """Permanently deletes folders under given `path`
        """
        query = f"DELETE FROM folders WHERE path LIKE ?"

        try:
            self.conn.execute(query, (f'{path}%', ))
            self.conn.commit()
        except Exception as e:
            Logger.error(e)
            return False

        return True
Exemplo n.º 16
0
    def selected_document(self) -> Optional[Document]:
        """Returns selected :model:`Document` or `None`
        """
        Logger.debug('DocumentGrid.selected_document')
        if self.is_folder_selected:
            return None

        if self.selected_path is None:
            return None

        model_iter = self.model.get_iter(self.selected_path)
        doc_id = self.model.get_value(model_iter, 3)
        return self.storage.get(doc_id)
Exemplo n.º 17
0
    def delete_documents(self, path: str) -> bool:
        """Permanently deletes documents under given `path`.

        Returns True if documents were deleted successfully.
        """
        query = 'DELETE FROM documents WHERE path LIKE ?'
        try:
            self.conn.execute(query, (f'{path}%', ))
            self.conn.commit()
        except Exception as e:
            Logger.error(e)
            return False

        return True
Exemplo n.º 18
0
    def count_documents(self,
                        path: str = '/',
                        with_archived: bool = False) -> int:
        """Counts documents in the given path.

        If `with_archived` is True then archived documents will be counted too.
        """
        query = 'SELECT COUNT (1) AS count FROM documents WHERE path=?'
        if not with_archived:
            query += " AND archived=0"
        cursor = self.conn.cursor().execute(query, (path, ))
        row = cursor.fetchone()
        Logger.debug(f'{row[0]} documents found in {path}')
        return row[0]
Exemplo n.º 19
0
    def load_file(self, path: str) -> bool:
        self.buffer.begin_not_undoable_action()
        try:
            txt = open(path).read()
        except Exception as e:
            Logger.error(e)
            return False

        self.buffer.set_text(txt)
        self.buffer.end_not_undoable_action()
        self.buffer.set_modified(False)
        self.buffer.place_cursor(self.buffer.get_start_iter())

        return True
Exemplo n.º 20
0
    def all(self, with_archived: bool = False) -> list:
        query = "SELECT * FROM documents"
        if not with_archived:
            query += " WHERE archived=0"

        Logger.debug('> ALL QUERY: %s', query)

        cursor = self.conn.cursor().execute(query)
        rows = cursor.fetchall()

        docs = []
        for row in rows:
            docs.append(Document.new_with_row(row))

        return docs
Exemplo n.º 21
0
    def delete(self, doc_id: int) -> bool:
        """Permanently deletes document with given `doc_id`.

        Returns True if document was deleted successfully.
        """
        query = f"DELETE FROM documents WHERE id=?"

        try:
            self.conn.execute(query, (doc_id, ))
            self.conn.commit()
        except Exception as e:
            Logger.error(e)
            return False

        return True
Exemplo n.º 22
0
    def move_folders(self, old_path: str, new_path: str) -> bool:
        query = f"UPDATE folders SET path=REPLACE(path, ?, ?) WHERE path LIKE ?"

        try:
            self.conn.execute(query, (
                old_path,
                new_path,
                f"{old_path}%",
            ))
            self.conn.commit()
        except Exception as e:
            Logger.error(e)
            return False

        return True
Exemplo n.º 23
0
    def on_window_delete_event(self, sender: Gtk.Widget = None) -> None:
        """Save opened document before window is closed.

        """
        try:
            if self.autosave:
                self.editor.save_document()
            else:
                print('Ask for action!')

            if not self.is_maximized():
                self.settings.set_value("window-size", GLib.Variant("ai", self.current_size))
                self.settings.set_value("window-position", GLib.Variant("ai", self.current_position))

        except Exception as e:
            Logger.error(e)
Exemplo n.º 24
0
 def on_settings_changed(self, settings, key):
     Logger.debug(f'SETTINGS: %s changed', key)
     if key == "autosave":
         self.window.autosave = settings.get_boolean(key)
     elif key == "spellcheck":
         self.window.toggle_spellcheck(settings.get_boolean(key))
     elif key == 'stylescheme':
         self.window.set_style_scheme(settings.get_string(key))
     elif key == 'autoindent':
         self.window.set_autoindent(settings.get_boolean('autoindent'))
     elif key == 'spaces-instead-of-tabs':
         self.window.set_tabs_spaces(settings.get_boolean('spaces-instead-of-tabs'))
     elif key == 'indent-width':
         self.window.set_indent_width(settings.get_int('indent-width'))
     elif key == 'font':
         self.window.editor.update_font(settings.get_string('font'))
Exemplo n.º 25
0
    def init(self):
        if not os.path.exists(self.base_path):
            os.mkdir(self.base_path)
            Logger.info('Storage folder created at %s', self.base_path)

        Logger.info(f'Storage located at %s', self.file_path)

        self.conn = sqlite3.connect(self.file_path)

        self.conn.execute("""
                CREATE TABLE IF NOT EXISTS `documents` (
                    `id` INTEGER PRIMARY KEY AUTOINCREMENT,
                    `title` TEXT NOT NULL,
                    `content` TEXT,
                    `archived` INTEGER NOT NULL DEFAULT 0 
                )
            """)
Exemplo n.º 26
0
    def on_document_item_activated(self, sender: Gtk.Widget,
                                   path: Gtk.TreePath) -> None:
        """Activate currently selected document in grid and open it in editor.

        :param sender:
        :param path:
        :return:
        """

        folder = self.document_grid.selected_folder
        if folder:
            self.folder_activate(folder.absolute_path)
            Logger.debug(f'Activated Folder {folder.absolute_path}')

        else:
            doc_id = self.document_grid.selected_document_id
            Logger.debug(f'Activated Document.Id {doc_id}')
            self.document_activate(doc_id)
Exemplo n.º 27
0
    def move(self, doc_id: int, path: str = '/') -> bool:
        """Moves document to the given `path`.

        Returns True if document was moved successfully.
        """
        query = 'UPDATE documents SET path=? WHERE id=?'

        try:
            self.conn.execute(query, (
                path,
                doc_id,
            ))
            self.conn.commit()
        except Exception as e:
            Logger.error(e)
            return False

        return True
Exemplo n.º 28
0
    def save_document(self) -> bool:
        if not self.document:
            return False

        text = self.buffer.get_text(
            self.buffer.get_start_iter(),
            self.buffer.get_end_iter(),
            True
        )
        if self.document.title in ('', 'Nameless'):
            try:
                self.document.title = text.partition('\n')[0].lstrip(' #')
            except TypeError:
                pass

        if storage.update(self.document.document_id, {"content": text, 'title': self.document.title}):
            self.document.content = text
            Logger.debug('Document %s saved', self.document.document_id)
            return True
Exemplo n.º 29
0
    def on_document_item_activated(self, sender: Gtk.Widget,
                                   path: Gtk.TreePath) -> None:
        """Activate currently selected document in grid and open it in editor.

        :param sender:
        :param path:
        :return:
        """
        model_iter = self.document_grid.model.get_iter(path)
        doc_id = self.document_grid.model.get_value(model_iter, 3)
        Logger.debug('Activated Document.Id %s', doc_id)

        editor = self.screens.get_child_by_name('editor-grid')
        editor.load_document(doc_id)
        self.screens.set_visible_child_name('editor-grid')

        self.header.toggle_document_mode()
        self.header.update_title(
            title=self.document_grid.model.get_value(model_iter, 1))
        self.settings.set_int('last-document-id', doc_id)
Exemplo n.º 30
0
    def delete_folder(self, folder: Folder) -> bool:
        """Permanently deletes `folder`

        :param folder: :class:`Folder` to be deleted.
        """
        query = f"DELETE FROM folders WHERE path=? AND title=?"

        try:
            self.conn.execute(query, (
                folder.path,
                folder.title,
            ))
            self.conn.commit()

            self.delete_documents(folder.absolute_path)
            self.delete_folders(folder.absolute_path)
        except Exception as e:
            Logger.error(e)
            return False

        return True