Use clipboard for exporting tables
authorJakob Cornell <jakob+gpg@jcornell.net>
Sun, 12 Jan 2020 20:05:51 +0000 (14:05 -0600)
committerJakob Cornell <jakob+gpg@jcornell.net>
Sun, 12 Jan 2020 20:05:51 +0000 (14:05 -0600)
main.py

diff --git a/main.py b/main.py
index 96f22b69c14c08d5747d19a62f6ae38801aae957..69abf53701aca63880ecf7949cd4ee18da546490 100644 (file)
--- a/main.py
+++ b/main.py
@@ -1,11 +1,9 @@
 from collections import defaultdict, namedtuple, OrderedDict
 from contextlib import contextmanager
 from enum import Enum
-import http.server
 import itertools
 import json
 from matplotlib import pyplot
-from threading import Thread
 
 import tkinter as tk
 from tkinter import ttk
@@ -16,6 +14,46 @@ from tkinter import (
 )
 
 
+def win_write_clipboard_html(text):
+       import win32clipboard as clip
+       fmt = clip.RegisterClipboardFormat('HTML Format')
+
+       @contextmanager
+       def open_clipboard():
+               clip.OpenClipboard()
+               yield
+               clip.CloseClipboard()
+
+       def compute_payload(text):
+               header = '\r\n'.join(
+                       'Version:0.9',
+                       'StartHTML:{}',
+                       'EndHTML:{}',
+                       'StartFragment:{}',
+                       'EndFragment:{}',
+                       '',
+               )
+               pre = '<html><body><!--StartFragment-->'.encode('utf-8')
+               post = '<!--EndFragment--></body></html>'.encode('utf-8')
+               def offsets_for(header_len):
+                       return (
+                               header_len,
+                               header_len + len(pre + text + post),
+                               header_len + len(pre),
+                               header_len + len(pre + text),
+                       )
+               get_hdr = lambda offsets: header.format(*offsets).encode('utf-8')
+               offsets = offsets_for(0)
+               need_len = len(get_hdr(offsets))
+               while need_len != offsets[0]:
+                       offsets = offsets_for(need_len)
+                       need_len = len(get_hdr(offsets))
+               return get_hdr(offsets) + pre + text + post
+
+       with open_clipboard():
+               clip.SetClipboardData(fmt, compute_payload(text.encode('utf-8')))
+
+
 TK_PAD = {'padx': 5, 'pady': 5}
 
 def center_on_parent(child, parent):
@@ -273,6 +311,8 @@ class MainView(View):
                self.gen_plot_btn = ttk.Button(actions_frame, text = "Generate plot", command = on_gen_plot)
 
                def on_gen_table():
+                       from xml.etree import ElementTree
+
                        name = self.controller.state['student']
                        head = list(DataEditModel.Record.DISPLAY_NAMES)
                        head.insert(5, "Score (Comp)")
@@ -280,16 +320,24 @@ class MainView(View):
                                new = list(record)
                                new.insert(5, round(record.overall_score(), 1))
                                return new
-                       rows = [head] + list(map(with_composite, self.controller.data[name]))
-                       data = json.dumps(rows).encode('utf-8')
-                       server = AsyncHttpServer(57853, data)
-                       server.start()
-                       messagebox.showinfo(
-                               "Serving Table Data…",
-                               "Table data is ready to be transferred to your browser. You may close this dialog when the transfer is complete.",
-                       )
-                       server.stop()
-               self.gen_table_btn = ttk.Button(actions_frame, text = "Export table", command = on_gen_table)
+                       rows = map(with_composite, self.controller.data[name])
+                       rows = [
+                               ['' if v is None else str(v) for v in row]
+                               for row in rows
+                       ]
+
+                       table = Et.Element('table')
+                       thead = Et.SubElement(table, 'thead')
+                       for v in head:
+                               Et.SubElement(thead, 'th').text = v
+                       tbody = Et.SubElement(table, 'tbody')
+                       for row in rows:
+                               tr = Et.SubElement(tbody, 'tr')
+                               for v in row:
+                                       Et.SubElement(tr, 'td').text = v
+
+                       win_write_clipboard_html(Et.dump(table))
+               self.gen_table_btn = ttk.Button(actions_frame, text = "Copy table to clipboard", command = on_gen_table)
 
                self.student_sel.pack(**TK_PAD, side = tk.LEFT)
                add_student_btn.pack(**TK_PAD, side = tk.LEFT)