*
* @param lineNo the line number (0..N-1) of the first position to delete
* @param col -1: join the current line with the previous line.
- * <line_length>: join the current line with the following
+ * >= line_length: join the current line with the following
* the column number (0..M-1) of the first position to delete
* @param count the number of character to delete
* @param withUndo <code>true</code>: prepares undo operation<br>
*/
bool ReLines::removePart(int lineNo, int col, int count, bool withUndo) {
bool rc = false;
- if (lineNo >= 0 && lineNo < lineCount()) {
+ if (lineNo >= 0 && lineNo < lineCount() && count > 0) {
const QString& current = at(lineNo);
- if (col == -1) {
+ int length = current.length();
+ if (col <= -1) {
if (lineNo > 0) {
if (withUndo)
storeJoin(lineNo - 1, at(lineNo - 1).length());
rc = joinLines(lineNo - 1);
}
- } else if (col == current.length()) {
+ } else if (col >= length) {
if (withUndo)
- storeJoin(lineNo, current.length());
+ storeJoin(lineNo, length);
rc = joinLines(lineNo);
- } else if (col >= 0) {
- int length = current.length();
- if (col < length - 1) {
- if (col + count > length)
- count = length - col;
- if (withUndo)
- storeRemovePart(lineNo, col, current.mid(col, count));
- if (col == 0)
- replace(lineNo, current.mid(count));
- else if (col + count >= length)
- replace(lineNo, current.mid(0, col));
- else
- replace(lineNo,
- current.mid(0, col) + current.mid(col + count));
- }
+ } else {
+ if (col + count > length)
+ count = length - col;
+ if (withUndo)
+ storeRemovePart(lineNo, col, current.mid(col, count));
+ if (col == 0)
+ replace(lineNo, current.mid(count));
+ else if (col + count >= length)
+ replace(lineNo, current.mid(0, col));
+ else
+ replace(lineNo, current.mid(0, col) + current.mid(col + count));
}
}
return rc;
/**
* Removes a given number of lines.
*
+ * If all lines are removed a single empty line will remain.
+ *
* @param start the line number (0..N-1) of the first line to remove
* @param count the number of lines to delete
* @param withUndo <code>true</code>: prepares undo operation<br>
count = length() - start;
if (withUndo)
storeRemoveLines(start, count, *this);
- for (int ix = start + count - 1; ix >= 0; ix--)
+ for (int ix = start + count - 1; ix >= start; ix--)
removeAt(ix);
+ if (length() == 0)
+ append(m_empty);
}
}
pushKey(Qt::Key_Return, "\n");
checkEqu("xy", m_lines.lineAt(2));
checkEqu("z", m_lines.lineAt(3));
- log("ok");
}
+ void testDeleteText() {
+ init("abcd\n1234\nxy");
+ m_screenWidth = 5;
+ m_firstLine = 0;
+ m_firstCol = 0;
+
+ // first line:
+ m_cursorLineNo = 0;
+ // in the middle of the line:
+ m_cursorCol = 1;
+ editorAction(EA_DEL_BEGIN_OF_LINE);
+ checkEqu("cd", m_lines.lineAt(0));
+ checkEqu("1234", m_lines.lineAt(1));
+ checkEqu(-1, m_cursorCol);
+ checkEqu(0, m_cursorLineNo);
+ // at the begin of the line:
+ init("abcd\n1234\nxy");
+ m_cursorCol = -1;
+ editorAction(EA_DEL_BEGIN_OF_LINE);
+ checkEqu("abcd", m_lines.lineAt(0));
+ checkEqu("1234", m_lines.lineAt(1));
+
+ // in the middle of the line:
+ init("abcd\n1234\nxy");
+ m_cursorCol = 1;
+ editorAction(EA_DEL_END_OF_LINE);
+ checkEqu("ab", m_lines.lineAt(0));
+ checkEqu("1234", m_lines.lineAt(1));
+ checkEqu(1, m_cursorCol);
+ checkEqu(0, m_cursorLineNo);
+ // at the end of the line:
+ init("abcd\n1234\nxy");
+ m_cursorCol = 3;
+ editorAction(EA_DEL_END_OF_LINE);
+ checkEqu("abcd", m_lines.lineAt(0));
+ checkEqu("1234", m_lines.lineAt(1));
+
+ // last line:
+ init("abcd\n1234\nxy");
+ m_cursorLineNo = 2;
+ // in the middle of the line:
+ m_cursorCol = 0;
+ editorAction(EA_DEL_BEGIN_OF_LINE);
+ checkEqu("abcd", m_lines.lineAt(0));
+ checkEqu("1234", m_lines.lineAt(1));
+ checkEqu("y", m_lines.lineAt(2));
+ checkEqu(-1, m_cursorCol);
+ checkEqu(2, m_cursorLineNo);
+ // at the begin of the line:
+ init("abcd\n1234\nxy");
+ m_cursorCol = -1;
+ editorAction(EA_DEL_BEGIN_OF_LINE);
+ checkEqu("abcd", m_lines.lineAt(0));
+ checkEqu("1234", m_lines.lineAt(1));
+
+ // in the middle of the line:
+ init("abcd\n1234\nxy");
+ m_cursorCol = 0;
+ editorAction(EA_DEL_END_OF_LINE);
+ checkEqu("abcd", m_lines.lineAt(0));
+ checkEqu("1234", m_lines.lineAt(1));
+ checkEqu("x", m_lines.lineAt(2));
+ checkEqu(0, m_cursorCol);
+ checkEqu(2, m_cursorLineNo);
+ // at the end of the line:
+ init("abcd\n1234\nxy");
+ m_cursorCol = 1;
+ editorAction(EA_DEL_END_OF_LINE);
+ checkEqu("abcd", m_lines.lineAt(0));
+ checkEqu("1234", m_lines.lineAt(1));
+ checkEqu("xy", m_lines.lineAt(2));
+ }
+ void testDeleteLine() {
+ init("abcd\n1234\nxy");
+ m_screenWidth = 5;
+ m_firstLine = 0;
+ m_firstCol = 0;
+
+ // first line:
+ m_cursorLineNo = 0;
+ m_cursorCol = 1;
+ editorAction(EA_DEL_LINE);
+ checkEqu(2, m_lines.lineCount());
+ checkEqu("1234", m_lines.lineAt(0));
+ checkEqu("xy", m_lines.lineAt(1));
+ checkEqu(-1, m_cursorCol);
+ checkEqu(0, m_cursorLineNo);
+
+ // middle line:
+ init("abcd\n1234\nxy");
+ m_cursorLineNo = 1;
+ m_cursorCol = 1;
+ editorAction(EA_DEL_LINE);
+ checkEqu(2, m_lines.lineCount());
+ checkEqu("abcd", m_lines.lineAt(0));
+ checkEqu("xy", m_lines.lineAt(1));
+ checkEqu(-1, m_cursorCol);
+ checkEqu(1, m_cursorLineNo);
+
+ // last line:
+ init("abcd\n1234\nxy");
+ m_cursorLineNo = 2;
+ m_cursorCol = 1;
+ editorAction(EA_DEL_LINE);
+ checkEqu(2, m_lines.lineCount());
+ checkEqu("abcd", m_lines.lineAt(0));
+ checkEqu("1234", m_lines.lineAt(1));
+ checkEqu(-1, m_cursorCol);
+ checkEqu(2, m_cursorLineNo);
+
+ // wrong line numbers:
+ init("abcd\n1234\nxy");
+ m_cursorCol = 1;
+ m_cursorLineNo = -1;
+ editorAction(EA_DEL_LINE);
+ checkEqu(3, m_lines.lineCount());
+ checkEqu("abcd", m_lines.lineAt(0));
+ checkEqu("1234", m_lines.lineAt(1));
+ checkEqu("xy", m_lines.lineAt(2));
+ m_cursorLineNo = 3;
+ editorAction(EA_DEL_LINE);
+ checkEqu(3, m_lines.lineCount());
+ checkEqu("abcd", m_lines.lineAt(0));
+ checkEqu("1234", m_lines.lineAt(1));
+ checkEqu("xy", m_lines.lineAt(2));
+
+ log("ok");
+}
virtual void run() {
+ testDeleteLine();
+ testDeleteText();
testEnterText();
testCursorMove();
testEnsureCursorVisible();
class TestReFile: public ReTest {
public:
TestReFile() :
- ReTest("ReFile") {
+ ReTest("ReFile") {
doIt();
}
void testBasic() {
QByteArray fn(ReFile::tempFile("big.txt", NULL, true));
const char* content =
- "123456789 123456789 123456789 123456789 123456789\n";
+ "123456789 123456789 123456789 123456789 123456789\n";
int contentLength = strlen(content);
ReFile::writeToFile(fn.constData(), content);
ReFile file(fn.constData());
checkNN(ptr);
checkEqu(4, length);
checkEqu(0,
- strncmp(content, reinterpret_cast<const char*>(ptr), length));
+ strncmp(content, reinterpret_cast<const char*>(ptr), length));
int part = size / 2;
ptr = file.remap(contentLength - part, size, length);
checkEqu(size / 2, length);
checkEqu(content + contentLength - part,
- reinterpret_cast<const char*>(ptr));
+ reinterpret_cast<const char*>(ptr));
for (int ix = 0; ix < contentLength - size; ix++) {
ptr = file.remap(ix, size, length);
checkNN(ptr);
checkEqu(length, size);
checkEqu(0,
- strncmp(content + ix, reinterpret_cast<const char*>(ptr),
- length));
+ strncmp(content + ix, reinterpret_cast<const char*>(ptr),
+ length));
}
}
}
double duration = double(clock() - start) / CLOCKS_PER_SEC;
printf("linecount (ReFile, %d kB): %d lines %.3f sec\n",
- int(blocksize / 1024), lines, duration);
+ int(blocksize / 1024), lines, duration);
}
void countLinesFopen(const char* filename) {
// no remove because of wrong arguments:
lines.removePart(-1, 3, 1, true);
checkEqu(3, lines.lineCount());
- lines.removePart(0, 2, 1, true);
- checkEqu(3, lines.lineCount());
lines.removePart(3, 1, 1, true);
checkEqu(3, lines.lineCount());
checkEqu("3", lines.lineAt(0));
checkEqu("1", lines.lineAt(0));
checkEqu("23", lines.lineAt(1));
checkEqu("abcdefg", lines.lineAt(2));
- // at the end of the line:
- lines.splitLine(1, 2, true);
+ // at the end of the line ""1\n23\abcdefg":
+ lines.splitLine(0, 2, true);
checkEqu(4, lines.lineCount());
checkEqu("1", lines.lineAt(0));
checkEqu("", lines.lineAt(1));
}
case EA_DEL_END_OF_LINE: {
int lastIx = lastColOfCurrent();
- if (m_cursorCol < lastIx) {
+ if (m_cursorCol <= lastIx) {
m_lines->removePart(m_cursorLineNo, m_cursorCol + 1,
lastIx - m_cursorCol, true);
ensureCursorVisible();
break;
}
case EA_DEL_BEGIN_OF_LINE:
- if (m_cursorCol > 0) {
+ if (m_cursorCol >= 0) {
m_lines->removePart(m_cursorLineNo, 0, m_cursorCol + 1, true);
m_cursorCol = -1;
ensureCursorVisible();
break;
case EA_DEL_LINE:
m_lines->removeLines(m_cursorLineNo, 1, true);
+ m_cursorLineNo = min(m_cursorLineNo, m_lines->lineCount() - 1);
m_cursorCol = m_firstCol == 0 ? -1 : m_firstCol;
+ reposition(min(m_firstLine, m_firstLine - pageSize), m_firstCol - 1);
ensureCursorVisible();
break;
case EA_UNDO:
editorAction(m_keyRaw[key]);
break;
default:
+ // the inserted char should be visible:
+ ensureCursorVisible();
m_lines->insertText(m_cursorLineNo, m_cursorCol + 1, keyText);
m_cursorCol++;
+ // the new position should be visible too:
+ ensureCursorVisible();
break;
}
} else if (shift && !keyText.isEmpty() && key != Qt::Key_Delete
painter.setBrush(*look->m_brush);
QRect editArea(rect.left() + m_widthLineNumbers, rect.top(),
rect.right() - m_widthVScrollBar, rect.bottom() - m_heightHScrollBar);
+ // Painting the frame of the edit field:
painter.drawRect(editArea);
+ // Painting the edit field area (text...)
draw(painter, rect.top(), rect.left() + m_widthLineNumbers);
+ // Painting the line numbers:
int left = rect.left() + m_widthLineNumbers - 3;
left = rect.left();
int y = 0;
int lineNo = firstLine + 1;
ReLook* lookStd = lookOf(ReLook::FG_STANDARD, ReLook::BG_STANDARD);
- for (int ix = 0; ix < m_list.length(); ix++, lineNo++) {
+ int maxIx = min(m_list.length(), m_lines->lineCount() - m_firstLine);
+ for (int ix = 0; ix < maxIx; ix++, lineNo++) {
QString number = QString::number(lineNo) + ":";
ReLook* look =
lineNo == m_cursorLineNo + 1 ?