def _code_convert_1_2(self, key: Tuple[int, int, int], code: str) -> str: """Converts chart and image code from v1.0 to v2.0 :param key: Key of cell with code :param code: Code in cell to be converted """ def get_image_code(image_data: str, width: int, height: int) -> str: """Returns code string for v2.0 :param image_data: b85encoded image data :param width: Image width :param height: Image height """ image_buffer_tpl = 'bz2.decompress(base64.b85decode({data}))' image_array_tpl = 'numpy.frombuffer({buffer}, dtype="uint8")' image_matrix_tpl = '{array}.reshape({height}, {width}, 3)' image_buffer = image_buffer_tpl.format(data=image_data) image_array = image_array_tpl.format(buffer=image_buffer) image_matrix = image_matrix_tpl.format(array=image_array, height=height, width=width) return image_matrix start_str = "bz2.decompress(base64.b64decode('" size_start_str = "wx.ImageFromData(" if size_start_str in code and start_str in code: size_start = code.index(size_start_str) + len(size_start_str) size_str_list = code[size_start:].split(",")[:2] width, height = tuple(map(int, size_str_list)) # We have a cell that displays a bitmap data_start = code.index(start_str) + len(start_str) data_stop = code.find("'", data_start) enc_data = bytes(code[data_start:data_stop], encoding='utf-8') compressed_image_data = b64decode(enc_data) reenc_data = b85encode(compressed_image_data) code = get_image_code(repr(reenc_data), width, height) selection = Selection([], [], [], [], [(key[0], key[1])]) tab = key[2] attr_dict = AttrDict([("renderer", "image")]) attr = CellAttribute(selection, tab, attr_dict) self.cell_attributes_postfixes.append(attr) elif "charts.ChartFigure(" in code: # We have a matplotlib figure selection = Selection([], [], [], [], [(key[0], key[1])]) tab = key[2] attr_dict = AttrDict([("renderer", "matplotlib")]) attr = CellAttribute(selection, tab, attr_dict) self.cell_attributes_postfixes.append(attr) return code
def redo(self): """Redo column deletion, updates screen""" # Store content of deleted columns self.old_col_widths = copy(self.model.code_array.col_widths) self.old_cell_attributes = copy(self.model.code_array.cell_attributes) self.old_code = {} columns = list(range(self.first, self.last + 1)) selection = Selection([], [], [], columns, []) for key in selection.cell_generator(self.model.shape, self.grid.table): self.old_code[key] = self.model.code_array(key) with self.model.removing_columns(self.index, self.first, self.last): self.model.removeColumns(self.column, self.count) self.grid.table_choice.on_table_changed(self.grid.current)
def redo(self): """Redo row deletion, updates screen""" # Store content of deleted rows self.old_row_heights = copy(self.model.code_array.row_heights) self.old_cell_attributes = copy(self.model.code_array.cell_attributes) self.old_code = {} rows = list(range(self.first, self.last + 1)) selection = Selection([], [], rows, [], []) for key in selection.cell_generator(self.model.shape, self.grid.table): self.old_code[key] = self.model.code_array(key) with self.model.removing_rows(self.index, self.first, self.last): self.model.removeRows(self.row, self.count) self.grid.table_choice.on_table_changed(self.grid.current)
def _pys2attributes_10(self, line: str): """Updates attributes in code_array - for save file version 1.0 :param line: Pys file line to be parsed """ splitline = self._split_tidy(line) selection_data = list(map(ast.literal_eval, splitline[:5])) selection = Selection(*selection_data) tab = int(splitline[5]) attr_dict = AttrDict() old_merged_cells = {} for col, ele in enumerate(splitline[6:]): if not (col % 2): # Odd entries are keys key = ast.literal_eval(ele) else: # Even cols are values value = ast.literal_eval(ele) # Convert old wx color values and merged cells key_, value_ = self._attr_convert_1to2(key, value) if key_ is None and value_ is not None: # We have a merged cell old_merged_cells[value_[:2]] = value_ try: attr_dict.pop("merge_area") except KeyError: pass attr_dict[key_] = value_ attr = CellAttribute(selection, tab, attr_dict) self.code_array.cell_attributes.append(attr) for key in old_merged_cells: selection = Selection([], [], [], [], [key]) attr_dict = AttrDict([("merge_area", old_merged_cells[key])]) attr = CellAttribute(selection, tab, attr_dict) self.code_array.cell_attributes.append(attr) old_merged_cells.clear()
def _pys2attributes(self, line: str): """Updates attributes in code_array :param line: Pys file line to be parsed """ splitline = self._split_tidy(line) selection_data = list(map(ast.literal_eval, splitline[:5])) selection = Selection(*selection_data) tab = int(splitline[5]) attr_dict = AttrDict() for col, ele in enumerate(splitline[6:]): if not (col % 2): # Odd entries are keys key = ast.literal_eval(ele) else: # Even cols are values value = ast.literal_eval(ele) attr_dict[key] = value attr = CellAttribute(selection, tab, attr_dict) self.code_array.cell_attributes.append(attr)
def redo(self): """Redo cell thawing""" row, column, table = current = self.current # Remove and store frozen cache content self.res_obj = self.model.code_array.frozen_cache.pop(repr(current)) # Remove the frozen state selection = Selection([], [], [], [], [(row, column)]) attr_dict = AttrDict([("frozen", False)]) attr = CellAttribute(selection, table, attr_dict) self.model.setData([], attr, Qt.DecorationRole) self.model.dataChanged.emit(QModelIndex(), QModelIndex())
def undo(self): """Undo button cell removal""" row, column, table = self.key selection = Selection([], [], [], [], [(row, column)]) attr_dict = AttrDict([("button_cell", self.text)]) ca = CellAttribute(selection, table, attr_dict) self.grid.model.setData([self.index], ca, Qt.DecorationRole) if table == self.grid.table: # Only add widget if we are in the right table button = CellButton(self.text, self.grid, self.key) self.grid.setIndexWidget(self.index, button) self.grid.widget_indices.append(self.index) self.grid.model.dataChanged.emit(self.index, self.index)
def redo(self): """Redo cell freezing""" row, column, table = self.current # Add frozen cache content res_obj = self.model.code_array[self.current] self.model.code_array.frozen_cache[repr(self.current)] = res_obj # Set the frozen state selection = Selection([], [], [], [], [(row, column)]) attr_dict = AttrDict([("frozen", True)]) attr = CellAttribute(selection, table, attr_dict) self.model.setData([], attr, Qt.DecorationRole) self.model.dataChanged.emit(QModelIndex(), QModelIndex())
def undo(self): """Undo button cell making""" if self.index not in self.grid.widget_indices: return row, column, table = self.key selection = Selection([], [], [], [], [(row, column)]) attr_dict = AttrDict([("button_cell", False)]) ca = CellAttribute(selection, table, attr_dict) self.grid.model.setData([self.index], ca, Qt.DecorationRole) if table == self.grid.table: # Only remove widget if we are in the right table self.grid.setIndexWidget(self.index, None) self.grid.widget_indices.remove(self.index) self.grid.model.dataChanged.emit(self.index, self.index)
def redo(self): """Redo grid size change and deletion of cell code outside new shape Cell formats are not deleted. """ model = self.grid.model code_array = model.code_array rows, columns, tables = self.new_shape shapeselection = Selection([(0, 0)], [(rows - 1, columns - 1)], [], [], []) for row, column, table in code_array.keys(): if not (table < tables and (row, column) in shapeselection): # Code outside grid shape. Delete it and store cell data key = row, column, table self.deleted_cells[key] = code_array.pop(key) # Now change the shape self.grid.model.shape = self.new_shape
def _adjust_merge_area(self, attrs: AttrDict, insertion_point: int, no_to_insert: int, axis: int) -> Tuple[int, int, int, int]: """Returns an updated merge area :param attrs: Cell attribute dictionary that shall be adjusted :param insertion_point: Point on axis at which insertion takes place :param no_to_insert: Number of rows/cols/tabs to be inserted (>=0) :param axis: Row insertion if 0, column insertion if 1, must be in 0, 1 """ if axis not in (0, 1): raise Warning("Axis {} not in (0, 1)".format(axis)) return if "merge_area" not in attrs or attrs["merge_area"] is None: return top, left, bottom, right = attrs["merge_area"] selection = Selection([(top, left)], [(bottom, right)], [], [], []) selection.insert(insertion_point, no_to_insert, axis) __top, __left = selection.block_tl[0] __bottom, __right = selection.block_br[0] # Adjust merge area if it is beyond the grid shape rows, cols, tabs = self.shape if __top < 0 and __bottom < 0: return if __top >= rows and __bottom >= rows: return if __left < 0 and __right < 0: return if __left >= cols and __right >= cols: return if __top < 0: __top = 0 if __top >= rows: __top = rows - 1 if __bottom < 0: __bottom = 0 if __bottom >= rows: __bottom = rows - 1 if __left < 0: __left = 0 if __left >= cols: __left = cols - 1 if __right < 0: __right = 0 if __right >= cols: __right = cols - 1 return __top, __left, __bottom, __right