示例#1
0
    def __init__(self):
        Gtk.Box.__init__(self)

        self.set_orientation(Gtk.Orientation.VERTICAL)

        self.label_row = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)

        self.label = Gtk.Label().new("Hex address or expression")
        self.label_row.pack_start(self.label, False, False, 0)

        self.input_row = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)

        self.address_input = Gtk.Entry()
        self.address_input.set_editable(True)

        self.confirm_button = Gtk.Button()
        self.confirm_button.set_label("Load")

        self.input_row.pack_start(self.address_input, False, False, 0)
        self.input_row.pack_start(self.confirm_button, False, False, 0)

        self.pack_start(self.label_row, False, False, 2)
        self.pack_start(self.input_row, False, False, 0)

        self.set_margin_left(10)

        self.on_address_selected = EventBroadcaster()

        self.confirm_button.connect("clicked",
                                    lambda *x: self.on_address_selected.notify(
                                        self.address_input.get_text()))
示例#2
0
    def __init__(self, toolbar_builder, debugger):
        signals = {
            "toolbar-run": lambda *x: self.run(),
            "toolbar-continue": lambda *x: self.cont(),
            "toolbar-stop": lambda *x: self.stop(),
            "toolbar-pause": lambda *x: self.pause(),
            "toolbar-step-over": lambda *x: self.step_over(),
            "toolbar-step-in": lambda *x: self.step_in(),
            "toolbar-step-out": lambda *x: self.step_out()
        }

        toolbar_builder.connect_signals(signals)

        self.toolbar_builder = toolbar_builder
        self.toolbar = toolbar_builder.get_object("toolbar")
        self.debugger = debugger
        self.debugger.on_process_state_changed.subscribe(
            self._handle_process_state_change)
        self.debugger.on_debugger_state_changed.subscribe(
            self._handle_debugger_state_change)

        self.grp_halt_control = ["stop", "pause"]
        self.grp_step = ["continue", "step_over", "step_in", "step_out"]

        self.on_run_process = EventBroadcaster()
示例#3
0
 def __init__(self, debugger, file, *args):
     self.debugger = debugger
     self.file = os.path.abspath(file)
     self.args = args
     self.parent_thread = None
     self.on_signal = EventBroadcaster()
     self.msg_queue = Queue.Queue()
     self.child_pid = None
     self.last_signal = None
示例#4
0
    def __init__(self, canvas, **properties):
        """
        @type canvas: drawing.canvas.Canvas
        """
        self.canvas = canvas

        self._position = self._parse_property(properties, "position",
                                              Vector(0, 0), Vector.vectorize)
        """@type _position: drawing.vector.Vector"""
        self._margin = self._parse_property(properties, "margin",
                                            Margin.all(0))
        """@type _margin: drawing.geometry.Margin"""
        self._padding = self._parse_property(properties, "padding",
                                             Padding.all(0))
        """@type _padding: drawing.geometry.Padding"""
        self._request_size = self._parse_property(properties, "size",
                                                  Size(-1, -1), Size.make_size)
        """@type _request_size: drawing.size.Size"""
        self._min_size = self._parse_property(properties, "min_size",
                                              Size(0, 0), Size.make_size)
        """@type _min_size: drawing.size.Size"""
        self._max_size = self._parse_property(properties, "max_size",
                                              Size(999, 999), Size.make_size)
        """@type _max_size: drawing.size.Size"""
        self.bg_color = self._parse_property(properties, "bg_color",
                                             Drawable.get_default_bg_color(),
                                             Color.make_color)
        """@type bg_color: drawing.drawable.Color"""
        self.name = self._parse_property(properties, "name", "")
        """@type name: str"""

        self.parent = None
        """@type parent: Drawable"""
        self.children = []
        self._visible = True

        self.click_handler = ClickHandler(self)

        self.on_mouse_click = EventBroadcaster()
        self.on_mouse_enter = EventBroadcaster()
        self.on_mouse_leave = EventBroadcaster()

        self.on_mouse_click.subscribe(self.handle_mouse_click)
        self.on_mouse_enter.subscribe(self.handle_mouse_enter)
        self.on_mouse_enter.subscribe(self.handle_tooltip_start)
        self.on_mouse_leave.subscribe(self.handle_mouse_leave)
        self.on_mouse_leave.subscribe(self.handle_tooltip_end)

        self.canvas.register_drawable(self)

        self.cached_rect = None
示例#5
0
    def __init__(self):
        super(Canvas, self).__init__()

        self.set_hexpand(True)
        self.set_vexpand(True)

        self.bg_color = Color(0.8, 0.8, 0.8, 1.0)

        self.add_events(Gdk.EventMask.POINTER_MOTION_MASK)
        self.connect("draw", lambda canvas, cr: self._handle_draw(cr))
        self.connect(
            "button-press-event",
            lambda widget, button_event: self._handle_press(
                button_event, True))
        self.connect(
            "button-release-event",
            lambda widget, button_event: self._handle_press(
                button_event, False))
        self.connect(
            "motion-notify-event",
            lambda widget, move_event: self._handle_mouse_move(move_event))
        self.connect(
            "scroll-event", lambda widget, scroll_event: self.
            _handle_mouse_scroll(scroll_event))

        self.mouse_data = MouseData(MouseButtonState.Up, MouseButtonState.Up,
                                    Vector(0, 0))
        self.translation_handler = TranslationHandler(self)

        self.zoom = 1.0
        self.zoom_limits = (0.5, 2.0)
        self.translation = Vector(0, 0)
        self.cr = None
        """@type cr: cairo.Context"""

        self.drawables = []
        """@type drawables: list of drawable.Drawable"""
        self.drawable_registry = []
        """@type drawable_registry: list of drawable.Drawable"""

        self.tooltip_drawable = None
        self.first_draw = True

        self.draw_scheduler = LayeredDrawScheduler(3)
        self.drag_manager = DragManager(self)

        self.on_load_start = EventBroadcaster()
        self.on_load_end = EventBroadcaster()

        self.redraw()
示例#6
0
    def __init__(self, debugger):
        super(SourceManager, self).__init__()

        self.debugger = debugger

        self.popup_enable()

        self.on_breakpoint_changed = EventBroadcaster()
        self.on_symbol_hover = EventBroadcaster()
        self.on_symbol_hover.subscribe(self._handle_symbol_hover)
        self.on_breakpoint_changed.subscribe(self._handle_breakpoint_change)

        self.debugger.on_process_state_changed.subscribe(
            self._handle_process_state_change)
        self.debugger.on_frame_changed.subscribe(self._handle_frame_change)
示例#7
0
    def __init__(self, debugger):
        super(SourceManager, self).__init__()

        self.debugger = debugger

        self.popup_enable()

        self.on_breakpoint_changed = EventBroadcaster()
        self.on_symbol_hover = EventBroadcaster()
        self.on_symbol_hover.subscribe(self._handle_symbol_hover)
        self.on_breakpoint_changed.subscribe(self._handle_breakpoint_change)

        self.debugger.on_process_state_changed.subscribe(
            self._handle_process_state_change)
        self.debugger.on_frame_changed.subscribe(self._handle_frame_change)
    def __init__(self, toolbar_builder, debugger):
        signals = {
            "toolbar-run": lambda *x: self.run(),
            "toolbar-continue": lambda *x: self.cont(),
            "toolbar-stop": lambda *x: self.stop(),
            "toolbar-pause": lambda *x: self.pause(),
            "toolbar-step-over": lambda *x: self.step_over(),
            "toolbar-step-in": lambda *x: self.step_in(),
            "toolbar-step-out": lambda *x: self.step_out()
        }

        toolbar_builder.connect_signals(signals)

        self.toolbar_builder = toolbar_builder
        self.toolbar = toolbar_builder.get_object("toolbar")
        self.debugger = debugger
        self.debugger.on_process_state_changed.subscribe(
            self._handle_process_state_change)
        self.debugger.on_debugger_state_changed.subscribe(
            self._handle_debugger_state_change)

        self.grp_halt_control = ["stop", "pause"]
        self.grp_step = ["continue", "step_over", "step_in", "step_out"]

        self.on_run_process = EventBroadcaster()
