def __init__(self, parent, font=None, lexer=None): super(AdvancedCodeWidget, self).__init__(parent) self.code = CodeWidget(self, font=font, lexer=lexer) self.find = FindWidget(self) self.find.hide() self.replace = ReplaceWidget(self) self.replace.hide() self.replace.replace_button.setEnabled(False) self.replace.replace_all_button.setEnabled(False) self.active_find_widget = None self.previous_find_widget = None self.code.selectionChanged.connect(self._update_replace_enabled) self.find.line_edit.returnPressed.connect(self.find_next) self.find.next_button.clicked.connect(self.find_next) self.find.prev_button.clicked.connect(self.find_prev) self.replace.line_edit.returnPressed.connect(self.find_next) self.replace.line_edit.textChanged.connect( self._update_replace_all_enabled) self.replace.next_button.clicked.connect(self.find_next) self.replace.prev_button.clicked.connect(self.find_prev) self.replace.replace_button.clicked.connect(self.replace_next) self.replace.replace_all_button.clicked.connect(self.replace_all) layout = QtGui.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.code) layout.addWidget(self.find) layout.addWidget(self.replace) self.setLayout(layout)
class AdvancedCodeWidget(QtGui.QWidget): """ Advanced widget for viewing and editing code, with support for search & replace """ ########################################################################### # AdvancedCodeWidget interface ########################################################################### def __init__(self, parent, font=None, lexer=None): super(AdvancedCodeWidget, self).__init__(parent) self.code = CodeWidget(self, font=font, lexer=lexer) self.find = FindWidget(self) self.find.hide() self.replace = ReplaceWidget(self) self.replace.hide() self.replace.replace_button.setEnabled(False) self.replace.replace_all_button.setEnabled(False) self.active_find_widget = None self.previous_find_widget = None self.code.selectionChanged.connect(self._update_replace_enabled) self.find.line_edit.returnPressed.connect(self.find_next) self.find.next_button.clicked.connect(self.find_next) self.find.prev_button.clicked.connect(self.find_prev) self.replace.line_edit.returnPressed.connect(self.find_next) self.replace.line_edit.textChanged.connect( self._update_replace_all_enabled) self.replace.next_button.clicked.connect(self.find_next) self.replace.prev_button.clicked.connect(self.find_prev) self.replace.replace_button.clicked.connect(self.replace_next) self.replace.replace_all_button.clicked.connect(self.replace_all) layout = QtGui.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.code) layout.addWidget(self.find) layout.addWidget(self.replace) self.setLayout(layout) def lines(self): """ Return the number of lines. """ return self.code.lines() def set_line_column(self, line, column): """ Move the cursor to a particular line/column position. """ self.code.set_line_column(line, column) def get_line_column(self): """ Get the current line and column numbers. """ return self.code.get_line_column() def get_selected_text(self): """ Return the currently selected text. """ return self.code.get_selected_text() def set_info_lines(self, info_lines): self.code.set_info_lines(info_lines) def set_warn_lines(self, warn_lines): self.code.set_warn_lines(warn_lines) def set_error_lines(self, error_lines): self.code.set_error_lines(error_lines) def enable_find(self): self.replace.hide() self.find.show() self.find.setFocus() if (self.active_find_widget == self.replace or (not self.active_find_widget and self.previous_find_widget == self.replace)): self.find.line_edit.setText(self.replace.line_edit.text()) self.find.line_edit.selectAll() self.active_find_widget = self.find def enable_replace(self): self.find.hide() self.replace.show() self.replace.setFocus() if (self.active_find_widget == self.find or (not self.active_find_widget and self.previous_find_widget == self.find)): self.replace.line_edit.setText(self.find.line_edit.text()) self.replace.line_edit.selectAll() self.active_find_widget = self.replace def find_in_document(self, search_text, direction='forward', replace=None): """ Finds the next occurance of the desired text and optionally replaces it. If 'replace' is None, a regular search will be executed, otherwise it will replace the occurance with the value of 'replace'. Returns the number of occurances found (0 or 1) """ if not search_text: return wrap = self.active_find_widget.wrap_action.isChecked() document = self.code.document() find_cursor = None flags = QtGui.QTextDocument.FindFlags(0) if self.active_find_widget.case_action.isChecked(): flags |= QtGui.QTextDocument.FindCaseSensitively if self.active_find_widget.word_action.isChecked(): flags |= QtGui.QTextDocument.FindWholeWords if direction == 'backward': flags |= QtGui.QTextDocument.FindBackward find_cursor = document.find(search_text, self.code.textCursor(), flags) if find_cursor.isNull() and wrap: if direction == 'backward': find_cursor = document.find(search_text, document.characterCount() - 1, flags) else: find_cursor = document.find(search_text, 0, flags) if not find_cursor.isNull(): if replace is not None: find_cursor.beginEditBlock() find_cursor.removeSelectedText() find_cursor.insertText(replace) find_cursor.endEditBlock() find_cursor.movePosition(QtGui.QTextCursor.Left, QtGui.QTextCursor.MoveAnchor, len(replace)) find_cursor.movePosition(QtGui.QTextCursor.Right, QtGui.QTextCursor.KeepAnchor, len(replace)) self.code.setTextCursor(find_cursor) else: self.code.setTextCursor(find_cursor) return find_cursor else: #else not found: beep or indicate? return None def find_next(self): if not self.active_find_widget: self.enable_find() search_text = unicode(self.active_find_widget.line_edit.text()) cursor = self.find_in_document(search_text=search_text) if cursor: return 1 return 0 def find_prev(self): if not self.active_find_widget: self.enable_find() search_text = unicode(self.active_find_widget.line_edit.text()) cursor = self.find_in_document(search_text=search_text, direction='backward') if cursor: return 1 return 0 def replace_next(self): search_text = self.replace.line_edit.text() replace_text = self.replace.replace_edit.text() cursor = self.code.textCursor() if cursor.selectedText() == search_text: cursor.beginEditBlock() cursor.removeSelectedText() cursor.insertText(replace_text) cursor.endEditBlock() return self.find_next() return 0 def replace_all(self): search_text = unicode(self.replace.line_edit.text()) replace_text = unicode(self.replace.replace_edit.text()) count = 0 cursor = self.code.textCursor() cursor.beginEditBlock() while self.find_in_document(search_text=search_text, replace=replace_text) != None: count += 1 cursor.endEditBlock() return count def print_(self, printer): """ Convenience method to call 'print_' on the CodeWidget. """ self.code.print_(printer) def ensureCursorVisible(self): self.code.ensureCursorVisible() def centerCursor(self): self.code.centerCursor() ########################################################################### # QWidget interface ########################################################################### def keyPressEvent(self, event): key_sequence = QtGui.QKeySequence(event.key() + int(event.modifiers())) if key_sequence.matches(QtGui.QKeySequence.Find): self.enable_find() elif key_sequence.matches(QtGui.QKeySequence.Replace): self.enable_replace() elif key_sequence.matches(QtCore.Qt.Key_Escape): if self.active_find_widget: self.find.hide() self.replace.hide() self.code.setFocus() self.previous_find_widget = self.active_find_widget self.active_find_widget = None return super(AdvancedCodeWidget, self).keyPressEvent(event) ########################################################################### # Private methods ########################################################################### def _update_replace_enabled(self): selection = self.code.textCursor().selectedText() find_text = self.replace.line_edit.text() self.replace.replace_button.setEnabled(selection == find_text) def _update_replace_all_enabled(self, text): self.replace.replace_all_button.setEnabled(len(text))
class AdvancedCodeWidget(QtGui.QWidget): """ Advanced widget for viewing and editing code, with support for search & replace """ ########################################################################### # AdvancedCodeWidget interface ########################################################################### def __init__(self, parent, font=None, lexer=None): super(AdvancedCodeWidget, self).__init__(parent) self.code = CodeWidget(self, font=font, lexer=lexer) self.find = FindWidget(self) self.find.hide() self.replace = ReplaceWidget(self) self.replace.hide() self.replace.replace_button.setEnabled(False) self.replace.replace_all_button.setEnabled(False) self.active_find_widget = None self.previous_find_widget = None self.code.selectionChanged.connect(self._update_replace_enabled) self.find.line_edit.returnPressed.connect(self.find_next) self.find.next_button.clicked.connect(self.find_next) self.find.prev_button.clicked.connect(self.find_prev) self.replace.line_edit.returnPressed.connect(self.find_next) self.replace.line_edit.textChanged.connect( self._update_replace_all_enabled) self.replace.next_button.clicked.connect(self.find_next) self.replace.prev_button.clicked.connect(self.find_prev) self.replace.replace_button.clicked.connect(self.replace_next) self.replace.replace_all_button.clicked.connect(self.replace_all) layout = QtGui.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.code) layout.addWidget(self.find) layout.addWidget(self.replace) self.setLayout(layout) def lines(self): """ Return the number of lines. """ return self.code.lines() def set_line_column(self, line, column): """ Move the cursor to a particular line/column position. """ self.code.set_line_column(line, column) def get_line_column(self): """ Get the current line and column numbers. """ return self.code.get_line_column() def get_selected_text(self): """ Return the currently selected text. """ return self.code.get_selected_text() def set_info_lines(self, info_lines): self.code.set_info_lines(info_lines) def set_warn_lines(self, warn_lines): self.code.set_warn_lines(warn_lines) def set_error_lines(self, error_lines): self.code.set_error_lines(error_lines) def enable_find(self): self.replace.hide() self.find.show() self.find.setFocus() if (self.active_find_widget == self.replace or (not self.active_find_widget and self.previous_find_widget == self.replace)): self.find.line_edit.setText(self.replace.line_edit.text()) self.find.line_edit.selectAll() self.active_find_widget = self.find def enable_replace(self): self.find.hide() self.replace.show() self.replace.setFocus() if (self.active_find_widget == self.find or (not self.active_find_widget and self.previous_find_widget == self.find)): self.replace.line_edit.setText(self.find.line_edit.text()) self.replace.line_edit.selectAll() self.active_find_widget = self.replace def find_in_document(self, search_text, direction='forward', replace=None): """ Finds the next occurance of the desired text and optionally replaces it. If 'replace' is None, a regular search will be executed, otherwise it will replace the occurance with the value of 'replace'. Returns the number of occurances found (0 or 1) """ if not search_text: return wrap = self.active_find_widget.wrap_action.isChecked() document = self.code.document() find_cursor = None flags = QtGui.QTextDocument.FindFlags(0) if self.active_find_widget.case_action.isChecked(): flags |= QtGui.QTextDocument.FindCaseSensitively if self.active_find_widget.word_action.isChecked(): flags |= QtGui.QTextDocument.FindWholeWords if direction == 'backward': flags |= QtGui.QTextDocument.FindBackward find_cursor = document.find(search_text, self.code.textCursor(), flags) if find_cursor.isNull() and wrap: if direction == 'backward': find_cursor = document.find(search_text, document.characterCount()-1, flags) else: find_cursor = document.find(search_text, 0, flags) if not find_cursor.isNull(): if replace is not None: find_cursor.beginEditBlock() find_cursor.removeSelectedText() find_cursor.insertText(replace) find_cursor.endEditBlock() find_cursor.movePosition( QtGui.QTextCursor.Left, QtGui.QTextCursor.MoveAnchor,len(replace)) find_cursor.movePosition( QtGui.QTextCursor.Right, QtGui.QTextCursor.KeepAnchor,len(replace)) self.code.setTextCursor(find_cursor) else: self.code.setTextCursor(find_cursor) return find_cursor else: #else not found: beep or indicate? return None def find_next(self): if not self.active_find_widget: self.enable_find() search_text = unicode(self.active_find_widget.line_edit.text()) cursor = self.find_in_document(search_text=search_text) if cursor: return 1 return 0 def find_prev(self): if not self.active_find_widget: self.enable_find() search_text = unicode(self.active_find_widget.line_edit.text()) cursor = self.find_in_document(search_text=search_text, direction='backward') if cursor: return 1 return 0 def replace_next(self): search_text = self.replace.line_edit.text() replace_text = self.replace.replace_edit.text() cursor = self.code.textCursor() if cursor.selectedText() == search_text: cursor.beginEditBlock() cursor.removeSelectedText() cursor.insertText(replace_text) cursor.endEditBlock() return self.find_next() return 0 def replace_all(self): search_text = unicode(self.replace.line_edit.text()) replace_text = unicode(self.replace.replace_edit.text()) count = 0 cursor = self.code.textCursor() cursor.beginEditBlock() while self.find_in_document(search_text=search_text, replace=replace_text) != None: count += 1 cursor.endEditBlock() return count def print_(self, printer): """ Convenience method to call 'print_' on the CodeWidget. """ self.code.print_(printer) def ensureCursorVisible(self): self.code.ensureCursorVisible() def centerCursor(self): self.code.centerCursor() ########################################################################### # QWidget interface ########################################################################### def keyPressEvent(self, event): key_sequence = QtGui.QKeySequence(event.key() + int(event.modifiers())) if key_sequence.matches(QtGui.QKeySequence.Find): self.enable_find() elif key_sequence.matches(QtGui.QKeySequence.Replace): self.enable_replace() elif key_sequence.matches(QtGui.QKeySequence(QtCore.Qt.Key_Escape)): if self.active_find_widget: self.find.hide() self.replace.hide() self.code.setFocus() self.previous_find_widget = self.active_find_widget self.active_find_widget = None return super(AdvancedCodeWidget, self).keyPressEvent(event) ########################################################################### # Private methods ########################################################################### def _update_replace_enabled(self): selection = self.code.textCursor().selectedText() find_text = self.replace.line_edit.text() self.replace.replace_button.setEnabled(selection == find_text) def _update_replace_all_enabled(self, text): self.replace.replace_all_button.setEnabled(len(text))