summaryrefslogtreecommitdiffstats
path: root/doc/src/examples/codeeditor.qdoc
blob: 9935e88c64bbb73017fb201f6197b7b3fdec2c06 (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** GNU Free Documentation License
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms
** and conditions contained in a signed written agreement between you
** and Nokia.
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \example widgets/codeeditor
    \title Code Editor Example

    \brief The Code Editor example shows how to create a simple editor that
    has line numbers and that highlights the current line.

    \image codeeditor-example.png

    As can be seen from the image, the editor displays the line
    numbers in an area to the left of the area for editing. The editor
    will highlight the line containing the cursor.

    We implement the editor in \c CodeEditor, which is a widget that
    inherits QPlainTextEdit. We keep a separate widget in \c
    CodeEditor (\c LineNumberArea) onto which we draw the line
    numbers.

    QPlainTextEdit inherits from QAbstractScrollArea, and editing
    takes place within its \l{QAbstractScrollArea::}{viewport()}'s
    margins. We make room for our line number area by setting the left
    margin of the viewport to the size we need to draw the line
    numbers.

    When it comes to editing code, we prefer QPlainTextEdit over
    QTextEdit because it is optimized for handling plain text. See
    the QPlainTextEdit class description for details.

    QPlainTextEdit lets us add selections in addition to the
    selection the user can make with the mouse or keyboard. We use
    this functionality to highlight the current line. More on this
    later.

    We will now move on to the definitions and implementations of \c
    CodeEditor and \c LineNumberArea. Let's start with the \c
    LineNumberArea class. 

    \section1 The LineNumberArea Class

    We paint the line numbers on this widget, and place it over the \c
    CodeEditor's \l{QAbstractScrollArea::}{viewport()}'s left margin
    area.

    We need to use protected functions in QPlainTextEdit while
    painting the area. So to keep things simple, we  paint the area in
    the \c CodeEditor class. The area also asks the editor to
    calculate its size hint.

    Note that we could simply paint the line numbers directly on the
    code editor, and drop the LineNumberArea class. However, the
    QWidget class helps us to \l{QWidget::}{scroll()} its contents.
    Also, having a separate widget is the right choice if we wish to
    extend the editor with breakpoints or other code editor features.
    The widget would then help in the handling of mouse events.

    \snippet widgets/codeeditor/codeeditor.h extraarea

    \section1 CodeEditor Class Definition

    Here is the code editor's class definition:

    \snippet widgets/codeeditor/codeeditor.h codeeditordefinition

    In the editor we resize and draw the line numbers on the \c
    LineNumberArea. We need to do this when the number of lines in the
    editor changes, and when the editor's viewport() is scrolled. Of
    course, it is also done when the editor's size changes. We do
    this in \c updateLineNumberWidth() and \c updateLineNumberArea().

    Whenever, the cursor's position changes, we highlight the current
    line in \c highlightCurrentLine().

    \section1 CodeEditor Class Implementation

    We will now go through the code editors implementation, starting
    off with the constructor.

    \snippet widgets/codeeditor/codeeditor.cpp constructor

    In the constructor we connect our slots to signals in
    QPlainTextEdit. It is necessary to calculate the line number area
    width and highlight the first line when the editor is created.

    \snippet widgets/codeeditor/codeeditor.cpp extraAreaWidth

    The \c lineNumberAreaWidth() function calculates the width of the
    \c LineNumberArea widget. We take the number of digits in the last
    line of the editor and multiply that with the maximum width of a
    digit.

    \snippet widgets/codeeditor/codeeditor.cpp slotUpdateExtraAreaWidth

    When we update the width of the line number area, we simply call
    QAbstractScrollArea::setViewportMargins().

    \snippet widgets/codeeditor/codeeditor.cpp slotUpdateRequest

    This slot is invoked when the editors viewport has been scrolled.
    The QRect given as argument is the part of the editing area that
    is do be updated (redrawn). \c dy holds the number of pixels the
    view has been scrolled vertically.

    \snippet widgets/codeeditor/codeeditor.cpp resizeEvent

    When the size of the editor changes, we also need to resize the
    line number area. 

    \snippet widgets/codeeditor/codeeditor.cpp cursorPositionChanged

    When the cursor position changes, we highlight the current line,
    i.e., the line containing the cursor.

    QPlainTextEdit gives the possibility to have more than one
    selection at the same time. we can set the character format
    (QTextCharFormat) of these selections. We clear the cursors
    selection before setting the new new
    QPlainTextEdit::ExtraSelection, else several lines would get
    highlighted when the user selects multiple lines with the mouse.
    \omit ask someone how this works \endomit

    One sets the selection with a text cursor. When using the
    FullWidthSelection property, the current cursor text block (line)
    will be selected. If you want to select just a portion of the text
    block, the cursor should be moved with QTextCursor::movePosition()
    from a position set with \l{QTextCursor::}{setPosition()}.

    \snippet widgets/codeeditor/codeeditor.cpp extraAreaPaintEvent_0

    The \c lineNumberAreaPaintEvent() is called from \c LineNumberArea
    whenever it receives a paint event. We start off by painting the
    widget's background. 

    \snippet widgets/codeeditor/codeeditor.cpp extraAreaPaintEvent_1

    We will now loop through all visible lines and paint the line
    numbers in the extra area for each line. Notice that in a plain
    text edit each line will consist of one QTextBlock; though, if
    line wrapping is enabled, a line may span several rows in the text
    edit's viewport. 

    We get the top and bottom y-coordinate of the first text block,
    and adjust these values by the height of the current text block in
    each iteration in the loop. 

    \snippet widgets/codeeditor/codeeditor.cpp extraAreaPaintEvent_2

    Notice that we check if the block is visible in addition to check
    if it is in the areas viewport - a block can, for example, be
    hidden by a window placed over the text edit.

    \section1 Suggestions for Extending the Code Editor

    No self-respecting code editor is without a syntax
    highligther; the \l{Syntax Highlighter Example} shows how to
    create one.

    In addition to line numbers, you can add more to the extra area,
    for instance, break points.
        
    QSyntaxHighlighter gives the possibility to add user data to each
    text block with
    \l{QSyntaxHighlighter::}{setCurrentBlockUserData()}. This can be
    used to implement parenthesis matching. In the \c
    highlightCurrentLine(), the data of the currentBlock() can be
    fetched with QTextBlock::userData(). Matching parentheses can be
    highlighted with an extra selection. The "Matching Parentheses
    with QSyntaxHighlighter" article in Qt Quarterly 31 implements
    this. You find it here: \l{http://doc.qt.nokia.com/qq/}.

    The line number area is now painted every time the cursor blinks
    (because we connect \l{QPlainTextEdit::}{updateRequest()} to
    \c updateLineNumberArea()). We can avoid this by introducing a new
    member variable to CodeEditor that keeps track of when the update
    request comes from a cursor blink (in which case we do not
    repaint). The code below requires the \c m_countCache variable,
    which is a QPair<int, int> initialized with \c -1 for both
    \l{QPair::}{first} and \l{QPair::}{second}.

    \code
        void CodeEditor::updateLineNumberArea(const QRect &rect, int dy) 
        {
            if (dy) {
                lineNumberArea->scroll(0, dy);
            } else if (m_countCache.first != blockCount()
                       || m_countCache.second != textCursor().block().lineCount()) {
                lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
                m_countCache.first = blockCount();
                m_countCache.second = textCursor().block().lineCount();
            }   

            if (rect.contains(viewport()->rect()))
                updateLineNumberAreaWidth(0);
        }
    \endcode
*/