def createDocument(self, rootFrame):

        # Create empty document
        self.document = QTextDocument()
        self.document.setUndoRedoEnabled(False)
        self.document.setIndentWidth(20)

        # Register a renderer for custom text objects
        mo = CustomObjectRenderer()
        mo.setParent(self.document)
        self.document.documentLayout().registerHandler(QTextCharFormat.UserObject+1, mo);

        self.cursor = QTextCursor(self.document)
        self.listLevel = 0
        self.paraFormat = None

        # add all root paragraphs
        for n in rootFrame.children:
            self.addNode(n)

        # Clean up the first paragraph if document is not empty
        self.cursor.movePosition(QTextCursor.Start)
        b = self.cursor.block()
        if b.length() == 1:
            cursor = QTextCursor(self.document.findBlockByLineNumber(0))
            cursor.select(QTextCursor.BlockUnderCursor)
            cursor.deleteChar()

        return self.document
Ejemplo n.º 2
0
    def find_text(self, pat, cursor):
        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())
        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, c.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(c.EndOfBlock, c.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
Ejemplo n.º 3
0
 def do_test(self):
     selections = []
     self.match_locs = []
     if self.regex_valid():
         text = unicode_type(self.preview.toPlainText())
         regex = unicode_type(self.regex.text())
         cursor = QTextCursor(self.preview.document())
         extsel = QTextEdit.ExtraSelection()
         extsel.cursor = cursor
         extsel.format.setBackground(QBrush(Qt.yellow))
         try:
             for match in compile_regular_expression(regex).finditer(text):
                 es = QTextEdit.ExtraSelection(extsel)
                 es.cursor.setPosition(match.start(),
                                       QTextCursor.MoveAnchor)
                 es.cursor.setPosition(match.end(), QTextCursor.KeepAnchor)
                 selections.append(es)
                 self.match_locs.append((match.start(), match.end()))
         except:
             pass
     self.preview.setExtraSelections(selections)
     if self.match_locs:
         self.next.setEnabled(True)
         self.previous.setEnabled(True)
     self.occurrences.setText(unicode_type(len(self.match_locs)))
Ejemplo n.º 4
0
 def copy_lines(self, lo, hi, cursor):
     ''' Copy specified lines from the syntax highlighted buffer into the
     destination cursor, preserving all formatting created by the syntax
     highlighter. '''
     self.highlighter.join()
     num = hi - lo
     if num > 0:
         block = self.findBlockByNumber(lo)
         while num > 0:
             num -= 1
             cursor.insertText(block.text())
             dest_block = cursor.block()
             c = QTextCursor(dest_block)
             try:
                 afs = block.layout().additionalFormats()
             except AttributeError:
                 afs = ()
             for af in afs:
                 start = dest_block.position() + af.start
                 c.setPosition(start), c.setPosition(
                     start + af.length, c.KeepAnchor)
                 c.setCharFormat(af.format)
             cursor.insertBlock()
             cursor.setCharFormat(NULL_FMT)
             block = next(block)
Ejemplo n.º 5
0
    def reformat_blocks(self, position, removed, added):
        doc = self.doc
        if doc is None or self.ignore_requests or not hasattr(self, 'state_map'):
            return

        block = doc.findBlock(position)
        if not block.isValid():
            return
        start_cursor = QTextCursor(block)
        last_block = doc.findBlock(position + added + (1 if removed > 0 else 0))
        if not last_block.isValid():
            last_block = doc.lastBlock()
        end_cursor = QTextCursor(last_block)
        end_cursor.movePosition(end_cursor.EndOfBlock)
        self.requests.append((start_cursor, end_cursor))
        QTimer.singleShot(0, self.do_one_block)
Ejemplo n.º 6
0
 def in_image():
     c = QTextCursor(doc.text)
     c.movePosition(QTextCursor.Start)
     while c.movePosition(QTextCursor.NextCharacter,
                          QTextCursor.KeepAnchor):
         if doc.in_image():
             break
Ejemplo n.º 7
0
    def __init__(self, config):
        super(Doc, self).__init__()
        self._text = QTextDocument()
        self._cfg = config
        self._text_edit_cursor = QTextCursor(self._text)
        self._text.setIndentWidth(self._cfg.get("TextEditor/IndentWidth", 24))

        self.set_default_font()
Ejemplo n.º 8
0
 def in_table():
     c = QTextCursor(doc.text)
     c.movePosition(QTextCursor.Start)
     while c.movePosition(QTextCursor.NextCharacter,
                          QTextCursor.KeepAnchor):
         if doc.in_table():
             cc = doc.table().cellAt(2, 1)
             cc.firstCursorPosition().insertText("Hello")
             doc.change(cc.firstCursorPosition())
Ejemplo n.º 9
0
 def goto_loc(self,
              loc,
              operation=QTextCursor.Right,
              mode=QTextCursor.KeepAnchor,
              n=0):
     cursor = QTextCursor(self.preview.document())
     cursor.setPosition(loc)
     if n:
         cursor.movePosition(operation, mode, n)
     self.preview.setTextCursor(cursor)
Ejemplo n.º 10
0
def apply_smart_comment(editor, opening='/*', closing='*/', line_comment=None):
    doc = editor.document()
    c = QTextCursor(editor.textCursor())
    c.clearSelection()
    before_opening = doc.find(opening, c, QTextDocument.FindFlag.FindBackward | QTextDocument.FindFlag.FindCaseSensitively)
    before_closing = doc.find(closing, c, QTextDocument.FindFlag.FindBackward | QTextDocument.FindFlag.FindCaseSensitively)
    after_opening = doc.find(opening, c, QTextDocument.FindFlag.FindCaseSensitively)
    after_closing = doc.find(closing, c, QTextDocument.FindFlag.FindCaseSensitively)
    in_block_comment = (not before_opening.isNull() and (before_closing.isNull() or before_opening.position() >= before_closing.position())) and \
        (not after_closing.isNull() and (after_opening.isNull() or after_closing.position() <= after_opening.position()))
    if in_block_comment:
        before_opening.removeSelectedText(), after_closing.removeSelectedText()
        return
    c = QTextCursor(editor.textCursor())
    left, right = min(c.position(), c.anchor()), max(c.position(), c.anchor())
    c.beginEditBlock()
    c.setPosition(right), c.insertText(closing)
    c.setPosition(left), c.insertText(opening)
    c.endEditBlock()
Ejemplo n.º 11
0
 def in_table():
     c = QTextCursor(doc.text)
     c.movePosition(QTextCursor.Start)
     while c.movePosition(QTextCursor.NextCharacter,
                          QTextCursor.KeepAnchor):
         if doc.in_table():
             doc.text_align(Qt.AlignRight, QTextCharFormat.AlignBottom)
             a = doc._text_edit_cursor.charFormat().verticalAlignment()
             self.assertEqual(a, QTextCharFormat.AlignBottom)
             break
Ejemplo n.º 12
0
 def in_table():
     # is exists table in document ?
     c = QTextCursor(doc.text)
     c.movePosition(QTextCursor.Start)
     _in_table = False
     while c.movePosition(QTextCursor.NextCharacter,
                          QTextCursor.KeepAnchor):
         if doc.in_table():
             _in_table = True
             break
     return _in_table
Ejemplo n.º 13
0
 def search(self, query, reverse=False):
     ''' Search for query, also searching the headers. Matches in headers
     are not highlighted as managing the highlight is too much of a pain.'''
     if not query.strip():
         return
     c = self.textCursor()
     lnum = c.block().blockNumber()
     cpos = c.positionInBlock()
     headers = dict(self.headers)
     if lnum in headers:
         cpos = self.search_header_pos
     lines = unicode(self.toPlainText()).splitlines()
     for hn, text in self.headers:
         lines[hn] = text
     prefix, postfix = lines[lnum][:cpos], lines[lnum][cpos:]
     before, after = enumerate(
         lines[0:lnum]), ((lnum + 1 + i, x)
                          for i, x in enumerate(lines[lnum + 1:]))
     if reverse:
         sl = chain([(lnum, prefix)], reversed(tuple(before)),
                    reversed(tuple(after)), [(lnum, postfix)])
     else:
         sl = chain([(lnum, postfix)], after, before, [(lnum, prefix)])
     flags = regex.REVERSE if reverse else 0
     pat = regex.compile(regex.escape(query, special_only=True),
                         flags=regex.UNICODE | regex.IGNORECASE | flags)
     for num, text in sl:
         try:
             m = next(pat.finditer(text))
         except StopIteration:
             continue
         start, end = m.span()
         length = end - start
         if text is postfix:
             start += cpos
         c = QTextCursor(self.document().findBlockByNumber(num))
         c.setPosition(c.position() + start)
         if num in headers:
             self.search_header_pos = start + length
         else:
             c.setPosition(c.position() + length, c.KeepAnchor)
             self.search_header_pos = 0
         if reverse:
             pos, anchor = c.position(), c.anchor()
             c.setPosition(pos), c.setPosition(anchor, c.KeepAnchor)
         self.setTextCursor(c)
         self.centerCursor()
         self.scrolled.emit()
         break
     else:
         info_dialog(self,
                     _('No matches found'),
                     _('No matches found for query: %s' % query),
                     show=True)
Ejemplo n.º 14
0
    def search_log_area(self):
        """ Search a word in log area.
        Keep last cursor and word used for iteration
        in the document.
        """

        cursor: QTextCursor
        doc: QTextDocument
        text: str
        search_format: QTextCharFormat

        text = self.log_filters.filter_line.text()
        doc = self.log_area.document()

        search_format = QTextCharFormat()
        color = QColor("yellow")
        color.setAlpha(255)
        search_format.setBackground(color)

        # remove the previous search highlight
        if not self.last_search_cursor.isNull():
            self.last_search_cursor.setCharFormat(QTextCharFormat())

        # if search word changed or erased, reset cursor and last_search
        if len(text) == 0 or text != self.last_search:
            self.last_search_cursor = QTextCursor()
            self.last_search = text
            self.log_area.unsetCursor()
        # if has no word to search, just return
        if len(text) == 0:
            return

        cursor = self.last_search_cursor if not self.last_search_cursor.isNull(
        ) else QTextCursor(doc)
        cursor = doc.find(text, cursor)
        if not cursor.isNull():
            self.log_area.setTextCursor(cursor)
            cursor.setCharFormat(search_format)
        else:
            self.log_area.unsetCursor()
        self.last_search_cursor = cursor
Ejemplo n.º 15
0
    def find_text(self, pat, cursor):
        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())
        c = QTextCursor(cursor)
        c.setPosition(cstart)
        block = c.block()
        in_text = find_tag_definition(block, 0)[0] is None

        def append(text, start):
            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:
            boundaries = sorted(block.userData().tags, key=get_offset)
            if not boundaries:
                # Add the whole line
                if in_text:
                    text = block.text()
                    if text:
                        append(text, block.position())
            else:
                start = block.position()
                c.setPosition(start)
                for b in boundaries:
                    if in_text:
                        c.setPosition(start + b.offset, c.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(c.EndOfBlock, c.KeepAnchor)
                    if c.hasSelection():
                        append(c.selectedText(), c.anchor())
            block = block.next()
        s, e = find_text_in_chunks(pat, chunks)
        return s != -1 and e != -1, s, e
Ejemplo n.º 16
0
        def in_table():
            c = QTextCursor(doc.text)
            c.movePosition(QTextCursor.Start)
            while c.movePosition(QTextCursor.NextCharacter,
                                 QTextCursor.KeepAnchor):
                if doc.in_table():
                    cc = doc.table().cellAt(2, 2)
                    cc.firstCursorPosition().insertText("Hello1")

                    cc = doc.table().cellAt(2, 1)
                    cc.firstCursorPosition().insertText("Hello")

                    c.movePosition(QTextCursor.EndOfBlock,
                                   QTextCursor.KeepAnchor)
                    break
Ejemplo n.º 17
0
 def in_table():
     # is exists table in document ?
     c = QTextCursor(doc.text)
     c.movePosition(QTextCursor.Start)
     _in_table = False
     while c.movePosition(QTextCursor.NextCharacter,
                          QTextCursor.KeepAnchor):
         if doc.in_table():
             _in_table = True
             doc.background_color("blue")
             cc = doc._text_edit_cursor
             cell = cc.currentTable().cellAt(cc).format()
             clr = cell.background().color().name()
             self.assertEqual(clr, QColor("blue").name())
             break
     return _in_table
Ejemplo n.º 18
0
 def set_document(self, doc, doc_name=None):
     old_doc = self.doc
     if old_doc is not None:
         old_doc.contentsChange.disconnect(self.reformat_blocks)
         c = QTextCursor(old_doc)
         c.beginEditBlock()
         blk = old_doc.begin()
         while blk.isValid():
             blk.layout().clearAdditionalFormats()
             blk = blk.next()
         c.endEditBlock()
     self.doc = self.doc_name = None
     if doc is not None:
         self.doc = doc
         self.doc_name = doc_name
         doc.contentsChange.connect(self.reformat_blocks)
         self.rehighlight()
Ejemplo n.º 19
0
    def resized(self):
        ' Resize images to fit in new view size and adjust all line number references accordingly '
        for v in (self.left, self.right):
            changes = []
            for i, (top, bot, kind) in enumerate(v.changes):
                if top in v.images:
                    img, oldw, oldlines = v.images[top]
                    lines, w = self.get_lines_for_image(img, v)
                    if lines != oldlines:
                        changes.append((i, lines, lines - oldlines, img, w))

            for i, lines, delta, img, w in changes:
                top, bot, kind = v.changes[i]
                c = QTextCursor(v.document().findBlockByNumber(top + 1))
                c.beginEditBlock()
                c.movePosition(c.StartOfBlock)
                if delta > 0:
                    for _ in xrange(delta):
                        c.insertBlock()
                else:
                    c.movePosition(c.NextBlock, c.KeepAnchor, -delta)
                    c.removeSelectedText()
                c.endEditBlock()
                v.images[top] = (img, w, lines)

                def mapnum(x):
                    return x if x <= top else x + delta

                lnm = LineNumberMap()
                lnm.max_width = v.line_number_map.max_width
                for x, val in v.line_number_map.iteritems():
                    dict.__setitem__(lnm, mapnum(x), val)
                v.line_number_map = lnm
                v.changes = [(mapnum(t), mapnum(b), k)
                             for t, b, k in v.changes]
                v.headers = [(mapnum(x), name) for x, name in v.headers]
                v.images = OrderedDict(
                    (mapnum(x), v) for x, v in v.images.iteritems())
            v.viewport().update()
Ejemplo n.º 20
0
    def __init__(self):
        super(MainWindow, self).__init__()

        self.log_area = None  # :type QPlainTextEdit
        self.main_document = None  # :type QTextDocument
        self.highlight_options_dialog = None  # :type HighlightOptionsDialog
        self.serial_dialog = None  # :type SerialDialog
        self.serial_menu = None  # :type QMenu
        self.highlight_options_menu = None  # :type QMenu
        self.help_menu = None  # :type QMenu
        self.log_filter_widget = None  # :type QWidget
        self.log_filters = None  # :type FilterPanel
        self.last_search = str()
        self.last_search_cursor = QTextCursor()

        container = QWidget()
        self.setup_menu()
        self.setup_text_area()
        self.setup_footer_panel()
        self.setup_serial_dialog()
        self.setup_highlight_options_dialog()

        self.first_search_flag = False

        self.serial_worker = SerialListenerWorker()
        self.serial_worker.signal.connect(self.add_line_to_log_area)

        self.log_area_layout = QVBoxLayout()
        self.log_area_layout.setContentsMargins(0, 0, 0, 0)
        self.log_area_layout.addWidget(self.log_area)
        self.log_area_layout.addWidget(self.log_filter_widget)
        container.setLayout(self.log_area_layout)

        self.setCentralWidget(container)

        self.setWindowTitle(APP_NAME)
        self.setGeometry(QRect(100, 100, 800, 600))
Ejemplo n.º 21
0
    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))