11/* *******************************************************************
2- * Copyright (C) 2010 - 2016 ArcEye <arceye AT mgware DOT co DOT uk>
3- *
4- * This program is free software; you can redistribute it and/or
5- * modify it under the terms of the GNU Lesser General Public
6- * License as published by the Free Software Foundation; either
7- * version 2.1 of the License, or (at your option) any later version.
8- *
9- * This program is distributed in the hope that it will be useful,
10- * but WITHOUT ANY WARRANTY; without even the implied warranty of
11- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12- * Lesser General Public License for more details.
13- *
14- * You should have received a copy of the GNU Lesser General Public
15- * License along with this library; if not, write to the Free Software
16- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17- ********************************************************************/
2+ * Copyright (C) 2010 - 2016 ArcEye <arceye AT mgware DOT co DOT uk>
3+ *
4+ * This program is free software; you can redistribute it and/or
5+ * modify it under the terms of the GNU Lesser General Public
6+ * License as published by the Free Software Foundation; either
7+ * version 2.1 of the License, or (at your option) any later version.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+ * Lesser General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU Lesser General Public
15+ * License along with this library; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ ********************************************************************/
18+
19+ /* *
20+ * @file QGCodeEditor.cpp
21+ * @brief Implementation of QGCodeEditor - a text editor for G-code files
22+ *
23+ * @class QGCodeEditor
24+ * @brief Extended QPlainTextEdit with G-code specific features:
25+ * - Syntax highlighting
26+ * - Line numbers
27+ * - Large file handling (chunks)
28+ * - Modification tracking
29+ *
30+ * New functions:
31+ * - cursorUp()
32+ * - cursorDown()
33+ * - getLineNo()
34+ * - highlightLine()
35+ * - isModified()
36+ * - getLineCount()
37+ * - getCurrentText()
38+ *
39+ * Overloaded:
40+ * - appendNewPlainText(const QString &text)
41+ * - clear()
42+ *
43+ * SubClassed:
44+ * - firstBlockNum() // first block in the viewport
45+ */
1846
1947#include < QtGui>
2048
3967
4068// ///////////////////////////////////////////////////////////////////////////
4169
70+ /* *
71+ * @brief Constructor
72+ * @param parent Parent widget
73+ *
74+ * Initializes the editor with:
75+ * - Line number area
76+ * - Syntax highlighter
77+ * - Large file handling (CHUNK_SIZE = 200 lines)
78+ * - Current line highlighting
79+ */
4280QGCodeEditor::QGCodeEditor (QWidget *parent) : QPlainTextEdit(parent)
4381{
4482 lineNumberArea = new LineNumberArea (this );
@@ -69,12 +107,15 @@ QGCodeEditor::QGCodeEditor(QWidget *parent) : QPlainTextEdit(parent)
69107
70108}
71109
110+ /* *
111+ * @brief Destructor
112+ */
72113QGCodeEditor::~QGCodeEditor ()
73114{
74115}
75116
76117
77- // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
118+ // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
78119// formats first and adds to QStringList before appending
79120// for later comparison using list to test if text changed
80121//
@@ -85,6 +126,13 @@ QGCodeEditor::~QGCodeEditor()
85126// the editor, to a 5 sec load into both editor and GL viewer
86127// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
87128
129+ /* *
130+ * @brief Appends formatted text to the editor
131+ * @param text Text to append
132+ *
133+ * Handles large files by caching content after CHUNK_SIZE (200) lines
134+ * to prevent GUI lockups. Uses chunked loading for files > 200 lines.
135+ */
88136void QGCodeEditor::appendNewPlainText (const QString &text)
89137{
90138QString str;
@@ -112,6 +160,12 @@ QFile file("/tmp/qgc_cache");
112160
113161// overloaded to clear the QStringList first
114162
163+ /* *
164+ * @brief Clears the editor content and internal buffers
165+ *
166+ * Overloaded to also clear the QStringList buffers used for
167+ * modification tracking and large file handling.
168+ */
115169void QGCodeEditor::clear ()
116170{
117171 excess->clear ();
@@ -121,6 +175,18 @@ void QGCodeEditor::clear()
121175 linesIn = 0 ;
122176}
123177
178+ /* *
179+ * @brief Formats a line of G-code for display
180+ * @param text Input line to format
181+ * @return Formatted G-code string
182+ *
183+ * Performs the following transformations:
184+ * - Converts to uppercase
185+ * - Removes extra spaces
186+ * - Strips line numbers (N-words)
187+ * - Adds spaces around G-code commands for readability
188+ * - Separates comments onto a new line
189+ */
124190QString QGCodeEditor::formatLine (QString text)
125191{
126192QString str, str2;
@@ -282,16 +348,134 @@ int QGCodeEditor::getLineCount()
282348
283349// /////////////////////////////////////////////////////////////////////////////////
284350
285- int QGCodeEditor::lineNumberAreaWidth ()
351+ // big problem with the base editor was that it registers that document changed and that
352+ // modification changed (usually by using Ctrl Z or Ctrl Shift Z)
353+ // but you still could not tell if the document is now different overall or not
354+ // By saving a copy of what was loaded and then comparing it to what is present, it
355+ // reports accurately on any change.
356+
357+ /* *
358+ * @brief Checks if the document has been modified
359+ * @return true if the document content differs from original, false otherwise
360+ *
361+ * Compares current document content against the stored original content
362+ * to accurately detect modifications.
363+ */
364+ bool QGCodeEditor::isModified ()
365+ {
366+ QString txt = toPlainText ();
367+ QStringList list = txt.split ( " \n " );
368+
369+ if ( contents->size () != list.size () )
370+ return true ;
371+
372+ for (int x = 0 ; x < contents->size (); x++)
373+ {
374+ if ( contents->at (x) != list[x] )
375+ return true ;
376+ }
377+ return false ;
378+ }
379+
380+
381+ /* *
382+ * @brief Gets the text at the current cursor position
383+ * @return Text of the line at cursor position, trimmed
384+ */
385+ QString QGCodeEditor::getCurrentText ()
386+ {
387+ QTextDocument *doc = document ();
388+
389+ QTextBlock block = doc->findBlock ( textCursor ().position ());
390+ return (block.text ().trimmed ().toLatin1 ());
391+ }
392+
393+ /* *
394+ * @brief Moves cursor up one block
395+ */
396+ void QGCodeEditor::cursorUp ()
397+ {
398+ moveCursor (QTextCursor::PreviousBlock);
399+ }
400+
401+ /* *
402+ * @brief Moves cursor down one block
403+ */
404+ void QGCodeEditor::cursorDown ()
405+ {
406+ moveCursor (QTextCursor::NextBlock);
407+ }
408+
409+ /* *
410+ * @brief Gets the current line number
411+ * @return Line number where cursor is positioned (1-based)
412+ */
413+ int QGCodeEditor::getLineNo ()
414+ {
415+ int numBlocks = blockCount ();
416+ QTextDocument *doc = document ();
417+
418+ QTextBlock blk = doc->findBlock ( textCursor ().position () );
419+ QTextBlock blk2 = doc->begin ();
420+
421+ for (int x = 1 ; x <= numBlocks; x++)
422+ {
423+ if (blk == blk2)
424+ return x;
425+ blk2 = blk2.next ();
426+ }
427+ return 0 ;
428+ }
429+
430+ /* *
431+ * @brief Moves cursor to specified line
432+ * @param line Line number to highlight (1-based)
433+ */
434+ void QGCodeEditor::highlightLine (int line)
286435{
287- int digits = 1 ;
288- int max = qMax (1 , blockCount ());
436+ int num = 0 ;
437+
438+ // when file loaded, highlights first blank line at end with EOF,
439+ // so never matched and returns 0 unless go up 1 first
289440
290- while (max >= 10 )
441+ if ( blockCount () )
291442 {
292- max /= 10 ;
293- ++digits;
443+ if (line > 0 && line <= blockCount ())
444+ {
445+ cursorUp ();
446+ num = getLineNo ();
447+ if (num > line)
448+ {
449+ do
450+ {
451+ cursorUp ();
452+ num--;
453+ }while (num > line);
454+ }
455+ else
456+ {
457+ while (num < line)
458+ {
459+ cursorDown ();
460+ num++;
461+ }
462+ }
463+ }
464+ else
465+ qDebug () << " Invalid line number passed" ;
294466 }
467+ else
468+ qDebug () << " No blocks found" ;
469+ }
470+
471+ /* *
472+ * @brief Gets the total line count
473+ * @return Number of lines in the document
474+ */
475+ int QGCodeEditor::getLineCount ()
476+ {
477+ return blockCount () - 1 ;
478+ }
295479
296480 int space;
297481#if QT_VERSION > QT_VERSION_CHECK(5, 3, 2)
@@ -303,11 +487,20 @@ int max = qMax(1, blockCount());
303487 return space;
304488}
305489
490+ /* *
491+ * @brief Updates the line number area width
492+ * @param newBlockCount Number of blocks (unused, kept for signature compatibility)
493+ */
306494void QGCodeEditor::updateLineNumberAreaWidth (int /* newBlockCount */ )
307495{
308496 setViewportMargins (lineNumberAreaWidth (), 0 , 0 , 0 );
309497}
310498
499+ /* *
500+ * @brief Updates the line number area
501+ * @param rect Rectangle to update
502+ * @param dy Vertical scroll offset
503+ */
311504void QGCodeEditor::updateLineNumberArea (const QRect &rect, int dy)
312505{
313506 if (dy)
@@ -319,6 +512,12 @@ void QGCodeEditor::updateLineNumberArea(const QRect &rect, int dy)
319512 updateLineNumberAreaWidth (0 );
320513}
321514
515+ /* *
516+ * @brief Handles resize events
517+ * @param e Resize event
518+ *
519+ * Updates the geometry of the line number area when the editor is resized.
520+ */
322521void QGCodeEditor::resizeEvent (QResizeEvent *e)
323522{
324523 QPlainTextEdit::resizeEvent (e);
@@ -327,6 +526,12 @@ void QGCodeEditor::resizeEvent(QResizeEvent *e)
327526 lineNumberArea->setGeometry (QRect (cr.left (), cr.top (), lineNumberAreaWidth (), cr.height ()));
328527}
329528
529+ /* *
530+ * @brief Highlights the current line
531+ *
532+ * Applies a highlight to the line containing the cursor.
533+ * Also triggers loading of the next chunk for large files.
534+ */
330535void QGCodeEditor::highlightCurrentLine ()
331536{
332537QList<QTextEdit::ExtraSelection> extraSelections;
@@ -352,6 +557,12 @@ QColor lineColor = QColor(Qt::darkBlue).lighter(60);
352557
353558// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
354559
560+ /* *
561+ * @brief Loads the next chunk of cached content
562+ *
563+ * Loads ADD_SIZE (100) lines from the excess cache into the visible editor.
564+ * Used for progressive loading of large files to prevent GUI freezing.
565+ */
355566void QGCodeEditor::loadNextChunk ()
356567{
357568int x, y;
@@ -385,6 +596,12 @@ QString str;
385596
386597// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
387598
599+ /* *
600+ * @brief Paints the line number area
601+ * @param event Paint event
602+ *
603+ * Draws line numbers in the left margin of the editor.
604+ */
388605void QGCodeEditor::lineNumberAreaPaintEvent (QPaintEvent *event)
389606{
390607QPainter painter (lineNumberArea);
0 commit comments