1 /****************************************************************************
2 **
3 ** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
4 **
5 ** This file is part of the Edyuk project <http://edyuk.org>
6 **
7 ** This file may be used under the terms of the GNU General Public License
8 ** version 3 as published by the Free Software Foundation and appearing in the
9 ** file GPL.txt included in the packaging of this file.
10 **
11 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 **
14 ****************************************************************************/
15 
16 #ifndef Header_QDocument
17 #define Header_QDocument
18 
19 #include "modifiedQObject.h"
20 
21 #include "qce-config.h"
22 
23 /*!
24 	\file qdocument.h
25 	\brief Definition of the QDocument class
26 
27 	\defgroup document Document related classes
28 */
29 
30 #include <QList>
31 #include <QMap>
32 #include <QVector>
33 //#include <QLinkedList>
34 #include <QFileInfo>
35 #include <QObject>
36 #include <QPalette>
37 #include <QMetaType>
38 #include <QFont>
39 #include <QTextCodec>
40 
41 #include "qdocumentcursor.h"
42 
43 class QRect;
44 class QPrinter;
45 class QDateTime;
46 class QFormatScheme;
47 class QLanguageDefinition;
48 
49 struct QCE_EXPORT QDocumentSelection
50 {
51 	int start, end;
52 	int startLine, endLine;
53 };
54 
55 class QDocumentLine;
56 //class QDocumentCursor;
57 class QDocumentPrivate;
58 class QDocumentCommand;
59 class QDocumentLineHandle;
60 class QDocumentCursorHandle;
61 
62 typedef QVector<QDocumentLineHandle*>::iterator QDocumentIterator;
63 typedef QVector<QDocumentLineHandle*>::const_iterator QDocumentConstIterator;
64 
65 template<typename T> class FastCache{
66 public:
67 	FastCache();
68 	T* insert(const int c, const T& width);
69 	bool contains(const int c) const;
70 	T value(const int c) const;
71 	bool valueIfThere(const int c, const T*& value) const;
72 	inline T* insert(const QChar& c, const T& width);
73 	inline bool contains(const QChar& c) const;
74 	inline T value(const QChar& c) const;
75 	inline bool valueIfThere(const QChar& c, const T*& value) const;
76 private:
77 	T fastMap[512];
78 	QMap<int, T> slowMap;
79 };
80 
81 template<typename T> class CacheCache {
82 public:
83 	FastCache<T> * getCache(int format);
84 	void clear();
85 private:
86 	QMap<int, FastCache<T>* > caches;
87 };
88 
89 Q_DECLARE_METATYPE(QDocumentIterator)
90 Q_DECLARE_METATYPE(QDocumentConstIterator)
91 
92 typedef void (*GuessEncodingCallback) (const QByteArray& data, QTextCodec *&guess, int &sure);
93 class QKeyEvent;
94 struct PlaceHolder
95 {
96 	class Affector
97 	{
98 	public:
~AffectorPlaceHolder99 		virtual ~Affector() {}
100 		virtual QString affect(const QKeyEvent *e, const QString& base, int ph, int mirror) const = 0;
101 	};
102 
PlaceHolderPlaceHolder103 	PlaceHolder() :
104            length(0), autoRemove(true), autoOverride(false), autoRemoveIfLeft(false), affector(nullptr) {}
PlaceHolderPlaceHolder105 	PlaceHolder(const PlaceHolder& ph) :
106 	       length(ph.length), autoRemove(ph.autoRemove), autoOverride(ph.autoOverride), autoRemoveIfLeft(ph.autoRemoveIfLeft), affector(ph.affector), cursor(ph.cursor), mirrors(ph.mirrors){}
PlaceHolderPlaceHolder107 	PlaceHolder(int len, const QDocumentCursor &cur):
108            length(len), autoRemove(true), autoOverride(false), autoRemoveIfLeft(false), affector(nullptr), cursor(cur) {}
109 	PlaceHolder& operator= (const PlaceHolder& ph) = default; // Silence -Wdeprecated-copy
110 
111 	int length;
112 	bool autoRemove, autoOverride, autoRemoveIfLeft;
113 	Affector *affector;
114 	QDocumentCursor cursor;
115 	QList<QDocumentCursor> mirrors;
116 };
117 
118 class QCE_EXPORT QDocument : public QObject
119 {
120 	friend class QMatcher;
121 	friend class QDocumentPrivate;
122 	friend class QDocumentCommand;
123 	friend class QDocumentCommandChangeCodec;
124 
125 	Q_OBJECT
126 
127 	public:
128 		struct PaintContext
129 		{
130             qreal width;
131             qreal height;
132             qreal xoffset;  // draw content from position x+xoffset at position x (used for horizontal scrolling).
133             qreal yoffset;
134 			QPalette palette;
135 			bool blinkingCursor;
136 			bool fillCursorRect;
137 			QList<QDocumentCursorHandle*> extra;
138 			QList<QDocumentCursorHandle*> cursors;
139 			QList<QDocumentSelection> selections;
140 			int curPlaceHolder, lastPlaceHolder;
141 			QList<PlaceHolder> placeHolders;
142 		};
143 
144 		enum LineEnding
145 		{
146 			Conservative,
147 			Local,
148 			Unix,
149 			Windows,
150 			Mac
151 		};
152 
153 		enum TextProcessing
154 		{
155 			RemoveTrailingWS		= 1,
156 			PreserveIndent			= 2,
157 			RestoreTrailingIndent	= 4
158 		};
159 
160 		enum WhiteSpaceFlag
161 		{
162 			ShowNone		= 0x00,
163 			ShowTrailing	= 0x01,
164 			ShowLeading		= 0x02,
165 			ShowTabs		= 0x04
166 		};
167 
168 		Q_DECLARE_FLAGS(WhiteSpaceMode, WhiteSpaceFlag)
169 
170 		enum WorkAroundFlag
171 		{
172 			DisableFixedPitchMode	= 0x01,
173 			DisableWidthCache		= 0x02,
174 			DisableLineCache            = 0x04,
175 			ForceQTextLayout            = 0x08,
176             ForceSingleCharacterDrawing = 0x10,
177             QImageCache = 0x20
178 		};
179 
180 		Q_DECLARE_FLAGS(WorkAroundMode, WorkAroundFlag)
181 
182         explicit QDocument(QObject *p = nullptr);
183 		virtual ~QDocument();
184 
185 		Q_INVOKABLE QString text(int mode) const;
186 		Q_INVOKABLE QString text(bool removeTrailing = false, bool preserveIndent = true) const;
187 		Q_INVOKABLE QStringList textLines() const;
188 		Q_INVOKABLE void setText(const QString& s, bool allowUndo);
189 
190 		void load(const QString& file, QTextCodec* codec);
191 		void startChunkLoading();
192 		void stopChunkLoading();
193 		void addChunk(const QString& txt);
194 
195 		QString getFileName() const;
196 		QFileInfo getFileInfo() const;
197 		QString getName() const;
198 		void setFileName_DONOTCALLTHIS(const QString& fileName);
199 
200 		LineEnding lineEnding() const;
201 		LineEnding originalLineEnding() const;
202 		Q_INVOKABLE QString lineEndingString() const;
203 		void setLineEnding(LineEnding le);
204         void setLineEndingDirect(LineEnding le,bool dontSendEmit=false);
205 
206 		QTextCodec* codec() const;
207 		void setCodec(QTextCodec* codec);
208 		void setCodecDirect(QTextCodec* codec);
209 
210 		bool isReadOnly() const;
211 		void setReadOnly(bool b);
212 
213 		QDateTime lastModified() const;
214 		void setLastModified(const QDateTime& d);
215 
216 		Q_INVOKABLE bool canUndo() const;
217 		Q_INVOKABLE bool canRedo() const;
218 
219         qreal width() const;
220         qreal height() const;
221         qreal widthConstraint() const;
222 
223 		int lines() const;
224 		Q_INVOKABLE int lineCount() const;
225 		int visualLines() const;
226 		Q_INVOKABLE int visualLineCount() const;
227 
228 		int visualLineNumber(int textLineNumber) const;
229 		int textLineNumber(int visualLineNumber) const;
230 
231         qreal y(int line) const;
232         int lineNumber(qreal ypos, int *wrap = nullptr) const;
233 
234         QRectF lineRect(int line) const;
235 
236 		QDocumentCursor* editCursor() const;
237 		void setEditCursor(QDocumentCursor *c);
238 
239 		QLanguageDefinition* languageDefinition() const;
240 		void setLanguageDefinition(QLanguageDefinition *l);
241 
242 		int maxMarksPerLine() const;
243 		int findNextMark(int id, int from = 0, int until = -1) const;
244 		int findPreviousMark(int id, int from = -1, int until = 0) const;
245 		void removeMarks(int id);
246         QList<int> marks(QDocumentLineHandle *dlh) const;
247         void removeMark(QDocumentLineHandle *dlh, int mid);
248 
249         QDocumentLine lineAt(const QPointF& p) const;
250         void cursorForDocumentPosition(const QPointF& p, int& line, int& column, bool disallowPositionBeyondLine = false) const;
251         QDocumentCursor cursorAt(const QPointF& p, bool disallowPositionBeyondLine = false) const;
252 
253 		QDocumentLine line(int line) const;
254 		QDocumentLine line(QDocumentConstIterator iterator) const;
255 
256 		Q_INVOKABLE QDocumentCursor cursor(int line, int column = 0, int lineTo=-1, int columnTo=-1) const;
257 
258 		QDocumentLine findLine(int& position) const;
259 		int findLineContaining(const QString &searchText,  const int& startLine=0, const Qt::CaseSensitivity cs = Qt::CaseSensitive, const bool backward=false) const;
260 		int findLineRegExp(const QString &searchText,  const int& startLine, const Qt::CaseSensitivity cs, const bool wholeWord, const bool useRegExp) const;
261 		int findNearLine(const QString &lineText, int startLine) const;
262 
263 		bool isLineModified(const QDocumentLine& l) const;
264 		bool hasLineEverBeenModified(const QDocumentLine& l) const;
265 
266 		virtual void draw(QPainter *p, PaintContext& cxt);
267 
268 		virtual QString exportAsHtml(const QDocumentCursor &range, bool includeHeader=true, bool simplifyCSS = false, int maxLineWidth = -1, int maxWrap = 0) const;
269 
270 		void execute(QDocumentCommand *cmd);
271 
impl()272 		inline QDocumentPrivate* impl() { return m_impl; }
273 
274 		QDocumentConstIterator begin() const;
275 		QDocumentConstIterator end() const;
276 
277 		QDocumentConstIterator iterator(int ln) const;
278 		QDocumentConstIterator iterator(const QDocumentLine& l) const;
279 
280 		Q_INVOKABLE void beginMacro();
281 		Q_INVOKABLE void endMacro();
282 		Q_INVOKABLE bool hasMacros();
283 
284 		//Defer contentChange-signals until the last call of endDelayedUpdateBlock() and then emit all of them.
285 		//ATTENTION: This only works if the commands don't change the document line count or all changes occur top-to-bottom.
286 		Q_INVOKABLE void beginDelayedUpdateBlock();
287 		Q_INVOKABLE void endDelayedUpdateBlock();
288 
289 		QFormatScheme* formatScheme() const;
290 		void setFormatScheme(QFormatScheme *f);
291 		QColor getBackground() const;
292 		QColor getForeground() const;
293 
294 		int getNextGroupId();
295 		void releaseGroupId(int groupId);
296 		void clearMatches(int groupId);
297 		//void clearMatchesFromToWhenFlushing(int groupId, int firstMatch, int lastMatch);
298 		void flushMatches(int groupId);
299 		void addMatch(int groupId, int line, int pos, int len, int format);
300 
301 		void clearLanguageMatches();
302 
303 		static QFont font();
304         static QFont baseFont();
305         static int fontSizeModifier();
306         static void setBaseFont(const QFont& f, bool forceUpdate = false);
307         static void setFontSizeModifier(int m, bool forceUpdate = false);
308 		//static const QFontMetrics fontMetrics() const;
309         static qreal getLineSpacing();
310 		static void setLineSpacingFactor(double scale);
311         void setCenterDocumentInEditor(bool center);
312 
313 		static LineEnding defaultLineEnding();
314 		static void setDefaultLineEnding(LineEnding le);
315 
316 		static QTextCodec* defaultCodec();
317 		static void setDefaultCodec(QTextCodec* codec);
318 		static void addGuessEncodingCallback(const GuessEncodingCallback& callback);
319 		static void removeGuessEncodingCallback(const GuessEncodingCallback& callback);
320 
321 		static int tabStop();
322 		static void setTabStop(int n);
323 
324 		static WhiteSpaceMode showSpaces();
325 		static void setShowSpaces(WhiteSpaceMode y);
326 
327 		static QFormatScheme* defaultFormatScheme();
328 		static void setDefaultFormatScheme(QFormatScheme *f);
329 		static void formatScheme(QFormatScheme *f);
330 		static void formatSchemeDeleted(QFormatScheme *f);
331 
332 		int getFormatId(const QString& id);
333 
334 		static int screenColumn(const QChar *d, int l, int tabStop, int column = 0);
335 		static QString screenable(const QChar *d, int l, int tabStop, int column = 0);
336 
markViewDirty()337         inline void markViewDirty() { emit formatsChanged(); }
338 
339 		bool isClean() const;
340 
341 		Q_INVOKABLE void expand(int line);
342 		Q_INVOKABLE void collapse(int line);
343 		Q_INVOKABLE void expandParents(int l);
344 		Q_INVOKABLE void foldBlockAt(bool unFold, int line);
345 		bool linesPartiallyFolded(int fromInc, int toInc);
346 		void correctFolding(int fromInc, int toInc, bool forceCorrection = false);
347 		QList<int> foldedLines();
348 		void foldLines(QList<int> &lines);
349 
350 		void adjustWidth(int line);
351 
352 		static void setWorkAround(WorkAroundFlag workAround, bool newValue);
353 		static bool hasWorkAround(WorkAroundFlag workAround);
354 
355 		bool getFixedPitch() const;
356 
357 		bool forceLineWrapCalculation() const;
358 		void setForceLineWrapCalculation(bool v);
359 		void setOverwriteMode(bool overwrite);
360 
361 		void applyHardLineWrap(const QList<QDocumentLineHandle*>& handles);
362         bool linesMerged(QDocumentLineHandle* dlh,int bo,QDocumentLineHandle* fromLineHandle);
363         void linesUnMerged(QDocumentLineHandle *dlh,QDocumentLineHandle *fromLineHandle);
364         int bookMarkId(int bookmarkNumber);
365 
getProposedPosition()366         QDocumentCursor getProposedPosition(){
367             return m_proposedPostion;
368         }
setProposedPosition(QDocumentCursor c)369         void setProposedPosition(QDocumentCursor c){
370             m_proposedPostion=c;
371         }
372 
373         QString debugUndoStack(int limit = 10000) const;
374 
375 	public slots:
376 		void clear();
377 
378 		void undo();
379 		void redo();
380 
381 		void clearUndo();
382 		void setClean();
383 
384 		void highlight();
385 
386 		void print(QPrinter *p);
387 
388 		void clearWidthConstraint();
389         void setWidthConstraint(int width);
390 		void markFormatCacheDirty();
391 
392 	signals:
393 		void cleanChanged(bool m);
394 
395 		void undoAvailable(bool y);
396 		void redoAvailable(bool y);
397 
398 		void formatsChanged();
399 		void contentsChanged();
400 		void fontChanged(QFont);
401 
402 		void formatsChange (int line, int lines);
403 		void contentsChange(int line, int lines);
404 
405 		void widthChanged(int width);
406 		void heightChanged(int height);
407 		void sizeChanged(const QSize& s);
408 
409 		void lineCountChanged(int n);
410 		void visualLineCountChanged(int n);
411 
412         void lineDeleted(QDocumentLineHandle *h,int hint=-1);
413         void lineRemoved(QDocumentLineHandle *h);
414 		void markChanged(QDocumentLineHandle *l, int m, bool on);
415 
416 		void lineEndingChanged(int lineEnding);
417 
418 		void slowOperationStarted();
419 		void slowOperationEnded();
420 
421         void bookmarkRemoved(QDocumentLineHandle *dlh);
422         void bookmarkAdded(QDocumentLineHandle *dlh,int nr);
423 	public:
424 		int indexOf(const QDocumentLineHandle* h, int hint = -1) const;
425 		int indexOf(const QDocumentLine& l, int hint = -1) const;
426 	private:
427 		QString m_leftOver;
428 		QDocumentPrivate *m_impl;
429         QDocumentCursor m_proposedPostion;
430 
431 };
432 
433 Q_DECLARE_OPERATORS_FOR_FLAGS(QDocument::WhiteSpaceMode)
434 
435 #endif
436 
437