示例#9
0
    def __init__(self, debugger, language="cpp"):
        """
        @type debugger: debugger.mi.MiDebugger
        @type language: str
        """
        self.buffer = GtkSource.Buffer()
        super(SourceEditor, self).__init__(buffer=self.get_buffer())

        self.debugger = debugger

        self.start_undoable()

        self.set_language(language)
        self.get_buffer().set_highlight_syntax(True)
        self.get_buffer().set_highlight_matching_brackets(True)
        self.set_editable(False)

        self.gutter_renderer = BreakpointRenderer(
            self, paths.get_resource("img/circle.png"),
            paths.get_resource("img/arrow.png"))
        gutter = self.get_gutter(Gtk.TextWindowType.LEFT)
        gutter.insert(self.gutter_renderer, 0)

        self.stop_undoable()

        self.set_show_line_numbers(True)
        self.set_highlight_current_line(True)
        self.set_show_right_margin(True)
        self.set_right_margin_position(80)

        self.file = None
        self.on_breakpoint_changed = EventBroadcaster()

        self.exec_line = None
        self.bp_lines = set()

        self.analyser = SourceAnalyzer()
        self.connect("motion-notify-event",
                     lambda widget, event: self._handle_mouse_move(event))
        self.connect("button-press-event",
                     lambda widget, event: self._handle_mouse_click(event))
        self.on_symbol_hover = EventBroadcaster()

        self.debugger.breakpoint_manager.on_breakpoint_changed.subscribe(
            self._handle_model_breakpoint_change)
        self.breakpoint_lines = []
示例#10
0
class ValueEntry(Gtk.Frame):
    @require_gui_thread
    def __init__(self, title, text):
        Gtk.Frame.__init__(self)

        self.set_label(title)
        self.set_label_align(0.0, 0.0)

        self.box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
        self.box.set_margin_bottom(5)
        self.box.set_margin_left(2)
        self.text_entry = Gtk.Entry()
        self.text_entry.set_text(text)
        self.confirm_button = Gtk.Button(label="Set")

        self.get_style_context().add_class("value-entry")

        self.box.pack_start(self.text_entry, False, False, 0)
        self.box.pack_start(self.confirm_button, False, False, 5)
        self.add(self.box)
        self.show_all()

        self.confirm_button.connect("clicked",
                                    lambda btn: self._handle_confirm_click())

        self.on_value_entered = EventBroadcaster()

    @require_gui_thread
    def set_value(self, value):
        """
        @type value: str
        """
        self.text_entry.set_text(value)

    def _handle_confirm_click(self):
        value = self.text_entry.get_text()
        self.set_value("")

        self.on_value_entered.notify(value)
        self.hide()
示例#11
0
    def __init__(self, title, text):
        Gtk.Frame.__init__(self)

        self.set_label(title)
        self.set_label_align(0.0, 0.0)

        self.box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
        self.box.set_margin_bottom(5)
        self.box.set_margin_left(2)
        self.text_entry = Gtk.Entry()
        self.text_entry.set_text(text)
        self.confirm_button = Gtk.Button(label="Set")

        self.get_style_context().add_class("value-entry")

        self.box.pack_start(self.text_entry, False, False, 0)
        self.box.pack_start(self.confirm_button, False, False, 5)
        self.add(self.box)
        self.show_all()

        self.confirm_button.connect("clicked",
                                    lambda btn: self._handle_confirm_click())

        self.on_value_entered = EventBroadcaster()
示例#12
0
    def __init__(self, debugger, language="cpp"):
        """
        @type debugger: debugger.mi.MiDebugger
        @type language: str
        """
        self.buffer = GtkSource.Buffer()
        super(SourceEditor, self).__init__(buffer=self.get_buffer())

        self.debugger = debugger

        self.start_undoable()

        self.set_language(language)
        self.get_buffer().set_highlight_syntax(True)
        self.get_buffer().set_highlight_matching_brackets(True)
        self.set_editable(False)

        self.gutter_renderer = BreakpointRenderer(self,
                                                  paths.get_resource(
                                                      "img/circle.png"),
                                                  paths.get_resource(
                                                      "img/arrow.png"))
        gutter = self.get_gutter(Gtk.TextWindowType.LEFT)
        gutter.insert(self.gutter_renderer, 0)

        self.stop_undoable()

        self.set_show_line_numbers(True)
        self.set_highlight_current_line(True)
        self.set_show_right_margin(True)
        self.set_right_margin_position(80)

        self.file = None
        self.on_breakpoint_changed = EventBroadcaster()

        self.exec_line = None
        self.bp_lines = set()

        self.analyser = SourceAnalyzer()
        self.connect("motion-notify-event",
                     lambda widget, event: self._handle_mouse_move(event))
        self.connect("button-press-event",
                     lambda widget, event: self._handle_mouse_click(event))
        self.on_symbol_hover = EventBroadcaster()

        self.debugger.breakpoint_manager.on_breakpoint_changed.subscribe(
            self._handle_model_breakpoint_change)
        self.breakpoint_lines = []
示例#13
0
    def __init__(self, canvas, **properties):
        """
        @type canvas: drawing.canvas.Canvas
        """
        self.canvas = canvas

        self._position = self._parse_property(properties, "position",
                                              Vector(0, 0), Vector.vectorize)
        """@type _position: drawing.vector.Vector"""
        self._margin = self._parse_property(properties, "margin",
                                            Margin.all(0))
        """@type _margin: drawing.geometry.Margin"""
        self._padding = self._parse_property(properties, "padding",
                                             Padding.all(0))
        """@type _padding: drawing.geometry.Padding"""
        self._request_size = self._parse_property(properties, "size",
                                                  Size(-1, -1), Size.make_size)
        """@type _request_size: drawing.size.Size"""
        self._min_size = self._parse_property(properties, "min_size",
                                              Size(0, 0), Size.make_size)
        """@type _min_size: drawing.size.Size"""
        self._max_size = self._parse_property(properties, "max_size",
                                              Size(999, 999), Size.make_size)
        """@type _max_size: drawing.size.Size"""
        self.bg_color = self._parse_property(properties, "bg_color",
                                             Drawable.get_default_bg_color(),
                                             Color.make_color)
        """@type bg_color: drawing.drawable.Color"""
        self.name = self._parse_property(properties, "name", "")
        """@type name: str"""

        self.parent = None
        """@type parent: Drawable"""
        self.children = []
        self._visible = True

        self.click_handler = ClickHandler(self)

        self.on_mouse_click = EventBroadcaster()
        self.on_mouse_enter = EventBroadcaster()
        self.on_mouse_leave = EventBroadcaster()

        self.on_mouse_click.subscribe(self.handle_mouse_click)
        self.on_mouse_enter.subscribe(self.handle_mouse_enter)
        self.on_mouse_enter.subscribe(self.handle_tooltip_start)
        self.on_mouse_leave.subscribe(self.handle_mouse_leave)
        self.on_mouse_leave.subscribe(self.handle_tooltip_end)

        self.canvas.register_drawable(self)

        self.cached_rect = None
