1 /************************************************************************
2 **
3 ** Copyright (C) 2015-2019 Kevin B. Hendricks, Stratford Ontario 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 #include <QtCore/QTimer>
24 #include <QtWidgets/QLayout>
25 #include <QtPrintSupport/QPrinter>
26 #include <QtPrintSupport/QPrintDialog>
27 #include <QtPrintSupport/QPrintPreviewDialog>
28
29 #include "ResourceObjects/TextResource.h"
30 #include "Tabs/TextTab.h"
31
TextTab(TextResource * resource,CodeViewEditor::HighlighterType type,int line_to_scroll_to,int position_to_scroll_to,QWidget * parent)32 TextTab::TextTab(TextResource *resource,
33 CodeViewEditor::HighlighterType type,
34 int line_to_scroll_to,
35 int position_to_scroll_to,
36 QWidget *parent)
37 :
38 ContentTab(resource, parent),
39 m_wCodeView(new CodeViewEditor(type, false, this)),
40 m_TextResource(resource),
41 m_LineToScrollTo(line_to_scroll_to),
42 m_PositionToScrollTo(position_to_scroll_to)
43 {
44 m_Layout->addWidget(m_wCodeView);
45 setFocusProxy(m_wCodeView);
46 ConnectSignalsToSlots();
47 // Make sure the resource is loaded as its file doesn't seem
48 // to exist when the resource tries to do an initial load.
49 m_TextResource->InitialLoad();
50 // We perform delayed initialization after the widget is on
51 // the screen. This way, the user perceives less load time.
52 QTimer::singleShot(0, this, SLOT(DelayedInitialization()));
53 }
54
~TextTab()55 TextTab::~TextTab()
56 {
57 if (m_wCodeView) {
58 delete m_wCodeView;
59 m_wCodeView = 0;
60 }
61 }
62
63
ScrollToLine(int line)64 void TextTab::ScrollToLine(int line)
65 {
66 m_wCodeView->ScrollToLine(line);
67 }
68
ScrollToPosition(int cursor_position)69 void TextTab::ScrollToPosition(int cursor_position)
70 {
71 m_wCodeView->ScrollToPosition(cursor_position);
72 }
73
IsModified()74 bool TextTab::IsModified()
75 {
76 return m_wCodeView->document()->isModified();
77 }
78
79
CutEnabled()80 bool TextTab::CutEnabled()
81 {
82 return m_wCodeView->textCursor().hasSelection();
83 }
84
85
CopyEnabled()86 bool TextTab::CopyEnabled()
87 {
88 return m_wCodeView->textCursor().hasSelection();
89 }
90
91
PasteEnabled()92 bool TextTab::PasteEnabled()
93 {
94 return m_wCodeView->canPaste();
95 }
96
DeleteLineEnabled()97 bool TextTab::DeleteLineEnabled()
98 {
99 return !m_wCodeView->document()->isEmpty();
100 }
101
CutCodeTagsEnabled()102 bool TextTab::CutCodeTagsEnabled()
103 {
104 return false;
105 }
106
107
GetCursorLine() const108 int TextTab::GetCursorLine() const
109 {
110 return m_wCodeView->GetCursorLine();
111 }
112
GetCursorPosition() const113 int TextTab::GetCursorPosition() const
114 {
115 return m_wCodeView->GetCursorPosition();
116 }
117
GetCursorColumn() const118 int TextTab::GetCursorColumn() const
119 {
120 return m_wCodeView->GetCursorColumn();
121 }
122
123
GetZoomFactor() const124 float TextTab::GetZoomFactor() const
125 {
126 return m_wCodeView->GetZoomFactor();
127 }
128
129
SetZoomFactor(float new_zoom_factor)130 void TextTab::SetZoomFactor(float new_zoom_factor)
131 {
132 m_wCodeView->SetZoomFactor(new_zoom_factor);
133 }
134
135
UpdateDisplay()136 void TextTab::UpdateDisplay()
137 {
138 m_wCodeView->UpdateDisplay();
139 }
140
141
GetSearchableContent()142 Searchable *TextTab::GetSearchableContent()
143 {
144 return m_wCodeView;
145 }
146
147
Undo()148 void TextTab::Undo()
149 {
150 if (m_wCodeView->hasFocus()) {
151 m_wCodeView->undo();
152 }
153 }
154
155
Redo()156 void TextTab::Redo()
157 {
158 if (m_wCodeView->hasFocus()) {
159 m_wCodeView->redo();
160 }
161 }
162
163
Cut()164 void TextTab::Cut()
165 {
166 if (m_wCodeView->hasFocus()) {
167 m_wCodeView->cut();
168 }
169 }
170
171
Copy()172 void TextTab::Copy()
173 {
174 if (m_wCodeView->hasFocus()) {
175 m_wCodeView->copy();
176 }
177 }
178
179
Paste()180 void TextTab::Paste()
181 {
182 m_wCodeView->paste();
183 }
184
185
DeleteLine()186 void TextTab::DeleteLine()
187 {
188 if (m_wCodeView->hasFocus()) {
189 m_wCodeView->DeleteLine();
190 }
191 }
192
MarkSelection()193 bool TextTab::MarkSelection()
194 {
195 return m_wCodeView->MarkSelection();
196 }
197
ClearMarkedText()198 bool TextTab::ClearMarkedText()
199 {
200 return m_wCodeView->ClearMarkedText();
201 }
202
CutCodeTags()203 void TextTab::CutCodeTags()
204 {
205 }
206
ChangeCasing(const Utility::Casing casing)207 void TextTab::ChangeCasing(const Utility::Casing casing)
208 {
209 if (m_wCodeView->hasFocus()) {
210 m_wCodeView->ApplyCaseChangeToSelection(casing);
211 }
212 }
213
214
SaveTabContent()215 void TextTab::SaveTabContent()
216 {
217 // We can't perform the document modified check
218 // here because that causes problems with epub export
219 // when the user has not changed the text file.
220 // (some text files have placeholder text on disk)
221 if (!m_wCodeView->document()->isModified()) {
222 ContentTab::SaveTabContent();
223 return;
224 }
225
226 // Losing focus will invoke SaveTabContent
227 // which may run SaveToDisk on the underlying resource
228 // that will reset the cursor to the end of file
229 // so save the cursor position and then put it
230 // back after the SaveToDisk
231 int cursorPosition = m_wCodeView->GetCursorPosition();
232
233 // The call to SaveToDisk **IS** needed here even though the
234 // QTextEdit is tied directly to the QtQPlainTextDocument.
235 // Webkit is passed in an xhtml file but all supporting files
236 // such as CSS, svg, and etc are only ever read from Disk,
237 // so any time focus is lost and the contents of the TextTab
238 // have changed, we should save them to disk
239 m_TextResource->SaveToDisk();
240
241 // Some systems (Linux/Windows) may lose text highlighting when
242 // ScrollToPosition is called unnecessarily. Only reposition
243 // if the cursor has actually moved.
244 int newcursorPosition = m_wCodeView->GetCursorPosition();
245 if (newcursorPosition != cursorPosition) m_wCodeView->ScrollToPosition(cursorPosition, false);
246 ContentTab::SaveTabContent();
247 }
248
249
SaveTabContent(QWidget * editor)250 void TextTab::SaveTabContent(QWidget *editor)
251 {
252 Q_UNUSED(editor);
253 SaveTabContent();
254 }
255
256
LoadTabContent()257 void TextTab::LoadTabContent()
258 {
259 }
260
261
LoadTabContent(QWidget * editor)262 void TextTab::LoadTabContent(QWidget *editor)
263 {
264 Q_UNUSED(editor);
265 LoadTabContent();
266 }
267
268
EmitUpdateCursorPosition()269 void TextTab::EmitUpdateCursorPosition()
270 {
271 emit UpdateCursorPosition(GetCursorLine(), GetCursorColumn());
272 }
273
DelayedInitialization()274 void TextTab::DelayedInitialization()
275 {
276 m_wCodeView->CustomSetDocument(m_TextResource->GetTextDocumentForWriting());
277 m_wCodeView->Zoom();
278 if (m_PositionToScrollTo > 0) {
279 m_wCodeView->ScrollToPosition(m_PositionToScrollTo);
280 } else {
281 m_wCodeView->ScrollToLine(m_LineToScrollTo);
282 }
283 }
284
285
ConnectSignalsToSlots()286 void TextTab::ConnectSignalsToSlots()
287 {
288 // We set the Code View as the focus proxy for the tab,
289 // so the ContentTab focusIn/Out handlers are not called.
290 connect(m_wCodeView, SIGNAL(FocusGained(QWidget *)), this, SLOT(LoadTabContent(QWidget *)));
291 connect(m_wCodeView, SIGNAL(FocusLost(QWidget *)), this, SLOT(SaveTabContent(QWidget *)));
292 connect(m_wCodeView, SIGNAL(FilteredTextChanged()), this, SIGNAL(ContentChanged()));
293 connect(m_wCodeView, SIGNAL(cursorPositionChanged()), this, SLOT(EmitUpdateCursorPosition()));
294 connect(m_wCodeView, SIGNAL(ZoomFactorChanged(float)), this, SIGNAL(ZoomFactorChanged(float)));
295 connect(m_wCodeView, SIGNAL(selectionChanged()), this, SIGNAL(SelectionChanged()));
296 connect(m_wCodeView, SIGNAL(OpenClipEditorRequest(ClipEditorModel::clipEntry *)), this, SIGNAL(OpenClipEditorRequest(ClipEditorModel::clipEntry *)));
297 connect(m_wCodeView, SIGNAL(MarkSelectionRequest()), this, SIGNAL(MarkSelectionRequest()));
298 connect(m_wCodeView, SIGNAL(ClearMarkedTextRequest()), this, SIGNAL(ClearMarkedTextRequest()));
299 }
300
301
PrintPreview()302 void TextTab::PrintPreview()
303 {
304 QPrintPreviewDialog *print_preview = new QPrintPreviewDialog(this);
305 connect(print_preview, SIGNAL(paintRequested(QPrinter *)), m_wCodeView, SLOT(print(QPrinter *)));
306 print_preview->exec();
307 print_preview->deleteLater();
308 }
309
Print()310 void TextTab::Print()
311 {
312 QPrinter printer;
313 QPrintDialog print_dialog(&printer, this);
314 print_dialog.setWindowTitle(tr("Print %1").arg(GetFilename()));
315
316 if (print_dialog.exec() == QDialog::Accepted) {
317 m_wCodeView->print(&printer);
318 }
319 }
320
321