1 /*
2     SPDX-FileCopyrightText: 2001-2004 Christoph Cullmann <cullmann@kde.org>
3     SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org>
4     SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
5     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
6 
7     SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9 
10 #ifndef _KATE_DOCUMENT_H_
11 #define _KATE_DOCUMENT_H_
12 
13 #include <QPointer>
14 #include <QStack>
15 #include <QTimer>
16 
17 #include <KJob>
18 
19 #include <ktexteditor/annotationinterface.h>
20 #include <ktexteditor/configinterface.h>
21 #include <ktexteditor/document.h>
22 #include <ktexteditor/inlinenoteinterface.h>
23 #include <ktexteditor/mainwindow.h>
24 #include <ktexteditor/markinterface.h>
25 #include <ktexteditor/message.h>
26 #include <ktexteditor/modificationinterface.h>
27 #include <ktexteditor/movinginterface.h>
28 
29 #include "katetextline.h"
30 #include <ktexteditor_export.h>
31 
32 class KateTemplateHandler;
33 namespace KTextEditor
34 {
35 class Plugin;
36 class Attribute;
37 class TemplateScript;
38 }
39 
40 namespace KIO
41 {
42 class TransferJob;
43 }
44 
45 namespace Kate
46 {
47 class SwapFile;
48 }
49 
50 class KateBuffer;
51 namespace KTextEditor
52 {
53 class ViewPrivate;
54 }
55 class KateDocumentConfig;
56 class KateHighlighting;
57 class KateUndoManager;
58 class KateOnTheFlyChecker;
59 class KateDocumentTest;
60 
61 class KateAutoIndent;
62 class KateModOnHdPrompt;
63 class KToggleAction;
64 
65 /**
66  * @brief Backend of KTextEditor::Document related public KTextEditor interfaces.
67  *
68  * @warning This file is @e private API and not part of the public
69  *          KTextEditor interfaces.
70  */
71 class KTEXTEDITOR_EXPORT KTextEditor::DocumentPrivate : public KTextEditor::Document,
72                                                         public KTextEditor::MarkInterfaceV2,
73                                                         public KTextEditor::ModificationInterface,
74                                                         public KTextEditor::ConfigInterface,
75                                                         public KTextEditor::AnnotationInterface,
76                                                         public KTextEditor::MovingInterface,
77                                                         private KTextEditor::MovingRangeFeedback
78 {
79     Q_OBJECT
80     Q_INTERFACES(KTextEditor::MarkInterface)
81     Q_INTERFACES(KTextEditor::MarkInterfaceV2)
82     Q_INTERFACES(KTextEditor::ModificationInterface)
83     Q_INTERFACES(KTextEditor::AnnotationInterface)
84     Q_INTERFACES(KTextEditor::ConfigInterface)
85     Q_INTERFACES(KTextEditor::MovingInterface)
86 
87     friend class KTextEditor::Document;
88     friend class ::KateDocumentTest;
89     friend class ::KateBuffer;
90 
91 public:
92     explicit DocumentPrivate(bool bSingleViewMode = false, bool bReadOnly = false, QWidget *parentWidget = nullptr, QObject * = nullptr);
93     ~DocumentPrivate() override;
94 
95     using ReadWritePart::closeUrl;
96     bool closeUrl() override;
97 
98     bool openUrl(const QUrl &url) override;
99 
100     KTextEditor::Range rangeOnLine(KTextEditor::Range range, int line) const;
101 
102     void setMetaData(const KPluginMetaData &metaData);
103 
104 private:
105     void showAndSetOpeningErrorAccess();
106     /*
107      * Overload this to have on-demand view creation
108      */
109 public:
110     /**
111      * @return The widget defined by this part, set by setWidget().
112      */
113     QWidget *widget() override;
114 
115 public:
readOnly()116     bool readOnly() const
117     {
118         return m_bReadOnly;
119     }
singleViewMode()120     bool singleViewMode() const
121     {
122         return m_bSingleViewMode;
123     }
124 
125 private:
126     // only to make part work, don't change it !
127     const bool m_bSingleViewMode;
128     const bool m_bReadOnly;
129 
130     //
131     // KTextEditor::Document stuff
132     //
133 public:
134     KTextEditor::View *createView(QWidget *parent, KTextEditor::MainWindow *mainWindow = nullptr) override;
135 
views()136     QList<KTextEditor::View *> views() const override
137     {
138         return m_viewsCache;
139     }
140 
activeView()141     virtual KTextEditor::View *activeView() const
142     {
143         return m_activeView;
144     }
145 
146 private:
147     QHash<KTextEditor::View *, KTextEditor::ViewPrivate *> m_views;
148     KTextEditor::View *m_activeView = nullptr;
149 
150     //
151     // KTextEditor::EditInterface stuff
152     //
153 public Q_SLOTS:
154     bool setText(const QString &) override;
155     bool setText(const QStringList &text) override;
156     bool clear() override;
157 
158     bool insertText(const KTextEditor::Cursor &position, const QString &s, bool block = false) override;
159     bool insertText(const KTextEditor::Cursor &position, const QStringList &text, bool block = false) override;
160 
161     bool insertLine(int line, const QString &s) override;
162     bool insertLines(int line, const QStringList &s) override;
163 
164     bool removeText(const KTextEditor::Range &range, bool block = false) override;
165     bool removeLine(int line) override;
166 
167     bool replaceText(const KTextEditor::Range &range, const QString &s, bool block = false) override;
168 
169     // unhide method...
replaceText(const KTextEditor::Range & r,const QStringList & l,bool b)170     bool replaceText(const KTextEditor::Range &r, const QStringList &l, bool b) override
171     {
172         return KTextEditor::Document::replaceText(r, l, b);
173     }
174 
175 public:
176     bool isEditingTransactionRunning() const override;
177     QString text(const KTextEditor::Range &range, bool blockwise = false) const override;
178     QStringList textLines(const KTextEditor::Range &range, bool block = false) const override;
179     QString text() const override;
180     QString line(int line) const override;
181     QChar characterAt(const KTextEditor::Cursor &position) const override;
182     QString wordAt(const KTextEditor::Cursor &cursor) const override;
183     KTextEditor::Range wordRangeAt(const KTextEditor::Cursor &cursor) const override;
184     bool isValidTextPosition(const KTextEditor::Cursor &cursor) const override;
185     int lines() const override;
186     bool isLineModified(int line) const override;
187     bool isLineSaved(int line) const override;
188     bool isLineTouched(int line) const override;
189     KTextEditor::Cursor documentEnd() const override;
190     int totalCharacters() const override;
191     int lineLength(int line) const override;
192 
193 Q_SIGNALS:
194     void charactersSemiInteractivelyInserted(const KTextEditor::Cursor &position, const QString &text);
195 
196     /**
197      * The \p document emits this signal whenever text was inserted.  The
198      * insertion occurred at range.start(), and new text now occupies up to
199      * range.end().
200      * \param document document which emitted this signal
201      * \param range range that the newly inserted text occupies
202      * \see insertText(), insertLine()
203      */
204     void textInsertedRange(KTextEditor::Document *document, const KTextEditor::Range &range);
205 
206     /**
207      * The \p document emits this signal whenever \p range was removed, i.e.
208      * text was removed.
209      * \param document document which emitted this signal
210      * \param range range that the removed text previously occupied
211      * \param oldText the text that has been removed
212      * \see removeText(), removeLine(), clear()
213      */
214     void textRemoved(KTextEditor::Document *document, const KTextEditor::Range &range, const QString &oldText);
215 
216 public:
217     // BEGIN editStart/editEnd (start, end, undo, cursor update, view update)
218     /**
219      * Enclose editor actions with @p editStart() and @p editEnd() to group
220      * them.
221      */
222     bool editStart();
223 
224     /**
225      * Alias for @p editStart()
226      */
editBegin()227     void editBegin()
228     {
229         editStart();
230     }
231 
232     /**
233      * End a editor operation.
234      * @see editStart()
235      */
236     bool editEnd();
237 
238     void pushEditState();
239     void popEditState();
240 
startEditing()241     virtual bool startEditing()
242     {
243         return editStart();
244     }
finishEditing()245     virtual bool finishEditing()
246     {
247         return editEnd();
248     }
249 
250     // END editStart/editEnd
251 
252     void inputMethodStart();
253     void inputMethodEnd();
254 
255     // BEGIN LINE BASED INSERT/REMOVE STUFF (editStart() and editEnd() included)
256     /**
257      * Add a string in the given line/column
258      * @param line line number
259      * @param col column
260      * @param s string to be inserted
261      * @return true on success
262      */
263     bool editInsertText(int line, int col, const QString &s);
264 
265     /**
266      * Remove a string in the given line/column
267      * @param line line number
268      * @param col column
269      * @param len length of text to be removed
270      * @return true on success
271      */
272     bool editRemoveText(int line, int col, int len);
273 
274     /**
275      * Mark @p line as @p autowrapped. This is necessary if static word warp is
276      * enabled, because we have to know whether to insert a new line or add the
277      * wrapped words to the following line.
278      * @param line line number
279      * @param autowrapped autowrapped?
280      * @return true on success
281      */
282     bool editMarkLineAutoWrapped(int line, bool autowrapped);
283 
284     /**
285      * Wrap @p line. If @p newLine is true, ignore the textline's flag
286      * KateTextLine::flagAutoWrapped and force a new line. Whether a new line
287      * was needed/added you can grab with @p newLineAdded.
288      * @param line line number
289      * @param col column
290      * @param newLine if true, force a new line
291      * @param newLineAdded return value is true, if new line was added (may be 0)
292      * @return true on success
293      */
294     bool editWrapLine(int line, int col, bool newLine = true, bool *newLineAdded = nullptr);
295 
296     /**
297      * Unwrap @p line. If @p removeLine is true, we force to join the lines. If
298      * @p removeLine is true, @p length is ignored (eg not needed).
299      * @param line line number
300      * @param removeLine if true, force to remove the next line
301      * @return true on success
302      */
303     bool editUnWrapLine(int line, bool removeLine = true, int length = 0);
304 
305     /**
306      * Insert a string at the given line.
307      * @param line line number
308      * @param s string to insert
309      * @return true on success
310      */
311     bool editInsertLine(int line, const QString &s);
312 
313     /**
314      * Remove a line
315      * @param line line number
316      * @return true on success
317      */
318     bool editRemoveLine(int line);
319 
320     bool editRemoveLines(int from, int to);
321 
322     /**
323      * Warp a line
324      * @param startLine line to begin wrapping
325      * @param endLine line to stop wrapping
326      * @return true on success
327      */
328     bool wrapText(int startLine, int endLine);
329 
330     /**
331      * Wrap lines touched by the selection with respect of existing paragraphs.
332      * To do so will the paragraph prior to the wrap joined as one single line
333      * which cause an almost perfect wrapped paragraph as long as there are no
334      * unneeded spaces exist or some formatting like this comment block.
335      * Without any selection the current line is wrapped.
336      * Empty lines around each paragraph are untouched.
337      * @param first line to begin wrapping
338      * @param last line to stop wrapping
339      * @return true on success
340      */
341     bool wrapParagraph(int first, int last);
342     // END LINE BASED INSERT/REMOVE STUFF
343 
344 Q_SIGNALS:
345     /**
346      * Emitted when text from @p line was wrapped at position pos onto line @p nextLine.
347      */
348     void editLineWrapped(int line, int col, int len);
349 
350     /**
351      * Emitted each time text from @p nextLine was upwrapped onto @p line.
352      */
353     void editLineUnWrapped(int line, int col);
354 
355 public:
356     bool isEditRunning() const;
357 
358     void setUndoMergeAllEdits(bool merge);
359 
360     enum EditingPositionKind { Previous, Next };
361 
362     /**
363      *Returns the next or previous position cursor in this document from the stack depending on the argument passed.
364      *@return cursor invalid if m_editingStack empty
365      */
366     KTextEditor::Cursor lastEditingPosition(EditingPositionKind nextOrPrevious, KTextEditor::Cursor);
367 
368 private:
369     int editSessionNumber = 0;
370     QStack<int> editStateStack;
371     bool editIsRunning = false;
372     bool m_undoMergeAllEdits = false;
373     KTextEditor::Cursor m_editLastChangeStartCursor = KTextEditor::Cursor::invalid();
374     QStack<QSharedPointer<KTextEditor::MovingCursor>> m_editingStack;
375     int m_editingStackPosition = -1;
376 
377     //
378     // KTextEditor::UndoInterface stuff
379     //
380 public Q_SLOTS:
381     void undo();
382     void redo();
383 
384     /**
385      * Removes all the elements in m_editingStack of the respective document.
386      */
387     void clearEditingPosStack();
388 
389     /**
390      * Saves the editing positions into the stack.
391      * If the consecutive editings happens in the same line, then remove
392      * the previous and add the new one with updated column no.
393      */
394     void saveEditingPositions(const KTextEditor::Cursor cursor);
395 
396 public:
397     uint undoCount() const;
398     uint redoCount() const;
399 
undoManager()400     KateUndoManager *undoManager()
401     {
402         return m_undoManager;
403     }
404 
405 protected:
406     KateUndoManager *const m_undoManager;
407 
408 Q_SIGNALS:
409     void undoChanged();
410 
411 public:
412     QVector<KTextEditor::Range> searchText(const KTextEditor::Range &range, const QString &pattern, const KTextEditor::SearchOptions options) const;
413 
414 private:
415     /**
416      * Return a widget suitable to be used as a dialog parent.
417      */
418     QWidget *dialogParent();
419 
420     /*
421      * Access to the mode/highlighting subsystem
422      */
423 public:
424     /**
425      * @copydoc KTextEditor::Document::defaultStyleAt()
426      */
427     KTextEditor::DefaultStyle defaultStyleAt(const KTextEditor::Cursor &position) const override;
428 
429     /**
430      * Return the name of the currently used mode
431      * \return name of the used mode
432      */
433     QString mode() const override;
434 
435     /**
436      * Return the name of the currently used mode
437      * \return name of the used mode
438      */
439     QString highlightingMode() const override;
440 
441     /**
442      * Return a list of the names of all possible modes
443      * \return list of mode names
444      */
445     QStringList modes() const override;
446 
447     /**
448      * Return a list of the names of all possible modes
449      * \return list of mode names
450      */
451     QStringList highlightingModes() const override;
452 
453     /**
454      * Set the current mode of the document by giving its name
455      * \param name name of the mode to use for this document
456      * \return \e true on success, otherwise \e false
457      */
458     bool setMode(const QString &name) override;
459 
460     /**
461      * Set the current mode of the document by giving its name
462      * \param name name of the mode to use for this document
463      * \return \e true on success, otherwise \e false
464      */
465     bool setHighlightingMode(const QString &name) override;
466     /**
467      * Returns the name of the section for a highlight given its @p index in the highlight
468      * list (as returned by highlightModes()).
469      * You can use this function to build a tree of the highlight names, organized in sections.
470      * \param index in the highlight list for which to find the section name.
471      */
472     QString highlightingModeSection(int index) const override;
473 
474     /**
475      * Returns the name of the section for a mode given its @p index in the highlight
476      * list (as returned by modes()).
477      * You can use this function to build a tree of the mode names, organized in sections.
478      * \param index index in the highlight list for which to find the section name.
479      */
480     QString modeSection(int index) const override;
481 
482     /*
483      * Helpers....
484      */
485 public:
486     void bufferHlChanged();
487 
488     /**
489      * allow to mark, that we changed hl on user wish and should not reset it
490      * atm used for the user visible menu to select highlightings
491      */
492     void setDontChangeHlOnSave();
493 
494     /**
495      * Set that the BOM marker is forced via the tool menu
496      */
497     void bomSetByUser();
498 
499 public:
500     /**
501      * Read session settings from the given \p config.
502      *
503      * Known flags:
504      *  "SkipUrl" => don't save/restore the file
505      *  "SkipMode" => don't save/restore the mode
506      *  "SkipHighlighting" => don't save/restore the highlighting
507      *  "SkipEncoding" => don't save/restore the encoding
508      *
509      * \param config read the session settings from this KConfigGroup
510      * \param flags additional flags
511      * \see writeSessionConfig()
512      */
513     void readSessionConfig(const KConfigGroup &config, const QSet<QString> &flags = QSet<QString>()) override;
514 
515     /**
516      * Write session settings to the \p config.
517      * See readSessionConfig() for more details.
518      *
519      * \param config write the session settings to this KConfigGroup
520      * \param flags additional flags
521      * \see readSessionConfig()
522      */
523     void writeSessionConfig(KConfigGroup &config, const QSet<QString> &flags = QSet<QString>()) override;
524 
525     //
526     // KTextEditor::MarkInterface
527     //
528 public Q_SLOTS:
529     void setMark(int line, uint markType) override;
530     void clearMark(int line) override;
531 
532     void addMark(int line, uint markType) override;
533     void removeMark(int line, uint markType) override;
534 
535     void clearMarks() override;
536 
537     void requestMarkTooltip(int line, QPoint position);
538 
539     /// Returns true if the click on the mark should not be further processed
540     bool handleMarkClick(int line);
541 
542     /// Returns true if the context-menu event should not further be processed
543     bool handleMarkContextMenu(int line, QPoint position);
544 
545     void setMarkPixmap(MarkInterface::MarkTypes, const QPixmap &) override;
546 
547     void setMarkDescription(MarkInterface::MarkTypes, const QString &) override;
548 
549     void setEditableMarks(uint markMask) override;
550 
551 public:
552     uint mark(int line) override;
553     const QHash<int, KTextEditor::Mark *> &marks() override;
554     QPixmap markPixmap(MarkInterface::MarkTypes) const override;
555     QString markDescription(MarkInterface::MarkTypes) const override;
556     virtual QColor markColor(MarkInterface::MarkTypes) const;
557     uint editableMarks() const override;
558 
559 Q_SIGNALS:
560     void markToolTipRequested(KTextEditor::Document *document, KTextEditor::Mark mark, QPoint position, bool &handled);
561 
562     void markContextMenuRequested(KTextEditor::Document *document, KTextEditor::Mark mark, QPoint pos, bool &handled);
563 
564     void markClicked(KTextEditor::Document *document, KTextEditor::Mark mark, bool &handled);
565 
566     void marksChanged(KTextEditor::Document *) override;
567     void markChanged(KTextEditor::Document *, KTextEditor::Mark, KTextEditor::MarkInterface::MarkChangeAction) override;
568 
569 private:
570     QHash<int, KTextEditor::Mark *> m_marks;
571     QHash<int, QVariant> m_markIcons; // QPixmap or QIcon, KF6: remove QPixmap support
572     QHash<int, QString> m_markDescriptions;
573     uint m_editableMarks = markType01;
574 
575     //
576     // KTextEditor::MarkInterfaceV2
577     //
578 public Q_SLOTS:
579     void setMarkIcon(MarkInterface::MarkTypes markType, const QIcon &icon) override;
580 
581 public:
582     QIcon markIcon(MarkInterface::MarkTypes markType) const override;
583 
584     // KTextEditor::PrintInterface
585     //
586 public Q_SLOTS:
587     bool print() override;
588     void printPreview() override;
589 
590     //
591     // KTextEditor::DocumentInfoInterface ( ### unfinished )
592     //
593 public:
594     /**
595      * Tries to detect mime-type based on file name and content of buffer.
596      *
597      * @return the name of the mimetype for the document.
598      */
599     QString mimeType() override;
600 
601     //
602     // once was KTextEditor::VariableInterface
603     //
604 public:
605     /**
606      * Returns the value for the variable @p name.
607      * If the Document does not have a variable called @p name,
608      * an empty QString() is returned.
609      *
610      * // TODO KF6: expose in KTextEditor::Document?
611      *
612      * @param name variable to query
613      * @return value of the variable @p name
614      * @see setVariable()
615      */
616     virtual QString variable(const QString &name) const;
617 
618     /**
619      * Set the variable @p name to @p value. Setting and changing a variable
620      * has immediate effect on the Document. For instance, setting the variable
621      * @e indent-mode to @e cstyle will immediately cause the Document to load
622      * the C Style indenter.
623      *
624      * // TODO KF6: expose in KTextEditor::Document?
625      *
626      * @param name the variable name
627      * @param value the value to be set
628      * @see variable()
629      */
630     virtual void setVariable(const QString &name, const QString &value);
631 
632 private:
633     std::map<QString, QString> m_storedVariables;
634 
635     //
636     // MovingInterface API
637     //
638 public:
639     /**
640      * Create a new moving cursor for this document.
641      * @param position position of the moving cursor to create
642      * @param insertBehavior insertion behavior
643      * @return new moving cursor for the document
644      */
645     KTextEditor::MovingCursor *newMovingCursor(const KTextEditor::Cursor &position,
646                                                KTextEditor::MovingCursor::InsertBehavior insertBehavior = KTextEditor::MovingCursor::MoveOnInsert) override;
647 
648     /**
649      * Create a new moving range for this document.
650      * @param range range of the moving range to create
651      * @param insertBehaviors insertion behaviors
652      * @param emptyBehavior behavior on becoming empty
653      * @return new moving range for the document
654      */
655     KTextEditor::MovingRange *newMovingRange(const KTextEditor::Range &range,
656                                              KTextEditor::MovingRange::InsertBehaviors insertBehaviors = KTextEditor::MovingRange::DoNotExpand,
657                                              KTextEditor::MovingRange::EmptyBehavior emptyBehavior = KTextEditor::MovingRange::AllowEmpty) override;
658 
659     /**
660      * Current revision
661      * @return current revision
662      */
663     qint64 revision() const override;
664 
665     /**
666      * Last revision the buffer got successful saved
667      * @return last revision buffer got saved, -1 if none
668      */
669     qint64 lastSavedRevision() const override;
670 
671     /**
672      * Lock a revision, this will keep it around until released again.
673      * But all revisions will always be cleared on buffer clear() (and therefor load())
674      * @param revision revision to lock
675      */
676     void lockRevision(qint64 revision) override;
677 
678     /**
679      * Release a revision.
680      * @param revision revision to release
681      */
682     void unlockRevision(qint64 revision) override;
683 
684     /**
685      * Transform a cursor from one revision to an other.
686      * @param cursor cursor to transform
687      * @param insertBehavior behavior of this cursor on insert of text at its position
688      * @param fromRevision from this revision we want to transform
689      * @param toRevision to this revision we want to transform, default of -1 is current revision
690      */
691     void transformCursor(KTextEditor::Cursor &cursor,
692                          KTextEditor::MovingCursor::InsertBehavior insertBehavior,
693                          qint64 fromRevision,
694                          qint64 toRevision = -1) override;
695 
696     /**
697      * Transform a cursor from one revision to an other.
698      * @param line line number of the cursor to transform
699      * @param column column number of the cursor to transform
700      * @param insertBehavior behavior of this cursor on insert of text at its position
701      * @param fromRevision from this revision we want to transform
702      * @param toRevision to this revision we want to transform, default of -1 is current revision
703      */
704     void
705     transformCursor(int &line, int &column, KTextEditor::MovingCursor::InsertBehavior insertBehavior, qint64 fromRevision, qint64 toRevision = -1) override;
706 
707     /**
708      * Transform a range from one revision to an other.
709      * @param range range to transform
710      * @param insertBehaviors behavior of this range on insert of text at its position
711      * @param emptyBehavior behavior on becoming empty
712      * @param fromRevision from this revision we want to transform
713      * @param toRevision to this revision we want to transform, default of -1 is current revision
714      */
715     void transformRange(KTextEditor::Range &range,
716                         KTextEditor::MovingRange::InsertBehaviors insertBehaviors,
717                         KTextEditor::MovingRange::EmptyBehavior emptyBehavior,
718                         qint64 fromRevision,
719                         qint64 toRevision = -1) override;
720 
721     //
722     // MovingInterface Signals
723     //
724 Q_SIGNALS:
725     /**
726      * This signal is emitted before the cursors/ranges/revisions of a document are destroyed as the document is deleted.
727      * @param document the document which the interface belongs too which is in the process of being deleted
728      */
729     void aboutToDeleteMovingInterfaceContent(KTextEditor::Document *document);
730 
731     /**
732      * This signal is emitted before the ranges of a document are invalidated and the revisions are deleted as the document is cleared (for example on
733      * load/reload). While this signal is emitted, still the old document content is around before the clear.
734      * @param document the document which the interface belongs too which will invalidate its data
735      */
736     void aboutToInvalidateMovingInterfaceContent(KTextEditor::Document *document);
737 
738     //
739     // Annotation Interface
740     //
741 public:
742     void setAnnotationModel(KTextEditor::AnnotationModel *model) override;
743     KTextEditor::AnnotationModel *annotationModel() const override;
744 
745 Q_SIGNALS:
746     void annotationModelChanged(KTextEditor::AnnotationModel *, KTextEditor::AnnotationModel *);
747 
748 private:
749     KTextEditor::AnnotationModel *m_annotationModel = nullptr;
750 
751     //
752     // KParts::ReadWrite stuff
753     //
754 public:
755     /**
756      * open the file obtained by the kparts framework
757      * the framework abstracts the loading of remote files
758      * @return success
759      */
760     bool openFile() override;
761 
762     /**
763      * save the file obtained by the kparts framework
764      * the framework abstracts the uploading of remote files
765      * @return success
766      */
767     bool saveFile() override;
768 
769     void setReadWrite(bool rw = true) override;
770 
771     void setModified(bool m) override;
772 
773     bool isAutoReload();
autoReloadToggleAction()774     KToggleAction *autoReloadToggleAction()
775     {
776         return m_autoReloadMode;
777     };
778     void delayAutoReload();
779 
780 private Q_SLOTS:
781     void autoReloadToggled(bool b);
782 
783 private:
784     void activateDirWatch(const QString &useFileName = QString());
785     void deactivateDirWatch();
786 
787     QString m_dirWatchFile;
788 
789     /**
790      * Make backup copy during saveFile, if configured that way.
791      * @return success? else saveFile should return false and not write the file
792      */
793     bool createBackupFile();
794 
795 public:
796     /**
797      * Type chars in a view.
798      * Characters are filtered in KateViewInternal::isAcceptableInput() before calling typeChars.
799      *
800      * @param view view that received the input
801      * @param chars characters to type
802      */
803     void typeChars(KTextEditor::ViewPrivate *view, QString chars);
804 
805     /**
806      * gets the last line number (lines() - 1)
807      */
lastLine()808     inline int lastLine() const
809     {
810         return lines() - 1;
811     }
812 
813     // Repaint all of all of the views
814     void repaintViews(bool paintOnlyDirty = true);
815 
816     KateHighlighting *highlight() const;
817 
818 public Q_SLOTS:
819     void tagLines(KTextEditor::LineRange lineRange);
820     void tagLine(int line);
821 
822 private Q_SLOTS:
823     void internalHlChanged();
824 
825 public:
826     void addView(KTextEditor::View *);
827     /** removes the view from the list of views. The view is *not* deleted.
828      * That's your job. Or, easier, just delete the view in the first place.
829      * It will remove itself. TODO: this could be converted to a private slot
830      * connected to the view's destroyed() signal. It is not currently called
831      * anywhere except from the KTextEditor::ViewPrivate destructor.
832      */
833     void removeView(KTextEditor::View *);
834     void setActiveView(KTextEditor::View *);
835 
836     bool ownedView(KTextEditor::ViewPrivate *);
837 
838     int toVirtualColumn(int line, int column) const;
839     int toVirtualColumn(const KTextEditor::Cursor) const;
840     int fromVirtualColumn(int line, int column) const;
841     int fromVirtualColumn(const KTextEditor::Cursor) const;
842 
843     enum NewLineIndent { Indent, NoIndent };
844 
845     void newLine(KTextEditor::ViewPrivate *view, NewLineIndent indent = NewLineIndent::Indent); // Changes input
846     void backspace(KTextEditor::ViewPrivate *view, const KTextEditor::Cursor);
847     void del(KTextEditor::ViewPrivate *view, const KTextEditor::Cursor);
848     void transpose(const KTextEditor::Cursor);
849     void swapTextRanges(KTextEditor::Range firstWord, KTextEditor::Range secondWord);
850     void paste(KTextEditor::ViewPrivate *view, const QString &text);
851 
852 public:
853     void indent(KTextEditor::Range range, int change);
854     void comment(KTextEditor::ViewPrivate *view, uint line, uint column, int change);
855     void align(KTextEditor::ViewPrivate *view, const KTextEditor::Range &range);
856     void insertTab(KTextEditor::ViewPrivate *view, const KTextEditor::Cursor);
857 
858     enum TextTransform { Uppercase, Lowercase, Capitalize };
859 
860     /**
861       Handling uppercase, lowercase and capitalize for the view.
862 
863       If there is a selection, that is transformed, otherwise for uppercase or
864       lowercase the character right of the cursor is transformed, for capitalize
865       the word under the cursor is transformed.
866     */
867     void transform(KTextEditor::ViewPrivate *view, const KTextEditor::Cursor, TextTransform);
868     /**
869       Unwrap a range of lines.
870     */
871     void joinLines(uint first, uint last);
872 
873 private:
874     bool removeStringFromBeginning(int line, const QString &str);
875     bool removeStringFromEnd(int line, const QString &str);
876 
877     /**
878       Expand tabs to spaces in typed text, if enabled.
879       @param cursorPos The current cursor position for the inserted characters.
880       @param str The typed characters to expand.
881     */
882     QString eventuallyReplaceTabs(const KTextEditor::Cursor cursorPos, const QString &str) const;
883 
884     /**
885       Find the position (line and col) of the next char
886       that is not a space. If found line and col point to the found character.
887       Otherwise they have both the value -1.
888       @param line Line of the character which is examined first.
889       @param col Column of the character which is examined first.
890       @return True if the specified or a following character is not a space
891                Otherwise false.
892     */
893     bool nextNonSpaceCharPos(int &line, int &col);
894 
895     /**
896       Find the position (line and col) of the previous char
897       that is not a space. If found line and col point to the found character.
898       Otherwise they have both the value -1.
899       @return True if the specified or a preceding character is not a space.
900                Otherwise false.
901     */
902     bool previousNonSpaceCharPos(int &line, int &col);
903 
904     /**
905      * Sets a comment marker as defined by the language providing the attribute
906      * @p attrib on the line @p line
907      */
908     void addStartLineCommentToSingleLine(int line, int attrib = 0);
909     /**
910      * Removes a comment marker as defined by the language providing the attribute
911      * @p attrib on the line @p line
912      */
913     bool removeStartLineCommentFromSingleLine(int line, int attrib = 0);
914 
915     /**
916      * @see addStartLineCommentToSingleLine.
917      */
918     void addStartStopCommentToSingleLine(int line, int attrib = 0);
919     /**
920      *@see removeStartLineCommentFromSingleLine.
921      */
922     bool removeStartStopCommentFromSingleLine(int line, int attrib = 0);
923     /**
924      *@see removeStartLineCommentFromSingleLine.
925      */
926     bool removeStartStopCommentFromRegion(const KTextEditor::Cursor start, const KTextEditor::Cursor end, int attrib = 0);
927 
928     /**
929      * Add a comment marker as defined by the language providing the attribute
930      * @p attrib to each line in the selection.
931      */
932     void addStartStopCommentToSelection(KTextEditor::ViewPrivate *view, int attrib = 0);
933     /**
934      * @see addStartStopCommentToSelection.
935      */
936     void addStartLineCommentToSelection(KTextEditor::ViewPrivate *view, int attrib = 0);
937 
938     /**
939      * Removes comment markers relevant to the language providing
940      * the attribute @p attrib from each line in the selection.
941      *
942      * @return whether the operation succeeded.
943      */
944     bool removeStartStopCommentFromSelection(KTextEditor::ViewPrivate *view, int attrib = 0);
945     /**
946      * @see removeStartStopCommentFromSelection.
947      */
948     bool removeStartLineCommentFromSelection(KTextEditor::ViewPrivate *view, int attrib = 0);
949 
950 public:
951     KTextEditor::Range findMatchingBracket(const KTextEditor::Cursor start, int maxLines);
952 
953 public:
documentName()954     QString documentName() const override
955     {
956         return m_docName;
957     }
958 
959 private:
960     void updateDocName();
961 
962 public:
963     /**
964      * @return whether the document is modified on disk since last saved
965      */
isModifiedOnDisc()966     bool isModifiedOnDisc()
967     {
968         return m_modOnHd;
969     }
970 
971     void setModifiedOnDisk(ModifiedOnDiskReason reason) override;
972 
973     void setModifiedOnDiskWarning(bool on) override;
974 
975 public Q_SLOTS:
976     /**
977      * Ask the user what to do, if the file has been modified on disk.
978      * Reimplemented from KTextEditor::Document.
979      */
980     virtual void slotModifiedOnDisk(KTextEditor::View *v = nullptr);
981 
982     /**
983      * Reloads the current document from disk if possible
984      */
985     bool documentReload() override;
986 
987     bool documentSave() override;
988     bool documentSaveAs() override;
989     bool documentSaveAsWithEncoding(const QString &encoding);
990     bool documentSaveCopyAs();
991 
992     bool save() override;
993 
994 public:
995     bool saveAs(const QUrl &url) override;
996 
997 Q_SIGNALS:
998     /**
999      * Indicate this file is modified on disk
1000      * @param doc the KTextEditor::Document object that represents the file on disk
1001      * @param isModified indicates the file was modified rather than created or deleted
1002      * @param reason the reason we are emitting the signal.
1003      */
1004     void modifiedOnDisk(KTextEditor::Document *doc, bool isModified, KTextEditor::ModificationInterface::ModifiedOnDiskReason reason) override;
1005 
1006 private:
1007     // helper to handle the embedded notification for externally modified files
1008     QPointer<KateModOnHdPrompt> m_modOnHdHandler;
1009 
1010 private Q_SLOTS:
1011     void onModOnHdSaveAs();
1012     void onModOnHdClose();
1013     void onModOnHdReload();
1014     void onModOnHdAutoReload();
1015     void onModOnHdIgnore();
1016 
1017 public:
1018     bool setEncoding(const QString &e) override;
1019     QString encoding() const override;
1020 
1021 public Q_SLOTS:
1022     void setWordWrap(bool on);
1023     void setWordWrapAt(uint col);
1024 
1025 public:
1026     bool wordWrap() const;
1027     uint wordWrapAt() const;
1028 
1029 public Q_SLOTS:
1030     void setPageUpDownMovesCursor(bool on);
1031 
1032 public:
1033     bool pageUpDownMovesCursor() const;
1034 
1035     // code folding
1036 public:
1037     /**
1038      * Same as plainKateTextLine(), except that it is made sure
1039      * the line is highlighted.
1040      */
1041     Kate::TextLine kateTextLine(int i);
1042 
1043     //! @copydoc KateBuffer::plainLine()
1044     Kate::TextLine plainKateTextLine(int i);
1045 
1046 Q_SIGNALS:
1047     void aboutToRemoveText(const KTextEditor::Range &);
1048 
1049 private Q_SLOTS:
1050     void slotModOnHdDirty(const QString &path);
1051     void slotModOnHdCreated(const QString &path);
1052     void slotModOnHdDeleted(const QString &path);
1053     void slotDelayedHandleModOnHd();
1054 
1055 private:
1056     /**
1057      * Create a git compatible sha1 checksum of the file, if it is a local file.
1058      * The result can be accessed through KateBuffer::digest().
1059      *
1060      * @return whether the operation was attempted and succeeded.
1061      */
1062     bool createDigest();
1063 
1064     /**
1065      * create a string for the modonhd warnings, giving the reason.
1066      */
1067     QString reasonedMOHString() const;
1068 
1069     /**
1070      * Removes all trailing whitespace in the document.
1071      */
1072     void removeTrailingSpaces();
1073 
1074 public:
1075     /**
1076      * Returns a git compatible sha1 checksum of this document on disk.
1077      * @return checksum for this document on disk
1078      */
1079     QByteArray checksum() const override;
1080 
1081     /**
1082      * @return false if @p newType is an invalid mode.
1083      */
1084     bool updateFileType(const QString &newType, bool user = false);
1085 
fileType()1086     QString fileType() const
1087     {
1088         return m_fileType;
1089     }
1090 
1091     /**
1092      * Get access to buffer of this document.
1093      * Is needed to create cursors and ranges for example.
1094      * @return document buffer
1095      */
buffer()1096     KateBuffer &buffer()
1097     {
1098         return *m_buffer;
1099     }
1100 
1101     /**
1102      * set indentation mode by user
1103      * this will remember that a user did set it and will avoid reset on save
1104      */
rememberUserDidSetIndentationMode()1105     void rememberUserDidSetIndentationMode()
1106     {
1107         m_indenterSetByUser = true;
1108     }
1109 
1110     /**
1111      * User did set encoding for next reload => enforce it!
1112      */
userSetEncodingForNextReload()1113     void userSetEncodingForNextReload()
1114     {
1115         m_userSetEncodingForNextReload = true;
1116     }
1117 
1118     //
1119     // REALLY internal data ;)
1120     //
1121 private:
1122     // text buffer
1123     KateBuffer *const m_buffer;
1124 
1125     // indenter
1126     KateAutoIndent *const m_indenter;
1127 
1128     bool m_hlSetByUser = false;
1129     bool m_bomSetByUser = false;
1130     bool m_indenterSetByUser = false;
1131     bool m_userSetEncodingForNextReload = false;
1132 
1133     bool m_modOnHd = false;
1134     KToggleAction *m_autoReloadMode;
1135     QTimer m_autoReloadThrottle;
1136     ModifiedOnDiskReason m_modOnHdReason = OnDiskUnmodified;
1137     ModifiedOnDiskReason m_prevModOnHdReason = OnDiskUnmodified;
1138 
1139     QString m_docName;
1140     int m_docNameNumber = 0;
1141 
1142     // file type !!!
1143     QString m_fileType;
1144     bool m_fileTypeSetByUser = false;
1145 
1146     /**
1147      * document is still reloading a file
1148      */
1149     bool m_reloading = false;
1150 
1151 public Q_SLOTS:
1152     void slotQueryClose_save(bool *handled, bool *abortClosing);
1153 
1154 public:
1155     bool queryClose() override;
1156 
1157     /**
1158      * Configuration
1159      */
1160 public:
config()1161     KateDocumentConfig *config()
1162     {
1163         return m_config.get();
1164     }
config()1165     KateDocumentConfig *config() const
1166     {
1167         return m_config.get();
1168     }
1169 
1170     void updateConfig();
1171 
1172 private:
1173     void makeAttribs(bool needInvalidate = true);
1174 
1175     std::unique_ptr<KateDocumentConfig> const m_config;
1176 
1177     /**
1178      * Variable Reader
1179      * TODO add register functionality/ktexteditor interface
1180      */
1181 private:
1182     /**
1183      * read dir config file
1184      */
1185     void readDirConfig();
1186 
1187     /**
1188       Reads all the variables in the document.
1189       Called when opening/saving a document
1190     */
1191     void readVariables(bool onlyViewAndRenderer = false);
1192 
1193     /**
1194       Reads and applies the variables in a single line
1195       TODO registered variables gets saved in a [map]
1196     */
1197     void readVariableLine(const QString &t, bool onlyViewAndRenderer = false);
1198     /**
1199       Sets a view variable in all the views.
1200     */
1201     void setViewVariable(const QString &var, const QString &val);
1202     /**
1203       @return weather a string value could be converted
1204       to a bool value as supported.
1205       The value is put in *result.
1206     */
1207     static bool checkBoolValue(QString value, bool *result);
1208     /**
1209       @return weather a string value could be converted
1210       to a integer value.
1211       The value is put in *result.
1212     */
1213     static bool checkIntValue(const QString &value, int *result);
1214     /**
1215       Feeds value into @p col using QColor::setNamedColor() and returns
1216       whether the color is valid
1217     */
1218     static bool checkColorValue(const QString &value, QColor &col);
1219 
1220     bool m_fileChangedDialogsActivated = false;
1221 
1222     //
1223     // KTextEditor::ConfigInterface
1224     //
1225 public:
1226     QStringList configKeys() const override;
1227     QVariant configValue(const QString &key) override;
1228     void setConfigValue(const QString &key, const QVariant &value) override;
1229 
1230     //
1231     // KTextEditor::RecoveryInterface
1232     //
1233 public:
1234     bool isDataRecoveryAvailable() const override;
1235     void recoverData() override;
1236     void discardDataRecovery() override;
1237 
1238     //
1239     // Highlighting information
1240     //
1241 public:
1242     QStringList embeddedHighlightingModes() const override;
1243     QString highlightingModeAt(const KTextEditor::Cursor &position) override;
1244 
1245     //
1246     // BEGIN: KTextEditor::MessageInterface
1247     //
1248 public:
1249     bool postMessage(KTextEditor::Message *message) override;
1250 
1251 public Q_SLOTS:
1252     void messageDestroyed(KTextEditor::Message *message);
1253 
1254 private:
1255     QHash<KTextEditor::Message *, QList<QSharedPointer<QAction>>> m_messageHash;
1256     // END KTextEditor::MessageInterface
1257 
1258 public:
1259     QString defaultDictionary() const;
1260     QList<QPair<KTextEditor::MovingRange *, QString>> dictionaryRanges() const;
1261     bool isOnTheFlySpellCheckingEnabled() const;
1262 
1263     QString dictionaryForMisspelledRange(const KTextEditor::Range &range) const;
1264     void clearMisspellingForWord(const QString &word);
1265 
1266 public Q_SLOTS:
1267     void clearDictionaryRanges();
1268     void setDictionary(const QString &dict, const KTextEditor::Range &range, bool blockmode);
1269     void setDictionary(const QString &dict, const KTextEditor::Range &range);
1270     void setDefaultDictionary(const QString &dict);
1271     void onTheFlySpellCheckingEnabled(bool enable);
1272     void refreshOnTheFlyCheck(const KTextEditor::Range &range = KTextEditor::Range::invalid());
1273 
1274 Q_SIGNALS:
1275     void dictionaryRangesPresent(bool yesNo);
1276     void defaultDictionaryChanged(KTextEditor::DocumentPrivate *document);
1277 
1278 public:
1279     bool containsCharacterEncoding(const KTextEditor::Range &range);
1280 
1281     typedef QList<QPair<int, int>> OffsetList;
1282 
1283     int computePositionWrtOffsets(const OffsetList &offsetList, int pos);
1284 
1285     /**
1286      * The first OffsetList is from decoded to encoded, and the second OffsetList from
1287      * encoded to decoded.
1288      **/
1289     QString decodeCharacters(const KTextEditor::Range &range,
1290                              KTextEditor::DocumentPrivate::OffsetList &decToEncOffsetList,
1291                              KTextEditor::DocumentPrivate::OffsetList &encToDecOffsetList);
1292     void replaceCharactersByEncoding(const KTextEditor::Range &range);
1293 
1294 protected:
1295     KateOnTheFlyChecker *m_onTheFlyChecker = nullptr;
1296     QString m_defaultDictionary;
1297     QList<QPair<KTextEditor::MovingRange *, QString>> m_dictionaryRanges;
1298 
1299     // from KTextEditor::MovingRangeFeedback
1300     void rangeInvalid(KTextEditor::MovingRange *movingRange) override;
1301     void rangeEmpty(KTextEditor::MovingRange *movingRange) override;
1302 
1303     void deleteDictionaryRange(KTextEditor::MovingRange *movingRange);
1304 
1305 private:
1306     Kate::SwapFile *m_swapfile;
1307 
1308 public:
1309     Kate::SwapFile *swapFile();
1310 
1311     // helpers for scripting and codefolding
1312     int defStyleNum(int line, int column);
1313     bool isComment(int line, int column);
1314 
1315 public:
1316     /**
1317      * Find the next modified/saved line, starting at @p startLine. If @p down
1318      * is \e true, the search is performed downwards, otherwise upwards.
1319      * @return the touched line in the requested search direction, or -1 if not found
1320      */
1321     int findTouchedLine(int startLine, bool down);
1322 
1323 private Q_SLOTS:
1324     /**
1325      * watch for all started io jobs to remember if file is perhaps loading atm
1326      * @param job started job
1327      */
1328     void slotStarted(KIO::Job *job);
1329     void slotCompleted();
1330     void slotCanceled();
1331 
1332     /**
1333      * trigger display of loading message, after 1000 ms
1334      */
1335     void slotTriggerLoadingMessage();
1336 
1337     /**
1338      * Abort loading
1339      */
1340     void slotAbortLoading();
1341 
1342     void slotUrlChanged(const QUrl &url);
1343 
1344 private:
1345     /**
1346      * different possible states
1347      */
1348     enum DocumentStates {
1349         /**
1350          * Idle
1351          */
1352         DocumentIdle,
1353 
1354         /**
1355          * Loading
1356          */
1357         DocumentLoading,
1358 
1359         /**
1360          * Saving
1361          */
1362         DocumentSaving,
1363 
1364         /**
1365          * Pre Saving As, this is between ::saveAs is called and ::save
1366          */
1367         DocumentPreSavingAs,
1368 
1369         /**
1370          * Saving As
1371          */
1372         DocumentSavingAs
1373     };
1374 
1375     /**
1376      * current state
1377      */
1378     DocumentStates m_documentState = DocumentIdle;
1379 
1380     /**
1381      * read-write state before loading started
1382      */
1383     bool m_readWriteStateBeforeLoading = false;
1384 
1385     /**
1386      * if the document is untitled
1387      */
1388     bool m_isUntitled = true;
1389     /**
1390      * loading job, we want to cancel with cancel in the loading message
1391      */
1392     QPointer<KJob> m_loadingJob;
1393 
1394     /**
1395      * message to show during loading
1396      */
1397     QPointer<KTextEditor::Message> m_loadingMessage;
1398 
1399     /**
1400      * Was there any open error on last file loading?
1401      */
1402     bool m_openingError = false;
1403 
1404     /**
1405      * Last open file error message
1406      */
1407     QString m_openingErrorMessage;
1408 
1409 public:
1410     /**
1411      * reads the line length limit from config, if it is not overridden
1412      */
1413     int lineLengthLimit() const;
1414 
1415 public Q_SLOTS:
1416     void openWithLineLengthLimitOverride();
1417 
1418 private:
1419     /**
1420      * timer for delayed handling of mod on hd
1421      */
1422     QTimer m_modOnHdTimer;
1423 
1424 private:
1425     /**
1426      * currently active template handler; there can be only one
1427      */
1428     QPointer<KateTemplateHandler> m_activeTemplateHandler;
1429 
1430 private:
1431     /**
1432      * current autobrace range
1433      */
1434     std::unique_ptr<KTextEditor::MovingRange> m_currentAutobraceRange;
1435     /**
1436      * current autobrace closing character (e.g. ']')
1437      */
1438     QChar m_currentAutobraceClosingChar;
1439 
1440 private Q_SLOTS:
1441     void checkCursorForAutobrace(KTextEditor::View *view, const KTextEditor::Cursor newPos);
1442 
1443 public:
1444     void setActiveTemplateHandler(KateTemplateHandler *handler);
1445 
1446 Q_SIGNALS:
1447     void loaded(KTextEditor::DocumentPrivate *document);
1448 
1449 private:
1450     // To calculate a QHash.keys() is quite expensive,
1451     // better keep a copy of that list updated when a view is added or removed.
1452     QList<KTextEditor::View *> m_viewsCache;
1453 };
1454 
1455 #endif
1456