Finish org previewer.

master
Andy Stewart 8 years ago
parent e531016146
commit 6ddd3f3763
  1. 19
      HACKING.md
  2. 18
      README.md
  3. 87
      app/orgpreviewer/buffer.py
  4. 3
      core/buffer.py
  5. 83
      eaf.el
  6. 7
      eaf.py
  7. BIN
      screenshot/org_previewer.gif

@ -134,9 +134,9 @@ You need implement "scroll" interface in AppBuffer, such as like PDF Viewer does
self.buffer_widget.scroll_down()
```
scroll_direction is string, "up" mean scroll buffer up, "down" mean scroll buffer down.
Argument "scroll_direction" is string, "up" mean scroll buffer up, "down" mean scroll buffer down.
scroll_type is string, "page" mean scroll buffer by page, "line" mean scroll buffer by line.
Argument "scroll_type" is string, "page" mean scroll buffer by page, "line" mean scroll buffer by line.
### Save/Restore session
We always need save and restore session for application, such as, save play position of video player.
@ -153,9 +153,22 @@ You need implement interfaces "save_session_data" and "restore_session_data", be
self.buffer_widget.media_player.setPosition(position)
```
session_data is string, you can put anything in it
Argument "session_data" is string, you can put anything in it
All session data save at ~/.emacs.d/eaf/session.json file.
### Update buffer
If you need update buffer sometimes, such as update org-file previewer after save org-file.
You need implement interfaces "update_with_data" , below is an example of Org Previewer does:
```Python
def update_with_data(self, update_data):
self.load_org_html_file()
self.buffer_widget.reload()
```
Argument "update_data" is pass from elisp side.
## Todolist
[Some works you can hacking ;)](TODOLIST.md)

@ -29,10 +29,11 @@ Using this framework, you can use PyQt develop powerful graphics programs to ext
| <img src="./screenshot/file_transfer.png" width="400"> | <img src="./screenshot/file_uploader.png" width="400"> |
| | |
| Air Share |
| :--------: |
| <img src="./screenshot/air_share.png" width="400"> |
| |
| Air Share | Org Previewer |
| :--------: | :--------: |
| <img src="./screenshot/air_share.png" width="400"> | <img src="./screenshot/org_previewer.gif" width="400"> |
| | |
## Installation
@ -79,13 +80,14 @@ There are mainly three obstacles:
| :-------- | :---- | :-----: | :---- |
| Browser | URL | Left Button | Open link current tab |
| | | Ctrl + Left Button | Open link in new tab |
| Markdown previewer | Markdown file path | | |
| Image Viewer | Image file path | j | Load next image in current directory |
| Markdown previewer | Type 'eaf-open' RET markdown filepath | | |
| Org file previewer | Type 'eaf-open' RET org filepath | | |
| Image Viewer | Type 'eaf-open' RET IMAGE filepath | j | Load next image in current directory |
| | | k | Load previous image in current directory |
| Video Player | Video file path | Space | Play or Pause |
| Video Player | Type 'eaf-open' RET video filepath | Space | Play or Pause |
| | | h | Seek backward |
| | | l | Seek forward |
| Pdf Viewer | Pdf file path | j | Scroll up |
| Pdf Viewer | Type 'eaf-open' RET PDF filepath | j | Scroll up |
| | | k | Scroll down |
| | | Space | Scroll up page |
| | | b | Scroll down page |

