aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/utils/multitextcursor.h
blob: 6f40b984c91e89e6f4be0f7bc55d871bfe37699a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#pragma once

#include "utils_global.h"

#include <QKeySequence>
#include <QTextCursor>

QT_BEGIN_NAMESPACE
class QKeyEvent;
class QPlainTextEdit;
QT_END_NAMESPACE

namespace Utils {

class PlainTextDocumentLayout;

class QTCREATOR_UTILS_EXPORT MultiTextCursor
{
public:
    MultiTextCursor();
    explicit MultiTextCursor(const QList<QTextCursor> &cursors);

    MultiTextCursor(const MultiTextCursor &multiCursor);
    MultiTextCursor &operator=(const MultiTextCursor &multiCursor);
    MultiTextCursor(const MultiTextCursor &&multiCursor);
    MultiTextCursor &operator=(const MultiTextCursor &&multiCursor);

    ~MultiTextCursor();

    /// Replaces all cursors with \param cursors and the last one will be the new main cursors.
    void setCursors(const QList<QTextCursor> &cursors);
    const QList<QTextCursor> cursors() const;

    /// Returns whether this multi cursor contains any cursor.
    bool isNull() const;
    /// Returns whether this multi cursor contains more than one cursor.
    bool hasMultipleCursors() const;
    /// Returns the number of cursors handled by this cursor.
    int cursorCount() const;

    bool containsCursor(const QTextCursor &cursor) const;
    void removeCursor(const QTextCursor &cursor);
    /// the \param cursor that is appended by added by \brief addCursor
    /// will be interpreted as the new main cursor
    void addCursor(const QTextCursor &cursor);
    void addCursors(const QList<QTextCursor> &cursors);
    /// convenience function that removes the old main cursor and appends
    /// \param cursor as the new main cursor
    void replaceMainCursor(const QTextCursor &cursor);
    /// Returns the main cursor.
    QTextCursor mainCursor() const;
    /// Returns the main cursor and removes it from this multi cursor.
    QTextCursor takeMainCursor();

    void beginEditBlock();
    void endEditBlock();
    /// merges overlapping cursors together
    void mergeCursors();

    /// applies the move key event \param e to all cursors in this multi cursor
    bool handleMoveKeyEvent(
        QKeyEvent *e, bool camelCaseNavigationEnabled, PlainTextDocumentLayout *layout = nullptr);
    /// applies the move \param operation to all cursors in this multi cursor \param n times
    /// with the move \param mode
    void movePosition(
        QTextCursor::MoveOperation operation,
        QTextCursor::MoveMode mode,
        int n = 1,
        PlainTextDocumentLayout *layout = nullptr);

    /// Returns whether any cursor has a selection.
    bool hasSelection() const;
    /// Returns the selected text of all cursors that have a selection separated by
    /// a newline character.
    QString selectedText() const;
    /// removes the selected text of all cursors that have a selection from the document
    void removeSelectedText();
    void clearSelection();

    /// inserts \param text into all cursors, potentially removing correctly selected text
    void insertText(const QString &text, bool selectNewText = false);

    bool operator==(const MultiTextCursor &other) const;
    bool operator!=(const MultiTextCursor &other) const;

    template <typename T, typename mapit>
    class BaseIterator {
    public:
        using iterator_category = std::input_iterator_tag;
        using difference_type = int;
        using value_type = T;
        using pointer = T *;
        using reference = T &;
        BaseIterator(const mapit &it) : internalit(it) {}
        BaseIterator &operator++() { ++internalit; return *this; }
        BaseIterator operator++(int) { auto result = *this; ++(*this); return result; }
        bool operator==(BaseIterator other) const { return internalit == other.internalit; }
        bool operator!=(BaseIterator other) const { return !(*this == other); }
        reference operator*() const { return *(internalit->second); }

    private:
        mapit internalit;
    };

    using iterator
        = BaseIterator<QTextCursor, std::map<int, std::list<QTextCursor>::iterator>::iterator>;
    using const_iterator
        = BaseIterator<const QTextCursor,
                       std::map<int, std::list<QTextCursor>::iterator>::const_iterator>;

    iterator begin() { return m_cursorMap.begin(); }
    iterator end() { return m_cursorMap.end(); }
    const_iterator begin() const { return m_cursorMap.begin(); }
    const_iterator end() const { return m_cursorMap.end(); }
    const_iterator constBegin() const { return m_cursorMap.cbegin(); }
    const_iterator constEnd() const { return m_cursorMap.cend(); }

    static bool multiCursorEvent(
        QKeyEvent *e,
        QKeySequence::StandardKey matchKey,
        Qt::KeyboardModifiers additionalFilterModifier = {});

private:
    std::list<QTextCursor> m_cursorList;
    std::map<int, std::list<QTextCursor>::iterator> m_cursorMap;

    void fillMapWithList();
};

} // namespace Utils