1 /************************************************************************
2 **
3 **  Copyright (C) 2015-2021 Kevin B. Hendricks Stratford, ON Canada
4 **  Copyright (C) 2009-2011  Strahinja Markovic  <strahinja.markovic@gmail.com>
5 **
6 **  This file is part of Sigil.
7 **
8 **  Sigil is free software: you can redistribute it and/or modify
9 **  it under the terms of the GNU General Public License as published by
10 **  the Free Software Foundation, either version 3 of the License, or
11 **  (at your option) any later version.
12 **
13 **  Sigil is distributed in the hope that it will be useful,
14 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 **  GNU General Public License for more details.
17 **
18 **  You should have received a copy of the GNU General Public License
19 **  along with Sigil.  If not, see <http://www.gnu.org/licenses/>.
20 **
21 *************************************************************************/
22 
23 #pragma once
24 #ifndef CODEVIEWEDITOR_H
25 #define CODEVIEWEDITOR_H
26 
27 #include <QtCore/QList>
28 #include <QtCore/QStack>
29 #include <QtWidgets/QPlainTextEdit>
30 #include <QtGui/QStandardItem>
31 #include <QtCore/QUrl>
32 
33 #include "Parsers/CSSInfo.h"
34 #include "Parsers/HTMLStyleInfo.h"
35 #include "Misc/PasteTarget.h"
36 #include "Misc/SettingsStore.h"
37 #include "Misc/Utility.h"
38 #include "Widgets/TextDocument.h"
39 #include "Parsers/TagLister.h"
40 #include "MiscEditors/ClipEditorModel.h"
41 #include "MiscEditors/IndexEditorModel.h"
42 #include "ViewEditors/ViewEditor.h"
43 
44 class QResizeEvent;
45 class QSize;
46 class QWidget;
47 class QPrinter;
48 class QShortcut;
49 class LineNumberArea;
50 class QSyntaxHighlighter;
51 class QContextMenuEvent;
52 class QSignalMapper;
53 
54 /**
55  * A text editor for source code.
56  * Also called the "Code View" because it shows
57  * the code of a section of the book. Provides syntax highlighting.
58  */
59 class CodeViewEditor : public QPlainTextEdit, public ViewEditor, public PasteTarget
60 {
61     Q_OBJECT
62 
63 public:
64 
65     /**
66      * What type of syntax highlighting to use.
67      */
68     enum HighlighterType {
69         Highlight_NONE,  /**< No source code highlighting */
70         Highlight_XHTML, /**< XHTML source code highlighting */
71         Highlight_CSS    /**< CSS source code highlighting */
72     };
73 
74     /**
75      * Constructor.
76      *
77      * @param highlighter_type Which syntax highlighter to use.
78      * @param parent The object's parent.
79      */
80     CodeViewEditor(HighlighterType highlighter_type, bool check_spelling = false, QWidget *parent = 0);
81     ~CodeViewEditor();
82 
83     void SetAppearance();
84 
85     QSize sizeHint() const;
86 
87     /**
88      * A custom implementation of QPlainTextEdit::setDocument()
89      * since that doesn't do everything we want it to.
90      *
91      * @param document The new text document.
92      */
93     void CustomSetDocument(TextDocument &document);
94 
95     void DeleteLine();
96 
97     void HighlightMarkedText();
98 
99     bool MoveToMarkedText(Searchable::Direction direction, bool wrap);
100 
101     /**
102      * Routines to handle cutting code tags from selected text
103      */
104     void CutCodeTags();
105     bool IsCutCodeTagsAllowed();
106 
107     void CutTagPair();
108     bool IsCutTagPairAllowed();
109 
110     bool TextIsSelected();
111     bool TextIsSelectedAndNotInStartOrEndTag();
112 
113     // No Longer Exists?
114     // bool TextIsSelectedAndNotContainingTag();
115 
116     QString StripCodeTags(QString text);
117 
118     bool IsSelectionOK();
119 
120     void InsertClosingTag();
121     bool IsInsertClosingTagAllowed();
122 
123     void GoToStyleDefinition();
124 
125     void AddMisspelledWord();
126     void IgnoreMisspelledWord();
127 
128     void AddToIndex();
129     bool IsAddToIndexAllowed();
130 
131     bool MarkForIndex(const QString &title);
132 
133     bool IsInsertFileAllowed();
134 
135     bool InsertId(const QString &attribute_value);
136     bool InsertHyperlink(const QString &attribute_value);
137     bool IsInsertIdAllowed();
138     bool IsInsertHyperlinkAllowed();
139     bool InsertTagAttribute(const QString &element_name, const QString &attribute_name,
140                             const QString &attribute_value, const QStringList &tag_list,
141                             bool ignore_seletion = false);
142 
143     /**
144     * Splits the section and returns the "upper" content.
145     * The current flow is split at the caret point.
146     *
147     * @return The content of the section up to the section break point.
148     *
149     * @note What we actually do when the user wants to split the loaded section
150     * is create a new tab with the XHTML content \em above the split point.
151     * The new tab is actually the "old" section, and this tab becomes the
152     * "new" section.
153     * \par
154     * Why? Because we can only avoid a tab render in the tab from which
155     * we remove elements. Since the users move from the top of a large HTML
156     * file down, the new section will be the one with the most content.
157     * So this way we \em try to avoid the painful render time on the biggest
158     * section, but there is still some render time left...
159     */
160     QString SplitSection();
161 
162     /**
163      * Inserts the SGF section marker code at the current caret location.
164      */
165     void InsertSGFSectionMarker();
166 
167     /**
168      * Paints the line number area.
169      * Receives the event directly from the area's paintEvent() handler.
170      *
171      * @param event The paint event to process.
172      */
173     void LineNumberAreaPaintEvent(QPaintEvent *event);
174 
175     /**
176      * Selects the line that was clicked on.
177      * Receives the event directly from the area's mouseEvent() handler.
178      *
179      * @param event The mouse event to process.
180      */
181     void LineNumberAreaMouseEvent(QMouseEvent *event);
182 
183     /**
184      * Returns the width the LinuNumberArea should take (in pixels).
185      *
186      * @return The width in pixels.
187      */
188     int CalculateLineNumberAreaWidth();
189 
190     /**
191      * Replaces the text of the entire document with the new text.
192      * Records the replacement as one action for the undo stack.
193      *
194      * @param new_text The new text of the document.
195      */
196     void ReplaceDocumentText(const QString &new_text);
197 
198     /**
199      * Scrolls the entire view to the top.
200      */
201     void ScrollToTop();
202 
203     void ScrollToPosition(int cursor_position, bool center_screen = true);
204 
205     /**
206      * Scrolls the view to the specified line.
207      *
208      * @param line The line to scroll to.
209      */
210     void ScrollToLine(int line);
211 
212     void ScrollToFragment(const QString &fragment);
213 
214     // get length of plain text
215     int textLength() const;
216 
217     // override and hide the toPlainText() call to prevent
218     // issues with lost non-breaking spaces (improperly
219     // converted to normal spaces)
220     QString toPlainText() const;
221 
222     // override the createMimeDataFromSelection() to
223     // prevent copy and cut from losing nbsp
224     // ala Kovid's solution in calibre PlainTextEdit
225     virtual QMimeData *createMimeDataFromSelection() const;
226 
227     // inherited
228     bool IsLoadingFinished();
229 
230     int GetCursorPosition() const;
231     int GetCursorLine() const;
232     int GetCursorColumn() const;
233 
234     void SetZoomFactor(float factor);
235 
236     float GetZoomFactor() const;
237 
238     void Zoom();
239 
240     void UpdateDisplay();
241 
242     SPCRE::MatchInfo GetMisspelledWord(const QString &text,
243                                        int start_offset,
244                                        int end_offset,
245                                        const QString &search_regex,
246                                        Searchable::Direction search_direction);
247 
248     bool FindNext(const QString &search_regex,
249                   Searchable::Direction search_direction,
250                   bool misspelled_words = false,
251                   bool ignore_selection_offset = false,
252                   bool wrap = true,
253                   bool selected_text = false);
254 
255     int Count(const QString &search_regex, Searchable::Direction direction, bool wrap, bool selected_text = false);
256 
257     bool ReplaceSelected(const QString &search_regex,
258                          const QString &replacement,
259                          Searchable::Direction direction = Searchable::Direction_Down,
260                          bool replace_current = false);
261 
262     int ReplaceAll(const QString &search_regex,
263                    const QString &replacement,
264                    Searchable::Direction direction,
265                    bool wrap,
266                    bool selected_text = false);
267 
268     QString GetSelectedText();
269 
270     void SetUpFindForSelectedText(const QString &search_regex);
271 
272     /**
273      * Sets flag to execute a centerCursor() call later
274      * with m_DelayedCursorScreenCenteringRequired.
275      */
276     void SetDelayedCursorScreenCenteringRequired();
277 
278     QString GetCaretElementName();
279 
280     // inherited
281     QList<ElementIndex> GetCaretLocation();
282 
283     // inherited
284     void StoreCaretLocationUpdate(const QList<ElementIndex> &hierarchy);
285 
286     // inherited
287     bool ExecuteCaretUpdate(bool default_to_top = false);
288 
289     /**
290      * Find the containing block for the cursor location and apply a new
291      * element tag name to it.
292      *
293      * @param element_name The name of the element to format the block to.
294      * @param preserve_attributes Whether to keep any existing attributes on the previous block tag.
295      */
296     void FormatBlock(const QString &element_name, bool preserve_attributes);
297 
298     /**
299      * Given the current cursor position/selection, look to toggle a format style tag
300      * around it. The rule on whether to insert a new tag or remove an existing one is
301      * attempting to emulate what would happen in BookView. If there is the same tag
302      * immediately adjacent to the selection (inside or outside it) then it is removed.
303      * Otherwise a new tag is inserted around the selection.
304      *
305      * @param element_name The name of the element to toggle the format of the selection.
306      * @param property_name If caret is in an inline CSS style instead of the body, property to change
307      * @param property_value If caret is in an inline CSS style instead of the body, value of property to change
308      */
309     void ToggleFormatSelection(const QString &element_name, const QString property_name = "", const QString property_value = "");
310 
311     /**
312      * Based on the cursor location (in html file) add/replace as
313      * appropriate a style="property_name: property_value" attribute.
314      *
315      * @param property_name The name of the style property to be inserted/replaced.
316      * @param property_value The new value to be assigned to this property.
317      */
318     void FormatStyle(const QString &property_name, const QString &property_value);
319 
320     /**
321      * Based on the cursor location (in html file) add/replace as
322      * appropriate a text direction dir="property_value" attribute.
323      *
324      * @param property_value The new value to be assigned to this property.
325      */
326     void FormatTextDir(const QString &attribute_value);
327 
328 
329     /**
330      * Based on the cursor location (in CSS file or inlined in HTML file)
331      * add/replace as appropriate a property_name: property_value property in
332      * the currently selected CSS style if any.
333      *
334      * @param property_name The name of the style property to be inserted/replaced.
335      * @param property_value The new value to be assigned to this property.
336      */
337     void FormatCSSStyle(const QString &property_name, const QString &property_value);
338 
339     bool IsSelectionValid(const QString &text);
340 
341     void WrapSelectionInElement(const QString &element, bool unwrap = false);
342 
343     void ApplyListToSelection(const QString &element);
344 
345     void ApplyCaseChangeToSelection(const Utility::Casing &casing);
346 
347     QString GetAttributeId();
348 
349     /**
350      * Based on the cursor location (in html file)
351      * get appropriate attribute_value for attribute_name.
352      *
353      */
354     QString GetAttribute(const QString &attribute_name, QStringList tag_list = QStringList(),
355                          bool must_be_in_attribute = false, bool skip_paired_tags = false,
356                          bool must_be_in_body = true);
357 
358 
359     QString SetAttribute(const QString &attribute_name, QStringList tag_list = QStringList(), const QString &attribute_value = QString(), bool must_be_in_attribute = false, bool skip_paired_tags = false);
360 
361     /**
362      * Based on the cursor location (in html file) add/replace as
363      * appropriate an attribute_name="attribute_value".
364      *
365      * @param attribute_name The name of the attribute to be inserted/replaced.
366      * @param attribute_value The new value to be assigned to this attribute.
367      */
368     QString ProcessAttribute(const QString &attribute_name, QStringList tag_list = QStringList(),
369                              const QString &attribute_value = QString(), bool set_attribute = false,
370                              bool must_be_in_attribute = false, bool skip_paired_tags = false,
371                              bool must_be_in_body = true);
372 
373     /**
374      * Control whether the Reformat CSS submenu is available on the context menu.
375      */
376     bool ReformatCSSEnabled();
377     void SetReformatCSSEnabled(bool value);
378 
379     /**
380      * Control wheter the Reformat (clean) HTML submenu is avaliable on the context menu.
381      */
382     bool ReformatHTMLEnabled();
383     void SetReformatHTMLEnabled(bool value);
384 
385     bool PasteClipNumber(int clip_number);
386 
387     void HighlightWord(const QString &word, int pos);
388 
389 signals:
390 
391     /**
392      * Emitted whenever the zoom factor changes.
393      *
394      * @param new_zoom_factor The new zoom factor of the View.
395      */
396     void ZoomFactorChanged(float new_zoom_factor);
397 
398     /**
399      * Emitted when the focus is lost.
400      */
401     void FocusLost(QWidget *editor);
402 
403     /**
404      * Emitted when the focus is gained.
405      */
406     void FocusGained(QWidget *editor);
407 
408     void FilteredCursorMoved();
409     void PageClicked();
410     void PageUpdated();
411 
412     /**
413      * A filtered version of the QPlainTextEdit::textChnaged signal.
414      * We use it to prevent our syntax highlighter from emitting that signal.
415      */
416     void FilteredTextChanged();
417 
418     void OpenClipEditorRequest(ClipEditorModel::clipEntry *);
419 
420     void OpenIndexEditorRequest(IndexEditorModel::indexEntry *);
421 
422     void LinkClicked(const QUrl &url);
423 
424     void ViewImage(const QUrl &url);
425 
426     void GoToLinkedStyleDefinitionRequest(const QString &element_name, const QString &style_class_name);
427 
428     void BookmarkLinkOrStyleLocationRequest();
429 
430     void SpellingHighlightRefreshRequest();
431 
432     void ShowStatusMessageRequest(const QString &message);
433 
434     void DocumentSet();
435 
436     void MarkSelectionRequest();
437     void ClearMarkedTextRequest();
438 
439 public slots:
440 
441     /**
442      * A slot wrapper around the base class print() function.
443      *
444      * @param printer The printer interface to use for printing.
445      */
446     void print(QPagedPaintDevice *printer);
447 
448     // Implementations for PasteTarget.h
449     void PasteText(const QString &text);
450     bool PasteClipEntries(const QList<ClipEditorModel::clipEntry *> &clips);
451 
452     void RefreshSpellingHighlighting();
453 
454     void OpenImageAction();
455 
456     void GoToLinkOrStyle();
457 
458     bool MarkSelection();
459 
460     bool ClearMarkedText();
461 
462     void RehighlightDocument();
463 
464 protected:
465 
466     /**
467      * The global event processing function.
468      *
469      * @param event The event to process.
470      */
471     bool event(QEvent *event);
472 
473     /**
474      * Handles the resize event for the editor.
475      *
476      * @param event The event to process.
477      */
478     void resizeEvent(QResizeEvent *event);
479 
480     /**
481      * Handles the mouse press event for the editor.
482      *
483      * @param event The event to process.
484      */
485     void mousePressEvent(QMouseEvent *event);
486 
487     void mouseReleaseEvent(QMouseEvent *event);
488 
489     void mouseDoubleClickEvent(QMouseEvent *event);
490 
491     /**
492      * Handles the content menu event for the editor.
493      *
494      * @param event The event to process.
495      */
496     void contextMenuEvent(QContextMenuEvent *event);
497 
498     /**
499      * Handles the focus in event for the editor.
500      *
501      * @param event The event to process.
502      */
503     void focusInEvent(QFocusEvent *event);
504 
505     /**
506      * Handles the focus out event for the editor.
507      *
508      * @param event The event to process.
509      */
510     void focusOutEvent(QFocusEvent *event);
511 
512 private slots:
513     void ResetLastFindMatch();
514 
515     void EmitFilteredCursorMoved();
516 
517     /**
518      * Filters the textChanged signal.
519      * It does this based on the availability of undo.
520      */
521     void TextChangedFilter();
522 
523     void PasteClipEntryFromName(const QString &name);
524 
525     /**
526      * Used solely to update the m_isUndoAvailable variable
527      * on undo availability change.
528      *
529      * @param available The current availability of the undo action.
530      */
531     void UpdateUndoAvailable(bool available);
532 
533     /**
534      * Creates a margin where the line number are can sit.
535      * Called whenever the number of lines changes.
536      */
537     void UpdateLineNumberAreaMargin();
538 
539     /**
540      * Repaints a part of the line number area as needed.
541      *
542      * @param rectangle Represents the area that the editor needs an update of.
543      * @param vertical_delta The amount of pixels the viewport has been vertically scrolled.
544      */
545     void UpdateLineNumberArea(const QRect &rectangle, int vertical_delta);
546 
547     /**
548      * Highlights the line the user is editing.
549      */
550     void HighlightCurrentLine(bool highlight_tags=true);
551 
552     /**
553      * Wrapper slot for the Scroll One Line Up shortcut.
554      */
555     void ScrollOneLineUp();
556 
557     /**
558       * Wrapper slot for the Scroll One Line Down shortcut.
559      */
560     void ScrollOneLineDown();
561 
562     void InsertText(const QString &text);
563 
564     void addToUserDictionary(const QString &text);
565     void addToDefaultDictionary(const QString &text);
566     void ignoreWord(const QString &text);
567 
568     void SaveClipAction();
569 
570     void GoToLinkOrStyleAction();
571 
572     void ReformatCSSMultiLineAction();
573     void ReformatCSSSingleLineAction();
574 
575     void ReformatHTMLCleanAction();
576     void ReformatHTMLCleanAllAction();
577     void ReformatHTMLToValidAction();
578     void ReformatHTMLToValidAllAction();
579 
580 private:
581     bool IsMarkedText();
582 
583     void MaybeRegenerateTagList();
584 
585     QString RemoveFirstTag(const QString &text, const QString &tagname);
586     QString RemoveLastTag(const QString &text, const QString &tagname);
587 
588     QString GetCurrentWordAtCaret(bool select_word);
589 
590     bool PasteClipEntry(ClipEditorModel::clipEntry *clip);
591 
592     /**
593      * Resets the currently used font.
594      */
595     void ResetFont();
596 
597     /**
598      * Updates the font used in the line number area
599      * and also repaints it.
600      *
601      * @param font The new font to use.
602      */
603     void UpdateLineNumberAreaFont(const QFont &font);
604 
605     void SetAppearanceColors();
606 
607     /**
608      * Executes a centerCursor() call if requested
609      * with m_DelayedCursorScreenCenteringRequired.
610      */
611     void DelayedCursorScreenCentering();
612 
613     /**
614      * Returns the selection offset from the start of the
615      * document depending on the search direction specified
616      *
617      * @param search_direction Depending on this, the anchor or the focus position is returned.
618      * @param ignore_selection_offset Should the selection offset be ignored.
619      */
620     int GetSelectionOffset(Searchable::Direction search_direction, bool ignore_selection_offset, bool marked_text) const;
621 
622     /**
623      * Scrolls the whole screen by one line.
624      * Used for ScrollOneLineUp and ScrollOneLineDown shortcuts.
625      * It will also move the cursor position if the
626      * scroll would make it "fall of the screen".
627      *
628      * @param down If \c true, we scroll down. Otherwise, we scroll up.
629      */
630     void ScrollByLine(bool down);
631 
632     /**
633      * Connects all the required signals to their respective slots.
634      */
635     void ConnectSignalsToSlots();
636 
637     void AddReformatCSSContextMenu(QMenu *menu);
638 
639     void AddReformatHTMLContextMenu(QMenu *menu);
640 
641     void AddGoToLinkOrStyleContextMenu(QMenu *menu);
642 
643     void AddClipContextMenu(QMenu *menu);
644 
645     void AddMarkSelectionMenu(QMenu *menu);
646 
647     bool AddSpellCheckContextMenu(QMenu *menu);
648 
649     void AddViewImageContextMenu(QMenu *menu);
650 
651     bool CreateMenuEntries(QMenu *parent_menu, QAction *topAction, QStandardItem *item);
652 
653     bool InViewableImage();
654 
655     /**
656      * An element on the stack when searching for
657      * the current caret location.
658      */
659     struct StackElement {
660         /**
661          * The tag name.
662          */
663         QString name;
664 
665         /**
666          * The number of child elements
667          * detected for the element, so far.
668          */
669         int num_children;
670     };
671 
672     /**
673      * Returns a stack of elements representing the
674      * current location of the caret in the document.
675      *
676      * @param offset The number of characters from document start to the end of
677      *               the start tag of the element the caret is residing in.
678      * @return The element location stack.
679      */
680     QStack<StackElement> GetCaretLocationStack(int offset) const;
681 
682     /**
683      * Takes the stack provided by GetCaretLocationStack()
684      * and converts it into the element location hierarchy
685      * used by other ViewEditors.
686      *
687      * @param stack The StackElement stack.
688      * @return The converted ElementIndex hierarchy.
689      */
690     QList<ElementIndex> ConvertStackToHierarchy(const QStack<StackElement> stack) const;
691 
692 
693     // Used to convert Hierarchy to QWedPath used by BV and Gumbo
694     QString ConvertHierarchyToQWebPath(const QList<ElementIndex>& hierarchy) const;
695 
696     /**
697      * Converts a ViewEditor element hierarchy to a tuple describing necessary caret moves.
698      * The tuple contains the vertical lines and horizontal chars move deltas
699      *
700      * @param hierarchy The caret location as ElementIndex hierarchy.
701      * @return The info needed to move the caret to the new location.
702      */
703     std::tuple<int, int> ConvertHierarchyToCaretMove(const QList<ElementIndex> &hierarchy) const;
704 
705     /**
706      * Insert HTML tags around the current selection.
707      */
708     void InsertHTMLTagAroundSelection(const QString &left_element_name, const QString &right_element_name, const QString &attributes = QString());
709 
710     void InsertHTMLTagAroundText(const QString &left_element_name, const QString &right_element_name, const QString &attributes, const QString &text);
711 
712     /**
713      * Is this position within the <body> tag of this text.
714      */
715     bool IsPositionInBody(int pos);
716     bool IsPositionInTag(int pos);
717     bool IsPositionInOpeningTag(int pos);
718     bool IsPositionInClosingTag(int pos);
719     QString GetOpeningTagName(int pos);
720     QString GetClosingTagName(int pos);
721 
722     void FormatSelectionWithinElement(const QString &element_name, int tagno, const QString &text);
723 
724     void ReplaceTags(const int &opening_tag_start, const int &opening_tag_end, const QString &opening_tag_text,
725                      const int &closing_tag_start, const int &closing_tag_end, const QString &closing_tag_text);
726 
727     /**
728      * An element on the stack when searching for
729      * the current caret location.
730      */
731     struct StyleTagElement {
StyleTagElementStyleTagElement732         StyleTagElement() {
733             name = QString();
734             classStyle = QString();
735         }
736         /**
737          * The tag name.
738          */
739         QString name;
740 
741         /**
742          * The class style under the caret location if cursor in the class section.
743          * If cursor is on the tag element, is the first style class of this element if any.
744          */
745         QString classStyle;
746     };
747 
748     StyleTagElement GetSelectedStyleTagElement();
749 
750     /**
751      * Given a list of CSS properties perform any pruning/replacing/adding as necessary to
752      * ensure that property_name:property_value is added (or removed if it already exists).
753      */
754     void ApplyChangeToProperties(QList<HTMLStyleInfo::CSSProperty> &css_properties, const QString &property_name, const QString &property_value);
755 
756     void ReformatCSS(bool multiple_line_format);
757 
758     void ReformatHTML(bool all, bool to_valid);
759 
760     QStringList GetUnmatchedTagsForBlock(int pos);
761 
762     void SelectAndScrollIntoView(int start_position, int end_position, Searchable::Direction direction, bool wrapped);
763 
764     ///////////////////////////////
765     // PRIVATE MEMBER VARIABLES
766     ///////////////////////////////
767 
768     /**
769      * \c true when an undo action can be performed.
770      */
771     bool m_isUndoAvailable;
772 
773     /**
774      * Keeps track of the last block count.
775      * Needed because QTextDocument::setPlainText sets
776      * this back to 1 before updating it.
777      */
778     int m_LastBlockCount;
779 
780     /**
781      * Keep tack of the currenlt selected line number when selected
782      * by by clicking on the LineNumberArea.
783      */
784     int m_LineNumberAreaBlockNumber;
785 
786     /**
787      * The line number area widget of the code view.
788      */
789     LineNumberArea *m_LineNumberArea;
790 
791     /**
792      * The syntax highlighter.
793      */
794     QSyntaxHighlighter *m_Highlighter;
795 
796     /**
797      * The view's current zoom factor.
798      */
799     float m_CurrentZoomFactor;
800 
801     /**
802      * Catches when the user wants to scroll the view by one line up.
803      */
804     QShortcut *m_ScrollOneLineUp;
805 
806     /**
807      * Catches when the user wants to scroll the view by one line down.
808      */
809     QShortcut *m_ScrollOneLineDown;
810 
811     /**
812      * Set to \c false whenever the page is loading content.
813      */
814     bool m_isLoadFinished;
815 
816     /**
817      * When \c true, a centerCursor() call will be executed
818      * once after the View is repainted.
819      */
820     bool m_DelayedCursorScreenCenteringRequired;
821 
822     int m_caretLocation;
823 
824     /**
825      * Stores the update for the caret location
826      * when switching from BookView to CodeView.
827      */
828     QList<ElementIndex> m_CaretUpdate;
829 
830     /**
831      * Whether spell checking is enabled on this view.
832      * Misspellings are marked by the QSyntaxHighlighter used.
833      */
834     bool m_checkSpelling;
835 
836     /**
837      * Whether reformat CSS context menu option is enabled on this view.
838      */
839     bool m_reformatCSSEnabled;
840 
841     /**
842      * Whether reformat (clean) HTML context menu option is enabled on this view.
843      */
844     bool m_reformatHTMLEnabled;
845 
846     /**
847      * Store the last match when doing a find so we can determine if
848      * found text is selected for doing a replace. We also need to store the
849      * match because we can't run the selected text though the PCRE engine
850      * (we don't want to because it's slower than caching) because it will fail
851      * if a look ahead or behind expression is in use.
852      */
853     SPCRE::MatchInfo m_lastMatch;
854     QString m_lastFindRegex;
855 
856     /**
857      * Map spelling suggestion actions from the context menu to the
858      * ReplaceSelected slot.
859      */
860     QSignalMapper *m_spellingMapper;
861     QSignalMapper *m_addSpellingMapper;
862     QSignalMapper *m_addDictMapper;
863     QSignalMapper *m_ignoreSpellingMapper;
864     QSignalMapper *m_clipMapper;
865 
866     int m_MarkedTextStart;
867     int m_MarkedTextEnd;
868     bool m_ReplacingInMarkedText;
869 
870     /**
871      * The fonts and colors for appearance of xhtml and text.
872      */
873     SettingsStore::CodeViewAppearance m_codeViewAppearance;
874 
875     /**
876      * Whether spelling highlighting should be reapplied when this tab is next given focus.
877      */
878     bool m_pendingSpellingHighlighting;
879     QString m_element_name;
880 
881     TagLister m_TagList;
882     bool m_regen_taglist;
883 };
884 
885 #endif // CODEVIEWEDITOR_H
886 
887