def show_context_menu(self, pos): m = QMenu(self) a = m.addAction c = self.editor.cursorForPosition(pos) origc = QTextCursor(c) current_cursor = self.editor.textCursor() r = origr = self.editor.syntax_range_for_cursor(c) if ( r is None or not r.format.property(SPELL_PROPERTY) ) and c.positionInBlock() > 0 and not current_cursor.hasSelection(): c.setPosition(c.position() - 1) r = self.editor.syntax_range_for_cursor(c) if r is not None and r.format.property(SPELL_PROPERTY): word = self.editor.text_for_range(c.block(), r) locale = self.editor.spellcheck_locale_for_cursor(c) orig_pos = c.position() c.setPosition(orig_pos - utf16_length(word)) found = False self.editor.setTextCursor(c) if self.editor.find_spell_word([word], locale.langcode, center_on_cursor=False): found = True fc = self.editor.textCursor() if fc.position() < c.position(): self.editor.find_spell_word([word], locale.langcode, center_on_cursor=False) spell_cursor = self.editor.textCursor() if current_cursor.hasSelection(): # Restore the current cursor so that any selection is preserved # for the change case actions self.editor.setTextCursor(current_cursor) if found: suggestions = dictionaries.suggestions(word, locale)[:7] if suggestions: for suggestion in suggestions: ac = m.addAction( suggestion, partial(self.editor.simple_replace, suggestion, cursor=spell_cursor)) f = ac.font() f.setBold(True), ac.setFont(f) m.addSeparator() m.addAction(actions['spell-next']) m.addAction(_('Ignore this word'), partial(self._nuke_word, None, word, locale)) dics = dictionaries.active_user_dictionaries if len(dics) > 0: if len(dics) == 1: m.addAction( _('Add this word to the dictionary: {0}').format( dics[0].name), partial(self._nuke_word, dics[0].name, word, locale)) else: ac = m.addAction(_('Add this word to the dictionary')) dmenu = QMenu(m) ac.setMenu(dmenu) for dic in dics: dmenu.addAction( dic.name, partial(self._nuke_word, dic.name, word, locale)) m.addSeparator() if origr is not None and origr.format.property(LINK_PROPERTY): href = self.editor.text_for_range(origc.block(), origr) m.addAction( _('Open %s') % href, partial(self.link_clicked.emit, href)) if origr is not None and (origr.format.property(TAG_NAME_PROPERTY) or origr.format.property(CSS_PROPERTY)): word = self.editor.text_for_range(origc.block(), origr) item_type = 'tag_name' if origr.format.property( TAG_NAME_PROPERTY) else 'css_property' url = help_url(word, item_type, self.editor.highlighter.doc_name, extra_data=current_container().opf_version) if url is not None: m.addAction( _('Show help for: %s') % word, partial(open_url, url)) for x in ('undo', 'redo'): ac = actions['editor-%s' % x] if ac.isEnabled(): a(ac) m.addSeparator() for x in ('cut', 'copy', 'paste'): ac = actions['editor-' + x] if ac.isEnabled(): a(ac) m.addSeparator() m.addAction(_('&Select all'), self.editor.select_all) if self.selected_text or self.has_marked_text: update_mark_text_action(self) m.addAction(actions['mark-selected-text']) if self.syntax != 'css' and actions['editor-cut'].isEnabled(): cm = QMenu(_('Change &case'), m) for ac in 'upper lower swap title capitalize'.split(): cm.addAction(actions['transform-case-' + ac]) m.addMenu(cm) if self.syntax == 'html': m.addAction(actions['multisplit']) m.exec_(self.editor.viewport().mapToGlobal(pos))
def find_text(self, pat, cursor, reverse): from calibre.gui2.tweak_book.text_search import find_text_in_chunks chunks = [] cstart = min(cursor.position(), cursor.anchor()) cend = max(cursor.position(), cursor.anchor()) if reverse: cend -= 1 c = QTextCursor(cursor) c.setPosition(cstart) block = c.block() in_text = find_tag_definition(block, 0)[0] is None if in_text: # Check if we are in comment/PI/etc. pb = block.previous() while pb.isValid(): boundaries = pb.userData().non_tag_structures if boundaries: if boundaries[-1].is_start: in_text = False break pb = pb.previous() def append(text, start): text = text.replace(PARAGRAPH_SEPARATOR, '\n') after = start + len(text) if start <= cend and cstart < after: extra = after - (cend + 1) if extra > 0: text = text[:-extra] extra = cstart - start if extra > 0: text = text[extra:] chunks.append((text, start + max(extra, 0))) while block.isValid() and block.position() <= cend: ud = block.userData() boundaries = sorted(chain(ud.tags, ud.non_tag_structures), key=get_offset) if not boundaries: # Add the whole line if in_text: text = block.text() + '\n' append(text, block.position()) else: start = block.position() c.setPosition(start) for b in boundaries: if in_text: c.setPosition(start + b.offset, QTextCursor.MoveMode.KeepAnchor) if c.hasSelection(): append(c.selectedText(), c.anchor()) in_text = not b.is_start c.setPosition(start + b.offset + 1) if in_text: # Add remaining text in block c.setPosition(block.position() + boundaries[-1].offset + 1) c.movePosition(QTextCursor.MoveOperation.EndOfBlock, QTextCursor.MoveMode.KeepAnchor) if c.hasSelection(): append(c.selectedText() + '\n', c.anchor()) block = block.next() s, e = find_text_in_chunks(pat, chunks) return s != -1 and e != -1, s, e