- Ausrücken mit Shift-Tab implementiert

- RÜcksprung mit Backspace implementiert
- Anzeige für veränderte Datei implementiert
This commit is contained in:
2026-05-24 13:09:00 +02:00
parent 36e074f43d
commit 250783f63b
2 changed files with 137 additions and 17 deletions

View File

@@ -269,19 +269,77 @@ void CodeEditor::highlightCurrentLine()
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Key handling auto-indent + Tab → spaces // Key handling Tab/Shift+Tab, Smart-Backspace, Auto-Indent
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
void CodeEditor::keyPressEvent(QKeyEvent *event) void CodeEditor::keyPressEvent(QKeyEvent *event)
{
// Tab key: insert spaces instead of a real tab character
if (event->key() == Qt::Key_Tab && m_settings->useSpacesForTabs())
{ {
const int tabSize = m_settings->tabSize(); const int tabSize = m_settings->tabSize();
// -----------------------------------------------------------------------
// Shift+Tab: Einrückung zurückziehen
// -----------------------------------------------------------------------
if (event->key() == Qt::Key_Backtab ||
(event->key() == Qt::Key_Tab && event->modifiers() & Qt::ShiftModifier))
{
QTextCursor cursor = textCursor();
QTextBlock startBlock = document()->findBlock(cursor.selectionStart());
QTextBlock endBlock = document()->findBlock(cursor.selectionEnd());
cursor.beginEditBlock();
for (QTextBlock b = startBlock; b != endBlock.next(); b = b.next())
{
const QString lineText = b.text();
int toRemove = 0;
if (m_settings->useSpacesForTabs())
{
// Bis zu tabSize führende Leerzeichen entfernen
for (int i = 0; i < tabSize && i < lineText.length(); ++i)
{
if (lineText[i] == ' ')
{
++toRemove;
}
else
{
break;
}
}
}
else
{
// Einen führenden Tab entfernen
if (!lineText.isEmpty() && lineText[0] == '\t')
{
toRemove = 1;
}
}
if (toRemove > 0)
{
QTextCursor lineCursor(b);
lineCursor.movePosition(QTextCursor::StartOfBlock);
lineCursor.movePosition(QTextCursor::Right,
QTextCursor::KeepAnchor,
toRemove);
lineCursor.removeSelectedText();
}
}
cursor.endEditBlock();
return;
}
// -----------------------------------------------------------------------
// Tab: Einrücken (Leerzeichen oder echter Tab)
// -----------------------------------------------------------------------
if (event->key() == Qt::Key_Tab)
{
QTextCursor cursor = textCursor(); QTextCursor cursor = textCursor();
if (cursor.hasSelection()) if (cursor.hasSelection())
{ {
// Indent selected lines // Mehrere Zeilen einrücken
QTextBlock startBlock = document()->findBlock(cursor.selectionStart()); QTextBlock startBlock = document()->findBlock(cursor.selectionStart());
QTextBlock endBlock = document()->findBlock(cursor.selectionEnd()); QTextBlock endBlock = document()->findBlock(cursor.selectionEnd());
@@ -289,27 +347,76 @@ void CodeEditor::keyPressEvent(QKeyEvent *event)
for (QTextBlock b = startBlock; b != endBlock.next(); b = b.next()) for (QTextBlock b = startBlock; b != endBlock.next(); b = b.next())
{ {
QTextCursor lineCursor(b); QTextCursor lineCursor(b);
lineCursor.movePosition(QTextCursor::StartOfBlock);
if (m_settings->useSpacesForTabs())
{
lineCursor.insertText(QString(tabSize, ' ')); lineCursor.insertText(QString(tabSize, ' '));
} }
else
{
lineCursor.insertText("\t");
}
}
cursor.endEditBlock(); cursor.endEditBlock();
} }
else else
{ {
// Calculate spaces needed to reach next tab stop if (m_settings->useSpacesForTabs())
{
// Zum nächsten Tab-Stop auffüllen
const int col = cursor.columnNumber(); const int col = cursor.columnNumber();
const int spacesNeeded = tabSize - (col % tabSize); const int spacesNeeded = tabSize - (col % tabSize);
cursor.insertText(QString(spacesNeeded, ' ')); cursor.insertText(QString(spacesNeeded, ' '));
} }
else
{
cursor.insertText("\t");
}
}
return; return;
} }
// Enter / Return: auto-indent // -----------------------------------------------------------------------
// Smart Backspace: springt zur vorherigen Einrückungsstufe
// -----------------------------------------------------------------------
if (event->key() == Qt::Key_Backspace
&& !textCursor().hasSelection()
&& m_settings->useSpacesForTabs())
{
QTextCursor cursor = textCursor();
const int col = cursor.columnNumber();
if (col > 0)
{
// Prüfen ob links vom Cursor nur Leerzeichen bis Zeilenbeginn stehen
const QString lineText = cursor.block().text();
const QString leftOfCursor = lineText.left(col);
const bool onlySpaces = leftOfCursor.trimmed().isEmpty();
if (onlySpaces && col > 0)
{
// Zur vorherigen Tab-Stop-Position springen
const int targetCol = ((col - 1) / tabSize) * tabSize;
const int toDelete = col - targetCol;
cursor.movePosition(QTextCursor::Left,
QTextCursor::KeepAnchor,
toDelete);
cursor.removeSelectedText();
return;
}
}
}
// -----------------------------------------------------------------------
// Enter / Return: Auto-Indent
// -----------------------------------------------------------------------
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
{ {
QTextCursor cursor = textCursor(); QTextCursor cursor = textCursor();
const QString currentLine = cursor.block().text(); const QString currentLine = cursor.block().text();
// Count leading whitespace // Führende Leerzeichen der aktuellen Zeile zählen
int leadingSpaces = 0; int leadingSpaces = 0;
for (const QChar &ch : currentLine) for (const QChar &ch : currentLine)
{ {
@@ -319,7 +426,7 @@ void CodeEditor::keyPressEvent(QKeyEvent *event)
} }
else if (ch == '\t') else if (ch == '\t')
{ {
leadingSpaces += m_settings->tabSize(); leadingSpaces += tabSize;
} }
else else
{ {
@@ -327,15 +434,13 @@ void CodeEditor::keyPressEvent(QKeyEvent *event)
} }
} }
// Let the base class insert the newline first
QPlainTextEdit::keyPressEvent(event); QPlainTextEdit::keyPressEvent(event);
// Then re-indent
if (leadingSpaces > 0) if (leadingSpaces > 0)
{ {
const QString indent = m_settings->useSpacesForTabs() const QString indent = m_settings->useSpacesForTabs()
? QString(leadingSpaces, ' ') ? QString(leadingSpaces, ' ')
: QString(leadingSpaces / m_settings->tabSize(), '\t'); : QString(leadingSpaces / tabSize, '\t');
textCursor().insertText(indent); textCursor().insertText(indent);
} }
return; return;
@@ -343,3 +448,4 @@ void CodeEditor::keyPressEvent(QKeyEvent *event)
QPlainTextEdit::keyPressEvent(event); QPlainTextEdit::keyPressEvent(event);
} }

