def gather_appearance(self): a = {} a["block", "margin"] = self.block_margin_spinner.get_value_as_int() a["border", "width"] = self.border_width_spinner.get_value_as_int() a["cell", "size"] = self.cell_size_spinner.get_value_as_int() a["line", "width"] = self.line_width_spinner.get_value_as_int() a["cell", "color"] = color_tuple(self.cell_color_button) a["line", "color"] = color_tuple(self.line_color_button) a["border", "color"] = color_tuple(self.border_color_button) a["block", "color"] = color_tuple(self.block_color_button) a["char", "color"] = color_tuple(self.char_color_button) a["number", "color"] = color_tuple(self.number_color_button) p = self.char_size_spinner.get_value_as_int() key = ("cell", "size") a["char", "size"] = (p, _relative_to(key, p / 100.0, d=a)) p = self.number_size_spinner.get_value_as_int() a["number", "size"] = (p, _relative_to(key, p / 100.0, d=a)) return a
def read_xpf(filename, warnings=True): results = [] try: doc = etree.parse(filename) except etree.XMLSyntaxError: raise XPFParserError(u"No valid XML syntax.") puzzles = doc.getroot() if puzzles.tag != "Puzzles": raise XPFParserError(u"No root element called Puzzles found.") version = puzzles.get("Version") if version is None: raise XPFParserError(u"No version specified for this XPF file. Possible older than v1.0?") try: version = float(version) except ValueError: raise XPFParserError("uXPF version is not a valid number") if version < 1.0: raise XPFParserError("uXPF versions older than 1.0 are not supported.") for puzzle in puzzles: if puzzle.tag != "Puzzle": if warnings: print "Warning: skipping a child of Puzzles that is not a Puzzle." continue r_meta = {} r_width = None r_height = None r_grid = None r_notepad = "" r_styles = {} r_gstyles = {} r_number_mode = constants.NUMBERING_AUTO for child in puzzle: if child.tag in XPF_META_ELEMS: r_meta[XPF_META_ELEMS[child.tag]] = child.text elif child.tag == "Size": for d in child: try: if d.tag == "Rows": r_height = int(d.text) elif d.tag == "Cols": r_width = int(d.text) except ValueError: raise XPFParserError(u"Invalid grid dimensions were specified.") elif child.tag == "Grid": if r_width is None: raise XPFParserError(u"The number of columns was not specified.") if r_height is None: raise XPFParserError(u"The number of rows was not specified.") assert r_width >= 0 assert r_height >= 0 r_grid = Grid(r_width, r_height) y = 0 for row in child: if row.tag != "Row": if warnings: print "Warning: skipping a child of Grid that is not a Row." continue if not row.text:# or len(row.text) < r_width: if warnings: print "Warning: skipping a row with missing content." continue for x, c in enumerate(row.text): if c == '.': r_grid.data[y][x]["block"] = True elif c == '~': r_grid.data[y][x]["void"] = True else: r_grid.data[y][x]["char"] = c if c != ' ' else '' y += 1 elif child.tag == "Circles": for circle in child: if circle.tag != "Circle": if warnings: print "Warning: skipping a child of Circles that is not a Circle." continue a_row = circle.get("Row") a_col = circle.get("Col") if not (a_row and a_col): if warnings: print "Warning: skipping a child of Circles with missing content." continue try: x = int(a_col) - 1 y = int(a_row) - 1 except ValueError: if warnings: print "Warning: skipping child of Circles with invalid coordinates." continue if (x, y) not in r_styles: r_styles[x, y] = CellStyle() r_styles[x, y]["circle"] = True elif child.tag == "RebusEntries": for rebus in child: if rebus.tag != "Rebus": if warnings: print "Warning: skipping a child of RebusEntries that is not a Rebus." continue a_row = rebus.get("Row") a_col = rebus.get("Col") a_short = rebus.get("Short") content = rebus.text if not (a_row and a_row and a_short and content): if warnings: print "Warning: skipping a child of RebusEntries with missing content." continue try: x = int(a_col) - 1 y = int(a_row) - 1 except ValueError: if warnings: print "Warning: skipping child of RebusEntries with invalid coordinates." continue r_grid.set_rebus(x, y, a_short, content) elif child.tag == "Shades": for shade in child: if shade.tag != "Shade": if warnings: print "Warning: skipping a child of Shades that is not a Shade." continue a_row = shade.get("Row") a_col = shade.get("Col") if not (a_row and a_col and shade.text): if warnings: print "Warning: skipping a child of Shades with missing content." continue try: x = int(a_col) - 1 y = int(a_row) - 1 except ValueError: if warnings: print "Warning: skipping a child of Shades with invalid coordinates." continue if (x, y) not in r_styles: r_styles[x, y] = CellStyle() if shade.text == "gray": rgb = (32767, 32767, 32767) elif shade.text[0] == '#': rgb = hex_to_color(shade.text) r_styles[x, y]["cell", "color"] = rgb elif child.tag == "Clues": for clue in child: if clue.tag != "Clue": if warnings: print "Warning: skipping a child of Clues that is not a Clue." continue a_row = clue.get("Row") a_col = clue.get("Col") a_num = clue.get("Num") a_dir = clue.get("Dir") a_ans = clue.get("Ans") if not (a_row and a_col and a_dir): if warnings: print "Warning: skipping a child of Clues with missing content." continue try: x = int(a_col) - 1 y = int(a_row) - 1 except ValueError: if warnings: print "Warning: skipping a child of Clues with invalid coordinates." continue dirs = {"Across": "across", "Down": "down"} if a_dir not in dirs: if warnings: print "Warning: skipping a clue with a direction that is not across or down." continue if not clue.text: if warnings: print "Warning: skipping clue without text." continue r_grid.store_clue(x, y, dirs[a_dir], "text", clue.text) elif child.tag == "Notepad": r_notepad = child.text elif child.tag == "Palabra": version = child.get("Version") if version > constants.VERSION: # for now, don't try if warnings: print "Warning: Palabra-specific puzzle content was not loaded as it was made in a newer version of Palabra." continue for c in child: if c.tag == "Explanation": a_row = c.get("Row") a_col = c.get("Col") a_dir = c.get("Dir") if not (a_row and a_col and a_dir): if warnings: print "Warning: skipping Explanation with missing content" continue try: x = int(a_col) - 1 y = int(a_row) - 1 except ValueError: if warnings: print "Warning: skipping Explanation with invalid coordinates." continue dirs = {"Across": "across", "Down": "down"} if a_dir not in dirs: if warnings: print "Warning: skipping Explanation with a direction that is not across or down." continue if not c.text: if warnings: print "Warning: skipping explanation without text." continue r_grid.store_clue(x, y, dirs[a_dir], "explanation", c.text) elif c.tag == "Style": for s in c: if s.tag == "Bar": width = s.get("Width") if width is not None: r_gstyles["bar", "width"] = int(width) elif s.tag == "Border": width = s.get("Width") if width is not None: r_gstyles["border", "width"] = int(width) color = s.get("Color") if color is not None: r_gstyles["border", "color"] = hex_to_color(color) elif s.tag == "Cell": size = s.get("Size") if size is not None: r_gstyles["cell", "size"] = int(size) color = s.get("Color") if color is not None: r_gstyles["cell", "color"] = hex_to_color(color) elif s.tag == "Line": width = s.get("Width") if width is not None: r_gstyles["line", "width"] = int(width) color = s.get("Color") if color is not None: r_gstyles["line", "color"] = hex_to_color(color) elif s.tag == "Block": color = s.get("Color") if color is not None: r_gstyles["block", "color"] = hex_to_color(color) margin = s.get("Margin") if margin is not None: r_gstyles["block", "margin"] = int(margin) elif s.tag == "Char": color = s.get("Color") if color is not None: r_gstyles["char", "color"] = hex_to_color(color) size = s.get("Size") if size is not None: s_s = int(size) s_k = ("cell", "size") s_d = {s_k: (r_gstyles[s_k] if s_k in r_gstyles else DEFAULTS[s_k])} s_r = _relative_to(s_k, s_s / 100.0, d=s_d) r_gstyles["char", "size"] = (s_s, s_r) elif s.tag == "Number": color = s.get("Color") if color is not None: r_gstyles["number", "color"] = hex_to_color(color) size = s.get("Size") if size is not None: s_s = int(size) s_k = ("cell", "size") s_d = {s_k: (r_gstyles[s_k] if s_k in r_gstyles else DEFAULTS[s_k])} s_r = _relative_to(s_k, s_s / 100.0, d=s_d) r_gstyles["number", "size"] = (s_s, s_r) if r_number_mode == constants.NUMBERING_AUTO: r_grid.assign_numbers() p = Puzzle(r_grid, r_styles, r_gstyles) p.metadata = r_meta p.type = constants.PUZZLE_XPF p.filename = filename p.notepad = r_notepad results.append(p) return results