# -*- coding: utf-8 -*-
"""The GUI for publishing -- flowcharts for the moment."""
import collections.abc
import logging
import tkinter as tk
import tkinter.ttk as ttk
import Pmw
import seamm_util
import seamm_widgets as sw
logger = logging.getLogger(__name__)
[docs]
class TkPublish(collections.abc.MutableMapping):
def __init__(self, tk_flowchart):
self.tk_flowchart = tk_flowchart
self._widgets = {"parent": tk_flowchart.pw}
# Provide dict like access to the widgets to make
# the code cleaner
def __getitem__(self, key):
"""Allow [] access to the widgets!"""
return self._widgets[key]
def __setitem__(self, key, value):
"""Allow x[key] access to the data"""
self._widgets[key] = value
def __delitem__(self, key):
"""Allow deletion of keys"""
if key in self._widgets:
self._widgets[key].destroy()
del self._widgets[key]
def __iter__(self):
"""Allow iteration over the object"""
return iter(self._widgets)
def __len__(self):
"""The len() command"""
return len(self._widgets)
[docs]
def create_dialog(self):
"""Create the dialog for publishing."""
if "dialog" in self:
return
toplevel = self["parent"].winfo_toplevel()
self["dialog"] = d = Pmw.Dialog(
toplevel,
buttons=("Publish", "Cancel"),
master=toplevel,
title="Publish the flowchart",
)
d.withdraw()
frame = self["frame"] = d.interior()
# P = self.parameters
# for item in ("what", "destination"):
# self[item] = P[item].widget(frame)
w = self["what"] = sw.LabeledCombobox(
frame,
labeltext="Publish the",
values=("flowchart",),
state="readonly",
)
w.set("flowchart")
w = self["destination"] = sw.LabeledCombobox(
frame,
labeltext="to",
values=("Zenodo", "Zenodo sandbox"),
state="readonly",
)
w.set("Zenodo")
for item in ("what",):
self[item].bind("<<ComboboxSelected>>", self.reset_dialog)
self[item].bind("<Return>", self.reset_dialog)
self[item].bind("<FocusOut>", self.reset_dialog)
# Need the start node for editing the flowchart metadata
start_node = self.tk_flowchart.get_node("1")
self["flowchart metadata"] = start_node.create_frame(frame)
self["doi"] = ttk.Label(frame, text="")
self.reset_dialog()
[docs]
def edit(self):
"""Present a dialog for editing the parameters."""
# Create the dialog if it doesn't exist
self.create_dialog()
# update the flowchart metadata
start_node = self.tk_flowchart.get_node("1")
start_node.update_widgets()
self.reset_dialog()
# And put it on-screen, the first time centered.
result = self["dialog"].activate(geometry="centerscreenfirst")
if result != "Publish":
# Reset everything!
start_node.cleanup_authors()
else:
# Handle the metadata first
start_node.capture_metadata()
start_node.cleanup_authors()
# Capture the parameters from the widgets
what = self["what"].get()
destination = self["destination"].get()
if what == "flowchart":
if destination == "Zenodo":
doi = self.publish_flowchart_to_zenodo()
elif destination == "Zenodo sandbox":
doi = self.publish_flowchart_to_zenodo(sandbox=True)
else:
raise RuntimeError(f"cannot handle destination '{destination}'")
tk.messagebox.showinfo(
master=self["parent"],
title="Published",
message=f"Published the {what} to {destination}\nDOI = {doi}",
)
else:
raise RuntimeError(f"cannot handle publishing '{what}'")
[docs]
def reset_dialog(self):
"""Layout the widgets in the dialog according to the parameters."""
what = self["what"].get()
# Temporary
if what != "flowchart":
what = "flowchart"
self["what"].set(what)
# Remove all the widgets
frame = self["frame"]
for slave in frame.grid_slaves():
slave.grid_forget()
# and put them back in as needed.
row = 0
self["what"].grid(row=row, column=0, sticky=tk.EW)
row += 1
self["destination"].grid(row=row, column=0, sticky=tk.EW)
row += 1
if what == "flowchart":
self["flowchart metadata"].grid(row=row, column=0, sticky=tk.EW)
row += 1
self["doi"].grid(row=row, column=0, sticky=tk.W)
row += 1
metadata = self.tk_flowchart.flowchart.metadata
if "doi" in metadata:
self["doi"]["text"] = metadata["doi"]
else:
self["doi"]["text"] = "not published"
[docs]
def publish_flowchart_to_zenodo(self, sandbox=False):
"""Publish the flowchart to Zenodo.
Parameters
----------
sandbox : bool = False
If true, publish to the Zenodo sandbox.
Returns
-------
str
The DOI.
"""
flowchart = self.tk_flowchart.flowchart
# Get check if the flowchart is fully released
if sandbox:
if flowchart.is_development:
print("Publishing a dirty version to the Zenodo sandbox.")
logger.warning("Publishing a dirty version to the Zenodo sandbox.")
else:
if flowchart.is_development:
return None
zenodo = seamm_util.Zenodo(use_sandbox=sandbox)
# If this flowchart has an existing DOI, create a new version.
metadata = flowchart.metadata
if "doi" in metadata:
_id = metadata["doi"].split("/zenodo.")[1]
record = zenodo.add_version(_id)
for filename in record.files():
record.remove_file(filename)
else:
record = zenodo.create_record()
# Set up the metadata for Zenodo.
record.upload_type = "other"
record.creators = metadata["creators"]
record.title = metadata["title"]
record.description = metadata["description"]
record.keywords = ["seamm-flowchart", *metadata["keywords"]]
if "grants" in metadata:
record.grants = [{"id": g} for g in metadata["grants"]]
# Update the metadata at Zenodo
record.update_metadata()
# Update the metadata in the flowchart
metadata["doi"] = record.doi
conceptdoi = record.conceptdoi
if conceptdoi is not None:
metadata["conceptdoi"] = conceptdoi
# Now we can add the flowchart to Zenodo with the correct DOI, etc.
record.add_file("flowchart.flow", contents=flowchart.to_text())
# And, finally, can publish!
record.publish()
return record.doi