View File

@@ -4,6 +4,7 @@
#include "SearchPanel.h" #include "SearchPanel.h"
#include <QFileInfo> #include <QFileInfo>
#include <QTextDocument>
EditorPanel::EditorPanel(Settings *settings, QWidget *parent) EditorPanel::EditorPanel(Settings *settings, QWidget *parent)
: QWidget(parent) : QWidget(parent)
@@ -70,7 +71,20 @@ void EditorPanel::openFile(const QString &filePath)
m_tabWidget->setTabToolTip(index, filePath); m_tabWidget->setTabToolTip(index, filePath);
m_openTabs.insert(filePath, tab); m_openTabs.insert(filePath, tab);
// Tab-Titel nach "Speichern unter" aktualisieren // Änderungsindikator im Tab-Titel (● = ungespeichert)
connect(tab->editor()->document(), &QTextDocument::modificationChanged,
this, [this, tab](bool modified)
{
const int idx = m_tabWidget->indexOf(tab);
if (idx == -1)
{
return;
}
const QString name = QFileInfo(tab->filePath()).fileName();
m_tabWidget->setTabText(idx, modified ? "" + name : name);
});
// Tab-Titel nach "Speichern unter" aktualisieren (neuer Dateiname, kein Punkt)
connect(tab->editor(), &CodeEditor::fileSaved, this, [this, tab](const QString &savedPath) connect(tab->editor(), &CodeEditor::fileSaved, this, [this, tab](const QString &savedPath)
{ {
const int idx = m_tabWidget->indexOf(tab); const int idx = m_tabWidget->indexOf(tab);