示例#14
0
class AddressInput(Gtk.Box):
    def __init__(self):
        Gtk.Box.__init__(self)

        self.set_orientation(Gtk.Orientation.VERTICAL)

        self.label_row = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)

        self.label = Gtk.Label().new("Hex address or expression")
        self.label_row.pack_start(self.label, False, False, 0)

        self.input_row = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)

        self.address_input = Gtk.Entry()
        self.address_input.set_editable(True)

        self.confirm_button = Gtk.Button()
        self.confirm_button.set_label("Load")

        self.input_row.pack_start(self.address_input, False, False, 0)
        self.input_row.pack_start(self.confirm_button, False, False, 0)

        self.pack_start(self.label_row, False, False, 2)
        self.pack_start(self.input_row, False, False, 0)

        self.set_margin_left(10)

        self.on_address_selected = EventBroadcaster()

        self.confirm_button.connect("clicked",
                                    lambda *x: self.on_address_selected.notify(
                                        self.address_input.get_text()))

    def set_enabled(self, value):
        """
        Sets whether the input should be enabled.
        @type value: bool
        """
        self.confirm_button.set_sensitive(value)
        self.address_input.set_sensitive(value)
示例#15
0
class ToolbarManager(object):
    def __init__(self, toolbar_builder, debugger):
        signals = {
            "toolbar-run": lambda *x: self.run(),
            "toolbar-continue": lambda *x: self.cont(),
            "toolbar-stop": lambda *x: self.stop(),
            "toolbar-pause": lambda *x: self.pause(),
            "toolbar-step-over": lambda *x: self.step_over(),
            "toolbar-step-in": lambda *x: self.step_in(),
            "toolbar-step-out": lambda *x: self.step_out()
        }

        toolbar_builder.connect_signals(signals)

        self.toolbar_builder = toolbar_builder
        self.toolbar = toolbar_builder.get_object("toolbar")
        self.debugger = debugger
        self.debugger.on_process_state_changed.subscribe(
            self._handle_process_state_change)
        self.debugger.on_debugger_state_changed.subscribe(
            self._handle_debugger_state_change)

        self.grp_halt_control = ["stop", "pause"]
        self.grp_step = ["continue", "step_over", "step_in", "step_out"]

        self.on_run_process = EventBroadcaster()

    @require_gui_thread
    def _get_items(self):
        return [self.toolbar.get_nth_item(i)
                for i in xrange(0, self.toolbar.get_n_items())]

    def _state_exited(self):
        self._change_grp_state(self.grp_halt_control, False)
        self._change_grp_state(self.grp_step, False)
        self._change_state("run", True)

    def _state_stopped(self):
        self._change_grp_state(self.grp_halt_control, False)
        self._change_grp_state(self.grp_step, True)

        self._change_state("stop", True)

    def _state_running(self):
        self._change_grp_state(self.grp_halt_control, True)
        self._change_grp_state(self.grp_step, False)
        self._change_state("run", False)

    def _handle_process_state_change(self, state, event_data):
        if state == ProcessState.Exited:
            self._state_exited()
        elif state == ProcessState.Stopped:
            self._state_stopped()
        elif state == ProcessState.Running:
            self._state_running()

    def _handle_debugger_state_change(self, state, old_value):
        if (state.is_set(DebuggerState.BinaryLoaded) and
                not state.is_set(DebuggerState.Running)):
            self._change_state("run", True)
        else:
            self._change_state("run", False)

    def _change_state(self, item_name, sensitive=True):
        run_on_gui(self._change_state_ui, item_name, sensitive)

    def _change_grp_state(self, group, sensitive=True):
        for item in group:
            self._change_state(item, sensitive)

    @require_gui_thread
    def _change_state_ui(self, item_name, sensitive=True):
        item = self.toolbar_builder.get_object(item_name)
        item.set_sensitive(sensitive)

    def run(self):
        self.on_run_process.notify()

    def cont(self):
        self.debugger.exec_continue()

    def stop(self):
        self.debugger.quit_program()

    def pause(self):
        self.debugger.exec_pause()

    def step_over(self):
        self.debugger.exec_step_over()

    def step_in(self):
        self.debugger.exec_step_in()

    def step_out(self):
        self.debugger.exec_step_out()
示例#16
0
class ProgramRunner(object):
    def __init__(self, debugger, file, *args):
        self.debugger = debugger
        self.file = os.path.abspath(file)
        self.args = args
        self.parent_thread = None
        self.on_signal = EventBroadcaster()
        self.msg_queue = Queue.Queue()
        self.child_pid = None
        self.last_signal = None

    def run(self):
        assert not self.parent_thread

        self.parent_thread = threading.Thread(target=self._start_process)
        self.parent_thread.start()

    def exec_step_single(self):
        self._add_queue_command("step-single")

    def exec_continue(self):
        self._add_queue_command("continue")

    def exec_interrupt(self):
        try:
            os.kill(self.child_pid, signal.SIGUSR1)
            return True
        except:
            return False

    def exec_kill(self):
        try:
            os.kill(self.child_pid, signal.SIGKILL)
            return True
        except:
            return False

    def _add_queue_command(self, cmd):
        self.msg_queue.put(cmd)

    def _start_process(self):
        child_pid = os.fork()

        if child_pid:
            self.child_pid = child_pid
            self._parent()
        else:
            self._child()

    def _child(self):
        if ptrace.ptrace(ptrace.PTRACE_TRACEME) < 0:
            raise Exception()

        os.execl(self.file, self.file, *self.args)
        exit(0)

    def _parent(self):
        try:
            while True:
                pid, status = os.waitpid(self.child_pid, os.WNOHANG)

                if pid != 0:
                    self._handle_child_status(status)

                try:
                    command = self.msg_queue.get(True, 0.1)
                    self._handle_command(self.child_pid, status, command)
                except Queue.Empty:
                    pass
                except:
                    traceback.print_exc()
        except OSError:
            self.on_signal.notify(ProcessState.Exited)
        except ProcessExitException:
            pass
        except:
            traceback.print_exc()

        self.child_pid = None
        self.parent_thread = None

    def _handle_child_status(self, status):
        if os.WIFSTOPPED(status):
            self._on_stop(status)
        elif os.WIFEXITED(status):
            self.on_signal.notify(ProcessState.Exited, os.WTERMSIG(status),
                                  os.WEXITSTATUS(status))
            raise ProcessExitException()

    def _handle_command(self, pid, status, command):
        if command == "continue":
            self._do_continue(pid)
        elif command == "step-single":
            self._do_step_single(pid)

    def _on_stop(self, status):
        self.last_signal = os.WSTOPSIG(status)
        self.debugger.breakpoint_manager.set_breakpoints(self.child_pid)

        self.on_signal.notify(ProcessState.Stopped, self.last_signal)

    def _continue_after_breakpoint(self, exec_continue):
        pid = self.child_pid
        regs = ptrace.ptrace_getregs(pid)
        orig_address = regs.eip - 1
        if self.debugger.breakpoint_manager.has_breakpoint_for_address(
                orig_address):
            self.debugger.breakpoint_manager.restore_instruction(
                pid, orig_address)
            regs.eip -= 1
            assert ptrace.ptrace_setregs(pid, regs)
            self._do_step_single(pid)
            pid, status = os.waitpid(pid, 0)
            self.debugger.breakpoint_manager.set_breakpoints(pid)

            if exec_continue:
                self.exec_continue()
            else:
                self._handle_child_status(status)
            return True
        else:
            return False

    def _do_continue(self, pid):
        if self.last_signal == 5:  # sigtrap
            if self._continue_after_breakpoint(True):
                return

        ptrace.ptrace(ptrace.PTRACE_CONT, pid)

    def _do_step_single(self, pid):
        if self.last_signal == 5:  # sigtrap
            if self._continue_after_breakpoint(False):
                return

        ptrace.ptrace(ptrace.PTRACE_SINGLESTEP, pid)
