Skip to content

Commit

Permalink
Implement ipuz exporting functionality to browser
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasvana10 committed Jul 14, 2024
1 parent 113c878 commit 01ebbb1
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 72 deletions.
53 changes: 19 additions & 34 deletions xpuz/import_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,15 @@

from json import dump, load
from os import PathLike, mkdir, path, rmdir
from tkinter import filedialog
from typing import Any, List, Union

from platformdirs import user_downloads_dir
from typing import Any, List

from xpuz.td import CrosswordData, CrosswordInfo
from xpuz.utils import GUIHelper
from xpuz.utils import GUIHelper, _get_saveas_filename, _get_open_filename


class Export(list):
"""Export all the crosswords a user has made into a single JSON fdile."""

def __init__(self, blocks: List["UserCrosswordBlock"]) -> None:
self.blocks = blocks
self.exported: bool = False
Expand All @@ -25,30 +22,23 @@ def start(self) -> None:
"""Commence the export process and provide information once it is done."""
self._assemble()
self._export()

if self.no_filepath:
return

if self.exported:
return GUIHelper.show_messagebox(export_success=True)
else:
return GUIHelper.show_messagebox(export_failure=True)

def _get_filepath(self) -> Union[str, PathLike]:
"""Acquire the path of where the user wants to save their exported
crossword JSON file.
"""
return filedialog.asksaveasfilename(
title=_("Select a destination to export your crosswords to"),
defaultextension=".json",
filetypes=[("JSON files", "*.json")],
initialdir=user_downloads_dir(),
initialfile=_("my-crosswords") + ".json",
)

def _export(self) -> None:
"""Write ``self`` to ``filepath``."""
filepath = self._get_filepath()
filepath = _get_saveas_filename(
_("Select a destination to export your crosswords to"),
_("my-crosswords"),
".json",
[("JSON files", "*.json")],
)

if not filepath:
self.no_filepath = True
Expand Down Expand Up @@ -81,7 +71,7 @@ def _assemble(self) -> None:

class Import:
"""Import a valid user-selected file to ``fp``."""

def __init__(self, master: "CrosswordPane", fp: PathLike) -> None:
self.master = master
self.fp = fp
Expand All @@ -96,10 +86,10 @@ def __init__(self, master: "CrosswordPane", fp: PathLike) -> None:
def start(self) -> None:
"""Commence the import process and provide information once it is done."""
self._import()

if self.no_filepath:
return

if self.invalid_file:
return GUIHelper.show_messagebox(import_failure=True)
elif (
Expand All @@ -115,20 +105,15 @@ def start(self) -> None:
partial_import_success=True,
)