@ -0,0 +1,87 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2018 Andy Stewart
#
# Author: Andy Stewart <lazycat.manatee@gmail.com>
# Maintainer: Andy Stewart <lazycat.manatee@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5 import QtCore
from PyQt5.QtCore import QUrl, Qt
from PyQt5.QtGui import QColor
from PyQt5.QtWebKitWidgets import QWebView, QWebPage
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebKit import QWebSettings
from core.buffer import Buffer
from core.utils import PostGui
import socket
import subprocess
import threading
import os
class AppBuffer(Buffer):
def __init__(self, buffer_id, url):
Buffer.__init__(self, buffer_id, url, False, QColor(255, 255, 255, 255))
self.url = url
self.add_widget(BrowserWidget())
self.load_org_html_file()
def load_org_html_file(self):
self.buffer_widget.setUrl(QUrl.fromLocalFile(os.path.splitext(self.url)[0]+".html"))
def update_with_data(self, update_data):
self.load_org_html_file()
self.buffer_widget.reload()
class BrowserWidget(QWebView):
def __init__(self):
super(QWebView, self).__init__()
self.web_page = WebPage()
self.setPage(self.web_page)
self.settings().setAttribute(QWebSettings.PluginsEnabled, True)
self.settings().setAttribute(QWebSettings.JavascriptEnabled, True)
self.settings().setAttribute(QWebSettings.JavascriptCanOpenWindows, True)
class WebPage(QWebPage):
open_url_in_new_tab = QtCore.pyqtSignal(str)
def __init__(self):
super(WebPage, self).__init__()
def acceptNavigationRequest(self, frame, request, type):
modifiers = QApplication.keyboardModifiers()
# Handle myself if got user event.
if type == QWebPage.NavigationTypeLinkClicked:
if modifiers == Qt.ControlModifier:
self.open_url_in_new_tab.emit(request.url().toString())
else:
self.view().load(request.url())
# Return False to stop default behavior.
return False
# # Otherwise, use default behavior.
return QWebPage.acceptNavigationRequest(self, frame, request, type)
def javaScriptConsoleMessage(self, msg, lineNumber, sourceID):
pass

@ -79,3 +79,6 @@ class Buffer(QGraphicsScene):
def restore_session_data(self, session_data):
pass
def update_with_data(self, update_data):
pass