示例#17
0
class SourceManager(Gtk.Notebook):
    def __init__(self, debugger):
        super(SourceManager, self).__init__()

        self.debugger = debugger

        self.popup_enable()

        self.on_breakpoint_changed = EventBroadcaster()
        self.on_symbol_hover = EventBroadcaster()
        self.on_symbol_hover.subscribe(self._handle_symbol_hover)
        self.on_breakpoint_changed.subscribe(self._handle_breakpoint_change)

        self.debugger.on_process_state_changed.subscribe(
            self._handle_process_state_change)
        self.debugger.on_frame_changed.subscribe(self._handle_frame_change)

    def _handle_symbol_hover(self, source_editor, symbol):
        if self.debugger.process_state == ProcessState.Stopped:
            variable = self.debugger.variable_manager.get_variable(symbol)
            if variable and variable.address:
                source_editor.set_tooltip_text(str(variable))

    def _handle_breakpoint_change(self, location, change_type):
        if change_type == BreakpointChangeType.Create:
            self.debugger.breakpoint_manager.add_breakpoint(*location)
        elif change_type == BreakpointChangeType.Delete:
            self.debugger.breakpoint_manager.remove_breakpoint(*location)

    def _handle_process_state_change(self, state, event_data):
        if state == ProcessState.Stopped:
            self._set_debugger_location()
        elif state == ProcessState.Exited:
            run_on_gui(self.unset_exec_line)

    def _handle_frame_change(self, frame):
        """
        @param frame: frame.Frame
        """
        self._set_debugger_location()

    def _set_debugger_location(self):
        location = self.debugger.file_manager.get_current_location()

        Logger.debug("Stop at {0}".format(location))

        if location and location[0]:
            run_on_gui(self.set_exec_line, location[0], location[1])

    @require_gui_thread
    def _create_label(self, path, widget):
        content = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)

        label = Gtk.Label(os.path.basename(path))

        button = Gtk.Button()
        button.add(Gtk.Image.new_from_stock(Gtk.STOCK_CLOSE,
                                            Gtk.IconSize.MENU))
        button.set_relief(Gtk.ReliefStyle.NONE)
        button.set_focus_on_click(False)
        button.connect("clicked", lambda *x: self._close_tab(widget))

        event_box = Gtk.EventBox.new()
        event_box.add(label)
        event_box.connect(
            "button-press-event",
            lambda source, event: self._handle_tab_label_press(event, widget))

        content.pack_start(event_box, True, True, 0)
        content.pack_start(button, False, False, 0)
        content.show_all()

        return content

    @require_gui_thread
    def _close_tab(self, widget):
        widget.editor.on_breakpoint_changed.clear()

        self.remove_page(self.get_tabs().index(widget))

    @require_gui_thread
    def _add_tab(self, file_path):
        editor = SourceEditor(self.debugger)
        editor.set_content_from_file(file_path)
        editor.set_hexpand(True)
        editor.set_vexpand(True)
        editor.show_all()

        window = SourceWindow(editor)

        label = self._create_label(file_path, window)

        menu_label = Gtk.Label(label=file_path)
        menu_label.set_alignment(0, 0)

        index = self.append_page_menu(window, label, menu_label)

        if index != -1:
            self.select_tab(index)
            self.set_tab_reorderable(window, True)
            editor.on_breakpoint_changed.redirect(self.on_breakpoint_changed)
            editor.on_symbol_hover.redirect(self.on_symbol_hover)
            return editor
        else:
            return None

    @require_gui_thread
    def _handle_tab_label_press(self, event, window):
        """
        @type event: Gdk.EventButton
        @type window: SourceWindow
        """
        if (event.type == Gdk.EventType.BUTTON_PRESS and event.button == 2):
            self._close_tab(window)

    @require_gui_thread
    def get_tabs(self):
        return [self.get_nth_page(i) for i in xrange(0, self.get_n_pages())]

    @require_gui_thread
    def open_file(self, file_path):
        for index, tab in enumerate(self.get_tabs()):
            if tab.editor.file == file_path:
                self.select_tab(index)
                return tab.editor

        return self._add_tab(file_path)

    @require_gui_thread
    def set_exec_line(self, file_path, line_number):
        self.unset_exec_line()

        tab = self.open_file(file_path)
        tab.set_exec_line(line_number - 1)

    @require_gui_thread
    def unset_exec_line(self):
        for tab in self.get_tabs():
            tab.editor.unset_exec_line()

    @require_gui_thread
    def get_selected_editor(self):
        selected = self.get_current_page()

        if selected != -1:
            return self.get_nth_page(selected).editor
        else:
            return None

    @require_gui_thread
    def select_tab(self, index):
        self.set_current_page(index)
示例#18
0
class SourceEditor(GtkSource.View):
    @staticmethod
    def load_file(path):
        try:
            return open(path).read()
        except:
            return None

    def __init__(self, debugger, language="cpp"):
        """
        @type debugger: debugger.mi.MiDebugger
        @type language: str
        """
        self.buffer = GtkSource.Buffer()
        super(SourceEditor, self).__init__(buffer=self.get_buffer())

        self.debugger = debugger

        self.start_undoable()

        self.set_language(language)
        self.get_buffer().set_highlight_syntax(True)
        self.get_buffer().set_highlight_matching_brackets(True)
        self.set_editable(False)

        self.gutter_renderer = BreakpointRenderer(
            self, paths.get_resource("img/circle.png"),
            paths.get_resource("img/arrow.png"))
        gutter = self.get_gutter(Gtk.TextWindowType.LEFT)
        gutter.insert(self.gutter_renderer, 0)

        self.stop_undoable()

        self.set_show_line_numbers(True)
        self.set_highlight_current_line(True)
        self.set_show_right_margin(True)
        self.set_right_margin_position(80)

        self.file = None
        self.on_breakpoint_changed = EventBroadcaster()

        self.exec_line = None
        self.bp_lines = set()

        self.analyser = SourceAnalyzer()
        self.connect("motion-notify-event",
                     lambda widget, event: self._handle_mouse_move(event))
        self.connect("button-press-event",
                     lambda widget, event: self._handle_mouse_click(event))
        self.on_symbol_hover = EventBroadcaster()

        self.debugger.breakpoint_manager.on_breakpoint_changed.subscribe(
            self._handle_model_breakpoint_change)
        self.breakpoint_lines = []

    def _handle_model_breakpoint_change(self, breakpoint):
        """
        @type breakpoint: debugee.Breakpoint
        """
        self._refresh_breakpoints()

    def _refresh_breakpoints(self):
        lines = []

        if (self.file
                and self.debugger.state.is_set(DebuggerState.BinaryLoaded)
                and self.debugger.process_state != ProcessState.Running):
            for bp in self.debugger.breakpoint_manager.get_breakpoints():
                if os.path.abspath(bp.location) == os.path.abspath(self.file):
                    lines.append(bp.line - 1)

        self.breakpoint_lines = lines

    def _handle_mouse_move(self, event):
        x, y = self.window_to_buffer_coords(Gtk.TextWindowType.TEXT, event.x,
                                            event.y)
        iter = self.get_iter_at_location(x, y)
        line = iter.get_line() + 1
        column = iter.get_line_offset() + 1
        symbol = self.analyser.get_symbol_name(line, column)

        if symbol is not None:
            self.on_symbol_hover.notify(self, symbol)

    def _handle_mouse_click(self, event):
        if (event.type == Gdk.EventType.BUTTON_PRESS
                and self.get_window(Gtk.TextWindowType.LEFT) == event.window):
            x, y = self.window_to_buffer_coords(Gtk.TextWindowType.LEFT,
                                                event.x, event.y)
            iter = self.get_iter_at_location(x, y)

            if self.debugger.state.is_set(DebuggerState.BinaryLoaded):
                self.toggle_breakpoint(iter.get_line())

    def get_buffer(self):
        return self.buffer

    def get_file(self):
        return self.file

    def get_breakpoint_lines(self):
        return self.breakpoint_lines

    @require_gui_thread
    def toggle_breakpoint(self, line):
        self.debugger.breakpoint_manager.toggle_breakpoint(self.file, line + 1)

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def set_language(self, key):
        manager = GtkSource.LanguageManager()
        language = manager.get_language(key)

        self.start_undoable()
        self.get_buffer().set_language(language)
        self.stop_undoable()

    @require_gui_thread
    def start_undoable(self):
        self.get_buffer().begin_not_undoable_action()

    @require_gui_thread
    def stop_undoable(self):
        self.get_buffer().end_not_undoable_action()

    @require_gui_thread
    def set_content_from_file(self, path):
        content = SourceEditor.load_file(path)

        if content:
            self.file = path
            self.start_undoable()
            self.get_buffer().set_text(content)
            self.stop_undoable()
            self.analyser.set_file(path)
            self._refresh_breakpoints()
            self.gutter_renderer.queue_draw()  # show existing breakpoints

    @require_gui_thread
    def get_cursor_iter(self):
        cursor_rectangle = self.get_cursor_locations(None)[0]
        return self.get_iter_at_location(cursor_rectangle.x,
                                         cursor_rectangle.y)

    @require_gui_thread
    def get_current_column(self):
        return self.get_cursor_iter().get_line_offset()

    @require_gui_thread
    def get_current_line(self):
        return self.get_cursor_iter().get_line()

    @require_gui_thread
    def get_line_iters(self, line_number):
        start_line = self.get_buffer().get_iter_at_line(line_number)
        end_line = start_line.copy()
        end_line.forward_to_line_end()
        return (start_line, end_line)

    @require_gui_thread
    def set_exec_line(self, line_number):
        self.unset_exec_line()
        line_iters = self.get_line_iters(line_number)
        self.scroll_to_iter(line_iters[0], 0.0, True, 0.5, 0.5)
        self.exec_line = line_number

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def unset_exec_line(self):
        self.exec_line = None

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def undo(self):
        if self.get_buffer().can_undo():
            self.get_buffer().undo()
            return True
        else:
            return False

    @require_gui_thread
    def redo(self):
        if self.get_buffer().can_redo():
            self.get_buffer().redo()
            return True
        else:
            return False
