def visualize(content, target): parser = AstParser() ast = parser.parse(content, rule_name='ast') graph = Digraph(comment=argv[1]) handle_node(ast, graph) handle_edges(ast.edges, graph) graph.render(target, view=False)
def __init__(self, parent=None): QMainWindow.__init__(self) super(MyWindowClass, self).__init__(parent) self.installEventFilter(self) self.setupUi(self) # self.QSciEditor = tabEditor(parent=self) # self.QSciEditor.setIndentationGuides(True) model = QFileSystemModel() model.setRootPath(path_of_me) self.label.setText(os.path.basename(path_of_me)) self.treeView.setModel(model) self.treeView.setRootIndex(model.index(path_of_me)) self.treeView.hideColumn(1) self.treeView.hideColumn(2) self.treeView.hideColumn(3) self.treeView.setHeaderHidden(True) self.treeView.doubleClicked.connect(self.tabHandler) self.terminal = embterminal(self.pageLayout) # self.process = QtCore.QProcess(self) # self.terminal = QtWidgets.QWidget(self) # self.pageLayout.addWidget(self.terminal) # self.process.start('xterm', ['-into', str(self.terminal.winId())]) # self.page.setLayout(layout) # self.infoBox.resize(531,0) # self.pageLayout self.tabWidget.tabCloseRequested.connect(self.delTab) self.shortcuts = [] for key in self.keybindings: self.shortcuts.append(QShortcut(self)) self.shortcuts[-1].setKey(key[0]) self.shortcuts[-1].activated.connect(getattr(self, key[1])) self.treeOutline.title = "Outline View" # Probably treeOutline will be a discrete class soon.. self.treeOutline.setContextMenuPolicy(Qt.CustomContextMenu) self.treeOutline.customContextMenuRequested.connect(self.openMenu) self.treeOutline.clicked.connect(self.outline_clicked) self.cleanButton.clicked.connect(self.clean) # self.gridLayout.addWidget(self.QSciEditor) self.ast = AstParser() self.show()
def __init__(self, handle): ShareableActivity.__init__(self, handle) self.old_eqs = [] self.ml = MathLib() self.parser = AstParser(self.ml) # These will result in 'Ans <operator character>' being inserted self._chars_ans_diadic = [ op[0] for op in self.parser.get_diadic_operators() ] try: self._chars_ans_diadic.remove('-') except: pass self.KEYMAP['multiply'] = self.ml.mul_sym self.KEYMAP['divide'] = self.ml.div_sym self.KEYMAP['equal'] = self.ml.equ_sym self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.select_reason = self.SELECT_SELECT self.buffer = u"" self.showing_version = 0 self.showing_error = False self.ans_inserted = False self.show_vars = False self.connect("key_press_event", self.keypress_cb) self.connect("destroy", self.cleanup_cb) self.color = sugar3.profile.get_color() self.layout = CalcLayout(self) self.label_entry = self.layout.label_entry self.text_entry = self.layout.text_entry self.last_eq_sig = None self.last_eqn_textview = None self.reset() self.layout.show_it() self.connect('joined', self._joined_cb) self.parser.log_debug_info()
def __init__(self, handle): ShareableActivity.__init__(self, handle) self.old_eqs = [] self.ml = MathLib() self.parser = AstParser(self.ml) # These will result in 'Ans <operator character>' being inserted self._chars_ans_diadic = [op[0] for op in self.parser.get_diadic_operators()] try: self._chars_ans_diadic.remove('-') except: pass self.KEYMAP['multiply'] = self.ml.mul_sym self.KEYMAP['divide'] = self.ml.div_sym self.KEYMAP['equal'] = self.ml.equ_sym self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.select_reason = self.SELECT_SELECT self.buffer = u"" self.showing_version = 0 self.showing_error = False self.ans_inserted = False self.show_vars = False self.connect("key_press_event", self.keypress_cb) self.connect("destroy", self.cleanup_cb) self.color = sugar3.profile.get_color() self.layout = CalcLayout(self) self.label_entry = self.layout.label_entry self.text_entry = self.layout.text_entry self.last_eq_sig = None self.last_eqn_textview = None self.reset() self.layout.show_it() self.connect('joined', self._joined_cb) self.parser.log_debug_info()
class Calculate(ShareableActivity): TYPE_FUNCTION = 1 TYPE_OP_PRE = 2 TYPE_OP_POST = 3 TYPE_TEXT = 4 SELECT_NONE = 0 SELECT_SELECT = 1 SELECT_TAB = 2 KEYMAP = { 'Return': lambda o: o.process(), 'period': '.', 'equal': '=', 'plus': '+', 'minus': '-', 'asterisk': '*', 'multiply': '×', 'divide': '÷', 'slash': '/', 'BackSpace': lambda o: o.remove_character(-1), 'Delete': lambda o: o.remove_character(1), 'parenleft': '(', 'parenright': ')', 'exclam': '!', 'ampersand': '&', 'bar': '|', 'asciicircum': '^', 'less': '<', 'greater': '>', 'percent': '%', 'comma': ',', 'underscore': '_', 'Left': lambda o: o.move_left(), 'Right': lambda o: o.move_right(), 'Up': lambda o: o.get_older(), 'Down': lambda o: o.get_newer(), 'colon': lambda o: o.label_entered(), 'Home': lambda o: o.text_entry.set_position(0), 'End': lambda o: o.text_entry.set_position( len(o.text_entry.get_text())), 'Tab': lambda o: o.tab_complete(), } CTRL_KEYMAP = { 'c': lambda o: o.text_copy(), 'v': lambda o: o.text_paste(), 'x': lambda o: o.text_cut(), 'q': lambda o: o.close(), 'a': lambda o: o.text_select_all(), } SHIFT_KEYMAP = { 'Left': lambda o: o.expand_selection(-1), 'Right': lambda o: o.expand_selection(1), 'Home': lambda o: o.expand_selection(-1000), 'End': lambda o: o.expand_selection(1000), } IDENTIFIER_CHARS = \ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ " def __init__(self, handle): ShareableActivity.__init__(self, handle) self.old_eqs = [] self.ml = MathLib() self.parser = AstParser(self.ml) # These will result in 'Ans <operator character>' being inserted self._chars_ans_diadic = [op[0] for op in self.parser.get_diadic_operators()] if '-' in self._chars_ans_diadic: self._chars_ans_diadic.remove('-') self.KEYMAP['multiply'] = self.ml.mul_sym self.KEYMAP['divide'] = self.ml.div_sym self.KEYMAP['equal'] = self.ml.equ_sym self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.select_reason = self.SELECT_SELECT self.buffer = "" self.showing_version = 0 self.showing_error = False self.ans_inserted = False self.show_vars = False self.connect("key_press_event", self.keypress_cb) self.connect("destroy", self.cleanup_cb) self.color = sugar3.profile.get_color() self.layout = CalcLayout(self) self.label_entry = self.layout.label_entry self.text_entry = self.layout.text_entry self.last_eq_sig = None self.last_eqn_textview = None self.reset() self.layout.show_it() self.connect('joined', self._joined_cb) self.parser.log_debug_info() def ignore_key_cb(self, widget, event): return True def cleanup_cb(self, arg): _logger.debug('Cleaning up...') def equation_pressed_cb(self, eqn): """Callback for when an equation box is clicked.""" if isinstance(eqn.result, SVGImage): return True if len(eqn.label) > 0: text = eqn.label else: # don't insert plain text if type(eqn.result) in (bytes, str): text = '' else: text = self.parser.ml.format_number(eqn.result) text = text.rstrip('0').rstrip('.') if '.' in text else text self.button_pressed(self.TYPE_TEXT, text) return True def set_last_equation(self, eqn): """Set the 'last equation' TextView.""" if self.last_eq_sig is not None: self.layout.last_eq.disconnect(self.last_eq_sig) self.last_eq_sig = None if not isinstance(eqn.result, ParserError): self.last_eq_sig = self.layout.last_eq.connect( 'button-press-event', lambda a1, a2, e: self.equation_pressed_cb(e), eqn) self.layout.last_eq.set_buffer(eqn.create_lasteq_textbuf()) def set_error_equation(self, eqn): """Set equation with error markers. Since set_last_equation implements this we can just forward the call.""" self.set_last_equation(eqn) def clear_equations(self): """Clear the list of old equations.""" self.old_eqs = [] self.showing_version = 0 def add_equation(self, eq, prepend=False, drawlasteq=False, tree=None): """ Insert equation in the history list and set variable if assignment. Input: eq: the equation object prepend: if True, prepend to list, else append drawlasteq: if True, draw in 'last equation' textbox and queue the buffer to be added to the history next time an equation is added. tree: the parsed tree, this will be used to set the label variable so that the equation can be used symbolicaly. """ if eq.equation is not None and len(eq.equation) > 0: if prepend: self.old_eqs.insert(0, eq) else: self.old_eqs.append(eq) self.showing_version = len(self.old_eqs) if self.last_eqn_textview is not None and drawlasteq: # Prepending here should be the opposite: prepend -> eqn on top. # We always own this equation self.layout.add_equation(self.last_eqn_textview, True, prepend=not prepend) self.last_eqn_textview = None if eq.label is not None and len(eq.label) > 0: w = self.create_var_textview(eq.label, eq.result) if w is not None: self.layout.add_variable(eq.label, w) if tree is None: tree = self.parser.parse(eq.equation) try: self.parser.set_var(eq.label, tree) except Exception as e: eq.result = ParseError(e.message, 0, "") self.set_error_equation(eq) return own = (eq.owner == self.get_owner_id()) w = eq.create_history_object() w.connect('button-press-event', lambda w, e: self.equation_pressed_cb(eq)) if drawlasteq: self.set_last_equation(eq) # SVG images can't be plotted in last equation window if isinstance(eq.result, SVGImage): self.layout.add_equation(w, own, prepend=not prepend) else: self.last_eqn_textview = w else: self.layout.add_equation(w, own, prepend=not prepend) # FIXME: to be implemented def process_async(self, eqn): """Parse and process an equation asynchronously.""" def process(self): """Parse the equation entered and show the result.""" s = _s(self.text_entry.get_text()) label = self.label_entry.get_text() _logger.debug('process(): parsing %r, label: %r', s, label) try: tree = self.parser.parse(s) res = self.parser.evaluate(tree) except ParserError as e: res = e self.showing_error = True if isinstance(res, str) and res.find('</svg>') > -1: res = SVGImage(data=res) _logger.debug('Result: %r', res) # Check whether assigning this label would cause recursion if not isinstance(res, ParserError) and len(label) > 0: lastpos = self.parser.get_var_used_ofs(label) if lastpos is not None: res = RuntimeError( _('Can not assign label: will cause recursion'), lastpos) # If parsing went ok, see if we have to replace the previous answer # to get a (more) exact result if self.ans_inserted and not isinstance(res, ParserError) \ and not isinstance(res, SVGImage): ansvar = self.format_insert_ans() pos = s.find(ansvar) if len(ansvar) > 6 and pos != -1: s2 = s.replace(ansvar, 'LastEqn') _logger.debug( 'process(): replacing previous answer %r: %r', ansvar, s2) tree = self.parser.parse(s2) res = self.parser.evaluate(tree) if isinstance(res, ParserError): eqn = Equation(label, _n(s), res, self.color, self.get_owner_id(), ml=self.ml) self.set_error_equation(eqn) else: eqn = Equation(label, _n(s), _n(str(res)), self.color, self.get_owner_id(), ml=self.ml) self.add_equation(eqn, drawlasteq=True, tree=tree) self.send_message("add_eq", value=str(eqn)) self.parser.set_var('Ans', eqn.result) # Setting LastEqn to the parse tree would certainly be faster, # however, it introduces recursion problems self.parser.set_var('LastEqn', eqn.result) self.showing_error = False self.ans_inserted = False self.text_entry.set_text('') self.label_entry.set_text('') return res is not None def create_var_textview(self, name, value): """Create a Gtk.TextView for a variable.""" reserved = ["Ans", "LastEqn", "help"] if name in reserved: return None w = Gtk.TextView() w.modify_base( Gtk.StateType.NORMAL, Gdk.color_parse(self.color.get_fill_color())) w.modify_bg( Gtk.StateType.NORMAL, Gdk.color_parse(self.color.get_stroke_color())) w.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) w.set_border_window_size(Gtk.TextWindowType.LEFT, 4) w.set_border_window_size(Gtk.TextWindowType.RIGHT, 4) w.set_border_window_size(Gtk.TextWindowType.TOP, 4) w.set_border_window_size(Gtk.TextWindowType.BOTTOM, 4) w.connect('realize', _textview_realize_cb) buf = w.get_buffer() # TODO Fix for old Sugar 0.82 builds, red_float not available bright = ( Gdk.color_parse(self.color.get_fill_color()).red_float + Gdk.color_parse(self.color.get_fill_color()).green_float + Gdk.color_parse(self.color.get_fill_color()).blue_float) / 3.0 if bright < 0.5: col = Gdk.color_parse('white') else: col = Gdk.color_parse('black') tag = buf.create_tag(font=CalcLayout.FONT_SMALL_NARROW, foreground=col) text = '%s:' % (name) buf.insert_with_tags(buf.get_end_iter(), text, tag) tag = buf.create_tag(font=CalcLayout.FONT_SMALL, foreground=col) text = '%s' % (str(value)) buf.insert_with_tags(buf.get_end_iter(), text, tag) return w def clear(self): self.text_entry.set_text('') self.text_entry.grab_focus() return True def reset(self): self.clear() return True # # Journal functions # def write_file(self, file_path): """Write journal entries, Calculate Journal Version (cjv) 1.0""" _logger.info(_('Writing to journal (%s)'), file_path) f = open(file_path, 'w') f.write("cjv 1.0\n") sel = self.text_entry.get_selection_bounds() pos = self.text_entry.get_position() if len(sel) == 0: sel = (pos, pos) f.write("%s;%d;%d;%d\n" % (self.text_entry.get_text(), pos, sel[0], sel[1])) # In reverse order for eq in self.old_eqs: f.write(str(eq)) f.close() def read_file(self, file_path): """Read journal entries, version 1.0""" _logger.info('Reading from journal (%s)', file_path) f = open(file_path, 'r') str = f.readline().rstrip("\r\n") # chomp k = str.split() if len(k) != 2: _logger.error('Unable to determine version') return False version = k[1] if len(version) > 1 and version[0:2] == "1.": _logger.info('Reading journal entry (version %s)', version) str = f.readline().rstrip("\r\n") k = str.split(';') if len(k) != 4: _logger.error('State line invalid (%s)', str) return False self.text_entry.set_text(k[0]) self.text_entry.set_position(int(k[1])) if k[2] != k[3]: self.text_entry.select_region(int(k[2]), int(k[3])) self.clear_equations() for str in f: eq = Equation(eqnstr=str, ml=self.ml) self.add_equation(eq, prepend=False) return True else: _logger.error( 'Unable to read journal entry, unknown version (%s)', version) return False # # User interaction functions # def remove_character(self, dir): pos = self.text_entry.get_position() sel = self.text_entry.get_selection_bounds() if len(sel) == 0: if pos + dir <= len(self.text_entry.get_text()) and pos + dir >= 0: if dir < 0: self.text_entry.delete_text(pos + dir, pos) pos -= 1 else: self.text_entry.delete_text(pos, pos + dir) pos += 1 else: self.text_entry.delete_text(sel[0], sel[1]) self.text_entry.grab_focus() self.text_entry.set_position(pos) def move_left(self): pos = self.text_entry.get_position() if pos > 0: pos -= 1 self.text_entry.set_position(pos) self.text_entry.grab_focus() self.text_entry.set_position(pos) def move_right(self): pos = self.text_entry.get_position() if pos < len(self.text_entry.get_text()): pos += 1 self.text_entry.set_position(pos) self.text_entry.grab_focus() self.text_entry.set_position(pos) def label_entered(self): if len(self.label_entry.get_text()) > 0: return pos = self.text_entry.get_position() str = self.text_entry.get_text() self.label_entry.set_text(str[:pos]) self.text_entry.set_text(str[pos:]) def tab_complete(self): # Get start of variable name str = self.text_entry.get_text() if len(str) == 0: return sel = self.text_entry.get_selection_bounds() if len(sel) == 0: end_ofs = self.text_entry.get_position() else: end_ofs = sel[0] start_ofs = end_ofs - 1 while start_ofs > 0 and str[start_ofs - 1] in self.IDENTIFIER_CHARS: start_ofs -= 1 if end_ofs - start_ofs <= 0: return False partial_name = str[start_ofs:end_ofs] _logger.debug('tab-completing %s...', partial_name) # Lookup matching variables vars = self.parser.get_names(start=partial_name) if len(vars) == 0: return False # Nothing selected, select first match if len(sel) == 0: name = vars[0] self.text_entry.set_text(str[:start_ofs] + name + str[end_ofs:]) # Select next matching variable else: full_name = str[start_ofs:sel[1]] if full_name not in vars: name = vars[0] else: name = vars[(vars.index(full_name) + 1) % len(vars)] self.text_entry.set_text(str[:start_ofs] + name + str[sel[1]:]) self.text_entry.set_position(start_ofs + len(name)) self.text_entry.select_region(end_ofs, start_ofs + len(name)) self.select_reason = self.SELECT_TAB return True # Selection related functions def expand_selection(self, dir): # logger.info('Expanding selection in dir %d', dir) sel = self.text_entry.get_selection_bounds() slen = len(self.text_entry.get_text()) pos = self.text_entry.get_position() if len(sel) == 0: sel = (pos, pos) if dir < 0: # apparently no such thing as a cursor position during select newpos = max(0, sel[0] + dir) self.text_entry.set_position(newpos) self.text_entry.select_region(newpos, sel[1]) elif dir > 0: newpos = min(sel[1] + dir, slen) self.text_entry.set_position(newpos) self.text_entry.select_region(sel[0], newpos) self.select_reason = self.SELECT_SELECT def text_copy(self): if self.layout.graph_selected is not None: self.clipboard.set_image( self.layout.graph_selected.get_child().get_pixbuf()) self.layout.toggle_select_graph(self.layout.graph_selected) else: str = self.text_entry.get_text() sel = self.text_entry.get_selection_bounds() # _logger.info('text_copy, sel: %r, str: %s', sel, str) if len(sel) == 2: (start, end) = sel self.clipboard.set_text(str[start:end], -1) def text_select_all(self): end = self.text_entry.get_text_length() self.text_entry.select_region(0, end) def get_clipboard_text(self): text = self.clipboard.wait_for_text() if text is None: return "" else: return text def text_paste(self): self.button_pressed(self.TYPE_TEXT, self.get_clipboard_text()) def text_cut(self): self.text_copy() self.remove_character(1) def keypress_cb(self, widget, event): if not self.text_entry.is_focus(): return key = Gdk.keyval_name(event.keyval) if event.hardware_keycode == 219: if (event.get_state() & Gdk.ModifierType.SHIFT_MASK): key = 'divide' else: key = 'multiply' _logger.debug('Key: %s (%r, %r)', key, event.keyval, event.hardware_keycode) if event.get_state() & Gdk.ModifierType.CONTROL_MASK: if key in self.CTRL_KEYMAP: f = self.CTRL_KEYMAP[key] return f(self) elif (event.get_state() & Gdk.ModifierType.SHIFT_MASK) and \ key in self.SHIFT_KEYMAP: f = self.SHIFT_KEYMAP[key] return f(self) elif str(key) in self.IDENTIFIER_CHARS: self.button_pressed(self.TYPE_TEXT, key) elif key in self.KEYMAP: f = self.KEYMAP[key] if isinstance(f, str) or \ isinstance(f, str): self.button_pressed(self.TYPE_TEXT, f) else: return f(self) return True def get_older(self): self.showing_version = max(0, self.showing_version - 1) if self.showing_version == len(self.old_eqs) - 1: self.buffer = self.text_entry.get_text() if len(self.old_eqs) > 0: self.text_entry.set_text( self.old_eqs[self.showing_version].equation) def get_newer(self): self.showing_version = min(len(self.old_eqs), self.showing_version + 1) if self.showing_version == len(self.old_eqs): self.text_entry.set_text(self.buffer) else: self.text_entry.set_text( self.old_eqs[self.showing_version].equation) def add_text(self, input_str): self.button_pressed(self.TYPE_TEXT, input_str) # This function should be split up properly def button_pressed(self, str_type, input_str): sel = self.text_entry.get_selection_bounds() pos = self.text_entry.get_position() # If selection by tab completion just manipulate end if len(sel) == 2 and self.select_reason != self.SELECT_SELECT: pos = sel[1] sel = () self.text_entry.grab_focus() if len(sel) == 2: (start, end) = sel text = self.text_entry.get_text() elif len(sel) != 0: _logger.error('button_pressed(): len(sel) != 0 or 2') return False if str_type == self.TYPE_FUNCTION: if len(sel) == 0: self.text_entry.insert_text(input_str + '()', pos) self.text_entry.set_position(pos + len(input_str) + 1) else: self.text_entry.set_text( text[:start] + input_str + '(' + text[start:end] + ')' + text[end:]) self.text_entry.set_position(end + len(input_str) + 2) elif str_type == self.TYPE_OP_PRE: if len(sel) == 2: pos = start self.text_entry.insert_text(input_str, pos) self.text_entry.set_position(pos + len(input_str)) elif str_type == self.TYPE_OP_POST: if len(sel) == 2: pos = end elif pos == 0: ans = self.format_insert_ans() input_str = ans + input_str self.ans_inserted = True self.text_entry.insert_text(input_str, pos) self.text_entry.set_position(pos + len(input_str)) elif str_type == self.TYPE_TEXT: tlen = len(self.text_entry.get_text()) if len(sel) == 2: tlen -= (end - start) if tlen == 0 and (input_str in self._chars_ans_diadic) and \ self.parser.get_var('Ans') is not None and \ type(self.parser.get_var('Ans')) is not str: ans = self.format_insert_ans() self.text_entry.set_text(ans + input_str) self.text_entry.set_position(len(ans) + len(input_str)) self.ans_inserted = True elif len(sel) == 2: self.text_entry.set_text(text[:start] + input_str + text[end:]) self.text_entry.set_position( pos + start - end + len(input_str)) else: self.text_entry.insert_text(input_str, pos) self.text_entry.set_position(pos + len(input_str)) else: _logger.error(_('button_pressed(): invalid type')) def message_received(self, msg, **kwargs): _logger.debug('Message received: %s(%r)', msg, kwargs) value = kwargs.get('value', None) if msg == "add_eq": eq = Equation(eqnstr=str(value), ml=self.ml) self.add_equation(eq) elif msg == "req_sync": data = [] for eq in self.old_eqs: data.append(str(eq)) self.send_message("sync", value=data) elif msg == "sync": self.clear_equations() for eq_str in value: _logger.debug('receive_message: %s', str(eq_str)) self.add_equation(Equation(eqnstr=str(eq_str)), ml=self.ml) def _joined_cb(self, gobj): _logger.debug('Requesting synchronization') self.send_message('req_sync') def format_insert_ans(self): ans = self.parser.get_var('Ans') if isinstance(ans, Rational): return str(ans) elif ans is not None: return self.ml.format_number(ans) else: return ''
class MyWindowClass(QMainWindow, Ui_MainWindow): keybindings = [ (Qt.CTRL + Qt.Key_S, "save"), (Qt.CTRL + Qt.Key_Q, "quit"), (Qt.CTRL + Qt.Key_R, "refresh_outline"), (Qt.CTRL + Qt.Key_Space, "autocomplete"), (Qt.Key_F1, "testplace"), ] tabs = [] def __init__(self, parent=None): QMainWindow.__init__(self) super(MyWindowClass, self).__init__(parent) self.installEventFilter(self) self.setupUi(self) # self.QSciEditor = tabEditor(parent=self) # self.QSciEditor.setIndentationGuides(True) model = QFileSystemModel() model.setRootPath(path_of_me) self.label.setText(os.path.basename(path_of_me)) self.treeView.setModel(model) self.treeView.setRootIndex(model.index(path_of_me)) self.treeView.hideColumn(1) self.treeView.hideColumn(2) self.treeView.hideColumn(3) self.treeView.setHeaderHidden(True) self.treeView.doubleClicked.connect(self.tabHandler) self.terminal = embterminal(self.pageLayout) # self.process = QtCore.QProcess(self) # self.terminal = QtWidgets.QWidget(self) # self.pageLayout.addWidget(self.terminal) # self.process.start('xterm', ['-into', str(self.terminal.winId())]) # self.page.setLayout(layout) # self.infoBox.resize(531,0) # self.pageLayout self.tabWidget.tabCloseRequested.connect(self.delTab) self.shortcuts = [] for key in self.keybindings: self.shortcuts.append(QShortcut(self)) self.shortcuts[-1].setKey(key[0]) self.shortcuts[-1].activated.connect(getattr(self, key[1])) self.treeOutline.title = "Outline View" # Probably treeOutline will be a discrete class soon.. self.treeOutline.setContextMenuPolicy(Qt.CustomContextMenu) self.treeOutline.customContextMenuRequested.connect(self.openMenu) self.treeOutline.clicked.connect(self.outline_clicked) self.cleanButton.clicked.connect(self.clean) # self.gridLayout.addWidget(self.QSciEditor) self.ast = AstParser() self.show() def createTab(self, filename, content): newTab = tabEditor(parent=self.tabWidget, filepath=filename, content=content) self.tabs.append(newTab) def delTab(self, index): widget = self.tabWidget.widget(index) if widget is not None: widget.deleteLater() self.tabWidget.removeTab(index) self.tabs[index].deleteLater() del (self.tabs[index]) def checkFileTabIsOpen(self, filename): returnText = "False" for i in range(0, len(self.tabs)): tabText = str(self.tabWidget.tabText(i)).replace("&", "") # print(tabText) # print(filename) if tabText == filename: # print("Found file") returnText = "True" return i, returnText return 0, returnText def tabHandler(self, signal): file_path = self.treeView.model().filePath(signal) filename = file_path.split("/")[-1] index, result = self.checkFileTabIsOpen(filename) if result == "False": try: if os.path.isfile(file_path): with open(file_path, 'r+') as currentFile: self.createTab(file_path, currentFile.read()) self.tabWidget.setCurrentIndex(len(self.tabs) - 1) self.refresh_outline() except Exception as e: print(e) else: self.tabWidget.setCurrentIndex(index) def save(self): current_tab = self.tabs[self.tabWidget.currentIndex()] file = open(current_tab._filepath, "w") file.write(current_tab.QSciEditor.text()) file.close() self.refresh_outline() debug(current_tab._filepath + " is saved...") def quit(self): debug("quitting...") app.quit() def openMenu(self, position): menu = QMenu() menu.addAction(self.tr("Go to")) menu.exec_(self.treeOutline.viewport().mapToGlobal(position)) def test(self, signal): file_path = self.treeView.model().filePath(signal) self.self.tabs[self.tabWidget.currentIndex( )].QSciEditor.filename = file_path # Soon will be used to save to that file. # try: if os.path.isfile(file_path): with open(file_path, 'r+') as currentFile: self.self.tabs[ self.tabWidget.currentIndex()].QSciEditor.setText( currentFile.read()) self.refresh_outline() def refresh_outline(self): kinds = [] kinds.append(CursorKind.FUNCTION_DECL) kinds.append(CursorKind.VAR_DECL) kinds.append(CursorKind.DECL_REF_EXPR) kinds.append(CursorKind.COMPOUND_STMT) # kinds.append(CursorKind.STRUCT_DECL) kinds.append(CursorKind.FIELD_DECL) outline = self.ast.get_outline( self.tabs[self.tabWidget.currentIndex()]._filepath, kinds) self.treeOutline.setModel(outline) # except Exception as e: # print(e) def outline_clicked(self, index): loc = (self.treeOutline.model().itemFromIndex(index).location) debug("Node Location: " + str(loc.line) + "," + str(loc.column)) self.tabs[self.tabWidget.currentIndex()].QSciEditor.setCursorPosition( loc.line - 1, loc.column - 1) self.tabs[self.tabWidget.currentIndex()].QSciEditor.ensureLineVisible( loc.line - 1) self.tabs[ self.tabWidget.currentIndex()].QSciEditor.ensureCursorVisible() self.tabs[self.tabWidget.currentIndex()].QSciEditor.setFocus() def clean(self, signal): debug("clean...") def autocomplete(self): self.tabs[ self.tabWidget.currentIndex()].QSciEditor.autoCompleteFromAll() debug("autocompleted...") def testplace(self): debug("This is for testing purposes...")
class Calculate(ShareableActivity): TYPE_FUNCTION = 1 TYPE_OP_PRE = 2 TYPE_OP_POST = 3 TYPE_TEXT = 4 SELECT_NONE = 0 SELECT_SELECT = 1 SELECT_TAB = 2 KEYMAP = { 'Return': lambda o: o.process(), 'period': '.', 'equal': '=', 'plus': '+', 'minus': '-', 'asterisk': '*', 'multiply': '×', 'divide': '÷', 'slash': '/', 'BackSpace': lambda o: o.remove_character(-1), 'Delete': lambda o: o.remove_character(1), 'parenleft': '(', 'parenright': ')', 'exclam': '!', 'ampersand': '&', 'bar': '|', 'asciicircum': '^', 'less': '<', 'greater': '>', 'percent': '%', 'comma': ',', 'underscore': '_', 'Left': lambda o: o.move_left(), 'Right': lambda o: o.move_right(), 'Up': lambda o: o.get_older(), 'Down': lambda o: o.get_newer(), 'colon': lambda o: o.label_entered(), 'Home': lambda o: o.text_entry.set_position(0), 'End': lambda o: o.text_entry.set_position(len(o.text_entry.get_text())), 'Tab': lambda o: o.tab_complete(), } CTRL_KEYMAP = { 'c': lambda o: o.text_copy(), 'v': lambda o: o.text_paste(), 'x': lambda o: o.text_cut(), 'q': lambda o: o.close(), 'a': lambda o: o.text_select_all(), } SHIFT_KEYMAP = { 'Left': lambda o: o.expand_selection(-1), 'Right': lambda o: o.expand_selection(1), 'Home': lambda o: o.expand_selection(-1000), 'End': lambda o: o.expand_selection(1000), } IDENTIFIER_CHARS = \ u"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ " def __init__(self, handle): ShareableActivity.__init__(self, handle) self.old_eqs = [] self.ml = MathLib() self.parser = AstParser(self.ml) # These will result in 'Ans <operator character>' being inserted self._chars_ans_diadic = [ op[0] for op in self.parser.get_diadic_operators() ] try: self._chars_ans_diadic.remove('-') except: pass self.KEYMAP['multiply'] = self.ml.mul_sym self.KEYMAP['divide'] = self.ml.div_sym self.KEYMAP['equal'] = self.ml.equ_sym self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.select_reason = self.SELECT_SELECT self.buffer = u"" self.showing_version = 0 self.showing_error = False self.ans_inserted = False self.show_vars = False self.connect("key_press_event", self.keypress_cb) self.connect("destroy", self.cleanup_cb) self.color = sugar3.profile.get_color() self.layout = CalcLayout(self) self.label_entry = self.layout.label_entry self.text_entry = self.layout.text_entry self.last_eq_sig = None self.last_eqn_textview = None self.reset() self.layout.show_it() self.connect('joined', self._joined_cb) self.parser.log_debug_info() def ignore_key_cb(self, widget, event): return True def cleanup_cb(self, arg): _logger.debug('Cleaning up...') def equation_pressed_cb(self, eqn): """Callback for when an equation box is clicked""" if isinstance(eqn.result, SVGImage): return True if len(eqn.label) > 0: text = eqn.label else: # don't insert plain text if type(eqn.result) in (types.StringType, types.UnicodeType): text = '' else: text = self.parser.ml.format_number(eqn.result) text = text.rstrip('0').rstrip('.') if '.' in text else text self.button_pressed(self.TYPE_TEXT, text) return True def set_last_equation(self, eqn): """Set the 'last equation' TextView""" if self.last_eq_sig is not None: self.layout.last_eq.disconnect(self.last_eq_sig) self.last_eq_sig = None if not isinstance(eqn.result, ParserError): self.last_eq_sig = self.layout.last_eq.connect( 'button-press-event', lambda a1, a2, e: self.equation_pressed_cb(e), eqn) self.layout.last_eq.set_buffer(eqn.create_lasteq_textbuf()) def set_error_equation(self, eqn): """Set equation with error markers. Since set_last_equation implements this we can just forward the call.""" self.set_last_equation(eqn) def clear_equations(self): """Clear the list of old equations.""" self.old_eqs = [] self.showing_version = 0 def add_equation(self, eq, prepend=False, drawlasteq=False, tree=None): """ Insert equation in the history list and set variable if assignment. Input: eq: the equation object prepend: if True, prepend to list, else append drawlasteq: if True, draw in 'last equation' textbox and queue the buffer to be added to the history next time an equation is added. tree: the parsed tree, this will be used to set the label variable so that the equation can be used symbolicaly. """ if eq.equation is not None and len(eq.equation) > 0: if prepend: self.old_eqs.insert(0, eq) else: self.old_eqs.append(eq) self.showing_version = len(self.old_eqs) if self.last_eqn_textview is not None and drawlasteq: # Prepending here should be the opposite: prepend -> eqn on top. # We always own this equation self.layout.add_equation(self.last_eqn_textview, True, prepend=not prepend) self.last_eqn_textview = None if eq.label is not None and len(eq.label) > 0: w = self.create_var_textview(eq.label, eq.result) if w is not None: self.layout.add_variable(eq.label, w) if tree is None: tree = self.parser.parse(eq.equation) try: self.parser.set_var(eq.label, tree) except Exception, e: eq.result = ParseError(e.message, 0, "") self.set_error_equation(eq) return own = (eq.owner == self.get_owner_id()) w = eq.create_history_object() w.connect('button-press-event', lambda w, e: self.equation_pressed_cb(eq)) if drawlasteq: self.set_last_equation(eq) # SVG images can't be plotted in last equation window if isinstance(eq.result, SVGImage): self.layout.add_equation(w, own, prepend=not prepend) else: self.last_eqn_textview = w else: self.layout.add_equation(w, own, prepend=not prepend)
class Calculate(ShareableActivity): TYPE_FUNCTION = 1 TYPE_OP_PRE = 2 TYPE_OP_POST = 3 TYPE_TEXT = 4 SELECT_NONE = 0 SELECT_SELECT = 1 SELECT_TAB = 2 KEYMAP = { 'Return': lambda o: o.process(), 'period': '.', 'equal': '=', 'plus': '+', 'minus': '-', 'asterisk': '*', 'multiply': '×', 'divide': '÷', 'slash': '/', 'BackSpace': lambda o: o.remove_character(-1), 'Delete': lambda o: o.remove_character(1), 'parenleft': '(', 'parenright': ')', 'exclam': '!', 'ampersand': '&', 'bar': '|', 'asciicircum': '^', 'less': '<', 'greater': '>', 'percent': '%', 'comma': ',', 'underscore': '_', 'Left': lambda o: o.move_left(), 'Right': lambda o: o.move_right(), 'Up': lambda o: o.get_older(), 'Down': lambda o: o.get_newer(), 'colon': lambda o: o.label_entered(), 'Home': lambda o: o.text_entry.set_position(0), 'End': lambda o: o.text_entry.set_position( len(o.text_entry.get_text())), 'Tab': lambda o: o.tab_complete(), } CTRL_KEYMAP = { 'c': lambda o: o.text_copy(), 'v': lambda o: o.text_paste(), 'x': lambda o: o.text_cut(), 'q': lambda o: o.close(), 'a': lambda o: o.text_select_all(), } SHIFT_KEYMAP = { 'Left': lambda o: o.expand_selection(-1), 'Right': lambda o: o.expand_selection(1), 'Home': lambda o: o.expand_selection(-1000), 'End': lambda o: o.expand_selection(1000), } IDENTIFIER_CHARS = \ u"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ " def __init__(self, handle): ShareableActivity.__init__(self, handle) self.old_eqs = [] self.ml = MathLib() self.parser = AstParser(self.ml) # These will result in 'Ans <operator character>' being inserted self._chars_ans_diadic = [op[0] for op in self.parser.get_diadic_operators()] try: self._chars_ans_diadic.remove('-') except: pass self.KEYMAP['multiply'] = self.ml.mul_sym self.KEYMAP['divide'] = self.ml.div_sym self.KEYMAP['equal'] = self.ml.equ_sym self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.select_reason = self.SELECT_SELECT self.buffer = u"" self.showing_version = 0 self.showing_error = False self.ans_inserted = False self.show_vars = False self.connect("key_press_event", self.keypress_cb) self.connect("destroy", self.cleanup_cb) self.color = sugar3.profile.get_color() self.layout = CalcLayout(self) self.label_entry = self.layout.label_entry self.text_entry = self.layout.text_entry self.last_eq_sig = None self.last_eqn_textview = None self.reset() self.layout.show_it() self.connect('joined', self._joined_cb) self.parser.log_debug_info() def ignore_key_cb(self, widget, event): return True def cleanup_cb(self, arg): _logger.debug('Cleaning up...') def equation_pressed_cb(self, eqn): """Callback for when an equation box is clicked""" if isinstance(eqn.result, SVGImage): return True if len(eqn.label) > 0: text = eqn.label else: # don't insert plain text if type(eqn.result) in (types.StringType, types.UnicodeType): text = '' else: text = self.parser.ml.format_number(eqn.result) text = text.rstrip('0').rstrip('.') if '.' in text else text self.button_pressed(self.TYPE_TEXT, text) return True def set_last_equation(self, eqn): """Set the 'last equation' TextView""" if self.last_eq_sig is not None: self.layout.last_eq.disconnect(self.last_eq_sig) self.last_eq_sig = None if not isinstance(eqn.result, ParserError): self.last_eq_sig = self.layout.last_eq.connect( 'button-press-event', lambda a1, a2, e: self.equation_pressed_cb(e), eqn) self.layout.last_eq.set_buffer(eqn.create_lasteq_textbuf()) def set_error_equation(self, eqn): """Set equation with error markers. Since set_last_equation implements this we can just forward the call.""" self.set_last_equation(eqn) def clear_equations(self): """Clear the list of old equations.""" self.old_eqs = [] self.showing_version = 0 def add_equation(self, eq, prepend=False, drawlasteq=False, tree=None): """ Insert equation in the history list and set variable if assignment. Input: eq: the equation object prepend: if True, prepend to list, else append drawlasteq: if True, draw in 'last equation' textbox and queue the buffer to be added to the history next time an equation is added. tree: the parsed tree, this will be used to set the label variable so that the equation can be used symbolicaly. """ if eq.equation is not None and len(eq.equation) > 0: if prepend: self.old_eqs.insert(0, eq) else: self.old_eqs.append(eq) self.showing_version = len(self.old_eqs) if self.last_eqn_textview is not None and drawlasteq: # Prepending here should be the opposite: prepend -> eqn on top. # We always own this equation self.layout.add_equation(self.last_eqn_textview, True, prepend=not prepend) self.last_eqn_textview = None if eq.label is not None and len(eq.label) > 0: w = self.create_var_textview(eq.label, eq.result) if w is not None: self.layout.add_variable(eq.label, w) if tree is None: tree = self.parser.parse(eq.equation) try: self.parser.set_var(eq.label, tree) except Exception, e: eq.result = ParseError(e.message, 0, "") self.set_error_equation(eq) return own = (eq.owner == self.get_owner_id()) w = eq.create_history_object() w.connect('button-press-event', lambda w, e: self.equation_pressed_cb(eq)) if drawlasteq: self.set_last_equation(eq) # SVG images can't be plotted in last equation window if isinstance(eq.result, SVGImage): self.layout.add_equation(w, own, prepend=not prepend) else: self.last_eqn_textview = w else: self.layout.add_equation(w, own, prepend=not prepend)
class Calculate(ShareableActivity): TYPE_FUNCTION = 1 TYPE_OP_PRE = 2 TYPE_OP_POST = 3 TYPE_TEXT = 4 SELECT_NONE = 0 SELECT_SELECT = 1 SELECT_TAB = 2 KEYMAP = { 'Return': lambda o: o.process(), 'period': '.', 'equal': '=', 'plus': '+', 'minus': '-', 'asterisk': '*', 'multiply': '×', 'divide': '÷', 'slash': '/', 'BackSpace': lambda o: o.remove_character(-1), 'Delete': lambda o: o.remove_character(1), 'parenleft': '(', 'parenright': ')', 'exclam': '!', 'ampersand': '&', 'bar': '|', 'asciicircum': '^', 'less': '<', 'greater': '>', 'percent': '%', 'comma': ',', 'underscore': '_', 'Left': lambda o: o.move_left(), 'Right': lambda o: o.move_right(), 'Up': lambda o: o.get_older(), 'Down': lambda o: o.get_newer(), 'colon': lambda o: o.label_entered(), 'Home': lambda o: o.text_entry.set_position(0), 'End': lambda o: o.text_entry.set_position(len(o.text_entry.get_text())), 'Tab': lambda o: o.tab_complete(), } CTRL_KEYMAP = { 'c': lambda o: o.text_copy(), 'v': lambda o: o.text_paste(), 'x': lambda o: o.text_cut(), 'q': lambda o: o.close(), 'a': lambda o: o.text_select_all(), } SHIFT_KEYMAP = { 'Left': lambda o: o.expand_selection(-1), 'Right': lambda o: o.expand_selection(1), 'Home': lambda o: o.expand_selection(-1000), 'End': lambda o: o.expand_selection(1000), } IDENTIFIER_CHARS = \ u"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ " def __init__(self, handle): ShareableActivity.__init__(self, handle) self.old_eqs = [] self.ml = MathLib() self.parser = AstParser(self.ml) # These will result in 'Ans <operator character>' being inserted self._chars_ans_diadic = [ op[0] for op in self.parser.get_diadic_operators() ] try: self._chars_ans_diadic.remove('-') except: pass self.KEYMAP['multiply'] = self.ml.mul_sym self.KEYMAP['divide'] = self.ml.div_sym self.KEYMAP['equal'] = self.ml.equ_sym self.clipboard = gtk.Clipboard() self.select_reason = self.SELECT_SELECT self.buffer = u"" self.showing_version = 0 self.showing_error = False self.ans_inserted = False self.show_vars = False self.connect("key_press_event", self.keypress_cb) self.connect("destroy", self.cleanup_cb) self.color = sugar.profile.get_color() self.layout = CalcLayout(self) self.label_entry = self.layout.label_entry self.text_entry = self.layout.text_entry self.last_eq_sig = None self.last_eqn_textview = None self.reset() self.layout.show_it() self.connect('joined', self._joined_cb) self.parser.log_debug_info() def ignore_key_cb(self, widget, event): return True def cleanup_cb(self, arg): _logger.debug('Cleaning up...') def equation_pressed_cb(self, eqn): """Callback for when an equation box is clicked""" if isinstance(eqn.result, SVGImage): return True if len(eqn.label) > 0: text = eqn.label else: # don't insert plain text if type(eqn.result) in (types.StringType, types.UnicodeType): text = '' else: text = self.parser.ml.format_number(eqn.result) self.button_pressed(self.TYPE_TEXT, text) return True def set_last_equation(self, eqn): """Set the 'last equation' TextView""" if self.last_eq_sig is not None: self.layout.last_eq.disconnect(self.last_eq_sig) self.last_eq_sig = None if not isinstance(eqn.result, ParserError): self.last_eq_sig = self.layout.last_eq.connect( 'button-press-event', lambda a1, a2, e: self.equation_pressed_cb(e), eqn) self.layout.last_eq.set_buffer(eqn.create_lasteq_textbuf()) def set_error_equation(self, eqn): """Set equation with error markers. Since set_last_equation implements this we can just forward the call.""" self.set_last_equation(eqn) def clear_equations(self): """Clear the list of old equations.""" self.old_eqs = [] self.showing_version = 0 def add_equation(self, eq, prepend=False, drawlasteq=False, tree=None): """ Insert equation in the history list and set variable if assignment. Input: eq: the equation object prepend: if True, prepend to list, else append drawlasteq: if True, draw in 'last equation' textbox and queue the buffer to be added to the history next time an equation is added. tree: the parsed tree, this will be used to set the label variable so that the equation can be used symbolicaly. """ if eq.equation is not None and len(eq.equation) > 0: if prepend: self.old_eqs.insert(0, eq) else: self.old_eqs.append(eq) self.showing_version = len(self.old_eqs) if self.last_eqn_textview is not None and drawlasteq: # Prepending here should be the opposite: prepend -> eqn on top. # We always own this equation self.layout.add_equation(self.last_eqn_textview, True, prepend=not prepend) self.last_eqn_textview = None own = (eq.owner == self.get_owner_id()) w = eq.create_history_object() w.connect('button-press-event', lambda w, e: self.equation_pressed_cb(eq)) if drawlasteq: self.set_last_equation(eq) # SVG images can't be plotted in last equation window if isinstance(eq.result, SVGImage): self.layout.add_equation(w, own, prepend=not prepend) else: self.last_eqn_textview = w else: self.layout.add_equation(w, own, prepend=not prepend) if eq.label is not None and len(eq.label) > 0: w = self.create_var_textview(eq.label, eq.result) if w is not None: self.layout.add_variable(eq.label, w) if tree is None: tree = self.parser.parse(eq.equation) self.parser.set_var(eq.label, tree) # FIXME: to be implemented def process_async(self, eqn): """Parse and process an equation asynchronously.""" def process(self): """Parse the equation entered and show the result""" s = unicode(self.text_entry.get_text()) label = unicode(self.label_entry.get_text()) _logger.debug('process(): parsing %r, label: %r', s, label) try: tree = self.parser.parse(s) res = self.parser.evaluate(tree) except ParserError, e: res = e self.showing_error = True if isinstance(res, str) and res.find('</svg>') > -1: res = SVGImage(data=res) _logger.debug('Result: %r', res) # Check whether assigning this label would cause recursion if not isinstance(res, ParserError) and len(label) > 0: lastpos = self.parser.get_var_used_ofs(label) if lastpos is not None: res = RuntimeError( _('Can not assign label: will cause recursion'), lastpos) # If parsing went ok, see if we have to replace the previous answer # to get a (more) exact result if self.ans_inserted and not isinstance(res, ParserError) \ and not isinstance(res, SVGImage): ansvar = self.format_insert_ans() pos = s.find(ansvar) if len(ansvar) > 6 and pos != -1: s2 = s.replace(ansvar, 'LastEqn') _logger.debug('process(): replacing previous answer %r: %r', ansvar, s2) tree = self.parser.parse(s2) res = self.parser.evaluate(tree) eqn = Equation(label, s, res, self.color, self.get_owner_id(), ml=self.ml) if isinstance(res, ParserError): self.set_error_equation(eqn) else: self.add_equation(eqn, drawlasteq=True, tree=tree) self.send_message("add_eq", value=str(eqn)) self.parser.set_var('Ans', eqn.result) # Setting LastEqn to the parse tree would certainly be faster, # however, it introduces recursion problems self.parser.set_var('LastEqn', eqn.result) self.showing_error = False self.ans_inserted = False self.text_entry.set_text(u'') self.label_entry.set_text(u'') return res is not None
class Calculate(ShareableActivity): TYPE_FUNCTION = 1 TYPE_OP_PRE = 2 TYPE_OP_POST = 3 TYPE_TEXT = 4 SELECT_NONE = 0 SELECT_SELECT = 1 SELECT_TAB = 2 KEYMAP = { 'Return': lambda o: o.process(), 'period': '.', 'equal': '=', 'plus': '+', 'minus': '-', 'asterisk': '*', 'multiply': '×', 'divide': '÷', 'slash': '/', 'BackSpace': lambda o: o.remove_character(-1), 'Delete': lambda o: o.remove_character(1), 'parenleft': '(', 'parenright': ')', 'exclam': '!', 'ampersand': '&', 'bar': '|', 'asciicircum': '^', 'less': '<', 'greater': '>', 'percent': '%', 'comma': ',', 'underscore': '_', 'Left': lambda o: o.move_left(), 'Right': lambda o: o.move_right(), 'Up': lambda o: o.get_older(), 'Down': lambda o: o.get_newer(), 'colon': lambda o: o.label_entered(), 'Home': lambda o: o.text_entry.set_position(0), 'End': lambda o: o.text_entry.set_position(len(o.text_entry.get_text())), 'Tab': lambda o: o.tab_complete(), } CTRL_KEYMAP = { 'c': lambda o: o.text_copy(), 'v': lambda o: o.text_paste(), 'x': lambda o: o.text_cut(), 'q': lambda o: o.close(), } SHIFT_KEYMAP = { 'Left': lambda o: o.expand_selection(-1), 'Right': lambda o: o.expand_selection(1), 'Home': lambda o: o.expand_selection(-1000), 'End': lambda o: o.expand_selection(1000), } IDENTIFIER_CHARS = u"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ " def __init__(self, handle): ShareableActivity.__init__(self, handle) self.old_eqs = [] self.ml = MathLib() self.parser = AstParser(self.ml) # These will result in 'Ans <operator character>' being inserted self._chars_ans_diadic = [op[0] for op in self.parser.get_diadic_operators()] try: self._chars_ans_diadic.remove('-') except: pass self.KEYMAP['multiply'] = self.ml.mul_sym self.KEYMAP['divide'] = self.ml.div_sym self.KEYMAP['equal'] = self.ml.equ_sym self.clipboard = gtk.Clipboard() self.select_reason = self.SELECT_SELECT self.buffer = u"" self.showing_version = 0 self.showing_error = False self.ans_inserted = False self.show_vars = False self.connect("key_press_event", self.keypress_cb) self.connect("destroy", self.cleanup_cb) self.color = sugar.profile.get_color() self.layout = CalcLayout(self) self.label_entry = self.layout.label_entry self.text_entry = self.layout.text_entry self.last_eq_sig = None self.last_eqn_textview = None self.reset() self.layout.show_it() self.connect('joined', self._joined_cb) self.parser.log_debug_info() def ignore_key_cb(self, widget, event): return True def cleanup_cb(self, arg): _logger.debug('Cleaning up...') def equation_pressed_cb(self, eqn): """Callback for when an equation box is clicked""" if isinstance(eqn.result, SVGImage): return True if len(eqn.label) > 0: text = eqn.label else: # don't insert plain text if type(eqn.result) in (types.StringType, types.UnicodeType): text = '' else: text = self.parser.ml.format_number(eqn.result) self.button_pressed(self.TYPE_TEXT, text) return True def set_last_equation(self, eqn): """Set the 'last equation' TextView""" if self.last_eq_sig is not None: self.layout.last_eq.disconnect(self.last_eq_sig) self.last_eq_sig = None if not isinstance(eqn.result, ParserError): self.last_eq_sig = self.layout.last_eq.connect( 'button-press-event', lambda a1, a2, e: self.equation_pressed_cb(e), eqn) self.layout.last_eq.set_buffer(eqn.create_lasteq_textbuf()) def set_error_equation(self, eqn): """Set equation with error markers. Since set_last_equation implements this we can just forward the call.""" self.set_last_equation(eqn) def clear_equations(self): """Clear the list of old equations.""" self.old_eqs = [] self.showing_version = 0 def add_equation(self, eq, prepend=False, drawlasteq=False, tree=None): """ Insert equation in the history list and set variable if assignment. Input: eq: the equation object prepend: if True, prepend to list, else append drawlasteq: if True, draw in 'last equation' textbox and queue the buffer to be added to the history next time an equation is added. tree: the parsed tree, this will be used to set the label variable so that the equation can be used symbolicaly. """ if eq.equation is not None and len(eq.equation) > 0: if prepend: self.old_eqs.insert(0, eq) else: self.old_eqs.append(eq) self.showing_version = len(self.old_eqs) if self.last_eqn_textview is not None and drawlasteq: # Prepending here should be the opposite: prepend -> eqn on top. # We always own this equation self.layout.add_equation(self.last_eqn_textview, True, prepend=not prepend) self.last_eqn_textview = None own = (eq.owner == self.get_owner_id()) w = eq.create_history_object() w.connect('button-press-event', lambda w, e: self.equation_pressed_cb(eq)) if drawlasteq: self.set_last_equation(eq) # SVG images can't be plotted in last equation window if isinstance(eq.result, SVGImage): self.layout.add_equation(w, own, prepend=not prepend) else: self.last_eqn_textview = w else: self.layout.add_equation(w, own, prepend=not prepend) if eq.label is not None and len(eq.label) > 0: w = self.create_var_textview(eq.label, eq.result) if w is not None: self.layout.add_variable(eq.label, w) if tree is None: tree = self.parser.parse(eq.equation) self.parser.set_var(eq.label, tree) # FIXME: to be implemented def process_async(self, eqn): """Parse and process an equation asynchronously.""" def process(self): """Parse the equation entered and show the result""" s = unicode(self.text_entry.get_text()) label = unicode(self.label_entry.get_text()) _logger.debug('process(): parsing %r, label: %r', s, label) try: tree = self.parser.parse(s) res = self.parser.evaluate(tree) except ParserError, e: res = e self.showing_error = True if type(res) == types.StringType and res.find('</svg>') > -1: res = SVGImage(data=res) _logger.debug('Result: %r', res) # Check whether assigning this label would cause recursion if not isinstance(res, ParserError) and len(label) > 0: lastpos = self.parser.get_var_used_ofs(label) if lastpos is not None: res = RuntimeError(_('Can not assign label: will cause recursion'), lastpos) # If parsing went ok, see if we have to replace the previous answer # to get a (more) exact result if self.ans_inserted and not isinstance(res, ParserError) \ and not isinstance(res, SVGImage): ansvar = self.format_insert_ans() pos = s.find(ansvar) if len(ansvar) > 6 and pos != -1: s2 = s.replace(ansvar, 'LastEqn') _logger.debug('process(): replacing previous answer %r: %r', ansvar, s2) tree = self.parser.parse(s2) res = self.parser.evaluate(tree) eqn = Equation(label, s, res, self.color, self.get_owner_id(), ml=self.ml) if isinstance(res, ParserError): self.set_error_equation(eqn) else: self.add_equation(eqn, drawlasteq=True, tree=tree) self.send_message("add_eq", value=str(eqn)) self.parser.set_var('Ans', eqn.result) # Setting LastEqn to the parse tree would certainly be faster, # however, it introduces recursion problems self.parser.set_var('LastEqn', eqn.result) self.showing_error = False self.ans_inserted = False self.text_entry.set_text(u'') self.label_entry.set_text(u'') return res is not None