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