示例#19
0
class SourceManager(Gtk.Notebook):
    def __init__(self, debugger):
        super(SourceManager, self).__init__()

        self.debugger = debugger

        self.popup_enable()

        self.on_breakpoint_changed = EventBroadcaster()
        self.on_symbol_hover = EventBroadcaster()
        self.on_symbol_hover.subscribe(self._handle_symbol_hover)
        self.on_breakpoint_changed.subscribe(self._handle_breakpoint_change)

        self.debugger.on_process_state_changed.subscribe(
            self._handle_process_state_change)
        self.debugger.on_frame_changed.subscribe(self._handle_frame_change)

    def _handle_symbol_hover(self, source_editor, symbol):
        if self.debugger.process_state == ProcessState.Stopped:
            variable = self.debugger.variable_manager.get_variable(symbol)
            if variable and variable.address:
                source_editor.set_tooltip_text(str(variable))

    def _handle_breakpoint_change(self, location, change_type):
        if change_type == BreakpointChangeType.Create:
            self.debugger.breakpoint_manager.add_breakpoint(*location)
        elif change_type == BreakpointChangeType.Delete:
            self.debugger.breakpoint_manager.remove_breakpoint(*location)

    def _handle_process_state_change(self, state, event_data):
        if state == ProcessState.Stopped:
            self._set_debugger_location()
        elif state == ProcessState.Exited:
            run_on_gui(self.unset_exec_line)

    def _handle_frame_change(self, frame):
        """
        @param frame: frame.Frame
        """
        self._set_debugger_location()

    def _set_debugger_location(self):
        location = self.debugger.file_manager.get_current_location()

        Logger.debug("Stop at {0}".format(location))

        if location and location[0]:
            run_on_gui(self.set_exec_line, location[0], location[1])

    @require_gui_thread
    def _create_label(self, path, widget):
        content = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)

        label = Gtk.Label(os.path.basename(path))

        button = Gtk.Button()
        button.add(Gtk.Image.new_from_stock(Gtk.STOCK_CLOSE,
                                            Gtk.IconSize.MENU))
        button.set_relief(Gtk.ReliefStyle.NONE)
        button.set_focus_on_click(False)
        button.connect("clicked", lambda *x: self._close_tab(widget))

        event_box = Gtk.EventBox.new()
        event_box.add(label)
        event_box.connect("button-press-event",
                          lambda source, event: self._handle_tab_label_press(
                              event, widget))

        content.pack_start(event_box, True, True, 0)
        content.pack_start(button, False, False, 0)
        content.show_all()

        return content

    @require_gui_thread
    def _close_tab(self, widget):
        widget.editor.on_breakpoint_changed.clear()

        self.remove_page(self.get_tabs().index(widget))

    @require_gui_thread
    def _add_tab(self, file_path):
        editor = SourceEditor(self.debugger)
        editor.set_content_from_file(file_path)
        editor.set_hexpand(True)
        editor.set_vexpand(True)
        editor.show_all()

        window = SourceWindow(editor)

        label = self._create_label(file_path, window)

        menu_label = Gtk.Label(label=file_path)
        menu_label.set_alignment(0, 0)

        index = self.append_page_menu(window, label, menu_label)

        if index != -1:
            self.select_tab(index)
            self.set_tab_reorderable(window, True)
            editor.on_breakpoint_changed.redirect(self.on_breakpoint_changed)
            editor.on_symbol_hover.redirect(self.on_symbol_hover)
            return editor
        else:
            return None

    @require_gui_thread
    def _handle_tab_label_press(self, event, window):
        """
        @type event: Gdk.EventButton
        @type window: SourceWindow
        """
        if (event.type == Gdk.EventType.BUTTON_PRESS and
                event.button == 2):
            self._close_tab(window)

    @require_gui_thread
    def get_tabs(self):
        return [self.get_nth_page(i) for i in xrange(0, self.get_n_pages())]

    @require_gui_thread
    def open_file(self, file_path):
        for index, tab in enumerate(self.get_tabs()):
            if tab.editor.file == file_path:
                self.select_tab(index)
                return tab.editor

        return self._add_tab(file_path)

    @require_gui_thread
    def set_exec_line(self, file_path, line_number):
        self.unset_exec_line()

        tab = self.open_file(file_path)
        tab.set_exec_line(line_number - 1)

    @require_gui_thread
    def unset_exec_line(self):
        for tab in self.get_tabs():
            tab.editor.unset_exec_line()

    @require_gui_thread
    def get_selected_editor(self):
        selected = self.get_current_page()

        if selected != -1:
            return self.get_nth_page(selected).editor
        else:
            return None

    @require_gui_thread
    def select_tab(self, index):
        self.set_current_page(index)
示例#20
0
class ToolbarManager(object):
    def __init__(self, toolbar_builder, debugger):
        signals = {
            "toolbar-run": lambda *x: self.run(),
            "toolbar-continue": lambda *x: self.cont(),
            "toolbar-stop": lambda *x: self.stop(),
            "toolbar-pause": lambda *x: self.pause(),
            "toolbar-step-over": lambda *x: self.step_over(),
            "toolbar-step-in": lambda *x: self.step_in(),
            "toolbar-step-out": lambda *x: self.step_out()
        }

        toolbar_builder.connect_signals(signals)

        self.toolbar_builder = toolbar_builder
        self.toolbar = toolbar_builder.get_object("toolbar")
        self.debugger = debugger
        self.debugger.on_process_state_changed.subscribe(
            self._handle_process_state_change)
        self.debugger.on_debugger_state_changed.subscribe(
            self._handle_debugger_state_change)

        self.grp_halt_control = ["stop", "pause"]
        self.grp_step = ["continue", "step_over", "step_in", "step_out"]

        self.on_run_process = EventBroadcaster()

    @require_gui_thread
    def _get_items(self):
        return [
            self.toolbar.get_nth_item(i)
            for i in xrange(0, self.toolbar.get_n_items())
        ]

    def _state_exited(self):
        self._change_grp_state(self.grp_halt_control, False)
        self._change_grp_state(self.grp_step, False)
        self._change_state("run", True)

    def _state_stopped(self):
        self._change_grp_state(self.grp_halt_control, False)
        self._change_grp_state(self.grp_step, True)

        self._change_state("stop", True)

    def _state_running(self):
        self._change_grp_state(self.grp_halt_control, True)
        self._change_grp_state(self.grp_step, False)
        self._change_state("run", False)

    def _handle_process_state_change(self, state, event_data):
        if state == ProcessState.Exited:
            self._state_exited()
        elif state == ProcessState.Stopped:
            self._state_stopped()
        elif state == ProcessState.Running:
            self._state_running()

    def _handle_debugger_state_change(self, state, old_value):
        if (state.is_set(DebuggerState.BinaryLoaded)
                and not state.is_set(DebuggerState.Running)):
            self._change_state("run", True)
        else:
            self._change_state("run", False)

    def _change_state(self, item_name, sensitive=True):
        run_on_gui(self._change_state_ui, item_name, sensitive)

    def _change_grp_state(self, group, sensitive=True):
        for item in group:
            self._change_state(item, sensitive)

    @require_gui_thread
    def _change_state_ui(self, item_name, sensitive=True):
        item = self.toolbar_builder.get_object(item_name)
        item.set_sensitive(sensitive)

    def run(self):
        self.on_run_process.notify()

    def cont(self):
        self.debugger.exec_continue()

    def stop(self):
        self.debugger.quit_program()

    def pause(self):
        self.debugger.exec_pause()

    def step_over(self):
        self.debugger.exec_step_over()

    def step_in(self):
        self.debugger.exec_step_in()

    def step_out(self):
        self.debugger.exec_step_out()
示例#21
0
class Drawable(object):
    @staticmethod
    def get_default_bg_color():
        return Color(0.5, 0.5, 0.5, 1.0)

    def __init__(self, canvas, **properties):
        """
        @type canvas: drawing.canvas.Canvas
        """
        self.canvas = canvas

        self._position = self._parse_property(properties, "position",
                                              Vector(0, 0), Vector.vectorize)
        """@type _position: drawing.vector.Vector"""
        self._margin = self._parse_property(properties, "margin",
                                            Margin.all(0))
        """@type _margin: drawing.geometry.Margin"""
        self._padding = self._parse_property(properties, "padding",
                                             Padding.all(0))
        """@type _padding: drawing.geometry.Padding"""
        self._request_size = self._parse_property(properties, "size",
                                                  Size(-1, -1), Size.make_size)
        """@type _request_size: drawing.size.Size"""
        self._min_size = self._parse_property(properties, "min_size",
                                              Size(0, 0), Size.make_size)
        """@type _min_size: drawing.size.Size"""
        self._max_size = self._parse_property(properties, "max_size",
                                              Size(999, 999), Size.make_size)
        """@type _max_size: drawing.size.Size"""
        self.bg_color = self._parse_property(properties, "bg_color",
                                             Drawable.get_default_bg_color(),
                                             Color.make_color)
        """@type bg_color: drawing.drawable.Color"""
        self.name = self._parse_property(properties, "name", "")
        """@type name: str"""

        self.parent = None
        """@type parent: Drawable"""
        self.children = []
        self._visible = True

        self.click_handler = ClickHandler(self)

        self.on_mouse_click = EventBroadcaster()
        self.on_mouse_enter = EventBroadcaster()
        self.on_mouse_leave = EventBroadcaster()

        self.on_mouse_click.subscribe(self.handle_mouse_click)
        self.on_mouse_enter.subscribe(self.handle_mouse_enter)
        self.on_mouse_enter.subscribe(self.handle_tooltip_start)
        self.on_mouse_leave.subscribe(self.handle_mouse_leave)
        self.on_mouse_leave.subscribe(self.handle_tooltip_end)

        self.canvas.register_drawable(self)

        self.cached_rect = None

    @property
    def visible(self):
        return self._visible

    @visible.setter
    def visible(self, value):
        self._visible = value
        self.invalidate()

    @property
    def margin(self):
        """
        @rtype: drawing.geometry.Margin
        """
        return self._margin

    @margin.setter
    def margin(self, value):
        """
        @type value: drawing.geometry.Margin
        """
        self._margin = value
        self.invalidate()

    @property
    def padding(self):
        """
        @rtype: drawing.geometry.Padding
        """
        return self._padding

    @padding.setter
    def padding(self, value):
        """
        @type value: drawing.geometry.Padding
        """
        self._padding = value
        self.invalidate()

    @property
    def request_size(self):
        """
        @rtype: drawing.size.Size
        """
        return self._request_size

    @request_size.setter
    def request_size(self, value):
        """
        @type value: drawing.size.Size
        """
        self._request_size = value
        self.invalidate()

    @property
    def min_size(self):
        """
        @rtype: drawing.size.Size
        """
        return self._min_size

    @min_size.setter
    def min_size(self, value):
        """
        @type value: drawing.size.Size
        """
        self._min_size = value
        self.invalidate()

    @property
    def max_size(self):
        """
        @rtype: drawing.size.Size
        """
        return self._max_size

    @max_size.setter
    def max_size(self, value):
        """
        @type value: drawing.size.Size
        """
        self._max_size = value
        self.invalidate()

    @property
    def position(self):
        """
        @rtype: drawing.vector.Vector
        """
        return self._position

    @position.setter
    def position(self, value):
        """
        @type value: drawing.vector.Vector
        """
        self._position = value.copy()
        self.cached_rect = None
        self.place_children()

    def toggle(self):
        self.visible = not self.visible

    def hide(self):
        self.visible = False

    def show(self):
        self.visible = True

    def get_content_size(self):
        raise NotImplementedError()

    def get_computed_size(self):
        content_size = self.get_content_size()

        width = self.request_size.width
        if width < 0:
            width = content_size.width

        height = self.request_size.height
        if height < 0:
            height = content_size.height

        if self.min_size.width >= 0:
            width = max((width, self.min_size.width))
        if self.min_size.height >= 0:
            height = max((height, self.min_size.height))

        if self.max_size.width >= 0:
            width = min((width, self.max_size.width))
        if self.max_size.height >= 0:
            height = min((height, self.max_size.height))

        return Size(width, height)

    def add_child(self, child):
        """
        @type child: Drawable
        """
        self.children.append(child)
        child.parent = self
        self.click_handler.propagate_handler(child.click_handler)
        self.invalidate()

    def add_children(self, children):
        """
        @type children: list of Drawable | tuple of Drawable
        """
        self.children += children
        for child in children:
            child.parent = self
            self.click_handler.propagate_handler(child.click_handler)

        if len(children) > 0:
            self.invalidate()

    def get_child_at(self, position):
        """
        @type position: vector.Vector
        @rtype: Drawable
        """
        for child in self.children:
            drawable = child.get_child_at(position)
            if drawable:
                return drawable
        if self.get_rect().is_point_inside(position):
            return self
        else:
            return None

    def handle_mouse_event(self, mouse_data):
        """
        @type mouse_data: drawing.mouse.MouseData
        """
        self.click_handler.handle_mouse_event(mouse_data)

    def handle_mouse_click(self, mouse_data):
        """
        @type mouse_data: drawing.mouse.MouseData
        """
        pass

    def handle_mouse_enter(self, mouse_data):
        """
        @type mouse_data: drawing.mouse.MouseData
        """
        pass

    def handle_mouse_leave(self, mouse_data):
        """
        @type mouse_data: drawing.mouse.MouseData
        """
        pass

    def handle_tooltip_start(self, mouse_data):
        """
        @type mouse_data: mouse.MouseData
        """
        tooltip = self.get_tooltip()

        if tooltip is not None:
            self.canvas.set_drawable_tooltip(self, tooltip)

    def handle_tooltip_end(self, mouse_data):
        """
        @type mouse_data: mouse.MouseData
        """
        self.canvas.set_drawable_tooltip(self, None)

    def handle_drag_cancel(self):
        pass

    def handle_drag_start(self):
        pass

    def handle_drag_end(self, target):
        """
        @type target: Drawable
        """
        pass

    def on_child_changed(self, child):
        """
        @type child: Drawable
        """
        self.invalidate()

    def get_tooltip(self):
        """
        @rtype: str | None
        """
        return None

    def get_rect(self):
        if self.cached_rect:
            return self.cached_rect

        if not self.visible:
            return RectangleBBox(self.position)

        self.cached_rect = RectangleBBox(self.position,
                                         self.get_computed_size() +
                                         self.padding.to_size())
        return self.cached_rect

    def get_center(self):
        """
        Returns the center of the drawable.
        @rtype: canvas.vector.Vector
        """
        rect = self.get_rect()
        x = rect.x + rect.width / 2.0
        y = rect.y + rect.height / 2.0
        return Vector(x, y)

    def place_children(self):
        pass

    def draw(self):
        if self.visible:
            for child in self.children:
                child.draw()

    def invalidate(self):
        """
        Invalidates this drawable, placing it's children and sending it's
        parent a message that it has changd.
        """
        self.cached_rect = None
        if self.parent:
            self.parent.on_child_changed(self)
        self.place_children()

    def _parse_property(self, properties, key, default, modifier=None):
        """
        Parses property from property dictionary.
        Modifier modifies the resulting value.
        @type properties: dict
        @type key: str
        @type default: object
        @type modifier: function
        @rtype: object
        """
        if key in properties:
            if modifier:
                return modifier(properties[key])
            else:
                return properties[key]
        else:
            return default
