diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 083d732..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -__pycache__ -.idea diff --git a/doc_manager.py b/doc_manager.py deleted file mode 100644 index 32d5a99..0000000 --- a/doc_manager.py +++ /dev/null @@ -1,142 +0,0 @@ -import logging -import os -import sys -from datetime import datetime -from typing import List - -import org_rw -from org_rw import OrgDoc, OrgTime - -EXTENSIONS = (".org", ".org.txt") - - -def is_today(ot: OrgTime): - now = datetime.now() - return ( - (ot.time.year == now.year) - and (ot.time.month == now.month) - and (ot.time.day == now.day) - ) - - -class Agenda: - def __init__( - self, - /, - with_hour: List[org_rw.Headline], - no_hour: List[org_rw.Headline], - ): - self.with_hour = with_hour - self.no_hour = no_hour - - def print(self): - for item in self.with_hour: - print(item.scheduled.time, item.state, item.title) - - if len(self.with_hour) > 0: - print("--------") - - for item in self.no_hour: - print(item.scheduled.time, item.state, item.title) - - -class DocumentManager: - docs: list[OrgDoc] - - def __init__(self, base_path: os.PathLike): - self.base_path = base_path - - def load(self): - top = os.path.abspath(self.base_path) - - docs = [] - - for root, dirs, files in os.walk(top): - # Prune dirs - i = 0 - while i < len(dirs): - if dirs[i].startswith(".git"): - del dirs[i] - else: - i += 1 - - # Process files - for name in files: - if all(map(lambda ext: not name.endswith(ext), EXTENSIONS)): - continue - - path = os.path.join(root, name) - - try: - doc = org_rw.load(open(path), extra_cautious=True) - docs.append(doc) - except Exception as err: - import traceback - - traceback.print_exc() - print(f"== On {path}") - sys.exit(1) - - logging.info("Loaded {} files".format(len(docs))) - - self.docs = docs - - def get_agenda(self) -> Agenda: - headline_count = 0 - items_in_agenda = [] - now = datetime.now() - - for doc in self.docs: - for hl in doc.getAllHeadlines(): - headline_count += 1 - - if hl.scheduled and isinstance(hl.scheduled, OrgTime): - if is_today(hl.scheduled): - items_in_agenda.append(hl) - elif (hl.scheduled.time.to_datetime() < now) and hl.is_todo: - items_in_agenda.append(hl) - - logging.info("Read {} items".format(headline_count)) - logging.info("{} items in agenda today".format(len(items_in_agenda))) - - items_with_hour = [ - item - for item in items_in_agenda - if item.scheduled and is_today(item.scheduled) and item.scheduled.time.hour - ] - other_items = [ - item - for item in items_in_agenda - if not ( - item.scheduled and is_today(item.scheduled) and item.scheduled.time.hour - ) - ] - - logging.info("{} items today for a specific hour".format(len(items_with_hour))) - - return Agenda( - with_hour=sorted(items_with_hour, key=lambda x: x.scheduled.time), - no_hour=other_items, - ) - - def get_notes(self, query) -> List[org_rw.Headline]: - headline_count = 0 - t0 = datetime.now() - notes = [] - query = [q.lower() for q in query] - - for doc in self.docs: - for hl in doc.getAllHeadlines(): - headline_count += 1 - - data = "\n".join(hl.get_contents("raw")).lower() - if all([q in data for q in query]): - notes.append(hl) - - logging.info( - "Filtered {} to {} items in {:.3f}s".format( - headline_count, len(notes), (datetime.now() - t0).total_seconds() - ) - ) - - return notes diff --git a/main.py b/main.py old mode 100755 new mode 100644 index 4be07ca..6cdcac7 --- a/main.py +++ b/main.py @@ -1,210 +1,60 @@ -#!/usr/bin/env python3 - -import logging -import os -import sys -import time -import webbrowser - -from PySide2.QtCore import QObject, QThread, Signal, Slot -from PySide2.QtWidgets import (QApplication, QDialog, QFrame, QGroupBox, - QHBoxLayout, QLabel, QLineEdit, QProgressBar, - QPushButton, QScrollArea, QScroller, QTabBar, - QVBoxLayout) - -import doc_manager - -DOCS_PATH = os.environ["ORG_PATH"] +from kivy.app import App +from kivy.core.window import Window +from kivy.modules import inspector +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.button import Button +from kivy.uix.gridlayout import GridLayout +from kivy.uix.scrollview import ScrollView +from kivy.uix.textinput import TextInput -class LoadDoneSignal(QObject): - sig = Signal(doc_manager.DocumentManager) - - -class DocumentLoader(QThread): - def __init__(self, manager): - QThread.__init__(self, None) - self.manager = manager - self.signal = LoadDoneSignal() - - def run(self): - self.manager.load() - self.signal.sig.emit(self.manager) - - -class Dialog(QDialog): +class TestApp(App): def __init__(self): - super(Dialog, self).__init__() + App.__init__(self) + self.results = [] - self.setWindowTitle("OrgEditor") - scrSize = self.screen().size() - self.resize(scrSize.width() / 1.5, scrSize.height() / 1.5) - self.loader = None - self.manager = doc_manager.DocumentManager(DOCS_PATH) + def on_omnibox_change(self, _instance, value): + print("⇒", value) + while self.results: + btn = self.results.pop() + self.layout.remove_widget(btn) - layout = QVBoxLayout() + for i in range(100): + btn = Button(text=value + str(i), height=40, size_hint_y=None) + self.layout.add_widget(btn) + self.results.append(btn) - # Edit box - self.progressBar = QProgressBar() - self.progressBar.setRange(0, 0) # Make undetermined - layout.addWidget(self.progressBar) + def build(self): + self.root = BoxLayout(orientation="vertical", spacing=5) + # Make sure the height is such that there is something to scroll. + self.root.bind(minimum_height=self.root.setter("height")) - self.edit = QLineEdit("", placeholderText="Search for notes") - self.edit.textEdited.connect(self.on_text_edited) - layout.addWidget(self.edit) - - layout.setSpacing(0) - - self.results = QScrollArea(widgetResizable=True) - layout.addWidget(self.results) - QScroller.grabGesture( - self.results.viewport(), - QScroller.LeftMouseButtonGesture, + self.omnibox = TextInput( + text="", + hint_text="Search here files and headlines", + multiline=False, + write_tab=False, + size_hint_y=None, + height=40, + focus=False, ) + self.omnibox.bind(text=self.on_omnibox_change) + self.root.add_widget(self.omnibox) - # Options - self.tabBar = QTabBar(shape=QTabBar.RoundedSouth) - - self.tabBar.addTab("Agenda") - self.tabBar.addTab("Notes") - self.tabBar.addTab("Tasks") - self.tabBar.currentChanged.connect(self.update_tab) - - layout.addWidget(self.tabBar) - - self.setLayout(layout) - self.startLoad() - - @Slot() - def on_text_edited(self): - if self.tabBar.currentIndex() != 1: - self.tabBar.setCurrentIndex(1) - else: - self.loadNotes() - - @Slot() - def update_tab(self): - tabIndex = self.tabBar.currentIndex() - if tabIndex == 0: - self.loadAgenda() - elif tabIndex == 1: - self.loadNotes() - elif tabIndex == 2: - self.loadTasks() - - def startLoad(self): - self.edit.setDisabled(True) - self.edit.setVisible(False) - self.tabBar.setDisabled(True) - self.progressBar.setVisible(True) - - self.loader = DocumentLoader(self.manager) - self.loader.signal.sig.connect(self.longoperationcomplete) - self.loading_start_time = time.time() - self.loader.start() - - def endLoad(self): - self.edit.setDisabled(False) - self.edit.setVisible(True) - self.tabBar.setDisabled(False) - self.progressBar.setVisible(False) - - self.update_tab() - - def longoperationcomplete(self, data): - logging.info( - "Loading complete in {:.3f}s".format(time.time() - self.loading_start_time) + self.viewer = ScrollView( + size_hint=(1, 1), size=(Window.width / 2, Window.height / 2) ) - self.endLoad() + self.layout = BoxLayout(orientation="vertical", spacing=2, size_hint_y=None) + self.layout.bind(minimum_height=self.layout.setter("height")) + for i in range(100): + btn = Button(text=str(i), height=40, size_hint_y=None) + self.layout.add_widget(btn) + self.results.append(btn) - def loadAgenda(self): - agenda = self.manager.get_agenda() - old = self.results.layout() - - if old: - print("Deleting old") - old.deleteLater() - - layout = QVBoxLayout() - - for item in agenda.with_hour: - layout.addWidget(self.build_agenda_task_widget(item)) - - # if len(agenda.with_hour) > 0 and len(agenda.no_hour) > 0: - # layout.addWidget(QSplitter()) - - for item in agenda.no_hour: - layout.addWidget(self.build_agenda_task_widget(item)) - - frame = QFrame(self.results) - frame.setLayout(layout) - self.results.setWidget(frame) - - def build_agenda_task_widget(self, item): - box = QHBoxLayout() - frame = QGroupBox() - frame.setLayout(box) - - state_button = QPushButton(text=f"{item.state or '-'}", maximumWidth=60) - if item.is_done: - state_button.setFlat(True) - box.addWidget(state_button) - - box.addWidget(QLabel(text=f"{item.scheduled.time}", maximumWidth=200)) - box.addWidget(QLabel(text=f"{item.title}")) - - def on_clicked(): - state_button.setText("DONE") - # state_button.setFlat(True) - # item.state = 'DONE' - - if not item.is_done: - state_button.clicked.connect(on_clicked) - - return frame - - def build_note_task_widget(self, item): - box = QHBoxLayout() - frame = QGroupBox() - frame.setLayout(box) - - titleButton = QPushButton(text=f"{item.title}") - box.addWidget(titleButton) - - def on_clicked(): - webbrowser.open("org-protocol://org-id?id=" + item.id) - - titleButton.clicked.connect(on_clicked) - - return frame - - def loadNotes(self): - query = self.edit.text() - notes = self.manager.get_notes(query.split()) - old = self.results.layout() - - if old: - print("Deleting old") - old.deleteLater() - - layout = QVBoxLayout() - - for note in notes: - layout.addWidget(self.build_note_task_widget(note)) - - frame = QFrame(self.results) - frame.setLayout(layout) - self.results.setWidget(frame) - - def loadTasks(self): - logging.warning("loadTasks not yet implemented") + self.viewer.add_widget(self.layout) + self.root.add_widget(self.viewer) + inspector.create_inspector(Window, self.root) + return self.root -# Create the Qt Application -if __name__ == "__main__": - logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s") - - app = QApplication(sys.argv) - - dialog = Dialog() - sys.exit(dialog.exec_()) +TestApp().run() diff --git a/org-mode.svg b/org-mode.svg deleted file mode 100644 index 917cf3a..0000000 --- a/org-mode.svg +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c098fc2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +kivy[base]