@ -114,6 +114,9 @@
(defvar eaf-title-length 30)
(defvar eaf-org-file-list '())
(defvar eaf-org-killed-file-list '())
(defcustom eaf-name "*eaf*"
"Name of eaf buffer."
:type 'string
@ -167,6 +170,11 @@
;; Clean cache url and app name, avoid next start process to open buffer.
(setq eaf-first-start-url nil)
(setq eaf-first-start-app-name nil)
;; Clean `eaf-org-file-list'
(dolist (org-file-name eaf-org-file-list)
(eaf-delete-org-preview-file org-file-name))
(setq eaf-org-file-list nil)
(setq eaf-org-killed-file-list nil)
))
(defun eaf-restart-process ()
@ -225,7 +233,7 @@ We need calcuate render allocation to make sure no black border around render co
(dolist (window (window-list))
(let ((buffer (window-buffer window)))
(with-current-buffer buffer
(if (string= "eaf-mode" (format "%s" major-mode))
(if (eq major-mode 'eaf-mode)
(let* ((window-allocation (eaf-get-window-allocation window))
(x (nth 0 window-allocation))
(y (nth 1 window-allocation))
@ -239,18 +247,53 @@ We need calcuate render allocation to make sure no black border around render co
(eaf-call "update_views" (mapconcat 'identity view-infos ","))
)))
(defun eaf-delete-org-preview-file (org-file)
(setq org-html-file (concat (file-name-sans-extension org-file) ".html"))
(when (file-exists-p org-html-file)
(delete-file org-html-file)
(message (format "Clean org preview file %s (%s)" org-html-file org-file))
))
(defun eaf-org-killed-buffer-clean ()
(dolist (org-killed-buffer eaf-org-killed-file-list)
(unless (get-file-buffer org-killed-buffer)
(setq eaf-org-file-list (remove org-killed-buffer eaf-org-file-list))
(eaf-delete-org-preview-file org-killed-buffer)
))
(setq eaf-org-killed-file-list nil))
(defun eaf-monitor-buffer-kill ()
(ignore-errors
(with-current-buffer (buffer-name)
(when (string= "eaf-mode" (format "%s" major-mode))
(eaf-call "kill_buffer" buffer-id)
(message (format "Kill %s" buffer-id))
))))
(cond ((eq major-mode 'org-mode)
;; NOTE:
;; Because save org buffer will trigger `kill-buffer' action,
;; but org buffer still live after do `kill-buffer' action.
;; So i run a timer to check org buffer is live after `kill-buffer' aciton.
(when (member (buffer-file-name) eaf-org-file-list)
(unless (member (buffer-file-name) eaf-org-killed-file-list)
(push (buffer-file-name) eaf-org-killed-file-list))
(run-with-timer 1 nil (lambda () (eaf-org-killed-buffer-clean)))
))
((eq major-mode 'eaf-mode)
(eaf-call "kill_buffer" buffer-id)
(message (format "Kill %s" buffer-id)))
))))
(defun eaf-monitor-buffer-save ()
(ignore-errors
(with-current-buffer (buffer-name)
(cond ((and
(eq major-mode 'org-mode)
(member (buffer-file-name) eaf-org-file-list))
(org-html-export-to-html)
(eaf-call "update_buffer_with_url" "app.orgpreviewer.buffer" (buffer-file-name) "")
(message (format "export %s to html" (buffer-file-name))))))))
(defun eaf-monitor-key-event ()
(ignore-errors
(with-current-buffer (buffer-name)
(when (string= "eaf-mode" (format "%s" major-mode))
(when (eq major-mode 'eaf-mode)
(let* ((event last-command-event)
(key (make-vector 1 event))
(key-command (format "%s" (key-binding key)))
@ -303,7 +346,7 @@ We need calcuate render allocation to make sure no black border around render co
(dolist (window (window-list))
(let ((buffer (window-buffer window)))
(with-current-buffer buffer
(if (string= "eaf-mode" (format "%s" major-mode))
(if (eq major-mode 'eaf-mode)
(let* ((window-allocation (eaf-get-window-allocation window))
(x (nth 0 window-allocation))
(y (nth 1 window-allocation))
@ -341,7 +384,7 @@ We need calcuate render allocation to make sure no black border around render co
(let ((buffer (window-buffer window)))
(with-current-buffer buffer
(when (and
(string= "eaf-mode" (format "%s" major-mode))
(eq major-mode 'eaf-mode)
(equal buffer-id bid))
(rename-buffer title)
(throw 'find-buffer t)
@ -371,6 +414,7 @@ We need calcuate render allocation to make sure no black border around render co
(add-hook 'window-configuration-change-hook #'eaf-monitor-configuration-change)
(add-hook 'pre-command-hook #'eaf-monitor-key-event)
(add-hook 'kill-buffer-hook #'eaf-monitor-buffer-kill)
(add-hook 'after-save-hook #'eaf-monitor-buffer-save)
(defun eaf-open-internal (url app-name)
(let* ((buffer (eaf-create-buffer url))
@ -398,11 +442,32 @@ We need calcuate render allocation to make sure no black border around render co
(cond ((member extension-name '("pdf" "xps" "oxps" "cbz" "epub" "fb2" "fbz"))
(setq app-name "pdfviewer"))
((member extension-name '("md"))
;; Split window to show file and previewer.
(delete-other-windows)
(find-file url)
(split-window-horizontally)
(other-window +1)
(setq app-name "markdownpreviewer"))
((member extension-name '("jpg" "png" "bmp"))
(setq app-name "imageviewer"))
((member extension-name '("avi" "rmvb" "ogg" "mp4"))
(setq app-name "videoplayer"))))
(setq app-name "videoplayer"))
((member extension-name '("org"))
;; Find file first, because `find-file' will trigger `kill-buffer' operation.
(save-excursion
(find-file url)
(with-current-buffer (buffer-name)
(org-html-export-to-html)))
;; Add file name to `eaf-org-file-list' after command `find-file'.
(unless (member url eaf-org-file-list)
(push url eaf-org-file-list))
;; Split window to show file and previewer.
(delete-other-windows)
(find-file url)
(split-window-horizontally)
(other-window +1)
(setq app-name "orgpreviewer")
)))
(t
(setq app-name "browser")
(unless (string-prefix-p "http" url)

@ -56,6 +56,13 @@ class EAF(dbus.service.Object):
# otherwise some library will throw error, such as fitz library.
return self.create_app(buffer_id, str(url), "app.{0}.buffer".format(str(app_name)))
@dbus.service.method(EAF_DBUS_NAME, in_signature="sss", out_signature="")
def update_buffer_with_url(self, module_path, buffer_url, update_data):
for buffer in list(self.buffer_dict.values()):
if buffer.module_path == module_path and buffer.url == buffer_url:
buffer.update_with_data(update_data)
break
@dbus.service.method(EAF_DBUS_NAME, in_signature="sss", out_signature="")
def scroll_buffer(self, view_info, scroll_direction, scroll_type):
(buffer_id, _, _, _, _) = view_info.split(":")

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 KiB

Loading…
Cancel
Save