diff --git a/ast_tool_box/controllers/code_presenter.py b/ast_tool_box/controllers/code_presenter.py index 899ae1d..f1d0808 100644 --- a/ast_tool_box/controllers/code_presenter.py +++ b/ast_tool_box/controllers/code_presenter.py @@ -143,7 +143,7 @@ def apply_codegen_transform(ast_root, argument_list): argument_values = [eval(x) for x in argument_values] tree_copy = copy.deepcopy(code_item.ast_tree) - new_code = apply_codegen_transform(tree_copy) + new_code = apply_codegen_transform(tree_copy, argument_values) new_code_item = code_model.GeneratedCodeItem( new_code, parent_link=code_model.CodeTransformLink(code_item=code_item, transform_item=transform_item), diff --git a/ast_tool_box/controllers/transform_presenter.py b/ast_tool_box/controllers/transform_presenter.py index 8658cbc..ad72ca8 100644 --- a/ast_tool_box/controllers/transform_presenter.py +++ b/ast_tool_box/controllers/transform_presenter.py @@ -77,36 +77,6 @@ def count(self): """return current transforms""" return len(list(self.transform_items())) - # def __getitem__(self, item): - # if isinstance(item, int): - # return self.transform_items[item] - # elif isinstance(item, str): - # return self.transforms_by_name[item] - - # def get_valid_index(self, index): - # """ - # convenience method for checking index - # if index is a string make it an int - # None returned if failed to convert or index out of range - # """ - # if not isinstance(index, int): - # try: - # index = int(index) - # except ValueError: - # return None - # - # if index >= 0: - # if index < len(self.transform_items): - # return index - # return None - - # def get_instance_by_name(self, transform_name): - # transform_item = self.transforms_by_name[transform_name] - # return transform_item.get_instance() - - # def __iter__(self): - # return iter(self.transform_items) - def load_file(self, file_name): print("loading %s" % file_name) if not os.path.isfile(file_name): @@ -129,6 +99,11 @@ def load_files(self, file_names): self.transform_pane.transform_tree_widget.build(self.transform_collections) + def update_file(self, transform_collection): + TransformPresenter.delete_module(transform_collection.package_name) + transform_collection.update() + self.transform_pane.transform_tree_widget.rebuild(transform_collection) + @staticmethod def delete_module(module_name): Util.clear_classes_in_package(module_name) diff --git a/ast_tool_box/transformers/identity_transform.py b/ast_tool_box/transformers/identity_transform.py index 8114970..e04c321 100644 --- a/ast_tool_box/transformers/identity_transform.py +++ b/ast_tool_box/transformers/identity_transform.py @@ -33,6 +33,11 @@ def __init__(self, **kwargs): self.args = kwargs +class Chick7Transform(Chick2Transform): + def __init__(self, **kwargs): + self.args = kwargs + + class NoisyIdentityTransform(ast.NodeTransformer): def __init__(self): super(NoisyIdentityTransform, self).__init__() diff --git a/ast_tool_box/views/code_views/code_pane.py b/ast_tool_box/views/code_views/code_pane.py index d44779a..936a141 100644 --- a/ast_tool_box/views/code_views/code_pane.py +++ b/ast_tool_box/views/code_views/code_pane.py @@ -211,7 +211,7 @@ def add_code_item(self, code_item): widget = EditorPane() widget.setPlainText(code_item.code) elif isinstance(code_item, AstTreeItem): - widget = AstTreePane(self.code_presenter, code_item.code) + widget = AstTreePane(self.code_presenter, code_item.code, tab_name=code_item.code_name) elif isinstance(code_item, GeneratedCodeItem): widget = EditorPane() widget.setPlainText(code_item.code) diff --git a/ast_tool_box/views/editor_widget.py b/ast_tool_box/views/editor_widget.py index a868b82..f179648 100644 --- a/ast_tool_box/views/editor_widget.py +++ b/ast_tool_box/views/editor_widget.py @@ -23,6 +23,8 @@ def __init__(self, parent_panel=None): if self.parent_panel: self.textChanged.connect(self.parent_panel.text_changed) + self.undoAvailable.connect(self.parent_panel.enable_undo) + self.redoAvailable.connect(self.parent_panel.enable_redo) self.highlighter = Highlighter(self.document()) @@ -45,6 +47,7 @@ class EditorPanel(QtGui.QGroupBox): def __init__(self, transform_pane=None): super(EditorPanel, self).__init__("Editor") self.transform_pane = transform_pane + self.transform_collection = None layout = QtGui.QVBoxLayout() button_panel = QtGui.QDialogButtonBox(QtCore.Qt.Horizontal) @@ -73,16 +76,24 @@ def text_changed(self): def undo(self): self.editor.undo() - if not self.editor.undoAvailable(): - self.undo_button.setEnabled(False) + # if not self.editor.undoAvailable(): + # self.undo_button.setEnabled(False) self.redo_button.setEnabled(True) + @QtCore.Slot(bool) + def enable_undo(self, value): + self.undo_button.setEnabled(value) + def redo(self): self.editor.redo() - if not self.editor.redoAvailable(): - self.redo_button.setEnabled(False) + # if not self.editor.redoAvailable(): + # self.redo_button.setEnabled(False) self.undo_button.setEnabled(True) + @QtCore.Slot(bool) + def enable_redo(self, value): + self.redo_button.setEnabled(value) + def save(self): print("Got save file for %s" % self.editor.file_name) file_text = self.editor.toPlainText() @@ -91,7 +102,12 @@ def save(self): self.editor.setPlainText(file_text) self.save_button.setEnabled(False) if self.transform_pane: - self.transform_pane.transform_presenter.reload_transforms() + if self.transform_collection: + print("calling update file") + self.transform_pane.transform_presenter.update_file(self.transform_collection) + else: + print("calling reload transforms") + self.transform_pane.transform_presenter.reload_transforms() def set_read_only(self, value): if value: diff --git a/ast_tool_box/views/image_viewer.py b/ast_tool_box/views/image_viewer.py new file mode 100644 index 0000000..25bdad9 --- /dev/null +++ b/ast_tool_box/views/image_viewer.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python + +############################################################################# +## +## Copyright (C) 2005-2005 Trolltech AS. All rights reserved. +## +## This file is part of the example classes of the Qt Toolkit. +## +## This file may be used under the terms of the GNU General Public +## License version 2.0 as published by the Free Software Foundation +## and appearing in the file LICENSE.GPL included in the packaging of +## this file. Please review the following information to ensure GNU +## General Public Licensing requirements will be met: +## http://www.trolltech.com/products/qt/opensource.html +## +## If you are unsure which license is appropriate for your use, please +## review the following information: +## http://www.trolltech.com/products/qt/licensing.html or contact the +## sales department at sales@trolltech.com. +## +## This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +## WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +## +############################################################################# + +from PySide import QtCore, QtGui + + +class ImageViewer(QtGui.QGroupBox): + def __init__(self, file_name="", tab_name="image"): + super(ImageViewer, self).__init__(tab_name) + + self.file_name = file_name + + self.printer = QtGui.QPrinter() + self.scaleFactor = 0.0 + + self.imageLabel = QtGui.QLabel() + self.imageLabel.setBackgroundRole(QtGui.QPalette.Base) + self.imageLabel.setSizePolicy(QtGui.QSizePolicy.Ignored, + QtGui.QSizePolicy.Ignored) + self.imageLabel.setScaledContents(True) + + self.scrollArea = QtGui.QScrollArea() + self.scrollArea.setBackgroundRole(QtGui.QPalette.Dark) + self.scrollArea.setWidget(self.imageLabel) + self.setCentralWidget(self.scrollArea) + + self.createActions() + self.createMenus() + + self.setWindowTitle("Image Viewer") + self.resize(500, 400) + + def open(self): + file_name, _ = QtGui.QFileDialog.getOpenFileName(self, "Open File", QtCore.QDir.currentPath()) + print("file %s" % file_name) + if file_name: + image = QtGui.QImage(file_name) + if image.isNull(): + QtGui.QMessageBox.information(self, "Image Viewer Cannot load %s." % file_name) + return + + self.imageLabel.setPixmap(QtGui.QPixmap.fromImage(image)) + self.scaleFactor = 1.0 + + self.printAct.setEnabled(True) + self.fitToWindowAct.setEnabled(True) + self.updateActions() + + if not self.fitToWindowAct.isChecked(): + self.imageLabel.adjustSize() + + def print_(self): + dialog = QtGui.QPrintDialog(self.printer, self) + if dialog.exec_(): + painter = QtGui.QPainter(self.printer) + rect = painter.viewport() + size = self.imageLabel.pixmap().size() + size.scale(rect.size(), QtCore.Qt.KeepAspectRatio) + painter.setViewport(rect.x(), rect.y(), size.width(), size.height()) + painter.setWindow(self.imageLabel.pixmap().rect()) + painter.drawPixmap(0, 0, self.imageLabel.pixmap()) + + def zoomIn(self): + self.scaleImage(1.25) + + def zoomOut(self): + self.scaleImage(0.8) + + def normalSize(self): + self.imageLabel.adjustSize() + self.scaleFactor = 1.0 + + def fitToWindow(self): + fitToWindow = self.fitToWindowAct.isChecked() + self.scrollArea.setWidgetResizable(fitToWindow) + if not fitToWindow: + self.normalSize() + + self.updateActions() + + def about(self): + QtGui.QMessageBox.about(self, "About Image Viewer", + "

The Image Viewer example shows how to combine " + "QLabel and QScrollArea to display an image. QLabel is " + "typically used for displaying text, but it can also display " + "an image. QScrollArea provides a scrolling view around " + "another widget. If the child widget exceeds the size of the " + "frame, QScrollArea automatically provides scroll bars.

" + "

The example demonstrates how QLabel's ability to scale " + "its contents (QLabel.scaledContents), and QScrollArea's " + "ability to automatically resize its contents " + "(QScrollArea.widgetResizable), can be used to implement " + "zooming and scaling features.

" + "

In addition the example shows how to use QPainter to " + "print an image.

") + + def createActions(self): + self.openAct = QtGui.QAction("&Open...", self, shortcut="Ctrl+O", + triggered=self.open) + + self.printAct = QtGui.QAction("&Print...", self, shortcut="Ctrl+P", + enabled=False, triggered=self.print_) + + self.exitAct = QtGui.QAction("E&xit", self, shortcut="Ctrl+Q", + triggered=self.close) + + self.zoomInAct = QtGui.QAction("Zoom &In (25%)", self, + shortcut="Ctrl++", enabled=False, triggered=self.zoomIn) + + self.zoomOutAct = QtGui.QAction("Zoom &Out (25%)", self, + shortcut="Ctrl+-", enabled=False, triggered=self.zoomOut) + + self.normalSizeAct = QtGui.QAction("&Normal Size", self, + shortcut="Ctrl+S", enabled=False, triggered=self.normalSize) + + self.fitToWindowAct = QtGui.QAction("&Fit to Window", self, + enabled=False, checkable=True, shortcut="Ctrl+F", + triggered=self.fitToWindow) + + self.aboutAct = QtGui.QAction("&About", self, triggered=self.about) + + self.aboutQtAct = QtGui.QAction("About &Qt", self, + triggered=QtGui.qApp.aboutQt) + + def createMenus(self): + self.fileMenu = QtGui.QMenu("&File", self) + self.fileMenu.addAction(self.openAct) + self.fileMenu.addAction(self.printAct) + self.fileMenu.addSeparator() + self.fileMenu.addAction(self.exitAct) + + self.viewMenu = QtGui.QMenu("&View", self) + self.viewMenu.addAction(self.zoomInAct) + self.viewMenu.addAction(self.zoomOutAct) + self.viewMenu.addAction(self.normalSizeAct) + self.viewMenu.addSeparator() + self.viewMenu.addAction(self.fitToWindowAct) + + self.helpMenu = QtGui.QMenu("&Help", self) + self.helpMenu.addAction(self.aboutAct) + self.helpMenu.addAction(self.aboutQtAct) + + self.menuBar().addMenu(self.fileMenu) + self.menuBar().addMenu(self.viewMenu) + self.menuBar().addMenu(self.helpMenu) + + def updateActions(self): + self.zoomInAct.setEnabled(not self.fitToWindowAct.isChecked()) + self.zoomOutAct.setEnabled(not self.fitToWindowAct.isChecked()) + self.normalSizeAct.setEnabled(not self.fitToWindowAct.isChecked()) + + def scaleImage(self, factor): + self.scaleFactor *= factor + self.imageLabel.resize(self.scaleFactor * self.imageLabel.pixmap().size()) + + self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor) + self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor) + + self.zoomInAct.setEnabled(self.scaleFactor < 3.0) + self.zoomOutAct.setEnabled(self.scaleFactor > 0.333) + + def adjustScrollBar(self, scrollBar, factor): + scrollBar.setValue(int(factor * scrollBar.value() + + ((factor - 1) * scrollBar.pageStep()/2))) + + +if __name__ == '__main__': + + import sys + + app = QtGui.QApplication(sys.argv) + imageViewer = ImageViewer() + imageViewer.show() + sys.exit(app.exec_()) diff --git a/ast_tool_box/views/transform_views/transform_pane.py b/ast_tool_box/views/transform_views/transform_pane.py index 229608d..64b0b38 100644 --- a/ast_tool_box/views/transform_views/transform_pane.py +++ b/ast_tool_box/views/transform_views/transform_pane.py @@ -86,9 +86,11 @@ def load_editor_from(self, widget_item): read_only = False transform_item = widget_item.source + file_item = None if isinstance(transform_item, TransformThing): if transform_item.transform_file: file_item = transform_item.transform_file + print("file_item set to %s" % file_item) file_name = file_item.file_name if not file_item.source_text: source_text = transform_item.source_text @@ -126,6 +128,12 @@ def load_editor_from(self, widget_item): title += " READ ONLY" self.editor_panel.setTitle(title) + if file_item: + print("set editor from has a file_item %s" % file_item) + self.editor_panel.transform_collection = file_item + else: + print("set_editor_from does not have a file_item") + self.editor.setCenterOnScroll(True) text_cursor = self.editor.textCursor() text_block = self.editor.document().findBlockByLineNumber(line_number - 1) diff --git a/ast_tool_box/views/transform_views/transform_tree_widget.py b/ast_tool_box/views/transform_views/transform_tree_widget.py index 474e88f..fb717af 100644 --- a/ast_tool_box/views/transform_views/transform_tree_widget.py +++ b/ast_tool_box/views/transform_views/transform_tree_widget.py @@ -116,6 +116,68 @@ def collapse_descendants(self, item=None): for child_index in range(item.childCount()): self.collapse_descendants(item.child(child_index)) + def rebuild(self, transform_file): + file_node = None + for index in range(self.topLevelItemCount()): + wi = self.topLevelItem(index) + if wi.source is transform_file: + file_node = wi + break + + if not file_node: + print("Could not find %s" % transform_file) + + def remove_children(node): + for child_index in xrange(node.childCount()-1, -1, -1): + print("removing child %d from node %s" % (child_index, node)) + remove_children(node.child(child_index)) + node.takeChild(child_index) + + remove_children(file_node) + self.build_children(transform_file, file_node) + self.expandToDepth(100) + + def build_children(self, transform_file, file_node): + first_node = None + if len(transform_file.node_transforms) > 0: + transforms_node = TransformTreeWidgetItem(file_node) + transforms_node.setText( + TransformTreeWidget.COL_NODE, + "ast.NodeTransformer : (%d)" % len(transform_file.node_transforms) + ) + for transform in transform_file.node_transforms: + transform_node = TransformTreeWidgetItem(transforms_node, name=transform.name, source=transform) + if not first_node: + first_node = transform_node + transform_node.setText(TransformTreeWidget.COL_NODE, transform.name()) + # print("loaded transform to tree %s" % transform.name) + transform_node.setToolTip(TransformTreeWidget.COL_NODE, transform.doc) + else: + if transform_file.load_error_info: + first_node = file_node + + if len(transform_file.code_generators) > 0: + code_generators_node = TransformTreeWidgetItem(file_node) + code_generators_node.setText( + TransformTreeWidget.COL_NODE, + "ctree.CodeGenVisitor : (%d)" % len(transform_file.code_generators) + ) + print("%d code_generators" % len(transform_file.code_generators)) + + for code_generator in transform_file.code_generators: + code_generator_node = TransformTreeWidgetItem( + code_generators_node, + name=code_generator.name, + source=code_generator + ) + if not first_node: + first_node = code_generator_node + code_generator_node.setText(TransformTreeWidget.COL_NODE, code_generator.name()) + code_generator_node.setToolTip(TransformTreeWidget.COL_NODE, code_generator.doc) + + return first_node + + def build(self, transform_files): self.clear() @@ -127,43 +189,9 @@ def build(self, transform_files): "%s (%s)" % (transform_file.base_name, transform_file.package_name) ) file_node.setToolTip(TransformTreeWidget.COL_NODE, transform_file.path) - - if len(transform_file.node_transforms) > 0: - transforms_node = TransformTreeWidgetItem(file_node) - transforms_node.setText( - TransformTreeWidget.COL_NODE, - "ast.NodeTransformer : (%d)" % len(transform_file.node_transforms) - ) - for transform in transform_file.node_transforms: - transform_node = TransformTreeWidgetItem(transforms_node, name=transform.name, source=transform) - if not first_node: - first_node = transform_node - transform_node.setText(TransformTreeWidget.COL_NODE, transform.name()) - print("loaded transform to tree %s" % transform.name) - transform_node.setToolTip(TransformTreeWidget.COL_NODE, transform.doc) - else: - if transform_file.load_error_info: - first_node = file_node - - if len(transform_file.code_generators) > 0: - code_generators_node = TransformTreeWidgetItem(file_node) - code_generators_node.setText( - TransformTreeWidget.COL_NODE, - "ctree.CodeGenVisitor : (%d)" % len(transform_file.code_generators) - ) - print("%d code_generators" % len(transform_file.code_generators)) - - for code_generator in transform_file.code_generators: - code_generator_node = TransformTreeWidgetItem( - code_generators_node, - name=code_generator.name, - source=code_generator - ) - if not first_node: - first_node = code_generator_node - print("XXXXXXXXX codegenerator.name %s" % code_generator.name()) - code_generator_node.setText(TransformTreeWidget.COL_NODE, code_generator.name()) - code_generator_node.setToolTip(TransformTreeWidget.COL_NODE, code_generator.doc) + node = self.build_children(transform_file, file_node) + if not first_node: + first_node = node self.expandToDepth(100) if first_node: