1
/***************************************************************************
2
lister.cpp - description
4
copyright : (C) 2009 + by Csaba Karai
5
e-mail : krusader@users.sourceforge.net
6
web site : http://krusader.sourceforge.net
7
---------------------------------------------------------------------------
9
***************************************************************************
13
db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
14
88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
15
88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
16
88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
17
88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
18
YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
22
***************************************************************************
24
* This program is free software; you can redistribute it and/or modify *
25
* it under the terms of the GNU General Public License as published by *
26
* the Free Software Foundation; either version 2 of the License, or *
27
* (at your option) any later version. *
29
***************************************************************************/
33
#include <QtCore/QFile>
34
#include <QtCore/QRect>
35
#include <QtCore/QDate>
36
#include <QtCore/QTextCodec>
37
#include <QtCore/QTextStream>
38
#include <QtGui/QLayout>
39
#include <QtGui/QLabel>
40
#include <QtGui/QPainter>
41
#include <QtGui/QFontMetrics>
42
#include <QtGui/QLineEdit>
43
#include <QtGui/QPushButton>
44
#include <QtGui/QToolButton>
45
#include <QtGui/QClipboard>
46
#include <QtGui/QSpacerItem>
47
#include <QtGui/QProgressBar>
48
#include <QtGui/QKeyEvent>
49
#include <QtGui/QScrollBar>
50
#include <QtGui/QHBoxLayout>
51
#include <QtGui/QMenu>
52
#include <QtGui/QPrintDialog>
53
#include <QtGui/QPrinter>
55
#include <kuiserverjobtracker.h>
56
#include <KColorScheme>
57
#include <KTemporaryFile>
58
#include <KMessageBox>
59
#include <KActionCollection>
60
#include <KInputDialog>
61
#include <KFileDialog>
63
#include <KGlobalSettings>
66
#include <KIO/CopyJob>
67
#include <KIO/JobUiDelegate>
69
#include "../krusader.h"
70
#include "../GUI/krremoteencodingmenu.h"
72
#define SEARCH_CACHE_CHARS 100000
73
#define SEARCH_MAX_ROW_LEN 4000
74
#define CONTROL_CHAR 752
75
#define CACHE_SIZE 100000
77
ListerTextArea::ListerTextArea(Lister *lister, QWidget *parent) : KTextEdit(parent), _lister(lister),
78
_sizeX(-1), _sizeY(-1), _cursorAnchorPos(-1), _inSliderOp(false), _inCursorUpdate(false), _hexMode(false)
80
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(slotCursorPositionChanged()));
82
setWordWrapMode(QTextOption::NoWrap);
83
setLineWrapMode(QTextEdit::NoWrap);
86
void ListerTextArea::reset()
90
_cursorAnchorPos = -1;
91
_cursorAtFirstColumn = true;
95
void ListerTextArea::sizeChanged()
97
if (_cursorAnchorPos > _lister->fileSize())
98
_cursorAnchorPos = -1;
99
if (_cursorPos > _lister->fileSize())
100
_cursorPos = _lister->fileSize();
102
redrawTextArea(true);
105
void ListerTextArea::resizeEvent(QResizeEvent * event)
107
KTextEdit::resizeEvent(event);
111
void ListerTextArea::calculateText(bool forcedUpdate)
113
QFontMetrics fm(font());
115
int fontHeight = fm.height();
119
QRect crect = viewport()->contentsRect();
120
int windowHeight = crect.height();
122
int sizeY = windowHeight / fontHeight;
125
QList<qint64> rowStarts;
127
int fontWidth = fm.width("W");
130
int windowWidth = crect.width() - fontWidth / 2;
134
setTabStopWidth(fontWidth * _tabWidth);
136
int sizeX = windowWidth / fontWidth;
138
_sizeChanged = (_sizeY != sizeY) || (_sizeX != sizeX) || forcedUpdate;
142
QStringList list = readLines(_screenStartPos, _screenEndPos, _sizeY, &rowStarts);
145
_averagePageSize = _screenEndPos - _screenStartPos;
149
rowStarts << _screenEndPos;
151
QStringList listRemn = readLines(_screenEndPos, _screenEndPos, 1);
154
if (list != _rowContent) {
155
setPlainText(list.join("\n"));
157
_rowStarts = rowStarts;
161
qint64 ListerTextArea::textToFilePosition(int x, int y, bool &isfirst)
164
if (y >= _rowStarts.count())
166
qint64 rowStart = _rowStarts[ y ];
171
qint64 pos = rowStart + _lister->hexPositionToIndex(_sizeX, x);
172
if (pos > _lister->fileSize())
173
pos = _lister->fileSize();
177
// we can't use fromUnicode because of the invalid encoded chars
178
int maxBytes = 2 * _sizeX * MAX_CHAR_LENGTH;
179
char * cache = _lister->cacheRef(rowStart, maxBytes);
180
QByteArray cachedBuffer(cache, maxBytes);
182
QTextStream stream(&cachedBuffer);
183
stream.setCodec(codec());
185
return rowStart + stream.pos();
188
void ListerTextArea::fileToTextPosition(qint64 p, bool isfirst, int &x, int &y)
190
if (p < _screenStartPos || p > _screenEndPos || _rowStarts.count() < 1) {
192
y = (p > _screenEndPos) ? -2 : -1;
195
while (y < _rowStarts.count() && _rowStarts[ y ] <= p)
203
qint64 rowStart = _rowStarts[ y ];
205
x = _lister->hexIndexToPosition(_sizeX, (int)(p - rowStart));
209
int maxBytes = 2 * _sizeX * MAX_CHAR_LENGTH;
212
if ((rowStart == p) && !isfirst && y > 0) {
213
qint64 previousRow = _rowStarts[ y - 1 ];
214
char * cache = _lister->cacheRef(previousRow, maxBytes);
215
QByteArray cachedBuffer(cache, p - previousRow);
217
QTextStream stream(&cachedBuffer);
218
stream.setCodec(codec());
219
stream.read(_rowContent[ y - 1].length());
220
if (previousRow + stream.pos() == p) {
222
x = _rowContent[ y ].length();
228
char * cache = _lister->cacheRef(rowStart, maxBytes);
229
QByteArray cachedBuffer(cache, p - rowStart);
231
QString res = codec()->toUnicode(cachedBuffer);
236
void ListerTextArea::getCursorPosition(int &x, int &y)
238
getScreenPosition(textCursor().position(), x, y);
241
void ListerTextArea::getScreenPosition(int position, int &x, int &y)
245
for (int i = 0; i < _rowContent.count(); i++) {
246
int rowLen = _rowContent[ i ].length() + 1;
255
void ListerTextArea::setCursorPosition(int x, int y, int anchorX, int anchorY)
257
_inCursorUpdate = true;
258
if (x == -1 || y < 0) {
261
_inCursorUpdate = false;
267
x = (_rowContent.count() > _sizeY) ? _rowContent[ _sizeY ].length() : 0;
273
QTextCursor::MoveMode mode = QTextCursor::MoveAnchor;
274
if (anchorX != -1 && anchorY != -1) {
275
if (anchorY >= _sizeY) {
276
moveCursor(QTextCursor::End, mode);
277
moveCursor(QTextCursor::StartOfLine, mode);
279
moveCursor(QTextCursor::Start, mode);
280
for (int i = 0; i < anchorY; i++)
281
moveCursor(QTextCursor::Down, mode);
284
if (_rowContent.count() > anchorY && anchorX > _rowContent[ anchorY ].length())
285
anchorX = _rowContent[ anchorY ].length();
287
for (int j = 0; j < anchorX; j++)
288
moveCursor(QTextCursor::Right, mode);
290
mode = QTextCursor::KeepAnchor;
294
moveCursor(QTextCursor::End, mode);
295
moveCursor(QTextCursor::StartOfLine, mode);
297
moveCursor(QTextCursor::Start, mode);
298
for (int i = 0; i < y; i++)
299
moveCursor(QTextCursor::Down, mode);
302
if (_rowContent.count() > y && x > _rowContent[ y ].length())
303
x = _rowContent[ y ].length();
305
for (int j = 0; j < x; j++)
306
moveCursor(QTextCursor::Right, mode);
308
_inCursorUpdate = false;
311
qint64 ListerTextArea::getCursorPosition(bool &isfirst)
313
if (cursorWidth() == 0) {
314
isfirst = _cursorAtFirstColumn;
319
getCursorPosition(x, y);
320
return textToFilePosition(x, y, isfirst);
323
void ListerTextArea::setCursorPosition(qint64 p, bool isfirst)
327
fileToTextPosition(p, isfirst, x, y);
329
int anchorX = -1, anchorY = -1;
330
if (_cursorAnchorPos != -1 && _cursorAnchorPos != p) {
331
int anchPos = _cursorAnchorPos;
332
bool anchorBelow = false, anchorAbove = false;
333
if (anchPos < _screenStartPos) {
334
anchPos = _screenStartPos;
338
if (anchPos > _screenEndPos) {
339
anchPos = _screenEndPos;
344
fileToTextPosition(anchPos, isfirst, anchorX, anchorY);
345
if (anchorAbove && _hexMode)
347
if (anchorBelow && _hexMode && _rowContent.count() > 0)
348
anchorX = _rowContent[ 0 ].length();
350
setCursorPosition(x, y, anchorX, anchorY);
353
void ListerTextArea::slotCursorPositionChanged()
357
int cursorX, cursorY;
358
getCursorPosition(cursorX, cursorY);
359
_cursorAtFirstColumn = (cursorX == 0);
360
_cursorPos = textToFilePosition(cursorX, cursorY, _cursorAtFirstColumn);
362
//fprintf( stderr, "Cursor pos: %d %d %Ld\n", cursorX, cursorY, _cursorPos );
365
QString ListerTextArea::readSection(qint64 p1, qint64 p2)
381
QStringList list = _lister->readHexLines(p1, p2, _sizeX, 1);
382
if (list.count() == 0)
384
if (!section.isEmpty())
385
section += QChar('\n');
386
section += list[ 0 ];
391
QTextCodec * textCodec = codec();
392
QTextDecoder * decoder = textCodec->makeDecoder();
395
int maxBytes = _sizeX * _sizeY * MAX_CHAR_LENGTH;
396
if (maxBytes > (p2 - pos))
397
maxBytes = (int)(p2 - pos);
398
char * cache = _lister->cacheRef(pos, maxBytes);
399
if (cache == 0 || maxBytes == 0)
401
section += decoder->toUnicode(cache, maxBytes);
409
QStringList ListerTextArea::readLines(qint64 filePos, qint64 &endPos, int lines, QList<qint64> * locs)
415
endPos = _lister->fileSize();
416
if (filePos >= endPos)
418
qint64 startPos = filePos;
419
int bytes = _lister->hexBytesPerLine(_sizeX);
420
filePos = startPos = ((startPos) / bytes) * bytes;
421
list = _lister->readHexLines(filePos, endPos, _sizeX, lines);
424
for (int i = 0; i != list.count(); i++) {
432
int maxBytes = _sizeX * _sizeY * MAX_CHAR_LENGTH;
433
char * cache = _lister->cacheRef(filePos, maxBytes);
434
if (cache == 0 || maxBytes == 0)
437
QTextCodec * textCodec = codec();
438
QTextDecoder * decoder = textCodec->makeDecoder();
446
bool isLastLongLine = false;
447
while (cnt < maxBytes && y < lines) {
449
QString chr = decoder->toUnicode(cache + (cnt++), 1);
450
if (!chr.isEmpty()) {
451
if ((chr[ 0 ] < 32) && (chr[ 0 ] != '\n') && (chr[ 0 ] != '\t'))
452
chr = QChar(CONTROL_CHAR);
454
if (!isLastLongLine) {
460
(*locs) << filePos + cnt;
462
isLastLongLine = false;
464
isLastLongLine = false;
466
effLength += _tabWidth - (effLength % _tabWidth) - 1;
467
if (effLength > _sizeX) {
473
(*locs) << filePos + lastCnt;
478
if (effLength >= _sizeX) {
484
(*locs) << filePos + cnt;
485
isLastLongLine = true;
495
while (locs->count() > lines) {
500
endPos = filePos + cnt;
506
QTextCodec * ListerTextArea::codec()
508
QString cs = _lister->characterSet();
510
return QTextCodec::codecForLocale();
512
return KGlobal::charsets()->codecForName(cs);
515
void ListerTextArea::setUpScrollBar()
517
if (_averagePageSize == _lister->fileSize()) {
518
_lister->scrollBar()->setPageStep(0);
519
_lister->scrollBar()->setMaximum(0);
520
_lister->scrollBar()->hide();
521
_lastPageStartPos = 0;
523
int maxPage = MAX_CHAR_LENGTH * _sizeX * _sizeY;
524
qint64 pageStartPos = _lister->fileSize() - maxPage;
526
if (pageStartPos < 0)
528
QStringList list = readLines(pageStartPos, endPos, maxPage);
529
if (list.count() <= _sizeY) {
530
_lastPageStartPos = 0;
532
readLines(pageStartPos, _lastPageStartPos, list.count() - _sizeY);
535
int maximum = (_lastPageStartPos > SLIDER_MAX) ? SLIDER_MAX : _lastPageStartPos;
536
int pageSize = (_lastPageStartPos > SLIDER_MAX) ? SLIDER_MAX * _averagePageSize / _lastPageStartPos : _averagePageSize;
540
_lister->scrollBar()->setPageStep(pageSize);
541
_lister->scrollBar()->setMaximum(maximum);
542
_lister->scrollBar()->show();
546
void ListerTextArea::keyPressEvent(QKeyEvent * ke)
548
if (Krusader::actCopy->shortcut().contains(QKeySequence(ke->key() | ke->modifiers()))) {
549
copySelectedToClipboard();
554
if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier) {
555
qint64 newAnchor = -1;
556
if (ke->modifiers() == Qt::ShiftModifier) {
557
newAnchor = _cursorAnchorPos;
558
if (_cursorAnchorPos == -1)
559
newAnchor = _cursorPos;
565
if (ke->modifiers() == Qt::ShiftModifier)
566
_lister->searchPrev();
568
_lister->searchNext();
572
_cursorAnchorPos = newAnchor;
575
_cursorAnchorPos = newAnchor;
576
ensureVisibleCursor();
578
getCursorPosition(x, y);
579
if (y == 0 && x == 0)
580
slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
583
case Qt::Key_Right: {
584
_cursorAnchorPos = newAnchor;
585
ensureVisibleCursor();
586
if (textCursor().position() == toPlainText().length())
587
slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
591
_cursorAnchorPos = newAnchor;
592
ensureVisibleCursor();
594
getCursorPosition(x, y);
596
slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
600
_cursorAnchorPos = newAnchor;
601
ensureVisibleCursor();
603
getCursorPosition(x, y);
605
slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
608
case Qt::Key_PageDown: {
609
_cursorAnchorPos = newAnchor;
610
ensureVisibleCursor();
613
getCursorPosition(x, y);
614
slotActionTriggered(QAbstractSlider::SliderPageStepAdd);
615
y += _sizeY - _skippedLines;
616
if (y > _rowContent.count()) {
617
y = _rowContent.count();
619
x = _rowContent[ y - 1 ].length();
623
_cursorPos = textToFilePosition(x, y, _cursorAtFirstColumn);
624
setCursorPosition(_cursorPos, _cursorAtFirstColumn);
627
case Qt::Key_PageUp: {
628
_cursorAnchorPos = newAnchor;
629
ensureVisibleCursor();
632
getCursorPosition(x, y);
633
slotActionTriggered(QAbstractSlider::SliderPageStepSub);
634
y -= _sizeY - _skippedLines;
639
_cursorPos = textToFilePosition(x, y, _cursorAtFirstColumn);
640
setCursorPosition(_cursorPos, _cursorAtFirstColumn);
645
if (ke->modifiers() == Qt::ControlModifier) {
649
_lister->jumpToPosition();
653
_lister->enableSearch(true);
656
_cursorAnchorPos = -1;
658
slotActionTriggered(QAbstractSlider::SliderToMinimum);
659
setCursorPosition((qint64)0, true);
663
_cursorAnchorPos = (ke->key() == Qt::Key_A) ? 0 : -1;
665
slotActionTriggered(QAbstractSlider::SliderToMaximum);
666
qint64 endPos = _lister->fileSize();
667
setCursorPosition(endPos, true);
672
slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
676
slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
678
case Qt::Key_PageDown:
680
slotActionTriggered(QAbstractSlider::SliderPageStepAdd);
684
slotActionTriggered(QAbstractSlider::SliderPageStepSub);
688
int oldAnchor = textCursor().anchor();
689
KTextEdit::keyPressEvent(ke);
690
handleAnchorChange(oldAnchor);
693
void ListerTextArea::mousePressEvent(QMouseEvent * e)
695
_cursorAnchorPos = -1;
696
int oldAnchor = textCursor().anchor();
697
KTextEdit::mousePressEvent(e);
698
handleAnchorChange(oldAnchor);
701
void ListerTextArea::mouseDoubleClickEvent(QMouseEvent * e)
703
_cursorAnchorPos = -1;
704
int oldAnchor = textCursor().anchor();
705
KTextEdit::mouseDoubleClickEvent(e);
706
handleAnchorChange(oldAnchor);
709
void ListerTextArea::mouseMoveEvent(QMouseEvent * e)
711
if (e->pos().y() < 0) {
712
slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
713
} else if (e->pos().y() > height()) {
714
slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
716
if (_cursorAnchorPos == -1)
717
_cursorAnchorPos = _cursorPos;
718
KTextEdit::mouseMoveEvent(e);
719
if (_cursorAnchorPos == _cursorPos)
720
_cursorAnchorPos = -1;
723
void ListerTextArea::wheelEvent(QWheelEvent * e)
725
int delta = e->delta();
730
slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
731
slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
732
slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
738
slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
739
slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
740
slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
747
void ListerTextArea::slotActionTriggered(int action)
750
case QAbstractSlider::SliderSingleStepAdd: {
752
readLines(_screenStartPos, endPos, 1);
753
if (endPos <= _lastPageStartPos) {
754
_screenStartPos = endPos;
758
case QAbstractSlider::SliderSingleStepSub: {
759
if (_screenStartPos == 0)
763
int bytesPerRow = _lister->hexBytesPerLine(_sizeX);
764
_screenStartPos = (_screenStartPos / bytesPerRow) * bytesPerRow;
765
_screenStartPos -= bytesPerRow;
766
if (_screenStartPos < 0)
769
int maxSize = _sizeX * _sizeY * MAX_CHAR_LENGTH;
770
QByteArray encodedEnter = codec()->fromUnicode(QString("\n"));
772
qint64 readPos = _screenStartPos - maxSize;
775
maxSize = _screenStartPos - readPos;
777
char * cache = _lister->cacheRef(readPos, maxSize);
778
QByteArray backBuffer(cache, maxSize);
783
from = backBuffer.lastIndexOf(encodedEnter, from);
786
int backRef = from - 20;
789
int size = from - backRef + encodedEnter.size();
790
QString decoded = codec()->toUnicode(cache + backRef, size);
791
if (decoded.endsWith(QLatin1String("\n"))) {
792
if (from < (maxSize - encodedEnter.size())) {
793
from += encodedEnter.size();
803
qint64 previousPos = readPos;
805
while (readPos < _screenStartPos) {
806
previousPos = readPos;
807
readLines(readPos, readPos, 1);
810
_screenStartPos = previousPos;
814
case QAbstractSlider::SliderPageStepAdd: {
818
for (int i = 0; i < _sizeY; i++) {
819
readLines(_screenStartPos, endPos, 1);
820
if (endPos <= _lastPageStartPos) {
821
_screenStartPos = endPos;
829
case QAbstractSlider::SliderPageStepSub: {
832
if (_screenStartPos == 0)
836
int bytesPerRow = _lister->hexBytesPerLine(_sizeX);
837
_screenStartPos = (_screenStartPos / bytesPerRow) * bytesPerRow;
838
_screenStartPos -= _sizeY * bytesPerRow;
839
if (_screenStartPos < 0)
842
int maxSize = 2 * _sizeX * _sizeY * MAX_CHAR_LENGTH;
843
QByteArray encodedEnter = codec()->fromUnicode(QString("\n"));
845
qint64 readPos = _screenStartPos - maxSize;
848
maxSize = _screenStartPos - readPos;
850
char * cache = _lister->cacheRef(readPos, maxSize);
851
QByteArray backBuffer(cache, maxSize);
853
int sizeY = _sizeY + 1;
854
int origSizeY = sizeY;
856
int lastEnter = maxSize;
858
repeat: while (from > 0) {
860
from = backBuffer.lastIndexOf(encodedEnter, from);
863
int backRef = from - 20;
866
int size = from - backRef + encodedEnter.size();
867
QString decoded = codec()->toUnicode(cache + backRef, size);
868
if (decoded.endsWith(QLatin1String("\n"))) {
869
if (from < (maxSize - encodedEnter.size())) {
870
int arrayStart = from + encodedEnter.size();
871
decoded = codec()->toUnicode(cache + arrayStart, lastEnter - arrayStart);
872
sizeY -= ((decoded.length() / (_sizeX + 1)) + 1);
884
qint64 searchPos = readPos + from;
887
while (searchPos < _screenStartPos) {
889
readLines(searchPos, searchPos, 1);
892
if (locs.count() >= _sizeY)
893
_screenStartPos = locs[ locs.count() - _sizeY ];
894
else if (from != 0) {
895
origSizeY += locs.count() + 1;
898
} else if (readPos == 0)
903
case QAbstractSlider::SliderToMinimum:
906
case QAbstractSlider::SliderToMaximum:
907
_screenStartPos = _lastPageStartPos;
909
case QAbstractSlider::SliderMove: {
910
if (_inSliderOp) // self created call?
912
qint64 pos = _lister->scrollBar()->sliderPosition();
914
if (pos == SLIDER_MAX) {
915
_screenStartPos = _lastPageStartPos;
917
} else if (pos == 0) {
922
if (_lastPageStartPos > SLIDER_MAX)
923
pos = _lastPageStartPos * pos / SLIDER_MAX;
927
int bytesPerRow = _lister->hexBytesPerLine(_sizeX);
928
pos = (pos / bytesPerRow) * bytesPerRow;
930
int maxSize = _sizeX * _sizeY * MAX_CHAR_LENGTH;
931
qint64 readPos = pos - maxSize;
934
qint64 previousPos = readPos;
936
while (readPos <= pos) {
937
previousPos = readPos;
938
readLines(readPos, readPos, 1);
945
_screenStartPos = pos;
948
case QAbstractSlider::SliderNoAction:
953
int value = (_lastPageStartPos > SLIDER_MAX) ? SLIDER_MAX * _screenStartPos / _lastPageStartPos : _screenStartPos;
954
_lister->scrollBar()->setSliderPosition(value);
960
void ListerTextArea::redrawTextArea(bool forcedUpdate)
963
qint64 pos = getCursorPosition(isfirst);
964
calculateText(forcedUpdate);
965
setCursorPosition(pos, isfirst);
968
void ListerTextArea::ensureVisibleCursor()
970
if (_cursorPos < _screenStartPos || _cursorPos > _screenEndPos) {
971
int delta = _sizeY / 2;
975
qint64 newScreenStart = _cursorPos;
977
int maxSize = _sizeX * MAX_CHAR_LENGTH;
978
qint64 readPos = newScreenStart - maxSize;
982
qint64 previousPos = readPos;
984
while (readPos < newScreenStart) {
985
previousPos = readPos;
986
readLines(readPos, readPos, 1);
987
if (readPos == previousPos)
991
newScreenStart = previousPos;
994
if (newScreenStart > _lastPageStartPos)
995
newScreenStart = _lastPageStartPos;
997
_screenStartPos = newScreenStart;
998
slotActionTriggered(QAbstractSlider::SliderNoAction);
1002
void ListerTextArea::setAnchorAndCursor(qint64 anchor, qint64 cursor)
1004
_cursorAnchorPos = anchor;
1005
setCursorPosition(cursor, false);
1006
ensureVisibleCursor();
1009
void ListerTextArea::copySelectedToClipboard()
1011
if (_cursorAnchorPos != -1 && _cursorAnchorPos != _cursorPos) {
1012
QString selection = readSection(_cursorAnchorPos, _cursorPos);
1013
QApplication::clipboard()->setText(selection);
1017
void ListerTextArea::handleAnchorChange(int oldAnchor)
1019
int cursor = textCursor().position();
1020
int anchor = textCursor().anchor();
1022
if (anchor == cursor) {
1023
_cursorAnchorPos = -1;
1025
if (oldAnchor != anchor) {
1028
getScreenPosition(anchor, x, y);
1029
_cursorAnchorPos = textToFilePosition(x, y, isfirst);
1034
void ListerTextArea::setHexMode(bool hexMode)
1037
qint64 pos = getCursorPosition(isfirst);
1039
_screenStartPos = 0;
1040
calculateText(true);
1041
setCursorPosition(pos, isfirst);
1042
ensureVisibleCursor();
1045
ListerBrowserExtension::ListerBrowserExtension(Lister * lister) : KParts::BrowserExtension(lister)
1049
emit enableAction("copy", true);
1050
emit enableAction("print", true);
1053
void ListerBrowserExtension::copy()
1055
_lister->textArea()->copySelectedToClipboard();
1058
void ListerBrowserExtension::print()
1063
class ListerEncodingMenu : public KrRemoteEncodingMenu
1066
ListerEncodingMenu(Lister *lister, const QString &text, const QString &icon, KActionCollection *parent) :
1067
KrRemoteEncodingMenu(text, icon, parent), _lister(lister) {
1071
virtual QString currentCharacterSet() {
1072
return _lister->characterSet();
1075
virtual void chooseDefault() {
1076
_lister->setCharacterSet(QString());
1079
virtual void chooseEncoding(QString encodingName) {
1080
QString charset = KGlobal::charsets()->encodingForName(encodingName);
1081
_lister->setCharacterSet(charset);
1087
Lister::Lister(QWidget *parent) : KParts::ReadOnlyPart(parent), _searchInProgress(false), _cache(0), _active(false), _searchLastFailedPosition(-1),
1088
_searchProgressCounter(0), _tempFile(0), _downloading(false)
1090
setXMLFile("krusaderlisterui.rc");
1092
_actionSaveSelected = new KAction(KIcon("document-save"), i18n("Save selection..."), this);
1093
connect(_actionSaveSelected, SIGNAL(triggered(bool)), SLOT(saveSelected()));
1094
actionCollection()->addAction("save_selected", _actionSaveSelected);
1096
_actionSaveAs = new KAction(KIcon("document-save-as"), i18n("Save as..."), this);
1097
connect(_actionSaveAs, SIGNAL(triggered(bool)), SLOT(saveAs()));
1098
actionCollection()->addAction("save_as", _actionSaveAs);
1100
_actionPrint = new KAction(KIcon("document-print"), i18n("Print..."), this);
1101
_actionPrint->setShortcut(Qt::CTRL + Qt::Key_P);
1102
connect(_actionPrint, SIGNAL(triggered(bool)), SLOT(print()));
1103
actionCollection()->addAction("print", _actionPrint);
1105
_actionSearch = new KAction(KIcon("system-search"), i18n("Search"), this);
1106
_actionSearch->setShortcut(Qt::CTRL + Qt::Key_F);
1107
connect(_actionSearch, SIGNAL(triggered(bool)), SLOT(searchAction()));
1108
actionCollection()->addAction("search", _actionSearch);
1110
_actionSearchNext = new KAction(KIcon("go-down"), i18n("Search next"), this);
1111
_actionSearchNext->setShortcut(Qt::Key_F3);
1112
connect(_actionSearchNext, SIGNAL(triggered(bool)), SLOT(searchNext()));
1113
actionCollection()->addAction("search_next", _actionSearchNext);
1115
_actionSearchPrev = new KAction(KIcon("go-up"), i18n("Search previous"), this);
1116
_actionSearchPrev->setShortcut(Qt::SHIFT + Qt::Key_F3);
1117
connect(_actionSearchPrev, SIGNAL(triggered(bool)), SLOT(searchPrev()));
1118
actionCollection()->addAction("search_prev", _actionSearchPrev);
1120
_actionJumpToPosition = new KAction(KIcon("go-jump"), i18n("Jump to position"), this);
1121
_actionJumpToPosition->setShortcut(Qt::CTRL + Qt::Key_G);
1122
connect(_actionJumpToPosition, SIGNAL(triggered(bool)), SLOT(jumpToPosition()));
1123
actionCollection()->addAction("jump_to_position", _actionJumpToPosition);
1125
_actionHexMode = new KAction(KIcon("document-preview"), i18n("Hex mode"), this);
1126
_actionHexMode->setShortcut(Qt::CTRL + Qt::Key_H);
1127
connect(_actionHexMode, SIGNAL(triggered(bool)), SLOT(toggleHexMode()));
1128
actionCollection()->addAction("hex_mode", _actionHexMode);
1130
_actionEncoding = new ListerEncodingMenu(this, i18n("Select charset"), "character-set", actionCollection());
1132
QWidget * widget = new QWidget(parent);
1133
widget->setFocusPolicy(Qt::StrongFocus);
1134
QGridLayout *grid = new QGridLayout(widget);
1135
_textArea = new ListerTextArea(this, widget);
1136
_textArea->setFont(KGlobalSettings::fixedFont());
1137
_textArea->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
1138
_textArea->setCursorWidth(2);
1139
_textArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1140
_textArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1141
widget->setFocusProxy(_textArea);
1142
grid->addWidget(_textArea, 0, 0);
1143
_scrollBar = new QScrollBar(Qt::Vertical, widget);
1144
grid->addWidget(_scrollBar, 0, 1);
1147
QWidget * statusWidget = new QWidget(widget);
1148
QHBoxLayout *hbox = new QHBoxLayout(statusWidget);
1150
_listerLabel = new QLabel(i18n("Lister:"), statusWidget);
1151
hbox->addWidget(_listerLabel);
1152
_searchProgressBar = new QProgressBar(statusWidget);
1153
_searchProgressBar->setMinimum(0);
1154
_searchProgressBar->setMaximum(1000);
1155
_searchProgressBar->setValue(0);
1156
_searchProgressBar->hide();
1157
hbox->addWidget(_searchProgressBar);
1159
_searchStopButton = new QToolButton(statusWidget);
1160
_searchStopButton->setIcon(KIcon("process-stop"));
1161
_searchStopButton->setToolTip(i18n("Stop search"));
1162
_searchStopButton->hide();
1163
connect(_searchStopButton, SIGNAL(clicked()), this, SLOT(searchDelete()));
1164
hbox->addWidget(_searchStopButton);
1166
_searchLineEdit = new KLineEdit(statusWidget);
1167
_searchLineEdit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
1169
_originalBackground = _searchLineEdit->palette().color(QPalette::Base);
1170
_originalForeground = _searchLineEdit->palette().color(QPalette::Text);
1172
connect(_searchLineEdit, SIGNAL(returnPressed()), this, SLOT(searchNext()));
1173
connect(_searchLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(searchTextChanged()));
1175
hbox->addWidget(_searchLineEdit);
1176
_searchNextButton = new QPushButton(KIcon("go-down"), i18n("Next"), statusWidget);
1177
_searchNextButton->setToolTip(i18n("Jump to next match"));
1178
connect(_searchNextButton, SIGNAL(clicked()), this, SLOT(searchNext()));
1179
hbox->addWidget(_searchNextButton);
1180
_searchPrevButton = new QPushButton(KIcon("go-up"), i18n("Previous"), statusWidget);
1181
_searchPrevButton->setToolTip(i18n("Jump to previous match"));
1182
connect(_searchPrevButton, SIGNAL(clicked()), this, SLOT(searchPrev()));
1183
hbox->addWidget(_searchPrevButton);
1184
_searchOptions = new QPushButton(i18n("Options"), statusWidget);
1185
_searchOptions->setToolTip(i18n("Modify search behavior"));
1186
QMenu * menu = new QMenu();
1187
_fromCursorAction = menu->addAction(i18n("From cursor"));
1188
_fromCursorAction->setCheckable(true);
1189
_fromCursorAction->setChecked(true);
1190
_caseSensitiveAction = menu->addAction(i18n("Case sensitive"));
1191
_caseSensitiveAction->setCheckable(true);
1192
_matchWholeWordsOnlyAction = menu->addAction(i18n("Match whole words only"));
1193
_matchWholeWordsOnlyAction->setCheckable(true);
1194
_regExpAction = menu->addAction(i18n("RegExp"));
1195
_regExpAction->setCheckable(true);
1196
_hexAction = menu->addAction(i18n("Hexadecimal"));
1197
_hexAction->setCheckable(true);
1198
_searchOptions->setMenu(menu);
1200
hbox->addWidget(_searchOptions);
1202
QSpacerItem* cbSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
1203
hbox->addItem(cbSpacer);
1205
_statusLabel = new QLabel(statusWidget);
1206
hbox->addWidget(_statusLabel);
1208
grid->addWidget(statusWidget, 1, 0, 1, 2);
1211
connect(_scrollBar, SIGNAL(actionTriggered(int)), _textArea, SLOT(slotActionTriggered(int)));
1212
connect(&_updateTimer, SIGNAL(timeout()), this, SLOT(slotUpdate()));
1214
_updateTimer.setSingleShot(false);
1216
new ListerBrowserExtension(this);
1217
enableSearch(false);
1226
if (_tempFile != 0) {
1232
bool Lister::openUrl(const KUrl &listerUrl)
1234
_downloading = false;
1243
if (listerUrl.isLocalFile()) {
1244
_filePath = listerUrl.path();
1245
if (!QFile::exists(_filePath))
1247
_fileSize = getFileSize();
1249
_tempFile = new KTemporaryFile();
1250
_tempFile->setSuffix(listerUrl.fileName());
1253
_filePath = _tempFile->fileName();
1255
KIO::Job * downloadJob = KIO::get(listerUrl, KIO::NoReload, KIO::HideProgressInfo);
1257
connect(downloadJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
1258
this, SLOT(slotFileDataReceived(KIO::Job *, const QByteArray &)));
1259
connect(downloadJob, SIGNAL(result(KJob*)),
1260
this, SLOT(slotFileFinished(KJob *)));
1261
_downloading = false;
1269
emit setWindowCaption(listerUrl.prettyUrl());
1274
void Lister::slotFileDataReceived(KIO::Job *, const QByteArray &array)
1276
if (array.size() != 0)
1277
_tempFile->write(array);
1280
void Lister::slotFileFinished(KJob *job)
1283
if (job->error()) { /* any error occurred? */
1284
KIO::TransferJob *kioJob = (KIO::TransferJob *)job;
1285
KMessageBox::error(_textArea, i18n("Error reading file %1!", kioJob->url().pathOrUrl()));
1287
_downloading = false;
1291
char * Lister::cacheRef(qint64 filePos, int &size)
1293
if (filePos >= _fileSize)
1295
if (_fileSize - filePos < size)
1296
size = _fileSize - filePos;
1297
if ((_cache != 0) && (filePos >= _cachePos) && (filePos + size <= _cachePos + _cacheSize))
1298
return _cache + (filePos - _cachePos);
1300
int cacheSize = CACHE_SIZE;
1301
int negativeOffset = CACHE_SIZE * 2 / 5;
1302
qint64 cachePos = filePos - negativeOffset;
1306
QFile myfile(_filePath);
1307
if (!myfile.open(QIODevice::ReadOnly)) {
1312
if (!myfile.seek(cachePos)) {
1317
char * newCache = new char [ cacheSize ];
1319
qint64 bytes = myfile.read(newCache, cacheSize);
1330
_cachePos = cachePos;
1331
int newSize = _cacheSize - (filePos - _cachePos);
1335
return _cache + (filePos - _cachePos);
1338
qint64 Lister::getFileSize()
1340
return QFile(_filePath).size();
1343
void Lister::guiActivateEvent(KParts::GUIActivateEvent * event)
1345
if (event->activated()) {
1347
_updateTimer.setInterval(150);
1348
_updateTimer.start();
1351
enableSearch(false);
1353
_updateTimer.stop();
1355
KParts::ReadOnlyPart::guiActivateEvent(event);
1358
void Lister::slotUpdate()
1360
qint64 oldSize = _fileSize;
1361
_fileSize = getFileSize();
1362
if (oldSize != _fileSize)
1363
_textArea->sizeChanged();
1365
int cursorX = 0, cursorY = 0;
1366
_textArea->getCursorPosition(cursorX, cursorY);
1367
bool isfirst = false;
1368
qint64 cursor = _textArea->getCursorPosition(isfirst);
1370
int percent = (_fileSize == 0) ? 0 : (int)((201 * cursor) / _fileSize / 2);
1372
QString status = i18n("Column: %1, Position: %2 (%3, %4%)")
1373
.arg(cursorX, 3, 10, QChar(' '))
1374
.arg(cursor).arg(_fileSize).arg(percent);
1375
_statusLabel->setText(status);
1377
if (_searchProgressCounter)
1378
_searchProgressCounter--;
1381
void Lister::enableSearch(bool enable)
1384
_listerLabel->setText(i18n("Search:"));
1385
_searchLineEdit->show();
1386
_searchNextButton->show();
1387
_searchPrevButton->show();
1388
_searchOptions->show();
1389
_searchLineEdit->setFocus();
1391
_listerLabel->setText(i18n("Lister:"));
1392
_searchLineEdit->hide();
1393
_searchNextButton->hide();
1394
_searchPrevButton->hide();
1395
_searchOptions->hide();
1399
void Lister::searchNext()
1404
void Lister::searchPrev()
1409
void Lister::search(bool forward, bool restart)
1411
_restartFromBeginning = restart;
1412
if (_searchInProgress || _searchLineEdit->text().isEmpty())
1414
if (_searchLineEdit->isHidden())
1417
_searchPosition = forward ? 0 : _fileSize;
1418
if (_fromCursorAction->isChecked()) {
1420
qint64 cursor = _textArea->getCursorPosition(isfirst);
1421
if (cursor != 0 && !forward)
1423
if (_searchLastFailedPosition == -1 || _searchLastFailedPosition != cursor)
1424
_searchPosition = cursor;
1426
bool caseSensitive = _caseSensitiveAction->isChecked();
1427
bool matchWholeWord = _matchWholeWordsOnlyAction->isChecked();
1428
bool regExp = _regExpAction->isChecked();
1429
bool hex = _hexAction->isChecked();
1432
QString hexcontent = _searchLineEdit->text();
1433
hexcontent.remove(QLatin1String("0x"));
1434
hexcontent.remove(' ');
1435
hexcontent.remove('\t');
1436
hexcontent.remove('\n');
1437
hexcontent.remove('\r');
1439
_searchHexQuery = QByteArray();
1441
if (hexcontent.length() & 1) {
1442
setColor(false, false);
1446
while (!hexcontent.isEmpty()) {
1447
QString hexData = hexcontent.left(2);
1448
hexcontent = hexcontent.mid(2);
1450
int c = hexData.toUInt(&ok, 16);
1452
setColor(false, false);
1455
_searchHexQuery.push_back((char) c);
1458
_searchQuery.setContent(_searchLineEdit->text(), caseSensitive, matchWholeWord, false, _textArea->codec()->name(), regExp);
1460
_searchIsForward = forward;
1461
_searchHexadecimal = hex;
1463
QTimer::singleShot(0, this, SLOT(slotSearchMore()));
1464
_searchInProgress = true;
1465
_searchProgressCounter = 3;
1467
enableActions(false);
1470
void Lister::enableActions(bool state)
1472
_actionSearch->setEnabled(state);
1473
_actionSearchNext->setEnabled(state);
1474
_actionSearchPrev->setEnabled(state);
1475
_actionJumpToPosition->setEnabled(state);
1478
void Lister::slotSearchMore()
1480
if (!_searchInProgress)
1483
updateProgressBar();
1484
if (!_searchIsForward)
1487
if (_searchPosition < 0 || _searchPosition >= _fileSize) {
1488
if (_restartFromBeginning)
1489
resetSearchPosition();
1496
int maxCacheSize = SEARCH_CACHE_CHARS;
1497
qint64 searchPos = _searchPosition;
1498
bool setPosition = true;
1499
if (!_searchIsForward) {
1500
qint64 origSearchPos = _searchPosition;
1501
searchPos -= maxCacheSize;
1502
if (searchPos <= 0) {
1504
_searchPosition = 0;
1505
setPosition = false;
1507
qint64 diff = origSearchPos - searchPos;
1508
if (diff < maxCacheSize)
1509
maxCacheSize = diff;
1512
char * cache = cacheRef(searchPos, maxCacheSize);
1513
if (cache == 0 || maxCacheSize == 0) {
1518
qint64 foundAnchor = -1;
1519
qint64 foundCursor = -1;
1522
if (_searchHexadecimal) {
1523
QByteArray cacheItems(cache, maxCacheSize);
1524
int ndx = _searchIsForward ? cacheItems.indexOf(_searchHexQuery) : cacheItems.lastIndexOf(_searchHexQuery);
1525
if (maxCacheSize > _searchHexQuery.length()) {
1526
if (_searchIsForward) {
1527
_searchPosition = searchPos + maxCacheSize;
1528
if ((_searchPosition < _fileSize) && (maxCacheSize > _searchHexQuery.length()))
1529
_searchPosition -= _searchHexQuery.length();
1530
cnt = _searchPosition - searchPos;
1532
if (_searchPosition > 0)
1533
_searchPosition += _searchHexQuery.length();
1537
foundAnchor = searchPos + ndx;
1538
foundCursor = foundAnchor + _searchHexQuery.length();
1541
QTextCodec * textCodec = _textArea->codec();
1542
QTextDecoder * decoder = textCodec->makeDecoder();
1548
while (cnt < maxCacheSize) {
1549
QString chr = decoder->toUnicode(cache + (cnt++), 1);
1550
if (!chr.isEmpty() || cnt >= maxCacheSize) {
1554
if (chr == "\n" || row.length() >= SEARCH_MAX_ROW_LEN || cnt >= maxCacheSize) {
1556
_searchPosition = searchPos + cnt;
1557
if (!_searchIsForward) {
1559
setPosition = false;
1563
if (_searchQuery.checkLine(row, !_searchIsForward)) {
1564
QByteArray cachedBuffer(cache + rowStart, maxCacheSize - rowStart);
1566
QTextStream stream(&cachedBuffer);
1567
stream.setCodec(textCodec);
1569
stream.read(_searchQuery.matchIndex());
1570
foundAnchor = searchPos + rowStart + stream.pos();
1572
stream.read(_searchQuery.matchLength());
1573
foundCursor = searchPos + rowStart + stream.pos();
1575
if (_searchIsForward)
1588
if (foundAnchor != -1 && foundCursor != -1) {
1589
_textArea->setAnchorAndCursor(foundAnchor, foundCursor);
1594
if (_searchIsForward && searchPos + cnt >= _fileSize) {
1595
if (_restartFromBeginning)
1596
resetSearchPosition();
1601
} else if (_searchPosition <= 0 || _searchPosition >= _fileSize) {
1602
if (_restartFromBeginning)
1603
resetSearchPosition();
1610
QTimer::singleShot(0, this, SLOT(slotSearchMore()));
1613
void Lister::resetSearchPosition()
1615
_restartFromBeginning = false;
1616
_searchPosition = _searchIsForward ? 0 : _fileSize - 1;
1619
void Lister::searchSucceeded()
1621
_searchInProgress = false;
1622
setColor(true, false);
1624
_searchLastFailedPosition = -1;
1626
enableActions(true);
1629
void Lister::searchFailed()
1631
_searchInProgress = false;
1632
setColor(false, false);
1635
_searchLastFailedPosition = _textArea->getCursorPosition(isfirst);
1636
if (!_searchIsForward)
1637
_searchLastFailedPosition--;
1639
enableActions(true);
1642
void Lister::searchDelete()
1644
_searchInProgress = false;
1645
setColor(false, true);
1647
_searchLastFailedPosition = -1;
1649
enableActions(true);
1652
void Lister::searchTextChanged()
1655
if (_fileSize < 0x10000) { // autosearch files less than 64k
1656
if (!_searchLineEdit->text().isEmpty()) {
1658
qint64 anchor = _textArea->getCursorAnchor();
1659
qint64 cursor = _textArea->getCursorPosition(isfirst);
1660
if (cursor > anchor && anchor != -1) {
1661
_textArea->setCursorPosition(anchor, true);
1668
void Lister::setColor(bool match, bool restore)
1673
KConfigGroup gc(krConfig, "Colors");
1675
QString foreground, background;
1678
foreground = "Quicksearch Match Foreground";
1679
background = "Quicksearch Match Background";
1681
back = QColor(192, 255, 192);
1683
foreground = "Quicksearch Non-match Foreground";
1684
background = "Quicksearch Non-match Background";
1686
back = QColor(255, 192, 192);
1689
if (gc.readEntry(foreground, QString()) == "KDE default")
1690
fore = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color();
1691
else if (!gc.readEntry(foreground, QString()).isEmpty())
1692
fore = gc.readEntry(foreground, fore);
1694
if (gc.readEntry(background, QString()) == "KDE default")
1695
back = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
1696
else if (!gc.readEntry(background, QString()).isEmpty())
1697
back = gc.readEntry(background, back);
1699
back = _originalBackground;
1700
fore = _originalForeground;
1703
QPalette pal = _searchLineEdit->palette();
1704
pal.setColor(QPalette::Base, back);
1705
pal.setColor(QPalette::Text, fore);
1706
_searchLineEdit->setPalette(pal);
1709
void Lister::hideProgressBar()
1711
if (!_searchProgressBar->isHidden()) {
1712
_searchProgressBar->hide();
1713
_searchStopButton->hide();
1714
_searchLineEdit->show();
1715
_searchNextButton->show();
1716
_searchPrevButton->show();
1717
_searchOptions->show();
1718
_listerLabel->setText(i18n("Search:"));
1722
void Lister::updateProgressBar()
1724
if (_searchProgressCounter)
1727
if (_searchProgressBar->isHidden()) {
1728
_searchProgressBar->show();
1729
_searchStopButton->show();
1730
_searchOptions->hide();
1731
_searchLineEdit->hide();
1732
_searchNextButton->hide();
1733
_searchPrevButton->hide();
1734
_listerLabel->setText(i18n("Search position:"));
1737
qint64 pcnt = (_fileSize == 0) ? 1000 : (2001 * _searchPosition) / _fileSize / 2;
1738
int pctInt = (int)pcnt;
1739
if (_searchProgressBar->value() != pctInt)
1740
_searchProgressBar->setValue(pctInt);
1743
void Lister::jumpToPosition()
1746
QString res = KInputDialog::getText(i18n("Jump to position"), i18n("Text position:"), "0",
1751
res = res.trimmed();
1753
if (res.startsWith(QLatin1String("0x"))) {
1756
qulonglong upos = res.toULongLong(&ok, 16);
1758
KMessageBox::error(_textArea, i18n("Invalid number!"), i18n("Jump to position"));
1764
qulonglong upos = res.toULongLong(&ok);
1766
KMessageBox::error(_textArea, i18n("Invalid number!"), i18n("Jump to position"));
1772
if (pos < 0 || pos > _fileSize) {
1773
KMessageBox::error(_textArea, i18n("Number out of range!"), i18n("Jump to position"));
1777
_textArea->deleteAnchor();
1778
_textArea->setCursorPosition(pos, true);
1779
_textArea->ensureVisibleCursor();
1782
void Lister::saveAs()
1784
KUrl url = KFileDialog::getSaveUrl(KUrl(), QString(), _textArea, i18n("Lister"));
1789
sourceUrl = KUrl(_filePath);
1791
sourceUrl = this->url();
1794
urlList << sourceUrl;
1796
KIO::Job *job = KIO::copy(urlList, url);
1797
job->setUiDelegate(new KIO::JobUiDelegate());
1798
KIO::getJobTracker()->registerJob(job);
1799
job->ui()->setAutoErrorHandlingEnabled(true);
1802
void Lister::saveSelected()
1805
qint64 start = _textArea->getCursorAnchor();
1806
qint64 end = _textArea->getCursorPosition(isfirst);
1807
if (start == -1 || start == end) {
1808
KMessageBox::error(_textArea, i18n("Nothing is selected!"), i18n("Save selection..."));
1812
_savePosition = end;
1815
_savePosition = start;
1819
KUrl url = KFileDialog::getSaveUrl(KUrl(), QString(), _textArea, i18n("Lister"));
1823
KIO::Job *saveJob = KIO::put(url, -1, KIO::Overwrite);
1824
connect(saveJob, SIGNAL(dataReq(KIO::Job *, QByteArray &)),
1825
this, SLOT(slotDataSend(KIO::Job *, QByteArray &)));
1826
connect(saveJob, SIGNAL(result(KJob*)),
1827
this, SLOT(slotSendFinished(KJob *)));
1829
saveJob->setUiDelegate(new KIO::JobUiDelegate());
1830
KIO::getJobTracker()->registerJob(saveJob);
1831
saveJob->ui()->setAutoErrorHandlingEnabled(true);
1833
_actionSaveSelected->setEnabled(false);
1836
void Lister::slotDataSend(KIO::Job *, QByteArray &array)
1838
if (_savePosition >= _saveEnd) {
1839
array = QByteArray();
1842
qint64 max = _saveEnd - _savePosition;
1845
int maxBytes = (int)max;
1846
char * cache = cacheRef(_savePosition, maxBytes);
1847
_savePosition += maxBytes;
1849
array = QByteArray(cache, maxBytes);
1852
void Lister::slotSendFinished(KJob *)
1854
_actionSaveSelected->setEnabled(true);
1857
void Lister::setCharacterSet(QString set)
1859
_characterSet = set;
1860
_textArea->redrawTextArea(true);
1863
void Lister::print()
1866
qint64 anchor = _textArea->getCursorAnchor();
1867
qint64 cursor = _textArea->getCursorPosition(isfirst);
1868
bool hasSelection = (anchor != -1 && anchor != cursor);
1870
QString docName = url().fileName();
1872
printer.setDocName(docName);
1874
QPointer<QPrintDialog> printDialog = new QPrintDialog(&printer, _textArea);
1877
printDialog->addEnabledOption(QAbstractPrintDialog::PrintSelection);
1879
if (printDialog->exec()) {
1880
if (printer.pageOrder() == QPrinter::LastPageFirst) {
1881
switch (KMessageBox::warningContinueCancel(_textArea,
1882
i18n("Reverse printing is not supported. Continue with normal printing?"))) {
1883
case KMessageBox::Continue :
1890
painter.begin(&printer);
1892
QDate date = QDate::currentDate();
1893
QString dateString = date.toString(Qt::SystemLocaleShortDate);
1895
QRect pageRect = printer.pageRect();
1896
QRect drawingRect(0, 0, pageRect.width(), pageRect.height());
1898
QFont normalFont = KGlobalSettings::generalFont();
1899
QFont fixedFont = KGlobalSettings::fixedFont();
1901
QFontMetrics fmNormal(normalFont);
1902
int normalFontHeight = fmNormal.height();
1904
QFontMetrics fmFixed(fixedFont);
1905
int fixedFontHeight = fmFixed.height();
1906
int fixedFontWidth = fmFixed.width("W");
1907
if (fixedFontHeight <= 0)
1908
fixedFontHeight = 1;
1909
if (fixedFontWidth <= 0)
1912
int effPageSize = drawingRect.height() - normalFontHeight - 1;
1913
int rowsPerPage = effPageSize / fixedFontHeight;
1914
if (rowsPerPage <= 0)
1916
int columnsPerPage = drawingRect.width() / fixedFontWidth;
1917
if (columnsPerPage <= 0)
1920
bool firstPage = true;
1922
qint64 startPos = 0;
1923
qint64 endPos = _fileSize;
1924
if (printer.printRange() == QPrinter::Selection) {
1925
if (anchor > cursor)
1926
startPos = cursor, endPos = anchor;
1928
startPos = anchor, endPos = cursor;
1931
for (int page = 1;; ++page) {
1932
QStringList rows = readLines(startPos, endPos, columnsPerPage, rowsPerPage);
1934
bool visible = true;
1935
if (printer.fromPage() && page < printer.fromPage())
1937
if (printer.toPage() && printer.toPage() >= printer.fromPage() && page > printer.toPage())
1944
// Use the painter to draw on the page.
1945
painter.setFont(normalFont);
1947
painter.drawText(drawingRect, Qt::AlignLeft, dateString);
1948
painter.drawText(drawingRect, Qt::AlignHCenter, docName);
1949
painter.drawText(drawingRect, Qt::AlignRight, QString("%1").arg(page));
1951
painter.drawLine(0, normalFontHeight, drawingRect.width(), normalFontHeight);
1953
painter.setFont(fixedFont);
1954
int yoffset = normalFontHeight + 1;
1955
foreach(const QString &row, rows) {
1956
painter.drawText(0, yoffset + fixedFontHeight, row);
1957
yoffset += fixedFontHeight;
1960
if (startPos >= endPos)
1968
QStringList Lister::readLines(qint64 &filePos, qint64 endPos, int columns, int lines)
1970
if (_textArea->hexMode())
1971
return readHexLines(filePos, endPos, columns, lines);
1973
int maxBytes = columns * lines * MAX_CHAR_LENGTH;
1974
if (maxBytes > (endPos - filePos))
1975
maxBytes = (int)(endPos - filePos);
1978
char * cache = cacheRef(filePos, maxBytes);
1979
if (cache == 0 || maxBytes == 0)
1982
QTextCodec * textCodec = _textArea->codec();
1983
QTextDecoder * decoder = textCodec->makeDecoder();
1988
bool isLastLongLine = false;
1989
while (cnt < maxBytes && y < lines) {
1990
QString chr = decoder->toUnicode(cache + (cnt++), 1);
1991
if (!chr.isEmpty()) {
1992
if ((chr[ 0 ] < 32) && (chr[ 0 ] != '\n') && (chr[ 0 ] != '\t'))
1995
if (!isLastLongLine) {
2000
isLastLongLine = false;
2002
isLastLongLine = false;
2004
int tabLength = _textArea->tabWidth() - (row.length() % _textArea->tabWidth());
2005
if (row.length() + tabLength > columns) {
2010
row += QString(tabLength, QChar(' '));
2014
if (row.length() >= columns) {
2018
isLastLongLine = true;
2033
int Lister::hexPositionDigits()
2035
int positionDigits = 0;
2036
qint64 checker = _fileSize;
2041
if (positionDigits < 8)
2043
return positionDigits;
2046
int Lister::hexBytesPerLine(int columns)
2048
int positionDigits = hexPositionDigits();
2049
int bytesPerRow = 8;
2050
if (columns >= positionDigits + 5 + 64)
2052
if (columns >= positionDigits + 5 + 128)
2058
QStringList Lister::readHexLines(qint64 &filePos, qint64 endPos, int columns, int lines)
2060
int positionDigits = hexPositionDigits();
2061
int bytesPerRow = hexBytesPerLine(columns);
2065
qint64 choppedPos = (filePos / bytesPerRow) * bytesPerRow;
2066
int maxBytes = bytesPerRow * lines;
2067
if (maxBytes > (endPos - choppedPos))
2068
maxBytes = (int)(endPos - choppedPos);
2072
char * cache = cacheRef(choppedPos, maxBytes);
2074
if (cache == 0 || maxBytes == 0)
2078
for (int l = 0; l < lines; l++) {
2079
if (filePos >= endPos)
2081
qint64 printPos = (filePos / bytesPerRow) * bytesPerRow;
2083
pos.setNum(printPos, 16);
2084
while (pos.length() < positionDigits)
2085
pos = QString("0") + pos;
2086
pos = QString("0x") + pos;
2087
pos += QString(": ");
2091
for (int i = 0; i != bytesPerRow; i++, cnt++) {
2092
qint64 currentPos = printPos + i;
2093
if (currentPos < filePos || currentPos >= endPos) {
2094
pos += QString(" ");
2095
charData += QString(" ");
2097
char c = cache[ cnt ];
2098
int charCode = (int)c;
2102
hex.setNum(charCode, 16);
2103
if (hex.length() < 2)
2104
hex = QString("0") + hex;
2105
pos += hex + QString(" ");
2106
if (c < 32 || c >= 128)
2108
charData += QChar(c);
2112
pos += QString(" ") + charData;
2114
filePos = printPos + bytesPerRow;
2117
if (filePos > endPos)
2123
int Lister::hexIndexToPosition(int columns, int index)
2125
int positionDigits = hexPositionDigits();
2126
int bytesPerRow = hexBytesPerLine(columns);
2128
if (index >= bytesPerRow)
2129
index = bytesPerRow;
2131
return positionDigits + 4 + (3*index);
2134
int Lister::hexPositionToIndex(int columns, int position)
2136
int positionDigits = hexPositionDigits();
2137
int bytesPerRow = hexBytesPerLine(columns);
2139
position -= 4 + positionDigits;
2144
if (position >= bytesPerRow)
2149
void Lister::toggleHexMode()
2151
setHexMode(!_textArea->hexMode());
2154
void Lister::setHexMode(bool mode)
2157
_textArea->setHexMode(true);
2158
_actionHexMode->setText(i18n("Text mode"));
2160
_textArea->setHexMode(false);
2161
_actionHexMode->setText(i18n("Hex mode"));