2828#include " services/settingsservice.h"
2929#include " utils/urlhandler.h"
3030
31+ // Initialize static member
32+ QOwnNotesMarkdownTextEdit *QOwnNotesMarkdownTextEdit::_activeAutocompleteEditor = nullptr ;
33+
3134QOwnNotesMarkdownTextEdit::QOwnNotesMarkdownTextEdit (QWidget *parent)
3235 : QMarkdownTextEdit(parent, false ) {
3336 // We need to set the internal variable to true, because we start with a highlighter
@@ -47,20 +50,32 @@ QOwnNotesMarkdownTextEdit::QOwnNotesMarkdownTextEdit(QWidget *parent)
4750 connect (_aiAutocompleteTimer, &QTimer::timeout, this ,
4851 &QOwnNotesMarkdownTextEdit::requestAiAutocomplete);
4952
50- // Connect to OpenAI service signals for all widgets
51- qDebug () << __func__ << " - Connecting AI autocomplete signals for widget:" << objectName ()
52- << " parent:" << (parent ? parent->objectName () : " null" );
53- qDebug () << __func__ << " - OpenAiService instance:" << OpenAiService::instance ();
54- qDebug () << __func__ << " - this instance:" << this ;
55-
56- // Use old-style SIGNAL/SLOT macros for better compatibility
57- bool conn1 = connect (OpenAiService::instance (), SIGNAL (autocompleteCompleted (QString)), this ,
58- SLOT (onAiAutocompleteCompleted (QString)), Qt::QueuedConnection);
59- bool conn2 = connect (OpenAiService::instance (), SIGNAL (autocompleteErrorOccurred (QString)),
60- this , SLOT (onAiAutocompleteTimeout (QString)), Qt::QueuedConnection);
53+ // NOTE: Callback registration is now done globally in OpenAiService constructor
54+ // We just need to register this editor as active if it's a note editor
55+ if (!parent || parent->objectName () != QStringLiteral (" LogWidget" )) {
56+ qDebug () << __func__ << " - Registering as active editor" ;
57+ registerAsActiveEditor ();
58+ } else {
59+ qDebug () << __func__ << " - Skipping registration for non-editor widget:" << objectName ();
60+ }
6161
62- qDebug () << __func__ << " - AI autocomplete signals connected, conn1:" << conn1
62+ // Use DirectConnection to ensure signal is delivered immediately before widget can be destroyed
63+ // This prevents the "0 receivers" problem when widgets are recreated
64+ bool conn1 = connect (
65+ OpenAiService::instance (), &OpenAiService::autocompleteCompleted, this ,
66+ [this ](const QString &result) {
67+ qDebug () << " *** LAMBDA RECEIVED autocompleteCompleted signal for widget:" << this
68+ << objectName ();
69+ this ->onAiAutocompleteCompleted (result);
70+ },
71+ Qt::DirectConnection);
72+ bool conn2 = connect (OpenAiService::instance (), &OpenAiService::autocompleteErrorOccurred, this ,
73+ &QOwnNotesMarkdownTextEdit::onAiAutocompleteTimeout, Qt::DirectConnection);
74+
75+ qDebug () << __func__
76+ << " - AI autocomplete signals connected (DirectConnection), conn1:" << conn1
6377 << " conn2:" << conn2;
78+ qDebug () << __func__ << " - Connected to OpenAiService instance:" << OpenAiService::instance ();
6479
6580 // Test: Call the slot directly to verify it exists
6681 qDebug () << __func__ << " - Testing slot by calling it directly..." ;
@@ -1313,8 +1328,15 @@ void QOwnNotesMarkdownTextEdit::requestAiAutocomplete() {
13131328 * Shows the AI autocomplete suggestion
13141329 */
13151330void QOwnNotesMarkdownTextEdit::showAiAutocompleteSuggestion (const QString &suggestion) {
1331+ qDebug () << " === showAiAutocompleteSuggestion CALLED ===" << this ;
1332+ qDebug () << __func__ << " - Widget:" << objectName ();
1333+
13161334 SettingsService settings;
1317- if (!settings.value (QStringLiteral (" ai/autocompleteEnabled" )).toBool ()) {
1335+ bool enabled = settings.value (QStringLiteral (" ai/autocompleteEnabled" )).toBool ();
1336+ qDebug () << __func__ << " - ai/autocompleteEnabled setting:" << enabled;
1337+
1338+ if (!enabled) {
1339+ qDebug () << __func__ << " - autocomplete not enabled in settings, returning" ;
13181340 return ;
13191341 }
13201342
@@ -1339,13 +1361,16 @@ void QOwnNotesMarkdownTextEdit::showAiAutocompleteSuggestion(const QString &sugg
13391361 _aiAutocompleteSuggestion = suggestion;
13401362 _isInsertingAiSuggestion = true ;
13411363
1342- qDebug () << __func__ << " - inserting suggestion" ;
1364+ qDebug () << __func__ << " - inserting suggestion text... " ;
13431365
13441366 // Insert the suggestion with a gray color format
13451367 QTextCursor cursor = textCursor ();
13461368 cursor.beginEditBlock ();
13471369
1348- // Store the format
1370+ // Store the original format to restore it later
1371+ QTextCharFormat originalFormat = cursor.charFormat ();
1372+
1373+ // Create the suggestion format
13491374 QTextCharFormat format;
13501375 format.setForeground (QColor (128 , 128 , 128 )); // Gray color
13511376 format.setFontItalic (true );
@@ -1357,10 +1382,14 @@ void QOwnNotesMarkdownTextEdit::showAiAutocompleteSuggestion(const QString &sugg
13571382 cursor.movePosition (QTextCursor::Right, QTextCursor::KeepAnchor,
13581383 _aiAutocompleteSuggestion.length ());
13591384
1385+ // Reset the character format to the original to prevent the italic format
1386+ // from affecting subsequent text
1387+ cursor.setCharFormat (originalFormat);
1388+
13601389 cursor.endEditBlock ();
13611390 setTextCursor (cursor);
13621391
1363- qDebug () << __func__ << " - suggestion inserted and selected" ;
1392+ qDebug () << __func__ << " - suggestion inserted and selected successfully! " ;
13641393
13651394 _isInsertingAiSuggestion = false ;
13661395}
@@ -1424,12 +1453,18 @@ void QOwnNotesMarkdownTextEdit::acceptAiAutocompleteSuggestion() {
14241453 * Called when AI autocomplete is completed
14251454 */
14261455void QOwnNotesMarkdownTextEdit::onAiAutocompleteCompleted (const QString &result) {
1456+ qDebug () << " === onAiAutocompleteCompleted CALLED ===" << this ;
1457+ qDebug () << __func__ << " - Widget:" << objectName ()
1458+ << " Parent:" << (parent () ? parent ()->objectName () : " null" );
14271459 qDebug () << __func__ << " - 'result': " << result;
14281460
14291461 if (result.isEmpty ()) {
1462+ qDebug () << __func__ << " - result is empty, returning" ;
14301463 return ;
14311464 }
14321465
1466+ qDebug () << __func__ << " - Processing result, length:" << result.length ();
1467+
14331468 // Extract the first line or first sentence as suggestion
14341469 QString suggestion = result.trimmed ();
14351470
@@ -1450,7 +1485,9 @@ void QOwnNotesMarkdownTextEdit::onAiAutocompleteCompleted(const QString &result)
14501485 qDebug () << __func__ << " - 'cursor position': " << textCursor ().position ();
14511486 qDebug () << __func__ << " - '_aiAutocompletePosition': " << _aiAutocompletePosition;
14521487
1488+ qDebug () << __func__ << " - Calling showAiAutocompleteSuggestion..." ;
14531489 showAiAutocompleteSuggestion (suggestion);
1490+ qDebug () << __func__ << " - showAiAutocompleteSuggestion returned" ;
14541491}
14551492
14561493/* *
@@ -1489,3 +1526,53 @@ void QOwnNotesMarkdownTextEdit::keyPressEvent(QKeyEvent *e) {
14891526 // Call parent implementation
14901527 QMarkdownTextEdit::keyPressEvent (e);
14911528}
1529+
1530+ /* *
1531+ * Override focusInEvent to register this editor as active when it receives focus
1532+ */
1533+ void QOwnNotesMarkdownTextEdit::focusInEvent (QFocusEvent *e) {
1534+ // Register as the active editor for autocomplete when receiving focus
1535+ // Skip for log widgets
1536+ if (objectName () != QStringLiteral (" logTextEdit" )) {
1537+ qDebug () << __func__ << " - Registering as active editor:" << this << objectName ();
1538+ registerAsActiveEditor ();
1539+ }
1540+
1541+ // Call parent implementation
1542+ QMarkdownTextEdit::focusInEvent (e);
1543+ }
1544+
1545+ /* *
1546+ * Register this editor as the active one for AI autocomplete
1547+ */
1548+ void QOwnNotesMarkdownTextEdit::registerAsActiveEditor () {
1549+ qDebug () << __func__ << " - Registering editor:" << this << objectName ();
1550+ _activeAutocompleteEditor = this ;
1551+ // Also store in QApplication property for access from OpenAiService callback
1552+ qApp->setProperty (" activeAutocompleteEditor" , QVariant::fromValue<QObject *>(this ));
1553+ }
1554+
1555+ /* *
1556+ * Unregister this editor from receiving AI autocomplete
1557+ */
1558+ void QOwnNotesMarkdownTextEdit::unregisterAsActiveEditor () {
1559+ qDebug () << __func__ << " - Unregistering editor:" << this << objectName ();
1560+ if (_activeAutocompleteEditor == this ) {
1561+ _activeAutocompleteEditor = nullptr ;
1562+ // Also clear QApplication property
1563+ qApp->setProperty (" activeAutocompleteEditor" , QVariant::fromValue<QObject *>(nullptr ));
1564+ }
1565+ }
1566+
1567+ /* *
1568+ * Get the currently active editor for AI autocomplete
1569+ */
1570+ QOwnNotesMarkdownTextEdit *QOwnNotesMarkdownTextEdit::getActiveEditorForAutocomplete () {
1571+ return _activeAutocompleteEditor;
1572+ }
1573+
1574+ QOwnNotesMarkdownTextEdit::~QOwnNotesMarkdownTextEdit () {
1575+ qDebug () << " *** QOwnNotesMarkdownTextEdit DESTROYED ***" << this << objectName ();
1576+ // Unregister if this was the active editor
1577+ unregisterAsActiveEditor ();
1578+ }
0 commit comments