forked from GCodeProjects/GCodeWorkShop
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocument.h
More file actions
723 lines (653 loc) · 19.2 KB
/
document.h
File metadata and controls
723 lines (653 loc) · 19.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
/*
* Copyright (C) 2024 Nick Egorrov, nicegorov@yandex.ru
*
* This file is part of GCodeWorkShop.
*
* GCodeWorkShop is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DOCUMENT_H
#define DOCUMENT_H
#include <QByteArray> // for QByteArray
#include <QDir> // for QDir
#include <QObject> // for QObject, Q_OBJECT, signals, slots
#include <QString> // for QString
class QCloseEvent;
class QMenu;
class QPoint;
class QWidget;
#include <documentinfo.h> // for DocumentInfo, DocumentInfo::Ptr
#include <documentstyle.h> // for DocumentStyle, DocumentStyle::Ptr
#include <documentwidgetproperties.h> // for DocumentWidgetProperties, DocumentWidgetProperties::Ptr
/**
* @brief A base class for displaying and editing documents.
*
* The derived class must have a unique type returned by type(). The value returned by
* brief() is used in a widget with a list of open documents. The guessFileName() function
* is called when an untitled document is saved to guess a possible file name. Whether the
* document is untitled can be checked using the isUntitled() function.
*
* The class has an associated widget, accessible using widget() function. The descendants
* must call setWidget() in the constructor to associate the widget with the document.
* The widget participates in the document's closing mechanism, for this purpose the class
* sets the widget's close event filter. The closing chain of the class looks as follows:
*
* @li A call to close() leads to a call to Widget::close()
* @li Widget::close() fires the QCloseEvent event
* @li The QCloseEvent event is intercepted by the filter and the closeEvent() function
* of this class is called.
* @li closeEvent() fires the closeRequested() signal.
* @li If the closeRequest() signal handler returns @c false, the closing of the document
* and widget is canceled and close() returns @c false. Otherwise, the document and
* widget are closed and close() returns @c true.
*
* A document can have styles that determine how the widget displays content. For example,
* for a text document, these are font type, font size, and highlighting colors. Styles
* are managed by documentStyle() and setDocumentStyle() functions. Widget behavior is
* controlled by properties, which are managed by documentWidgetProperties() and
* setDocumentWidgetProperties(). Both the styles and properties of a particular document
* type are independent of the content. Instead, information about the document is
* individualized and can be retrieved using documentInfo().
*
* Document stores the full path to the file from which the document is loaded or saved.
* The full path can be obtained using filePath(). The full path is also contained in an
* instance of the DocumentInfo class, which is returned by the documentInfo() function.
* The full path is also used to monitor file changes on disk. Requests to enable and
* disable file change monitoring are emitted when a file is loaded and saved. This
* behavior is implemented in the class and does not require additional actions in the
* class descendants.
*
* To load a document from a file, the application uses the load() function; this function
* must be implemented in a descendant of the class. In general, the load() function calls
* loadFile() with the filePath() argument and does some additional actions specific to a
* particular document type. The loadFile() function is implemented in this class and does
* not require overriding, it reads data from a file and passes this data to the
* setRawData() function. The loadTemplate() function is similar to load(), but when
* calling loadFile() it should additionally specify that tracking the file is unnecessary.
*
* Saving to a file is similar: the save() function calls saveFile() with the filePath()
* argument, in turn saveFile() uses the rawData() function to get the data written to the
* file.
*
* The class generates @ref fileWatchRequested() "requests to monitor" a file changes
* on disk:
*
* @li Before saving or closing a document, a request to stop watching is emitted.
* @li After loading or saving a document, a request to run watching is emitted.
*
* A descendant of a class may support undo and redo operations, in which case the
* descendant must override redo(), undo(), and clearUndoRedoStacks(). The descendant must
* also call setRedoAvailable() and setUndoAvailable() when the availability of the undo
* and redo operation changes; this ensures that the isRedoAvailable() and
* isUndoAvailable() functions work correctly.
*/
class Document : public QObject
{
Q_OBJECT
protected:
explicit Document(QObject* parent = nullptr);
~Document();
public:
/**
* @brief Returns the type of the document.
*/
virtual QString type() const = 0;
/**
* @brief Returns the path to a file as a QDir object.
*
* @see setDir()
* @see path()
*/
QDir dir() const;
/**
* @brief Sets the path to a file as a QDir object.
*
* @param dir The path to a file.
*
* @see dir()
*/
void setDir(const QDir& dir);
/**
* @brief Returns the path to a file without a filename.
*
* @see setPath()
* @see fileName()
* @see filePath()
*/
QString path() const;
/**
* @brief Sets the path to a file without a filename.
*
* @param path The path to a file.
*
* @see path()
*/
void setPath(const QString& path);
/**
* @brief Returns the file name.
*
* @see setFileName()
* @see filePath()
* @see path()
* @see guessFileName()
*/
QString fileName() const;
/**
* @brief sets the file name.
*
* @param fileName The file name.
*
* @see fileName()
*/
void setFileName(const QString& fileName);
/**
* @brief Returns the full file name, including the path.
*
* @see setFilePath()
* @see path()
* @see fileName()
*/
QString filePath() const;
/**
* @brief Sets the full file name, including the path.
*
* @param filePath The full file name.
*
* @see filePath()
*/
void setFilePath(const QString& filePath);
/**
* @brief Returns the document information.
*
* The document information contains the state of the document that can be saved to
* disk. The base implementation contains the full file name, widget position and
* size, and whether the the document is readonly.
*
* @see setDocumentInfo()
*/
virtual DocumentInfo::Ptr documentInfo() const;
/**
* @brief Sets the document information.
*
* The base implementation sets:
*
* @li The full file name on condition that the info->filePath field is not empty.
* @li The position and size of the widget.
* @li Whether the document is readonly.
*
* @param info The document information.
*
* @see documentInfo()
*/
virtual void setDocumentInfo(const DocumentInfo::Ptr& info);
/**
* @brief Returns the document style.
*/
virtual DocumentStyle::Ptr documentStyle() const = 0;
/**
* @brief Sets the document style.
*
* @param style The document style.
*/
virtual void setDocumentStyle(const DocumentStyle::Ptr& style) = 0;
/**
* @brief Returns the document widget properties.
*/
virtual DocumentWidgetProperties::Ptr documentWidgetProperties() const = 0;
/**
* @brief Sets the document widget properties.
*
* @param properties Document widget properties.
*/
virtual void setDocumentWidgetProperties(const DocumentWidgetProperties::Ptr& properties) = 0;
/**
* @brief Guesses the file name from the contents of the document.
*
* @return The default implementation of the function returns fileName().
*/
virtual QString guessFileName() const;
/**
* @brief Returns a brief description of the document.
*
* The short description is based on the content of the document. For example, for
* G-code it could be the program number or the first comment.
*/
QString brief() const;
protected:
/**
* @brief Sets a short description of the document.
*
* If the description changes, the briefChanged() signal is emitted.
*
* @param brief Brief description of the document.
*
* @see brief()
*/
void setBrief(const QString& brief);
signals:
/**
* @brief Emitted when the brief description is changed.
*
* @param doc This document.
*
* @see setBrief()
* @see brief()
*/
void briefChanged(Document* doc);
public:
/**
* @brief Returns a widget of the document.
*
* Each document has its own widget for displaying and editing the document.
*
* @return A widget of the document.
*
* @see setWidget()
*/
QWidget* widget() const;
protected:
/**
* @brief Sets the widget to display and edit the document.
*
* Class descendants must use this function in the constructor. The function specifies
* some widget properties and sets an event filter to handle the widget close event.
*
* @param widget The widget to display and edit the document.
*
* @see closeEvent()
*/
void setWidget(QWidget* widget);
/**
* @brief Sets the widget title.
*
* @param title The widget title.
*/
void setWidgetTitle(const QString& title);
public:
/**
* @brief Closes the document.
*
* An attempt to close the document results in an attempt to close the widget, which
* in turn emits the closeRequested() signal. If the signal handler returns @c false,
* the closing of the document and the widget is canceled.
*
* @return Returns @c true if the document is closed.
*/
bool close();
protected slots:
/**
* @brief Widget close event handler.
*
* The setWidget() function sets the event filter for the widget close event.
* The closing event is redirected to this slot.
*
* The slot emits the closeRequested() signal. If the signal returns @c true, the widget
* and document are closed.
*
* @param event Widget closing event.
*
* @see close()
*/
void closeEvent(QCloseEvent* event);
signals:
/**
* @brief Emitted when requesting to close a document.
*
* The signal connection to the slot must be with the
* Qt::ConnectionType::DirectConnection flag.
*
* @param doc This document.
*
* @return Returns @c true if document closing is allowed.
*
* @see close()
* @see closeEvent()
*/
bool closeRequested(Document* doc);
/**
* @brief Emitted before the document is closed.
*
* @param doc This document.
*
* @see close()
*/
void closed(Document* doc);
public:
/**
* @brief Loads a document from a template.
*
* Unlike load(), loading a template does not reset the untitled flag.
*
* @param fileName The full path and filename of the document template file.
*
* @see isUntitled()
*/
virtual void loadTemplate(const QString& fileName = QString()) = 0;
/**
* @brief Loads a document from a file.
*
* The file name and path must be specified using setFilePath() or setDocumentInfo()
* functions.
*
* If the file is successfully loaded, the untitled flag is reset. If it fails, the
* reason can be found out using the ioErrorString() function.
*
* @return Returns true on success.
*
* @see isUntitled()
*/
virtual bool load() = 0;
/**
* @brief Saves the document to a file.
*
* The file name and path must be specified using setFilePath() or setDocumentInfo()
* functions.
*
* If the saving is successful, the untitled flag is reset. If it fails, the reason
* can be found out using the ioErrorString() function.
*
* @return Returns true on success.
*
* @see isUntitled()
*/
virtual bool save() = 0;
/**
* @brief Returns the reason for an I/O error.
*
* If the load() or save() functions return false, this function returns a description
* of the error that occurred.
*
* @return Text describing the I/O error.
*/
QString ioErrorString() const;
protected:
/**
* @brief Loads the specified file into the document.
*
* The function reads binary data from the file and passes it to setRawData(). No data
* transformations are performed.
*
* If the file is successfully loaded, the untitled flag is reset. If it fails,
* the reason can be found out using the ioErrorString() function.
*
* @param filePath Full file name, including path.
* @param watch Whether to request watch for the specified file.
*
* @return Returns true on success.
*/
bool loadFile(const QString& filePath, bool watch = true);
/**
* @brief Saves the document to the specified file.
*
* The function obtains binary data from rawData() and writes it to a file. No data
* transformations are performed.
*
* If the file is successfully saved, the untitled flag is reset. If it fails,
* the reason can be found out using the ioErrorString() function.
*
* @param filePath Full file name, including path.
*
* @return Returns true on success.
*/
bool saveFile(const QString& filePath);
public:
/**
* @brief Returns the raw data.
*
* Raw data is suitable for direct writing to a file.
*/
virtual QByteArray rawData() const = 0;
/**
* @brief Sets the raw data.
*
* Raw data is usually obtained when reading from a file.
*
* @param data The raw data.
*/
virtual void setRawData(const QByteArray& data) = 0;
/**
* @brief Creates the standard context menu.
*
* The function should create a standard context menu which is shown when the right
* mouse button is clicked.
*/
virtual QMenu* createStandardContextMenu(const QPoint& pos) = 0;
protected slots:
/**
* @brief This slot catches the QWidget::customContextMenuRequested() from
* the document widget and emits the customContextMenuRequested() signal.
*
* @param pos The position of the mouse pointer relative to the document widget.
*
* @see QWidget::mapToGlobal()
*/
void customContextMenuRequest(const QPoint& pos);
signals:
/**
* @brief A custom context menu was requested.
*
* @param doc This document.
* @param pos The position of the mouse pointer relative to the document widget.
*/
void customContextMenuRequested(Document* doc, const QPoint& pos);
public:
/**
* @brief Whether the document is untitled.
*
* This function returns @c true if the document was created empty or from
* a template (using loadTemplate()) and has not yet been saved to a file.
* After the first successful call to load() or save(), this function will
* always return @c false.
*
* @return Returns @c true if the document is untitled.
*
* @see setUntitled()
*/
bool isUntitled() const;
protected:
/**
* @brief Sets the untitled flag.
*
* @param untitled The new value of the untitled flag.
*
* @see isUntitled()
*/
void setUntitled(bool untitled);
public:
/**
* @brief Whether the document is readonly.
*
* @see setReadOnly()
*/
virtual bool isReadOnly() const;
/**
* @brief Sets the readonly flag.
*
* @param readonly The new value of the readonly flag.
*
* @see isReadOnly()
*/
virtual void setReadOnly(bool readonly);
/**
* @brief Whether the document has been modified.
*
* @return Returns true if the document has been modified.
*
* @see setModified()
* @see modificationChanged()
*/
bool isModified() const;
public slots:
/**
* @brief Sets the document modification flag.
*
* If the flag state has changed, the modificationChanged() signal is emitted
* and the widget's modification flag is updated.
*
* @param modified The new value of the document modification flag.
*
* @see isModified()
*/
void setModified(bool modified);
signals:
/**
* @brief The document modification status has changed.
*
* @param doc This document.
* @param mod The current status of the document modification.
*
* @see setModified()
* @see isModified()
*/
void modificationChanged(Document* doc, bool mod);
public:
/**
* @brief Redoes the last operation.
*
* @see isRedoAvailable()
*/
virtual void redo();
/**
* @brief Undoes the last operation.
*
* @see isUndoAvailable()
*/
virtual void undo();
/**
* @brief Clears the undo/redo stacks.
*
* @see isRedoAvailable()
* @see isUndoAvailable()
*/
virtual void clearUndoRedoStacks();
/**
* @brief Returns @c true if @ref redo() "redo" is available; otherwise returns false.
*/
bool isRedoAvailable() const;
/**
* @brief Returns @c true if @ref undo() "undo" is available; otherwise returns false.
*/
bool isUndoAvailable() const;
protected slots:
/**
* @brief Sets the availability of redo.
*
* If the availability has changed, the redoAvailable() signal is emitted.
*
* @param available Redo availability.
*
* @see isRedoAvailable()
*/
void setRedoAvailable(bool available);
/**
* @brief Sets the availability of undo.
*
* If the availability has changed, the undoAvailable() signal is emitted.
*
* @param available Undo availability.
*
* @see isUndoAvailable()
*/
void setUndoAvailable(bool available);
signals:
/**
* @brief The redo availability has changed.
*
* @param doc This document.
* @param available Redo availability.
*
* @see setRedoAvailable()
*/
void redoAvailable(Document* doc, bool available);
/**
* @brief The undo availability has changed.
*
* @param doc This document.
* @param available Undo availability.
*
* @see setUndoAvailable()
*/
void undoAvailable(Document* doc, bool available);
protected slots:
/**
* @brief Emits the cursorPositionChanged() signal.
*/
void cursorMoved();
signals:
/**
* @brief Emitted when the @ref cursorMoved() "cursor position is changed".
*
* @param doc This document.
*/
void cursorPositionChanged(Document* doc);
protected slots:
/**
* @brief Emits the selectionChanged() signal.
*/
void selectionUpdated();
signals:
/**
* @brief Emitted when the @ref selectionUpdated() "selection is changed".
*
* @param doc This document.
*/
void selectionChanged(Document* doc);
public:
/**
* @brief Returns the name of the watched file.
*
* This is the name of the file with which the last successful call to loadFile() or
* saveFile() was made. If these two functions have not been called yet, an empty
* string will be returned.
*/
QString watchedFile() const;
protected:
/**
* @brief Starts watching the file.
*
* @param watchedFile The name of the watched file.
*
* @see fileWatchRequested()
*/
void fileWatchStart(const QString& watchedFile);
/**
* @brief Stops watching the file.
*
* @see fileWatchRequested()
*/
void fileWatchStop();
signals:
/**
* @brief Emitted when file watching is requested.
*
* @param filePath The name of the watched file.
* @param watch @c true if file monitoring is requested to start; @c false if file
* monitoring is requested to stop.
*
* @see fileWatchStart()
* @see fileWatchStop()
*/
void fileWatchRequested(const QString& filePath, bool watch);
private:
QString m_brief;
QWidget* m_widget;
QDir m_dir;
QString m_fileName;
QString m_ioErrorString;
QString m_watchedFile;
bool m_isUntitled;
bool m_isModified;
bool m_redoAvailable;
bool m_undoAvailable;
};
#endif // DOCUMENT_H