1 | /* This file is part of the Kate project. |
2 | * |
3 | * Copyright (C) 2010 Christoph Cullmann <cullmann@kde.org> |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Library General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Library General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Library General Public License |
16 | * along with this library; see the file COPYING.LIB. If not, write to |
17 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | * Boston, MA 02110-1301, USA. |
19 | */ |
20 | |
21 | #ifndef KATE_TEXTBUFFER_H |
22 | #define KATE_TEXTBUFFER_H |
23 | |
24 | #include <QtCore/QObject> |
25 | #include <QtCore/QString> |
26 | #include <QtCore/QVector> |
27 | #include <QtCore/QSet> |
28 | #include <QtCore/QTextCodec> |
29 | |
30 | #include <ktexteditor/document.h> |
31 | |
32 | #include "katedocument.h" |
33 | #include "katepartprivate_export.h" |
34 | #include "katetextblock.h" |
35 | #include "katetextcursor.h" |
36 | #include "katetextrange.h" |
37 | #include "katetexthistory.h" |
38 | |
39 | // encoding prober |
40 | #include <kencodingprober.h> |
41 | |
42 | namespace Kate { |
43 | |
44 | /** |
45 | * Class representing a text buffer. |
46 | * The interface is line based, internally the text will be stored in blocks of text lines. |
47 | */ |
48 | class KATEPART_TESTS_EXPORT TextBuffer : public QObject { |
49 | friend class TextCursor; |
50 | friend class TextRange; |
51 | friend class TextBlock; |
52 | |
53 | Q_OBJECT |
54 | |
55 | public: |
56 | /** |
57 | * End of line mode |
58 | */ |
59 | enum EndOfLineMode { |
60 | eolUnknown = -1 |
61 | , eolUnix = 0 |
62 | , eolDos = 1 |
63 | , eolMac = 2 |
64 | }; |
65 | |
66 | /** |
67 | * Construct an empty text buffer. |
68 | * Empty means one empty line in one block. |
69 | * @param parent parent qobject |
70 | * @param blockSize block size in lines the buffer should try to hold, default 64 lines |
71 | */ |
72 | TextBuffer (KateDocument *parent, int blockSize = 64); |
73 | |
74 | /** |
75 | * Destruct the text buffer |
76 | * Virtual, we allow inheritance |
77 | */ |
78 | virtual ~TextBuffer (); |
79 | |
80 | /** |
81 | * Clears the buffer, reverts to initial empty state. |
82 | * Empty means one empty line in one block. |
83 | * Virtual, can be overwritten. |
84 | */ |
85 | virtual void clear (); |
86 | |
87 | /** |
88 | * Set encoding prober type for this buffer to use for load. |
89 | * @param proberType prober type to use for encoding |
90 | */ |
91 | void setEncodingProberType (KEncodingProber::ProberType proberType) { m_encodingProberType = proberType; } |
92 | |
93 | /** |
94 | * Get encoding prober type for this buffer |
95 | * @return currently in use prober type of this buffer |
96 | */ |
97 | KEncodingProber::ProberType encodingProberType () const { return m_encodingProberType; } |
98 | |
99 | /** |
100 | * Set fallback codec for this buffer to use for load. |
101 | * @param codec fallback QTextCodec to use for encoding |
102 | */ |
103 | void setFallbackTextCodec (QTextCodec *codec) { m_fallbackTextCodec = codec; } |
104 | |
105 | /** |
106 | * Get fallback codec for this buffer |
107 | * @return currently in use fallback codec of this buffer |
108 | */ |
109 | QTextCodec *fallbackTextCodec () const { return m_fallbackTextCodec; } |
110 | |
111 | /** |
112 | * Set codec for this buffer to use for load/save. |
113 | * Loading might overwrite this, if it encounters problems and finds a better codec. |
114 | * Might change BOM setting. |
115 | * @param codec QTextCodec to use for encoding |
116 | */ |
117 | void setTextCodec (QTextCodec *codec); |
118 | |
119 | /** |
120 | * Get codec for this buffer |
121 | * @return currently in use codec of this buffer |
122 | */ |
123 | QTextCodec *textCodec () const { return m_textCodec; } |
124 | |
125 | /** |
126 | * Generate byte order mark on save. |
127 | * Loading might overwrite this setting, if there is a BOM found inside the file. |
128 | * @param generateByteOrderMark should BOM be generated? |
129 | */ |
130 | void setGenerateByteOrderMark (bool generateByteOrderMark) { m_generateByteOrderMark = generateByteOrderMark; } |
131 | |
132 | /** |
133 | * Generate byte order mark on save? |
134 | * @return should BOM be generated? |
135 | */ |
136 | bool generateByteOrderMark () const { return m_generateByteOrderMark; } |
137 | |
138 | /** |
139 | * Set end of line mode for this buffer, not allowed to be set to unknown. |
140 | * Loading might overwrite this setting, if there is a eol found inside the file. |
141 | * @param endOfLineMode new eol mode |
142 | */ |
143 | void setEndOfLineMode (EndOfLineMode endOfLineMode) { Q_ASSERT (endOfLineMode != eolUnknown); m_endOfLineMode = endOfLineMode; } |
144 | |
145 | /** |
146 | * Get end of line mode |
147 | * @return end of line mode |
148 | */ |
149 | EndOfLineMode endOfLineMode () const { return m_endOfLineMode; } |
150 | |
151 | /** |
152 | * Set whether to insert a newline character on save at the end of the file |
153 | * @param newlineAtEof should newline be added if non-existing |
154 | */ |
155 | void setNewLineAtEof(bool newlineAtEof) { m_newLineAtEof = newlineAtEof; } |
156 | |
157 | /** |
158 | * Set line length limit |
159 | * @param lineLengthLimit new line length limit |
160 | */ |
161 | void setLineLengthLimit (int lineLengthLimit) { m_lineLengthLimit = lineLengthLimit; } |
162 | |
163 | /** |
164 | * Load the given file. This will first clear the buffer and then load the file. |
165 | * Even on error during loading the buffer will still be cleared. |
166 | * Before calling this, setTextCodec must have been used to set codec! |
167 | * @param filename file to open |
168 | * @param encodingErrors were there problems occurred while decoding the file? |
169 | * @param tooLongLinesWrapped were too long lines found and wrapped? |
170 | * @param enforceTextCodec enforce to use only the set text codec |
171 | * @return success, the file got loaded, perhaps with encoding errors |
172 | * Virtual, can be overwritten. |
173 | */ |
174 | virtual bool load (const QString &filename, bool &encodingErrors, bool &tooLongLinesWrapped, bool enforceTextCodec); |
175 | |
176 | /** |
177 | * Save the current buffer content to the given file. |
178 | * Before calling this, setTextCodec and setFallbackTextCodec must have been used to set codec! |
179 | * @param filename file to save |
180 | * @return success |
181 | * Virtual, can be overwritten. |
182 | */ |
183 | virtual bool save (const QString &filename); |
184 | |
185 | /** |
186 | * Lines currently stored in this buffer. |
187 | * This is never 0, even clear will let one empty line remain. |
188 | */ |
189 | int lines () const { Q_ASSERT (m_lines > 0); return m_lines; } |
190 | |
191 | /** |
192 | * Revision of this buffer. Is set to 0 on construction, clear() (load will trigger clear()). |
193 | * Is incremented on each change to the buffer. |
194 | * @return current revision |
195 | */ |
196 | qint64 revision () const { return m_revision; } |
197 | |
198 | /** |
199 | * Retrieve a text line. |
200 | * @param line wanted line number |
201 | * @return text line |
202 | */ |
203 | TextLine line (int line) const; |
204 | |
205 | /** |
206 | * Retrieve text of complete buffer. |
207 | * @return text for this buffer, lines separated by '\n' |
208 | */ |
209 | QString text () const; |
210 | |
211 | /** |
212 | * Start an editing transaction, the wrapLine/unwrapLine/insertText and removeText functions |
213 | * are only to be allowed to be called inside a editing transaction. |
214 | * Editing transactions can stack. The number startEdit and endEdit calls must match. |
215 | * @return returns true, if no transaction was already running |
216 | * Virtual, can be overwritten. |
217 | */ |
218 | virtual bool startEditing (); |
219 | |
220 | /** |
221 | * Finish an editing transaction. Only allowed to be called if editing transaction is started. |
222 | * @return returns true, if this finished last running transaction |
223 | * Virtual, can be overwritten. |
224 | */ |
225 | virtual bool finishEditing (); |
226 | |
227 | /** |
228 | * Query the number of editing transactions running atm. |
229 | * @return number of running transactions |
230 | */ |
231 | int editingTransactions () const { return m_editingTransactions; } |
232 | |
233 | /** |
234 | * Query the revsion of this buffer before the ongoing editing transactions. |
235 | * @return revision of buffer before current editing transaction altered it |
236 | */ |
237 | qint64 editingLastRevision () const { return m_editingLastRevision; } |
238 | |
239 | /** |
240 | * Query the number of lines of this buffer before the ongoing editing transactions. |
241 | * @return number of lines of buffer before current editing transaction altered it |
242 | */ |
243 | int editingLastLines () const { return m_editingLastLines; } |
244 | |
245 | /** |
246 | * Query information from the last editing transaction: was the content of the buffer changed? |
247 | * This is checked by comparing the editingLastRevision() with the current revision(). |
248 | * @return content of buffer was changed in last transaction? |
249 | */ |
250 | bool editingChangedBuffer () const { return editingLastRevision() != revision(); } |
251 | |
252 | /** |
253 | * Query information from the last editing transaction: was the number of lines of the buffer changed? |
254 | * This is checked by comparing the editingLastLines() with the current lines(). |
255 | * @return content of buffer was changed in last transaction? |
256 | */ |
257 | bool editingChangedNumberOfLines () const { return editingLastLines() != lines(); } |
258 | |
259 | /** |
260 | * Get minimal line number changed by last editing transaction |
261 | * @return maximal line number changed by last editing transaction, or -1, if none changed |
262 | */ |
263 | int editingMinimalLineChanged () const { return m_editingMinimalLineChanged; } |
264 | |
265 | /** |
266 | * Get maximal line number changed by last editing transaction |
267 | * @return maximal line number changed by last editing transaction, or -1, if none changed |
268 | */ |
269 | int editingMaximalLineChanged () const { return m_editingMaximalLineChanged; } |
270 | |
271 | /** |
272 | * Wrap line at given cursor position. |
273 | * @param position line/column as cursor where to wrap |
274 | * Virtual, can be overwritten. |
275 | */ |
276 | virtual void wrapLine (const KTextEditor::Cursor &position); |
277 | |
278 | /** |
279 | * Unwrap given line. |
280 | * @param line line to unwrap |
281 | * Virtual, can be overwritten. |
282 | */ |
283 | virtual void unwrapLine (int line); |
284 | |
285 | /** |
286 | * Insert text at given cursor position. Does nothing if text is empty, beside some consistency checks. |
287 | * @param position position where to insert text |
288 | * @param text text to insert |
289 | * Virtual, can be overwritten. |
290 | */ |
291 | virtual void insertText (const KTextEditor::Cursor &position, const QString &text); |
292 | |
293 | /** |
294 | * Remove text at given range. Does nothing if range is empty, beside some consistency checks. |
295 | * @param range range of text to remove, must be on one line only. |
296 | * Virtual, can be overwritten. |
297 | */ |
298 | virtual void removeText (const KTextEditor::Range &range); |
299 | |
300 | /** |
301 | * TextHistory of this buffer |
302 | * @return text history for this buffer |
303 | */ |
304 | TextHistory &history () { return m_history; } |
305 | |
306 | Q_SIGNALS: |
307 | /** |
308 | * Buffer got cleared. This is emitted when constructor or load have called clear() internally, |
309 | * or when the user of the buffer has called clear() itself. |
310 | */ |
311 | void cleared (); |
312 | |
313 | /** |
314 | * Buffer loaded successfully a file |
315 | * @param filename file which was loaded |
316 | * @param encodingErrors were there problems occurred while decoding the file? |
317 | */ |
318 | void loaded (const QString &filename, bool encodingErrors); |
319 | |
320 | /** |
321 | * Buffer saved successfully a file |
322 | * @param filename file which was saved |
323 | */ |
324 | void saved (const QString &filename); |
325 | |
326 | /** |
327 | * Editing transaction has started. |
328 | */ |
329 | void editingStarted (); |
330 | |
331 | /** |
332 | * Editing transaction has finished. |
333 | */ |
334 | void editingFinished (); |
335 | |
336 | /** |
337 | * A line got wrapped. |
338 | * @param position position where the wrap occurred |
339 | */ |
340 | void lineWrapped (const KTextEditor::Cursor &position); |
341 | |
342 | /** |
343 | * A line got unwrapped. |
344 | * @param line line where the unwrap occurred |
345 | */ |
346 | void lineUnwrapped (int line); |
347 | |
348 | /** |
349 | * Text got inserted. |
350 | * @param position position where the insertion occurred |
351 | * @param text inserted text |
352 | */ |
353 | void textInserted (const KTextEditor::Cursor &position, const QString &text); |
354 | |
355 | /** |
356 | * Text got removed. |
357 | * @param range range where the removal occurred |
358 | * @param text removed text |
359 | */ |
360 | void textRemoved (const KTextEditor::Range &range, const QString &text); |
361 | |
362 | private: |
363 | /** |
364 | * Find block containing given line. |
365 | * @param line we want to find block for this line |
366 | * @return index of found block |
367 | */ |
368 | int blockForLine (int line) const; |
369 | |
370 | /** |
371 | * Fix start lines of all blocks after the given one |
372 | * @param startBlock index of block from which we start to fix |
373 | */ |
374 | void fixStartLines (int startBlock); |
375 | |
376 | /** |
377 | * Balance the given block. Look if it is too small or too large. |
378 | * @param index block to balance |
379 | */ |
380 | void balanceBlock (int index); |
381 | |
382 | /** |
383 | * Block for given index in block list. |
384 | * @param index block index |
385 | * @return block matching this index |
386 | */ |
387 | TextBlock *blockForIndex (int index) { return m_blocks[index]; } |
388 | |
389 | /** |
390 | * A range changed, notify the views, in case of attributes or feedback. |
391 | * @param view which view is affected? 0 for all views |
392 | * @param startLine start line of change |
393 | * @param endLine end line of change |
394 | * @param rangeWithAttribute attribute changed or is active, this will perhaps lead to repaints |
395 | */ |
396 | void notifyAboutRangeChange (KTextEditor::View *view, int startLine, int endLine, bool rangeWithAttribute); |
397 | |
398 | /** |
399 | * Mark all modified lines as lines saved on disk (modified line system). |
400 | */ |
401 | void markModifiedLinesAsSaved(); |
402 | |
403 | public: |
404 | /** |
405 | * Gets the document to which this buffer is bound. |
406 | * \return a pointer to the document |
407 | */ |
408 | KateDocument *document () const { return m_document; } |
409 | |
410 | /** |
411 | * Debug output, print whole buffer content with line numbers and line length |
412 | * @param title title for this output |
413 | */ |
414 | void debugPrint (const QString &title) const; |
415 | |
416 | /** |
417 | * Return the ranges which affect the given line. |
418 | * @param line line to look at |
419 | * @param view only return ranges associated with given view |
420 | * @param rangesWithAttributeOnly only return ranges which have a attribute set |
421 | * @return list of ranges affecting this line |
422 | */ |
423 | QList<TextRange *> rangesForLine (int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const; |
424 | |
425 | /** |
426 | * Check if the given range pointer is still valid. |
427 | * @return range pointer still belongs to range for this buffer |
428 | */ |
429 | bool (TextRange *range) const { return m_ranges.contains (range); } |
430 | |
431 | /** |
432 | * Invalidate all ranges in this buffer. |
433 | */ |
434 | void invalidateRanges(); |
435 | |
436 | // |
437 | // md5 checksum handling |
438 | // |
439 | public: |
440 | /** |
441 | * md5 digest of the document on disk, set either through file loading |
442 | * in openFile() or in KateDocument::saveFile() |
443 | * @return md5 digest for this document |
444 | */ |
445 | const QByteArray &digest () const; |
446 | |
447 | /** |
448 | * Set the md5sum of this buffer. Make sure this checksum is up-to-date |
449 | * when reading digest(). |
450 | * @param md5sum md5 digest for the document on disk |
451 | */ |
452 | void setDigest (const QByteArray & md5sum); |
453 | |
454 | private: |
455 | QByteArray m_digest; |
456 | |
457 | private: |
458 | /** |
459 | * parent document |
460 | */ |
461 | KateDocument *m_document; |
462 | |
463 | /** |
464 | * text history |
465 | */ |
466 | TextHistory m_history; |
467 | |
468 | /** |
469 | * block size in lines the buffer will try to hold |
470 | */ |
471 | const int m_blockSize; |
472 | |
473 | /** |
474 | * List of blocks which contain the lines of this buffer |
475 | */ |
476 | QVector<TextBlock *> m_blocks; |
477 | |
478 | /** |
479 | * Number of lines in buffer |
480 | */ |
481 | int m_lines; |
482 | |
483 | /** |
484 | * Last used block in the buffer. Is used for speeding up blockForLine. |
485 | * May contain invalid index, must be checked before using. |
486 | */ |
487 | mutable int m_lastUsedBlock; |
488 | |
489 | /** |
490 | * Revision of the buffer. |
491 | */ |
492 | qint64 m_revision; |
493 | |
494 | /** |
495 | * Current number of running edit transactions |
496 | */ |
497 | int m_editingTransactions; |
498 | |
499 | /** |
500 | * Revision remembered at start of current editing transaction |
501 | */ |
502 | qint64 m_editingLastRevision; |
503 | |
504 | /** |
505 | * Number of lines remembered at start of current editing transaction |
506 | */ |
507 | int m_editingLastLines; |
508 | |
509 | /** |
510 | * minimal line number changed by last editing transaction |
511 | */ |
512 | int m_editingMinimalLineChanged; |
513 | |
514 | /** |
515 | * maximal line number changed by last editing transaction |
516 | */ |
517 | int m_editingMaximalLineChanged; |
518 | |
519 | /** |
520 | * Set of invalid cursors for this whole buffer. |
521 | * Valid cursors are inside the block the belong to. |
522 | */ |
523 | QSet<TextCursor *> m_invalidCursors; |
524 | |
525 | /** |
526 | * Set of ranges of this whole buffer. |
527 | */ |
528 | QSet<TextRange *> m_ranges; |
529 | |
530 | /** |
531 | * Encoding prober type to use |
532 | */ |
533 | KEncodingProber::ProberType m_encodingProberType; |
534 | |
535 | /** |
536 | * Fallback text codec to use |
537 | */ |
538 | QTextCodec *m_fallbackTextCodec; |
539 | |
540 | /** |
541 | * Text codec to use |
542 | */ |
543 | QTextCodec *m_textCodec; |
544 | |
545 | /** |
546 | * Mime-Type used for transparent compression/decompression support |
547 | * Set by load(), reset by clear() |
548 | */ |
549 | QString m_mimeTypeForFilterDev; |
550 | |
551 | /** |
552 | * Should byte order mark be created? |
553 | */ |
554 | bool m_generateByteOrderMark; |
555 | |
556 | /** |
557 | * End of line mode, default is Unix |
558 | */ |
559 | EndOfLineMode m_endOfLineMode; |
560 | |
561 | /** |
562 | * Insert newline character at the end of the file? |
563 | */ |
564 | bool m_newLineAtEof; |
565 | |
566 | /** |
567 | * Limit for line length, longer lines will be wrapped on load |
568 | */ |
569 | int m_lineLengthLimit; |
570 | }; |
571 | |
572 | } |
573 | |
574 | #endif |
575 | |