示例#22
0
class Drawable(object):
    @staticmethod
    def get_default_bg_color():
        return Color(0.5, 0.5, 0.5, 1.0)

    def __init__(self, canvas, **properties):
        """
        @type canvas: drawing.canvas.Canvas
        """
        self.canvas = canvas

        self._position = self._parse_property(properties, "position",
                                              Vector(0, 0), Vector.vectorize)
        """@type _position: drawing.vector.Vector"""
        self._margin = self._parse_property(properties, "margin",
                                            Margin.all(0))
        """@type _margin: drawing.geometry.Margin"""
        self._padding = self._parse_property(properties, "padding",
                                             Padding.all(0))
        """@type _padding: drawing.geometry.Padding"""
        self._request_size = self._parse_property(properties, "size",
                                                  Size(-1, -1), Size.make_size)
        """@type _request_size: drawing.size.Size"""
        self._min_size = self._parse_property(properties, "min_size",
                                              Size(0, 0), Size.make_size)
        """@type _min_size: drawing.size.Size"""
        self._max_size = self._parse_property(properties, "max_size",
                                              Size(999, 999), Size.make_size)
        """@type _max_size: drawing.size.Size"""
        self.bg_color = self._parse_property(properties, "bg_color",
                                             Drawable.get_default_bg_color(),
                                             Color.make_color)
        """@type bg_color: drawing.drawable.Color"""
        self.name = self._parse_property(properties, "name", "")
        """@type name: str"""

        self.parent = None
        """@type parent: Drawable"""
        self.children = []
        self._visible = True

        self.click_handler = ClickHandler(self)

        self.on_mouse_click = EventBroadcaster()
        self.on_mouse_enter = EventBroadcaster()
        self.on_mouse_leave = EventBroadcaster()

        self.on_mouse_click.subscribe(self.handle_mouse_click)
        self.on_mouse_enter.subscribe(self.handle_mouse_enter)
        self.on_mouse_enter.subscribe(self.handle_tooltip_start)
        self.on_mouse_leave.subscribe(self.handle_mouse_leave)
        self.on_mouse_leave.subscribe(self.handle_tooltip_end)

        self.canvas.register_drawable(self)

        self.cached_rect = None

    @property
    def visible(self):
        return self._visible

    @visible.setter
    def visible(self, value):
        self._visible = value
        self.invalidate()

    @property
    def margin(self):
        """
        @rtype: drawing.geometry.Margin
        """
        return self._margin

    @margin.setter
    def margin(self, value):
        """
        @type value: drawing.geometry.Margin
        """
        self._margin = value
        self.invalidate()

    @property
    def padding(self):
        """
        @rtype: drawing.geometry.Padding
        """
        return self._padding

    @padding.setter
    def padding(self, value):
        """
        @type value: drawing.geometry.Padding
        """
        self._padding = value
        self.invalidate()

    @property
    def request_size(self):
        """
        @rtype: drawing.size.Size
        """
        return self._request_size

    @request_size.setter
    def request_size(self, value):
        """
        @type value: drawing.size.Size
        """
        self._request_size = value
        self.invalidate()

    @property
    def min_size(self):
        """
        @rtype: drawing.size.Size
        """
        return self._min_size

    @min_size.setter
    def min_size(self, value):
        """
        @type value: drawing.size.Size
        """
        self._min_size = value
        self.invalidate()

    @property
    def max_size(self):
        """
        @rtype: drawing.size.Size
        """
        return self._max_size

    @max_size.setter
    def max_size(self, value):
        """
        @type value: drawing.size.Size
        """
        self._max_size = value
        self.invalidate()

    @property
    def position(self):
        """
        @rtype: drawing.vector.Vector
        """
        return self._position

    @position.setter
    def position(self, value):
        """
        @type value: drawing.vector.Vector
        """
        self._position = value.copy()
        self.cached_rect = None
        self.place_children()

    def toggle(self):
        self.visible = not self.visible

    def hide(self):
        self.visible = False

    def show(self):
        self.visible = True

    def get_content_size(self):
        raise NotImplementedError()

    def get_computed_size(self):
        content_size = self.get_content_size()

        width = self.request_size.width
        if width < 0:
            width = content_size.width

        height = self.request_size.height
        if height < 0:
            height = content_size.height

        if self.min_size.width >= 0:
            width = max((width, self.min_size.width))
        if self.min_size.height >= 0:
            height = max((height, self.min_size.height))

        if self.max_size.width >= 0:
            width = min((width, self.max_size.width))
        if self.max_size.height >= 0:
            height = min((height, self.max_size.height))

        return Size(width, height)

    def add_child(self, child):
        """
        @type child: Drawable
        """
        self.children.append(child)
        child.parent = self
        self.click_handler.propagate_handler(child.click_handler)
        self.invalidate()

    def add_children(self, children):
        """
        @type children: list of Drawable | tuple of Drawable
        """
        self.children += children
        for child in children:
            child.parent = self
            self.click_handler.propagate_handler(child.click_handler)

        if len(children) > 0:
            self.invalidate()

    def get_child_at(self, position):
        """
        @type position: vector.Vector
        @rtype: Drawable
        """
        for child in self.children:
            drawable = child.get_child_at(position)
            if drawable:
                return drawable
        if self.get_rect().is_point_inside(position):
            return self
        else:
            return None

    def handle_mouse_event(self, mouse_data):
        """
        @type mouse_data: drawing.mouse.MouseData
        """
        self.click_handler.handle_mouse_event(mouse_data)

    def handle_mouse_click(self, mouse_data):
        """
        @type mouse_data: drawing.mouse.MouseData
        """
        pass

    def handle_mouse_enter(self, mouse_data):
        """
        @type mouse_data: drawing.mouse.MouseData
        """
        pass

    def handle_mouse_leave(self, mouse_data):
        """
        @type mouse_data: drawing.mouse.MouseData
        """
        pass

    def handle_tooltip_start(self, mouse_data):
        """
        @type mouse_data: mouse.MouseData
        """
        tooltip = self.get_tooltip()

        if tooltip is not None:
            self.canvas.set_drawable_tooltip(self, tooltip)

    def handle_tooltip_end(self, mouse_data):
        """
        @type mouse_data: mouse.MouseData
        """
        self.canvas.set_drawable_tooltip(self, None)

    def handle_drag_cancel(self):
        pass

    def handle_drag_start(self):
        pass

    def handle_drag_end(self, target):
        """
        @type target: Drawable
        """
        pass

    def on_child_changed(self, child):
        """
        @type child: Drawable
        """
        self.invalidate()

    def get_tooltip(self):
        """
        @rtype: str | None
        """
        return None

    def get_rect(self):
        if self.cached_rect:
            return self.cached_rect

        if not self.visible:
            return RectangleBBox(self.position)

        self.cached_rect = RectangleBBox(
            self.position,
            self.get_computed_size() + self.padding.to_size())
        return self.cached_rect

    def get_center(self):
        """
        Returns the center of the drawable.
        @rtype: canvas.vector.Vector
        """
        rect = self.get_rect()
        x = rect.x + rect.width / 2.0
        y = rect.y + rect.height / 2.0
        return Vector(x, y)

    def place_children(self):
        pass

    def draw(self):
        if self.visible:
            for child in self.children:
                child.draw()

    def invalidate(self):
        """
        Invalidates this drawable, placing it's children and sending it's
        parent a message that it has changd.
        """
        self.cached_rect = None
        if self.parent:
            self.parent.on_child_changed(self)
        self.place_children()

    def _parse_property(self, properties, key, default, modifier=None):
        """
        Parses property from property dictionary.
        Modifier modifies the resulting value.
        @type properties: dict
        @type key: str
        @type default: object
        @type modifier: function
        @rtype: object
        """
        if key in properties:
            if modifier:
                return modifier(properties[key])
            else:
                return properties[key]
        else:
            return default