def _get_filepath(self) -> Union[str, PathLike]:
"""Acquire the path of the user's crossword JSON."""
return filedialog.askopenfilename(
title=_(
def _import(self) -> None:
"""Read the contents of ``filepath`` and call ``self._write``."""
filepath = _get_open_filename(
_(
"Select a valid crossword JSON file that was exported using xpuz"
),
initialdir=user_downloads_dir(),
filetypes=[("JSON Files", "*.json")],
[("JSON files", "*.json")],
)

def _import(self) -> None:
"""Read the contents of ``filepath`` and call ``self._write``."""
filepath = self._get_filepath()

if not filepath:
self.no_filepath = True
return
Expand Down
74 changes: 74 additions & 0 deletions xpuz/ipuz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from datetime import date
from json import dump

from xpuz.wrappers import CrosswordWrapper
from xpuz.td import IPuzV2
from xpuz.constants import EMPTY
from xpuz.utils import GUIHelper, _get_saveas_filename


class IPuz(dict):
def __init__(
self,
cwrapper: CrosswordWrapper,
# Refer to ``utils._interpret_cword_data`` for information on these params
starting_word_matrix,
definitions_a,
definitions_d,
) -> None:
self.cwrapper = cwrapper
self.crossword = self.cwrapper.crossword

self.starting_word_matrix = starting_word_matrix
self.definitions_a, self.definitions_d = definitions_a, definitions_d

def write(self) -> None:
filepath = _get_saveas_filename(
_("Select a destination to export your ipuz to"),
self.cwrapper.display_name,
".json",
[("JSON files", "*.json")],
)
if not filepath:
return
if not filepath.endswith(".ipuz.json"):
filepath += ".ipuz.json"

self = IPuzV2.create(
dimensions={
"width": self.crossword.dimensions,
"height": self.crossword.dimensions,
},
puzzle=self.starting_word_matrix,
solution=list(
map(
lambda row: [
cell if cell != EMPTY else None for cell in row
],
self.crossword.grid,
)
),
clues={
"Across": [
[
list(definition.keys())[0],
list(definition.values())[0][1],
]
for definition in self.definitions_a
],
"Down": [
[
list(definition.keys())[0],
list(definition.values())[0][1],
]
for definition in self.definitions_d
],
},
date=date.today().strftime("%m/%d/%Y"),
difficulty=self.cwrapper.translated_difficulty,
title=self.cwrapper.translated_name,
)

with open(filepath, "w") as f:
dump(self, f, indent=None)
GUIHelper.show_messagebox(ipuz_write_success=True)
14 changes: 10 additions & 4 deletions xpuz/pages/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def _make_content(self) -> None:

self.l_export = CTkLabel(
self.export_container,
text=_("Export options"),
text=_("Export as"),
state="disabled",
font=self.BOLD_TEXT_FONT,
text_color_disabled=(
Expand Down Expand Up @@ -588,7 +588,14 @@ def _export(self) -> None:
self._export_ipuz()

def _export_ipuz(self) -> None:
...
from xpuz.ipuz import IPuz

IPuz(
self.cwrapper,
self.starting_word_matrix,
self.definitions_a,
self.definitions_d,
).write()

def _export_pdf(self) -> None:
try:
Expand Down Expand Up @@ -883,7 +890,6 @@ def __init__(
category_object=category_object,
value=value,
)
self.localised_difficulty: str = _(self.cwrapper.difficulty)

self._set_fonts()
self._make_content()
Expand Down Expand Up @@ -968,7 +974,7 @@ def _make_content(self) -> None:
self.l_difficulty = CTkLabel(
self,
font=self.TEXT_FONT,
text=f"{_('Difficulty')}: {self.localised_difficulty}",
text=f"{_('Difficulty')}: {self.cwrapper.translated_difficulty}",
)

self.bottom_colour_tag = CTkLabel(
Expand Down
53 changes: 21 additions & 32 deletions xpuz/pdf.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
from os import PathLike
from typing import List
from platformdirs import user_downloads_dir
from tkinter import filedialog

from cairo import (
FONT_SLANT_NORMAL,
Expand All @@ -21,7 +18,7 @@
PDF_WIDTH,
)
from xpuz.wrappers import CrosswordWrapper
from xpuz.utils import GUIHelper
from xpuz.utils import GUIHelper, _get_saveas_filename


class PDF:
Expand All @@ -46,7 +43,7 @@ def __init__(
self.grid: List[List[str]] = self.crossword.grid
self.dimensions: int = self.crossword.dimensions
self.drawn: bool = False
self.display_name = f"{self.cwrapper.translated_name} ({_(self.cwrapper.difficulty)})"
self.display_name = self.cwrapper.display_name

self.starting_word_positions = starting_word_positions
self.starting_word_matrix = starting_word_matrix
Expand All @@ -63,37 +60,30 @@ def __init__(
self.cell_fontsize = self.cell_dim * 0.8

def write(self) -> None:
filepath = PDF._get_pdf_filepath(self.display_name)
filepath = _get_saveas_filename(
_("Select a destination to download your PDF to"),
self.display_name,
".pdf",
[("PDF files", "*.pdf")],
)
if not filepath:
bad_filepath = True
else:
if not filepath.endswith(".pdf"):
filepath += ".pdf"
bad_filepath = False

return
if not filepath.endswith(".pdf"):
filepath += ".pdf"

try:
if not bad_filepath:
self._s: PDFSurface = PDFSurface(filepath, PDF_WIDTH, PDF_HEIGHT)
self._c: Context = Context(self._s)
self._c.set_line_width(1)
self._s: PDFSurface = PDFSurface(filepath, PDF_WIDTH, PDF_HEIGHT)
self._c: Context = Context(self._s)
self._c.set_line_width(1)

self._draw_all()
self.drawn = True

self._draw_all()
self.drawn = True
except Exception:
pass

self._on_finish()

@staticmethod
def _get_pdf_filepath(name: str) -> PathLike:
return filedialog.asksaveasfilename(
title=_("Select a destination to download your PDF to"),
defaultextension=".pdf",
filetypes=[("PDF files", "*.pdf")],
initialdir=user_downloads_dir(),
initialfile=name + ".pdf",
)


def _on_finish(self) -> None:
if not self.drawn:
return GUIHelper.show_messagebox(pdf_write_err=True)
Expand Down Expand Up @@ -207,8 +197,7 @@ def _draw_grid_lines(self) -> None:

for row in range(
self.dimensions + 1
): # Account for far right and bottom
# edges by adding 1
): # Account for far right and bottom edges by adding 1
self._c.move_to(0, row * self.cell_dim)
self._c.line_to(
self.dimensions * self.cell_dim, row * self.cell_dim
Expand Down
28 changes: 28 additions & 0 deletions xpuz/td.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
except ImportError:
from typing_extensions import TypedDict

from xpuz.constants import PROJECT_URL


class Placement(TypedDict):
"""A dictionary specifying the placement information of ``word`` at ``pos``
Expand Down Expand Up @@ -35,3 +37,29 @@ class CrosswordInfo(TypedDict):
name: str
translated_name: Union[None, str]
category: str

class IPuzV2(TypedDict):
"""ipuz v2 structure (JSON)."""

version: str
kind: List[str]
origin: str
author: str
date: str
title: str
difficulty: str
dimensions: Dict[str, int]
puzzle: List[List[Union[int, None]]]
solution: List[List[Union[str, None]]]
clues: Dict[str, List[List[Union[int, str]]]]

@classmethod
def create(
cls,
version: str = "http://ipuz.org/v2",
kind: List[str] = ["http://ipuz.org/crossword#1"],
origin: str = PROJECT_URL,
author: str = "xpuz Crossword Generator",
**kwargs,
) -> "IPuzV2":
return cls(version=version, kind=kind, **kwargs)
Loading

0 comments on commit 01ebbb1

Please sign in to comment.