示例#23
0
class SourceEditor(GtkSource.View):
    @staticmethod
    def load_file(path):
        try:
            return open(path).read()
        except:
            return None

    def __init__(self, debugger, language="cpp"):
        """
        @type debugger: debugger.mi.MiDebugger
        @type language: str
        """
        self.buffer = GtkSource.Buffer()
        super(SourceEditor, self).__init__(buffer=self.get_buffer())

        self.debugger = debugger

        self.start_undoable()

        self.set_language(language)
        self.get_buffer().set_highlight_syntax(True)
        self.get_buffer().set_highlight_matching_brackets(True)
        self.set_editable(False)

        self.gutter_renderer = BreakpointRenderer(self,
                                                  paths.get_resource(
                                                      "img/circle.png"),
                                                  paths.get_resource(
                                                      "img/arrow.png"))
        gutter = self.get_gutter(Gtk.TextWindowType.LEFT)
        gutter.insert(self.gutter_renderer, 0)

        self.stop_undoable()

        self.set_show_line_numbers(True)
        self.set_highlight_current_line(True)
        self.set_show_right_margin(True)
        self.set_right_margin_position(80)

        self.file = None
        self.on_breakpoint_changed = EventBroadcaster()

        self.exec_line = None
        self.bp_lines = set()

        self.analyser = SourceAnalyzer()
        self.connect("motion-notify-event",
                     lambda widget, event: self._handle_mouse_move(event))
        self.connect("button-press-event",
                     lambda widget, event: self._handle_mouse_click(event))
        self.on_symbol_hover = EventBroadcaster()

        self.debugger.breakpoint_manager.on_breakpoint_changed.subscribe(
            self._handle_model_breakpoint_change)
        self.breakpoint_lines = []

    def _handle_model_breakpoint_change(self, breakpoint):
        """
        @type breakpoint: debugee.Breakpoint
        """
        self._refresh_breakpoints()

    def _refresh_breakpoints(self):
        lines = []

        if (self.file and
                self.debugger.state.is_set(DebuggerState.BinaryLoaded) and
                self.debugger.process_state != ProcessState.Running):
            for bp in self.debugger.breakpoint_manager.get_breakpoints():
                if os.path.abspath(bp.location) == os.path.abspath(self.file):
                    lines.append(bp.line - 1)

        self.breakpoint_lines = lines

    def _handle_mouse_move(self, event):
        x, y = self.window_to_buffer_coords(Gtk.TextWindowType.TEXT,
                                            event.x,
                                            event.y)
        iter = self.get_iter_at_location(x, y)
        line = iter.get_line() + 1
        column = iter.get_line_offset() + 1
        symbol = self.analyser.get_symbol_name(line, column)

        if symbol is not None:
            self.on_symbol_hover.notify(self, symbol)

    def _handle_mouse_click(self, event):
        if (event.type == Gdk.EventType.BUTTON_PRESS and
                self.get_window(Gtk.TextWindowType.LEFT) == event.window):
            x, y = self.window_to_buffer_coords(Gtk.TextWindowType.LEFT,
                                                event.x,
                                                event.y)
            iter = self.get_iter_at_location(x, y)

            if self.debugger.state.is_set(DebuggerState.BinaryLoaded):
                self.toggle_breakpoint(iter.get_line())

    def get_buffer(self):
        return self.buffer

    def get_file(self):
        return self.file

    def get_breakpoint_lines(self):
        return self.breakpoint_lines

    @require_gui_thread
    def toggle_breakpoint(self, line):
        self.debugger.breakpoint_manager.toggle_breakpoint(self.file, line + 1)

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def set_language(self, key):
        manager = GtkSource.LanguageManager()
        language = manager.get_language(key)

        self.start_undoable()
        self.get_buffer().set_language(language)
        self.stop_undoable()

    @require_gui_thread
    def start_undoable(self):
        self.get_buffer().begin_not_undoable_action()

    @require_gui_thread
    def stop_undoable(self):
        self.get_buffer().end_not_undoable_action()

    @require_gui_thread
    def set_content_from_file(self, path):
        content = SourceEditor.load_file(path)

        if content:
            self.file = path
            self.start_undoable()
            self.get_buffer().set_text(content)
            self.stop_undoable()
            self.analyser.set_file(path)
            self._refresh_breakpoints()
            self.gutter_renderer.queue_draw()  # show existing breakpoints

    @require_gui_thread
    def get_cursor_iter(self):
        cursor_rectangle = self.get_cursor_locations(None)[0]
        return self.get_iter_at_location(cursor_rectangle.x,
                                         cursor_rectangle.y)

    @require_gui_thread
    def get_current_column(self):
        return self.get_cursor_iter().get_line_offset()

    @require_gui_thread
    def get_current_line(self):
        return self.get_cursor_iter().get_line()

    @require_gui_thread
    def get_line_iters(self, line_number):
        start_line = self.get_buffer().get_iter_at_line(line_number)
        end_line = start_line.copy()
        end_line.forward_to_line_end()
        return (start_line, end_line)

    @require_gui_thread
    def set_exec_line(self, line_number):
        self.unset_exec_line()
        line_iters = self.get_line_iters(line_number)
        self.scroll_to_iter(line_iters[0], 0.0, True, 0.5, 0.5)
        self.exec_line = line_number

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def unset_exec_line(self):
        self.exec_line = None

        self.gutter_renderer.queue_draw()

    @require_gui_thread
    def undo(self):
        if self.get_buffer().can_undo():
            self.get_buffer().undo()
            return True
        else:
            return False

    @require_gui_thread
    def redo(self):
        if self.get_buffer().can_redo():
            self.get_buffer().redo()
            return True
        else:
            return False