~ubuntu-branches/ubuntu/precise/krusader/precise

« back to all changes in this revision

Viewing changes to krusader/KViewer/lister.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Scott Kitterman
  • Date: 2010-05-05 22:26:37 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100505222637-ydv3cwjwy365on2r
Tags: 1:2.1.0~beta1-1ubuntu1
* Merge from Debian Unstable.  Remaining changes:
  - Retain Kubuntu doc path

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                         lister.cpp  -  description
 
3
                             -------------------
 
4
    copyright            : (C) 2009 + by Csaba Karai
 
5
    e-mail               : krusader@users.sourceforge.net
 
6
    web site             : http://krusader.sourceforge.net
 
7
 ---------------------------------------------------------------------------
 
8
  Description
 
9
 ***************************************************************************
 
10
 
 
11
  A
 
12
 
 
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
 
19
 
 
20
                                                     S o u r c e    F i l e
 
21
 
 
22
 ***************************************************************************
 
23
 *                                                                         *
 
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.                                   *
 
28
 *                                                                         *
 
29
 ***************************************************************************/
 
30
 
 
31
#include "lister.h"
 
32
 
 
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>
 
54
 
 
55
#include <kuiserverjobtracker.h>
 
56
#include <KColorScheme>
 
57
#include <KTemporaryFile>
 
58
#include <KMessageBox>
 
59
#include <KActionCollection>
 
60
#include <KInputDialog>
 
61
#include <KFileDialog>
 
62
#include <KLocale>
 
63
#include <KGlobalSettings>
 
64
#include <KCharsets>
 
65
#include <KIO/Job>
 
66
#include <KIO/CopyJob>
 
67
#include <KIO/JobUiDelegate>
 
68
 
 
69
#include "../krusader.h"
 
70
#include "../GUI/krremoteencodingmenu.h"
 
71
 
 
72
#define  SEARCH_CACHE_CHARS 100000
 
73
#define  SEARCH_MAX_ROW_LEN 4000
 
74
#define  CONTROL_CHAR       752
 
75
#define  CACHE_SIZE         100000
 
76
 
 
77
ListerTextArea::ListerTextArea(Lister *lister, QWidget *parent) : KTextEdit(parent), _lister(lister),
 
78
        _sizeX(-1), _sizeY(-1), _cursorAnchorPos(-1), _inSliderOp(false), _inCursorUpdate(false), _hexMode(false)
 
79
{
 
80
    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(slotCursorPositionChanged()));
 
81
    _tabWidth = 4;
 
82
    setWordWrapMode(QTextOption::NoWrap);
 
83
    setLineWrapMode(QTextEdit::NoWrap);
 
84
}
 
85
 
 
86
void ListerTextArea::reset()
 
87
{
 
88
    _screenStartPos = 0;
 
89
    _cursorPos = 0;
 
90
    _cursorAnchorPos = -1;
 
91
    _cursorAtFirstColumn = true;
 
92
    calculateText();
 
93
}
 
94
 
 
95
void ListerTextArea::sizeChanged()
 
96
{
 
97
    if (_cursorAnchorPos > _lister->fileSize())
 
98
        _cursorAnchorPos = -1;
 
99
    if (_cursorPos > _lister->fileSize())
 
100
        _cursorPos = _lister->fileSize();
 
101
 
 
102
    redrawTextArea(true);
 
103
}
 
104
 
 
105
void ListerTextArea::resizeEvent(QResizeEvent * event)
 
106
{
 
107
    KTextEdit::resizeEvent(event);
 
108
    redrawTextArea();
 
109
}
 
110
 
 
111
void ListerTextArea::calculateText(bool forcedUpdate)
 
112
{
 
113
    QFontMetrics fm(font());
 
114
 
 
115
    int fontHeight = fm.height();
 
116
    if (fontHeight < 1)
 
117
        fontHeight = 1;
 
118
 
 
119
    QRect crect = viewport()->contentsRect();
 
120
    int windowHeight = crect.height();
 
121
 
 
122
    int sizeY = windowHeight / fontHeight;
 
123
    _pageSize = sizeY;
 
124
 
 
125
    QList<qint64> rowStarts;
 
126
 
 
127
    int fontWidth = fm.width("W");
 
128
    if (fontWidth < 1)
 
129
        fontWidth = 1;
 
130
    int windowWidth = crect.width() - fontWidth / 2;
 
131
    if (windowWidth < 1)
 
132
        windowWidth = 0;
 
133
 
 
134
    setTabStopWidth(fontWidth * _tabWidth);
 
135
 
 
136
    int sizeX = windowWidth / fontWidth;
 
137
 
 
138
    _sizeChanged = (_sizeY != sizeY) || (_sizeX != sizeX) || forcedUpdate;
 
139
    _sizeY = sizeY;
 
140
    _sizeX = sizeX;
 
141
 
 
142
    QStringList list = readLines(_screenStartPos, _screenEndPos, _sizeY, &rowStarts);
 
143
 
 
144
    if (_sizeChanged) {
 
145
        _averagePageSize = _screenEndPos - _screenStartPos;
 
146
        setUpScrollBar();
 
147
    }
 
148
 
 
149
    rowStarts << _screenEndPos;
 
150
 
 
151
    QStringList listRemn = readLines(_screenEndPos, _screenEndPos, 1);
 
152
    list << listRemn;
 
153
 
 
154
    if (list != _rowContent) {
 
155
        setPlainText(list.join("\n"));
 
156
        _rowContent = list;
 
157
        _rowStarts = rowStarts;
 
158
    }
 
159
}
 
160
 
 
161
qint64 ListerTextArea::textToFilePosition(int x, int y, bool &isfirst)
 
162
{
 
163
    isfirst = (x == 0);
 
164
    if (y >= _rowStarts.count())
 
165
        return -1;
 
166
    qint64 rowStart = _rowStarts[ y ];
 
167
    if (x == 0)
 
168
        return rowStart;
 
169
 
 
170
    if (_hexMode) {
 
171
        qint64 pos = rowStart + _lister->hexPositionToIndex(_sizeX, x);
 
172
        if (pos > _lister->fileSize())
 
173
            pos = _lister->fileSize();
 
174
        return pos;
 
175
    }
 
176
 
 
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);
 
181
 
 
182
    QTextStream stream(&cachedBuffer);
 
183
    stream.setCodec(codec());
 
184
    stream.read(x);
 
185
    return rowStart + stream.pos();
 
186
}
 
187
 
 
188
void ListerTextArea::fileToTextPosition(qint64 p, bool isfirst, int &x, int &y)
 
189
{
 
190
    if (p < _screenStartPos || p > _screenEndPos || _rowStarts.count() < 1) {
 
191
        x = -1;
 
192
        y = (p > _screenEndPos) ? -2 : -1;
 
193
    } else {
 
194
        y = 0;
 
195
        while (y < _rowStarts.count() && _rowStarts[ y ] <= p)
 
196
            y++;
 
197
        y--;
 
198
        if (y < 0) {
 
199
            x = y = -1;
 
200
            return;
 
201
        }
 
202
 
 
203
        qint64 rowStart = _rowStarts[ y ];
 
204
        if (_hexMode) {
 
205
            x = _lister->hexIndexToPosition(_sizeX, (int)(p - rowStart));
 
206
            return;
 
207
        }
 
208
 
 
209
        int maxBytes = 2 * _sizeX * MAX_CHAR_LENGTH;
 
210
        x = 0;
 
211
        if (rowStart >= p) {
 
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);
 
216
 
 
217
                QTextStream stream(&cachedBuffer);
 
218
                stream.setCodec(codec());
 
219
                stream.read(_rowContent[ y - 1].length());
 
220
                if (previousRow + stream.pos() == p) {
 
221
                    y--;
 
222
                    x = _rowContent[ y ].length();
 
223
                }
 
224
            }
 
225
            return;
 
226
        }
 
227
 
 
228
        char * cache = _lister->cacheRef(rowStart, maxBytes);
 
229
        QByteArray cachedBuffer(cache, p - rowStart);
 
230
 
 
231
        QString res = codec()->toUnicode(cachedBuffer);
 
232
        x = res.length();
 
233
    }
 
234
}
 
235
 
 
236
void ListerTextArea::getCursorPosition(int &x, int &y)
 
237
{
 
238
    getScreenPosition(textCursor().position(), x, y);
 
239
}
 
240
 
 
241
void ListerTextArea::getScreenPosition(int position, int &x, int &y)
 
242
{
 
243
    x = position;
 
244
    y = 0;
 
245
    for (int i = 0; i < _rowContent.count(); i++) {
 
246
        int rowLen = _rowContent[ i ].length() + 1;
 
247
        if (x >= rowLen) {
 
248
            x -= rowLen;
 
249
            y++;
 
250
        } else
 
251
            break;
 
252
    }
 
253
}
 
254
 
 
255
void ListerTextArea::setCursorPosition(int x, int y, int anchorX, int anchorY)
 
256
{
 
257
    _inCursorUpdate = true;
 
258
    if (x == -1 || y < 0) {
 
259
        setCursorWidth(0);
 
260
        if (anchorY == -1) {
 
261
            _inCursorUpdate = false;
 
262
            return;
 
263
        }
 
264
 
 
265
        if (y == -2) {
 
266
            y = _sizeY;
 
267
            x = (_rowContent.count() > _sizeY) ? _rowContent[ _sizeY ].length() : 0;
 
268
        } else
 
269
            x = y = 0;
 
270
    } else
 
271
        setCursorWidth(2);
 
272
 
 
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);
 
278
        } else {
 
279
            moveCursor(QTextCursor::Start, mode);
 
280
            for (int i = 0; i < anchorY; i++)
 
281
                moveCursor(QTextCursor::Down, mode);
 
282
        }
 
283
 
 
284
        if (_rowContent.count() > anchorY && anchorX > _rowContent[ anchorY ].length())
 
285
            anchorX = _rowContent[ anchorY ].length();
 
286
 
 
287
        for (int j = 0; j < anchorX; j++)
 
288
            moveCursor(QTextCursor::Right, mode);
 
289
 
 
290
        mode = QTextCursor::KeepAnchor;
 
291
    }
 
292
 
 
293
    if (y >= _sizeY) {
 
294
        moveCursor(QTextCursor::End, mode);
 
295
        moveCursor(QTextCursor::StartOfLine, mode);
 
296
    } else {
 
297
        moveCursor(QTextCursor::Start, mode);
 
298
        for (int i = 0; i < y; i++)
 
299
            moveCursor(QTextCursor::Down, mode);
 
300
    }
 
301
 
 
302
    if (_rowContent.count() > y && x > _rowContent[ y ].length())
 
303
        x = _rowContent[ y ].length();
 
304
 
 
305
    for (int j = 0; j < x; j++)
 
306
        moveCursor(QTextCursor::Right, mode);
 
307
 
 
308
    _inCursorUpdate = false;
 
309
}
 
310
 
 
311
qint64 ListerTextArea::getCursorPosition(bool &isfirst)
 
312
{
 
313
    if (cursorWidth() == 0) {
 
314
        isfirst = _cursorAtFirstColumn;
 
315
        return _cursorPos;
 
316
    }
 
317
 
 
318
    int x, y;
 
319
    getCursorPosition(x, y);
 
320
    return textToFilePosition(x, y, isfirst);
 
321
}
 
322
 
 
323
void ListerTextArea::setCursorPosition(qint64 p, bool isfirst)
 
324
{
 
325
    _cursorPos = p;
 
326
    int x, y;
 
327
    fileToTextPosition(p, isfirst, x, y);
 
328
 
 
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;
 
335
            anchorY = -2;
 
336
            anchorAbove = true;
 
337
        }
 
338
        if (anchPos > _screenEndPos) {
 
339
            anchPos = _screenEndPos;
 
340
            anchorY = -3;
 
341
            anchorBelow = true;
 
342
        }
 
343
 
 
344
        fileToTextPosition(anchPos, isfirst, anchorX, anchorY);
 
345
        if (anchorAbove && _hexMode)
 
346
            anchorX = 0;
 
347
        if (anchorBelow && _hexMode && _rowContent.count() > 0)
 
348
            anchorX = _rowContent[ 0 ].length();
 
349
    }
 
350
    setCursorPosition(x, y, anchorX, anchorY);
 
351
}
 
352
 
 
353
void ListerTextArea::slotCursorPositionChanged()
 
354
{
 
355
    if (_inCursorUpdate)
 
356
        return;
 
357
    int cursorX, cursorY;
 
358
    getCursorPosition(cursorX, cursorY);
 
359
    _cursorAtFirstColumn = (cursorX == 0);
 
360
    _cursorPos = textToFilePosition(cursorX, cursorY, _cursorAtFirstColumn);
 
361
    setCursorWidth(2);
 
362
    //fprintf( stderr, "Cursor pos: %d %d %Ld\n", cursorX, cursorY, _cursorPos );
 
363
}
 
364
 
 
365
QString ListerTextArea::readSection(qint64 p1, qint64 p2)
 
366
{
 
367
    if (p1 == p2)
 
368
        return QString();
 
369
 
 
370
    if (p1 > p2) {
 
371
        qint64 tmp = p1;
 
372
        p1 = p2;
 
373
        p2 = tmp;
 
374
    }
 
375
 
 
376
    QString section;
 
377
    qint64 pos = p1;
 
378
 
 
379
    if (_hexMode) {
 
380
        while (p1 != p2) {
 
381
            QStringList list = _lister->readHexLines(p1, p2, _sizeX, 1);
 
382
            if (list.count() == 0)
 
383
                break;
 
384
            if (!section.isEmpty())
 
385
                section += QChar('\n');
 
386
            section += list[ 0 ];
 
387
        }
 
388
        return section;
 
389
    }
 
390
 
 
391
    QTextCodec * textCodec = codec();
 
392
    QTextDecoder * decoder = textCodec->makeDecoder();
 
393
 
 
394
    do {
 
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)
 
400
            break;
 
401
        section += decoder->toUnicode(cache, maxBytes);
 
402
        pos += maxBytes;
 
403
    } while (pos < p2);
 
404
 
 
405
    delete decoder;
 
406
    return section;
 
407
}
 
408
 
 
409
QStringList ListerTextArea::readLines(qint64 filePos, qint64 &endPos, int lines, QList<qint64> * locs)
 
410
{
 
411
    endPos = filePos;
 
412
    QStringList list;
 
413
 
 
414
    if (_hexMode) {
 
415
        endPos = _lister->fileSize();
 
416
        if (filePos >= endPos)
 
417
            return list;
 
418
        qint64 startPos = filePos;
 
419
        int bytes = _lister->hexBytesPerLine(_sizeX);
 
420
        filePos = startPos = ((startPos) / bytes) * bytes;
 
421
        list = _lister->readHexLines(filePos, endPos, _sizeX, lines);
 
422
        endPos = filePos;
 
423
        if (locs) {
 
424
            for (int i = 0; i != list.count(); i++) {
 
425
                (*locs) << startPos;
 
426
                startPos += bytes;
 
427
            }
 
428
        }
 
429
        return list;
 
430
    }
 
431
 
 
432
    int maxBytes = _sizeX * _sizeY * MAX_CHAR_LENGTH;
 
433
    char * cache = _lister->cacheRef(filePos, maxBytes);
 
434
    if (cache == 0 || maxBytes == 0)
 
435
        return list;
 
436
 
 
437
    QTextCodec * textCodec = codec();
 
438
    QTextDecoder * decoder = textCodec->makeDecoder();
 
439
 
 
440
    int cnt = 0;
 
441
    int y = 0;
 
442
    QString row = "";
 
443
    int effLength = 0;
 
444
    if (locs)
 
445
        (*locs) << filePos;
 
446
    bool isLastLongLine = false;
 
447
    while (cnt < maxBytes && y < lines) {
 
448
        int lastCnt = cnt;
 
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);
 
453
            if (chr == "\n") {
 
454
                if (!isLastLongLine) {
 
455
                    list << row;
 
456
                    effLength = 0;
 
457
                    row = "";
 
458
                    y++;
 
459
                    if (locs)
 
460
                        (*locs) << filePos + cnt;
 
461
                }
 
462
                isLastLongLine = false;
 
463
            } else {
 
464
                isLastLongLine = false;
 
465
                if (chr == "\t") {
 
466
                    effLength += _tabWidth - (effLength % _tabWidth) - 1;
 
467
                    if (effLength > _sizeX) {
 
468
                        list << row;
 
469
                        effLength = 0;
 
470
                        row = "";
 
471
                        y++;
 
472
                        if (locs)
 
473
                            (*locs) << filePos + lastCnt;
 
474
                    }
 
475
                }
 
476
                row += chr;
 
477
                effLength++;
 
478
                if (effLength >= _sizeX) {
 
479
                    list << row;
 
480
                    effLength = 0;
 
481
                    row = "";
 
482
                    y++;
 
483
                    if (locs)
 
484
                        (*locs) << filePos + cnt;
 
485
                    isLastLongLine = true;
 
486
                }
 
487
            }
 
488
        }
 
489
    }
 
490
 
 
491
    if (y < lines)
 
492
        list << row;
 
493
 
 
494
    if (locs) {
 
495
        while (locs->count() > lines) {
 
496
            locs->removeLast();
 
497
        }
 
498
    }
 
499
 
 
500
    endPos = filePos + cnt;
 
501
 
 
502
    delete decoder;
 
503
    return list;
 
504
}
 
505
 
 
506
QTextCodec * ListerTextArea::codec()
 
507
{
 
508
    QString cs = _lister->characterSet();
 
509
    if (cs.isEmpty())
 
510
        return QTextCodec::codecForLocale();
 
511
    else
 
512
        return KGlobal::charsets()->codecForName(cs);
 
513
}
 
514
 
 
515
void ListerTextArea::setUpScrollBar()
 
516
{
 
517
    if (_averagePageSize == _lister->fileSize()) {
 
518
        _lister->scrollBar()->setPageStep(0);
 
519
        _lister->scrollBar()->setMaximum(0);
 
520
        _lister->scrollBar()->hide();
 
521
        _lastPageStartPos = 0;
 
522
    } else {
 
523
        int maxPage = MAX_CHAR_LENGTH * _sizeX * _sizeY;
 
524
        qint64 pageStartPos = _lister->fileSize() - maxPage;
 
525
        qint64 endPos;
 
526
        if (pageStartPos < 0)
 
527
            pageStartPos = 0;
 
528
        QStringList list = readLines(pageStartPos, endPos, maxPage);
 
529
        if (list.count() <= _sizeY) {
 
530
            _lastPageStartPos = 0;
 
531
        } else {
 
532
            readLines(pageStartPos, _lastPageStartPos, list.count() - _sizeY);
 
533
        }
 
534
 
 
535
        int maximum = (_lastPageStartPos > SLIDER_MAX) ? SLIDER_MAX : _lastPageStartPos;
 
536
        int pageSize = (_lastPageStartPos > SLIDER_MAX) ? SLIDER_MAX * _averagePageSize / _lastPageStartPos : _averagePageSize;
 
537
        if (pageSize == 0)
 
538
            pageSize++;
 
539
 
 
540
        _lister->scrollBar()->setPageStep(pageSize);
 
541
        _lister->scrollBar()->setMaximum(maximum);
 
542
        _lister->scrollBar()->show();
 
543
    }
 
544
}
 
545
 
 
546
void ListerTextArea::keyPressEvent(QKeyEvent * ke)
 
547
{
 
548
    if (Krusader::actCopy->shortcut().contains(QKeySequence(ke->key() | ke->modifiers()))) {
 
549
        copySelectedToClipboard();
 
550
        ke->accept();
 
551
        return;
 
552
    }
 
553
 
 
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;
 
560
        }
 
561
 
 
562
        switch (ke->key()) {
 
563
        case Qt::Key_F3:
 
564
            ke->accept();
 
565
            if (ke->modifiers() == Qt::ShiftModifier)
 
566
                _lister->searchPrev();
 
567
            else
 
568
                _lister->searchNext();
 
569
            return;
 
570
        case Qt::Key_Home:
 
571
        case Qt::Key_End:
 
572
            _cursorAnchorPos = newAnchor;
 
573
            break;
 
574
        case Qt::Key_Left: {
 
575
            _cursorAnchorPos = newAnchor;
 
576
            ensureVisibleCursor();
 
577
            int x, y;
 
578
            getCursorPosition(x, y);
 
579
            if (y == 0 && x == 0)
 
580
                slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
 
581
        }
 
582
        break;
 
583
        case Qt::Key_Right: {
 
584
            _cursorAnchorPos = newAnchor;
 
585
            ensureVisibleCursor();
 
586
            if (textCursor().position() == toPlainText().length())
 
587
                slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
 
588
        }
 
589
        break;
 
590
        case Qt::Key_Up: {
 
591
            _cursorAnchorPos = newAnchor;
 
592
            ensureVisibleCursor();
 
593
            int x, y;
 
594
            getCursorPosition(x, y);
 
595
            if (y == 0)
 
596
                slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
 
597
        }
 
598
        break;
 
599
        case Qt::Key_Down: {
 
600
            _cursorAnchorPos = newAnchor;
 
601
            ensureVisibleCursor();
 
602
            int x, y;
 
603
            getCursorPosition(x, y);
 
604
            if (y >= _sizeY)
 
605
                slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
 
606
        }
 
607
        break;
 
608
        case Qt::Key_PageDown: {
 
609
            _cursorAnchorPos = newAnchor;
 
610
            ensureVisibleCursor();
 
611
            ke->accept();
 
612
            int x, y;
 
613
            getCursorPosition(x, y);
 
614
            slotActionTriggered(QAbstractSlider::SliderPageStepAdd);
 
615
            y += _sizeY - _skippedLines;
 
616
            if (y > _rowContent.count()) {
 
617
                y = _rowContent.count();
 
618
                if (y > 0)
 
619
                    x = _rowContent[ y - 1 ].length();
 
620
                else
 
621
                    x = 0;
 
622
            }
 
623
            _cursorPos = textToFilePosition(x, y, _cursorAtFirstColumn);
 
624
            setCursorPosition(_cursorPos, _cursorAtFirstColumn);
 
625
        }
 
626
        return;
 
627
        case Qt::Key_PageUp: {
 
628
            _cursorAnchorPos = newAnchor;
 
629
            ensureVisibleCursor();
 
630
            ke->accept();
 
631
            int x, y;
 
632
            getCursorPosition(x, y);
 
633
            slotActionTriggered(QAbstractSlider::SliderPageStepSub);
 
634
            y -= _sizeY - _skippedLines;
 
635
            if (y < 0) {
 
636
                y = 0;
 
637
                x = 0;
 
638
            }
 
639
            _cursorPos = textToFilePosition(x, y, _cursorAtFirstColumn);
 
640
            setCursorPosition(_cursorPos, _cursorAtFirstColumn);
 
641
        }
 
642
        return;
 
643
        }
 
644
    }
 
645
    if (ke->modifiers() == Qt::ControlModifier) {
 
646
        switch (ke->key()) {
 
647
        case Qt::Key_G:
 
648
            ke->accept();
 
649
            _lister->jumpToPosition();
 
650
            return;
 
651
        case Qt::Key_F:
 
652
            ke->accept();
 
653
            _lister->enableSearch(true);
 
654
            return;
 
655
        case Qt::Key_Home:
 
656
            _cursorAnchorPos = -1;
 
657
            ke->accept();
 
658
            slotActionTriggered(QAbstractSlider::SliderToMinimum);
 
659
            setCursorPosition((qint64)0, true);
 
660
            return;
 
661
        case Qt::Key_A:
 
662
        case Qt::Key_End: {
 
663
            _cursorAnchorPos = (ke->key() == Qt::Key_A) ? 0 : -1;
 
664
            ke->accept();
 
665
            slotActionTriggered(QAbstractSlider::SliderToMaximum);
 
666
            qint64 endPos = _lister->fileSize();
 
667
            setCursorPosition(endPos, true);
 
668
            return;
 
669
        }
 
670
        case Qt::Key_Down:
 
671
            ke->accept();
 
672
            slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
 
673
            return;
 
674
        case Qt::Key_Up:
 
675
            ke->accept();
 
676
            slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
 
677
            return;
 
678
        case Qt::Key_PageDown:
 
679
            ke->accept();
 
680
            slotActionTriggered(QAbstractSlider::SliderPageStepAdd);
 
681
            return;
 
682
        case Qt::Key_PageUp:
 
683
            ke->accept();
 
684
            slotActionTriggered(QAbstractSlider::SliderPageStepSub);
 
685
            return;
 
686
        }
 
687
    }
 
688
    int oldAnchor = textCursor().anchor();
 
689
    KTextEdit::keyPressEvent(ke);
 
690
    handleAnchorChange(oldAnchor);
 
691
}
 
692
 
 
693
void ListerTextArea::mousePressEvent(QMouseEvent * e)
 
694
{
 
695
    _cursorAnchorPos = -1;
 
696
    int oldAnchor = textCursor().anchor();
 
697
    KTextEdit::mousePressEvent(e);
 
698
    handleAnchorChange(oldAnchor);
 
699
}
 
700
 
 
701
void ListerTextArea::mouseDoubleClickEvent(QMouseEvent * e)
 
702
{
 
703
    _cursorAnchorPos = -1;
 
704
    int oldAnchor = textCursor().anchor();
 
705
    KTextEdit::mouseDoubleClickEvent(e);
 
706
    handleAnchorChange(oldAnchor);
 
707
}
 
708
 
 
709
void ListerTextArea::mouseMoveEvent(QMouseEvent * e)
 
710
{
 
711
    if (e->pos().y() < 0) {
 
712
        slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
 
713
    } else if (e->pos().y() > height()) {
 
714
        slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
 
715
    }
 
716
    if (_cursorAnchorPos == -1)
 
717
        _cursorAnchorPos = _cursorPos;
 
718
    KTextEdit::mouseMoveEvent(e);
 
719
    if (_cursorAnchorPos == _cursorPos)
 
720
        _cursorAnchorPos = -1;
 
721
}
 
722
 
 
723
void ListerTextArea::wheelEvent(QWheelEvent * e)
 
724
{
 
725
    int delta = e->delta();
 
726
    if (delta) {
 
727
        if (delta > 0) {
 
728
            e->accept();
 
729
            while (delta > 0) {
 
730
                slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
 
731
                slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
 
732
                slotActionTriggered(QAbstractSlider::SliderSingleStepSub);
 
733
                delta -= 120;
 
734
            }
 
735
        } else {
 
736
            e->accept();
 
737
            while (delta < 0) {
 
738
                slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
 
739
                slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
 
740
                slotActionTriggered(QAbstractSlider::SliderSingleStepAdd);
 
741
                delta += 120;
 
742
            }
 
743
        }
 
744
    }
 
745
}
 
746
 
 
747
void ListerTextArea::slotActionTriggered(int action)
 
748
{
 
749
    switch (action) {
 
750
    case QAbstractSlider::SliderSingleStepAdd: {
 
751
        qint64 endPos;
 
752
        readLines(_screenStartPos, endPos, 1);
 
753
        if (endPos <= _lastPageStartPos) {
 
754
            _screenStartPos = endPos;
 
755
        }
 
756
    }
 
757
    break;
 
758
    case QAbstractSlider::SliderSingleStepSub: {
 
759
        if (_screenStartPos == 0)
 
760
            break;
 
761
 
 
762
        if (_hexMode) {
 
763
            int bytesPerRow = _lister->hexBytesPerLine(_sizeX);
 
764
            _screenStartPos = (_screenStartPos / bytesPerRow) * bytesPerRow;
 
765
            _screenStartPos -= bytesPerRow;
 
766
            if (_screenStartPos < 0)
 
767
                _screenStartPos = 0;
 
768
        } else {
 
769
            int maxSize = _sizeX * _sizeY * MAX_CHAR_LENGTH;
 
770
            QByteArray encodedEnter = codec()->fromUnicode(QString("\n"));
 
771
 
 
772
            qint64 readPos = _screenStartPos - maxSize;
 
773
            if (readPos < 0)
 
774
                readPos = 0;
 
775
            maxSize = _screenStartPos - readPos;
 
776
 
 
777
            char * cache = _lister->cacheRef(readPos, maxSize);
 
778
            QByteArray backBuffer(cache, maxSize);
 
779
 
 
780
            int from = maxSize;
 
781
            while (from > 0) {
 
782
                from--;
 
783
                from = backBuffer.lastIndexOf(encodedEnter, from);
 
784
                if (from == -1)
 
785
                    break;
 
786
                int backRef = from - 20;
 
787
                if (backRef < 0)
 
788
                    backRef = 0;
 
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();
 
794
                        break;
 
795
                    }
 
796
                }
 
797
            }
 
798
 
 
799
            if (from == -1)
 
800
                from = 0;
 
801
            readPos += from;
 
802
 
 
803
            qint64 previousPos = readPos;
 
804
 
 
805
            while (readPos < _screenStartPos) {
 
806
                previousPos = readPos;
 
807
                readLines(readPos, readPos, 1);
 
808
            }
 
809
 
 
810
            _screenStartPos = previousPos;
 
811
        }
 
812
    }
 
813
    break;
 
814
    case QAbstractSlider::SliderPageStepAdd: {
 
815
        _skippedLines = 0;
 
816
 
 
817
        qint64 endPos;
 
818
        for (int i = 0; i < _sizeY; i++) {
 
819
            readLines(_screenStartPos, endPos, 1);
 
820
            if (endPos <= _lastPageStartPos) {
 
821
                _screenStartPos = endPos;
 
822
                _skippedLines++;
 
823
            } else {
 
824
                break;
 
825
            }
 
826
        }
 
827
    }
 
828
    break;
 
829
    case QAbstractSlider::SliderPageStepSub: {
 
830
        _skippedLines = 0;
 
831
 
 
832
        if (_screenStartPos == 0)
 
833
            break;
 
834
 
 
835
        if (_hexMode) {
 
836
            int bytesPerRow = _lister->hexBytesPerLine(_sizeX);
 
837
            _screenStartPos = (_screenStartPos / bytesPerRow) * bytesPerRow;
 
838
            _screenStartPos -= _sizeY * bytesPerRow;
 
839
            if (_screenStartPos < 0)
 
840
                _screenStartPos = 0;
 
841
        } else {
 
842
            int maxSize = 2 * _sizeX * _sizeY * MAX_CHAR_LENGTH;
 
843
            QByteArray encodedEnter = codec()->fromUnicode(QString("\n"));
 
844
 
 
845
            qint64 readPos = _screenStartPos - maxSize;
 
846
            if (readPos < 0)
 
847
                readPos = 0;
 
848
            maxSize = _screenStartPos - readPos;
 
849
 
 
850
            char * cache = _lister->cacheRef(readPos, maxSize);
 
851
            QByteArray backBuffer(cache, maxSize);
 
852
 
 
853
            int sizeY = _sizeY + 1;
 
854
            int origSizeY = sizeY;
 
855
            int from = maxSize;
 
856
            int lastEnter = maxSize;
 
857
 
 
858
        repeat:     while (from > 0) {
 
859
                from--;
 
860
                from = backBuffer.lastIndexOf(encodedEnter, from);
 
861
                if (from == -1)
 
862
                    break;
 
863
                int backRef = from - 20;
 
864
                if (backRef < 0)
 
865
                    backRef = 0;
 
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);
 
873
                        if (sizeY < 0) {
 
874
                            from = arrayStart;
 
875
                            break;
 
876
                        }
 
877
                    }
 
878
                    lastEnter = from;
 
879
                }
 
880
            }
 
881
 
 
882
            if (from == -1)
 
883
                from = 0;
 
884
            qint64 searchPos = readPos + from;
 
885
 
 
886
            QList<qint64> locs;
 
887
            while (searchPos < _screenStartPos) {
 
888
                locs << searchPos;
 
889
                readLines(searchPos, searchPos, 1);
 
890
            }
 
891
 
 
892
            if (locs.count() >= _sizeY)
 
893
                _screenStartPos = locs[ locs.count() - _sizeY ];
 
894
            else if (from != 0) {
 
895
                origSizeY += locs.count() + 1;
 
896
                sizeY = origSizeY;
 
897
                goto repeat;
 
898
            } else if (readPos == 0)
 
899
                _screenStartPos = 0;
 
900
        }
 
901
    }
 
902
    break;
 
903
    case QAbstractSlider::SliderToMinimum:
 
904
        _screenStartPos = 0;
 
905
        break;
 
906
    case QAbstractSlider::SliderToMaximum:
 
907
        _screenStartPos = _lastPageStartPos;
 
908
        break;
 
909
    case QAbstractSlider::SliderMove: {
 
910
        if (_inSliderOp)  // self created call?
 
911
            return;
 
912
        qint64 pos = _lister->scrollBar()->sliderPosition();
 
913
 
 
914
        if (pos == SLIDER_MAX) {
 
915
            _screenStartPos = _lastPageStartPos;
 
916
            break;
 
917
        } else if (pos == 0) {
 
918
            _screenStartPos = 0;
 
919
            break;
 
920
        }
 
921
 
 
922
        if (_lastPageStartPos > SLIDER_MAX)
 
923
            pos = _lastPageStartPos * pos / SLIDER_MAX;
 
924
 
 
925
        if (pos != 0) {
 
926
            if (_hexMode) {
 
927
                int bytesPerRow = _lister->hexBytesPerLine(_sizeX);
 
928
                pos = (pos / bytesPerRow) * bytesPerRow;
 
929
            } else {
 
930
                int maxSize = _sizeX * _sizeY * MAX_CHAR_LENGTH;
 
931
                qint64 readPos = pos - maxSize;
 
932
                if (readPos < 0)
 
933
                    readPos = 0;
 
934
                qint64 previousPos = readPos;
 
935
 
 
936
                while (readPos <= pos) {
 
937
                    previousPos = readPos;
 
938
                    readLines(readPos, readPos, 1);
 
939
                }
 
940
 
 
941
                pos = previousPos;
 
942
            }
 
943
        }
 
944
 
 
945
        _screenStartPos = pos;
 
946
    }
 
947
    break;
 
948
    case QAbstractSlider::SliderNoAction:
 
949
        break;
 
950
    };
 
951
 
 
952
    _inSliderOp = true;
 
953
    int value = (_lastPageStartPos > SLIDER_MAX) ? SLIDER_MAX * _screenStartPos / _lastPageStartPos : _screenStartPos;
 
954
    _lister->scrollBar()->setSliderPosition(value);
 
955
    _inSliderOp = false;
 
956
 
 
957
    redrawTextArea();
 
958
}
 
959
 
 
960
void ListerTextArea::redrawTextArea(bool forcedUpdate)
 
961
{
 
962
    bool isfirst;
 
963
    qint64 pos = getCursorPosition(isfirst);
 
964
    calculateText(forcedUpdate);
 
965
    setCursorPosition(pos, isfirst);
 
966
}
 
967
 
 
968
void ListerTextArea::ensureVisibleCursor()
 
969
{
 
970
    if (_cursorPos < _screenStartPos || _cursorPos > _screenEndPos) {
 
971
        int delta = _sizeY / 2;
 
972
        if (delta == 0)
 
973
            delta++;
 
974
 
 
975
        qint64 newScreenStart = _cursorPos;
 
976
        while (delta) {
 
977
            int maxSize = _sizeX * MAX_CHAR_LENGTH;
 
978
            qint64 readPos = newScreenStart - maxSize;
 
979
            if (readPos < 0)
 
980
                readPos = 0;
 
981
 
 
982
            qint64 previousPos = readPos;
 
983
 
 
984
            while (readPos < newScreenStart) {
 
985
                previousPos = readPos;
 
986
                readLines(readPos, readPos, 1);
 
987
                if (readPos == previousPos)
 
988
                    break;
 
989
            }
 
990
 
 
991
            newScreenStart = previousPos;
 
992
            delta--;
 
993
        }
 
994
        if (newScreenStart > _lastPageStartPos)
 
995
            newScreenStart = _lastPageStartPos;
 
996
 
 
997
        _screenStartPos = newScreenStart;
 
998
        slotActionTriggered(QAbstractSlider::SliderNoAction);
 
999
    }
 
1000
}
 
1001
 
 
1002
void ListerTextArea::setAnchorAndCursor(qint64 anchor, qint64 cursor)
 
1003
{
 
1004
    _cursorAnchorPos = anchor;
 
1005
    setCursorPosition(cursor, false);
 
1006
    ensureVisibleCursor();
 
1007
}
 
1008
 
 
1009
void ListerTextArea::copySelectedToClipboard()
 
1010
{
 
1011
    if (_cursorAnchorPos != -1 && _cursorAnchorPos != _cursorPos) {
 
1012
        QString selection = readSection(_cursorAnchorPos, _cursorPos);
 
1013
        QApplication::clipboard()->setText(selection);
 
1014
    }
 
1015
}
 
1016
 
 
1017
void ListerTextArea::handleAnchorChange(int oldAnchor)
 
1018
{
 
1019
    int cursor = textCursor().position();
 
1020
    int anchor = textCursor().anchor();
 
1021
 
 
1022
    if (anchor == cursor) {
 
1023
        _cursorAnchorPos = -1;
 
1024
    } else {
 
1025
        if (oldAnchor != anchor) {
 
1026
            int x, y;
 
1027
            bool isfirst;
 
1028
            getScreenPosition(anchor, x, y);
 
1029
            _cursorAnchorPos = textToFilePosition(x, y, isfirst);
 
1030
        }
 
1031
    }
 
1032
}
 
1033
 
 
1034
void ListerTextArea::setHexMode(bool hexMode)
 
1035
{
 
1036
    bool isfirst;
 
1037
    qint64 pos = getCursorPosition(isfirst);
 
1038
    _hexMode = hexMode;
 
1039
    _screenStartPos = 0;
 
1040
    calculateText(true);
 
1041
    setCursorPosition(pos, isfirst);
 
1042
    ensureVisibleCursor();
 
1043
}
 
1044
 
 
1045
ListerBrowserExtension::ListerBrowserExtension(Lister * lister) : KParts::BrowserExtension(lister)
 
1046
{
 
1047
    _lister = lister;
 
1048
 
 
1049
    emit enableAction("copy", true);
 
1050
    emit enableAction("print", true);
 
1051
}
 
1052
 
 
1053
void ListerBrowserExtension::copy()
 
1054
{
 
1055
    _lister->textArea()->copySelectedToClipboard();
 
1056
}
 
1057
 
 
1058
void ListerBrowserExtension::print()
 
1059
{
 
1060
    _lister->print();
 
1061
}
 
1062
 
 
1063
class ListerEncodingMenu : public KrRemoteEncodingMenu
 
1064
{
 
1065
public:
 
1066
    ListerEncodingMenu(Lister *lister, const QString &text, const QString &icon, KActionCollection *parent) :
 
1067
            KrRemoteEncodingMenu(text, icon, parent), _lister(lister) {
 
1068
    }
 
1069
 
 
1070
protected:
 
1071
    virtual QString currentCharacterSet() {
 
1072
        return _lister->characterSet();
 
1073
    }
 
1074
 
 
1075
    virtual void chooseDefault() {
 
1076
        _lister->setCharacterSet(QString());
 
1077
    }
 
1078
 
 
1079
    virtual void chooseEncoding(QString encodingName) {
 
1080
        QString charset = KGlobal::charsets()->encodingForName(encodingName);
 
1081
        _lister->setCharacterSet(charset);
 
1082
    }
 
1083
 
 
1084
    Lister * _lister;
 
1085
};
 
1086
 
 
1087
Lister::Lister(QWidget *parent) : KParts::ReadOnlyPart(parent), _searchInProgress(false), _cache(0), _active(false), _searchLastFailedPosition(-1),
 
1088
        _searchProgressCounter(0), _tempFile(0), _downloading(false)
 
1089
{
 
1090
    setXMLFile("krusaderlisterui.rc");
 
1091
 
 
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);
 
1095
 
 
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);
 
1099
 
 
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);
 
1104
 
 
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);
 
1109
 
 
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);
 
1114
 
 
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);
 
1119
 
 
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);
 
1124
 
 
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);
 
1129
 
 
1130
    _actionEncoding = new ListerEncodingMenu(this, i18n("Select charset"), "character-set", actionCollection());
 
1131
 
 
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);
 
1145
    _scrollBar->hide();
 
1146
 
 
1147
    QWidget * statusWidget = new QWidget(widget);
 
1148
    QHBoxLayout *hbox = new QHBoxLayout(statusWidget);
 
1149
 
 
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);
 
1158
 
 
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);
 
1165
 
 
1166
    _searchLineEdit = new KLineEdit(statusWidget);
 
1167
    _searchLineEdit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
 
1168
 
 
1169
    _originalBackground = _searchLineEdit->palette().color(QPalette::Base);
 
1170
    _originalForeground = _searchLineEdit->palette().color(QPalette::Text);
 
1171
 
 
1172
    connect(_searchLineEdit, SIGNAL(returnPressed()), this, SLOT(searchNext()));
 
1173
    connect(_searchLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(searchTextChanged()));
 
1174
 
 
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);
 
1199
 
 
1200
    hbox->addWidget(_searchOptions);
 
1201
 
 
1202
    QSpacerItem* cbSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
 
1203
    hbox->addItem(cbSpacer);
 
1204
 
 
1205
    _statusLabel = new QLabel(statusWidget);
 
1206
    hbox->addWidget(_statusLabel);
 
1207
 
 
1208
    grid->addWidget(statusWidget, 1, 0, 1, 2);
 
1209
    setWidget(widget);
 
1210
 
 
1211
    connect(_scrollBar, SIGNAL(actionTriggered(int)), _textArea, SLOT(slotActionTriggered(int)));
 
1212
    connect(&_updateTimer, SIGNAL(timeout()), this, SLOT(slotUpdate()));
 
1213
 
 
1214
    _updateTimer.setSingleShot(false);
 
1215
 
 
1216
    new ListerBrowserExtension(this);
 
1217
    enableSearch(false);
 
1218
}
 
1219
 
 
1220
Lister::~Lister()
 
1221
{
 
1222
    if (_cache != 0) {
 
1223
        delete []_cache;
 
1224
        _cache = 0;
 
1225
    }
 
1226
    if (_tempFile != 0) {
 
1227
        delete _tempFile;
 
1228
        _tempFile = 0;
 
1229
    }
 
1230
}
 
1231
 
 
1232
bool Lister::openUrl(const KUrl &listerUrl)
 
1233
{
 
1234
    _downloading = false;
 
1235
    setUrl(listerUrl);
 
1236
 
 
1237
    if (_tempFile) {
 
1238
        delete _tempFile;
 
1239
        _tempFile = 0;
 
1240
    }
 
1241
    _fileSize = 0;
 
1242
 
 
1243
    if (listerUrl.isLocalFile()) {
 
1244
        _filePath = listerUrl.path();
 
1245
        if (!QFile::exists(_filePath))
 
1246
            return false;
 
1247
        _fileSize = getFileSize();
 
1248
    } else {
 
1249
        _tempFile = new KTemporaryFile();
 
1250
        _tempFile->setSuffix(listerUrl.fileName());
 
1251
        _tempFile->open();
 
1252
 
 
1253
        _filePath = _tempFile->fileName();
 
1254
 
 
1255
        KIO::Job * downloadJob = KIO::get(listerUrl, KIO::NoReload, KIO::HideProgressInfo);
 
1256
 
 
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;
 
1262
    }
 
1263
    if (_cache) {
 
1264
        delete []_cache;
 
1265
        _cache = 0;
 
1266
    }
 
1267
    _textArea->reset();
 
1268
    emit started(0);
 
1269
    emit setWindowCaption(listerUrl.prettyUrl());
 
1270
    emit completed();
 
1271
    return true;
 
1272
}
 
1273
 
 
1274
void Lister::slotFileDataReceived(KIO::Job *, const QByteArray &array)
 
1275
{
 
1276
    if (array.size() != 0)
 
1277
        _tempFile->write(array);
 
1278
}
 
1279
 
 
1280
void Lister::slotFileFinished(KJob *job)
 
1281
{
 
1282
    _tempFile->flush();
 
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()));
 
1286
    }
 
1287
    _downloading = false;
 
1288
}
 
1289
 
 
1290
 
 
1291
char * Lister::cacheRef(qint64 filePos, int &size)
 
1292
{
 
1293
    if (filePos >= _fileSize)
 
1294
        return 0;
 
1295
    if (_fileSize - filePos < size)
 
1296
        size = _fileSize - filePos;
 
1297
    if ((_cache != 0) && (filePos >= _cachePos) && (filePos + size <= _cachePos + _cacheSize))
 
1298
        return _cache + (filePos - _cachePos);
 
1299
 
 
1300
    int cacheSize = CACHE_SIZE;
 
1301
    int negativeOffset = CACHE_SIZE * 2 / 5;
 
1302
    qint64 cachePos = filePos - negativeOffset;
 
1303
    if (cachePos < 0)
 
1304
        cachePos = 0;
 
1305
 
 
1306
    QFile myfile(_filePath);
 
1307
    if (!myfile.open(QIODevice::ReadOnly)) {
 
1308
        myfile.close();
 
1309
        return 0;
 
1310
    }
 
1311
 
 
1312
    if (!myfile.seek(cachePos)) {
 
1313
        myfile.close();
 
1314
        return 0;
 
1315
    }
 
1316
 
 
1317
    char * newCache = new char [ cacheSize ];
 
1318
 
 
1319
    qint64 bytes = myfile.read(newCache, cacheSize);
 
1320
    if (bytes == -1) {
 
1321
        delete []newCache;
 
1322
        myfile.close();
 
1323
        return 0;
 
1324
    }
 
1325
    if (_cache)
 
1326
        delete []_cache;
 
1327
 
 
1328
    _cache = newCache;
 
1329
    _cacheSize = bytes;
 
1330
    _cachePos = cachePos;
 
1331
    int newSize = _cacheSize - (filePos - _cachePos);
 
1332
    if (newSize < size)
 
1333
        size = newSize;
 
1334
 
 
1335
    return _cache + (filePos - _cachePos);
 
1336
}
 
1337
 
 
1338
qint64 Lister::getFileSize()
 
1339
{
 
1340
    return QFile(_filePath).size();
 
1341
}
 
1342
 
 
1343
void Lister::guiActivateEvent(KParts::GUIActivateEvent * event)
 
1344
{
 
1345
    if (event->activated()) {
 
1346
        _active = true;
 
1347
        _updateTimer.setInterval(150);
 
1348
        _updateTimer.start();
 
1349
        slotUpdate();
 
1350
    } else {
 
1351
        enableSearch(false);
 
1352
        _active = false;
 
1353
        _updateTimer.stop();
 
1354
    }
 
1355
    KParts::ReadOnlyPart::guiActivateEvent(event);
 
1356
}
 
1357
 
 
1358
void Lister::slotUpdate()
 
1359
{
 
1360
    qint64 oldSize = _fileSize;
 
1361
    _fileSize = getFileSize();
 
1362
    if (oldSize != _fileSize)
 
1363
        _textArea->sizeChanged();
 
1364
 
 
1365
    int cursorX = 0, cursorY = 0;
 
1366
    _textArea->getCursorPosition(cursorX, cursorY);
 
1367
    bool isfirst = false;
 
1368
    qint64 cursor = _textArea->getCursorPosition(isfirst);
 
1369
 
 
1370
    int percent = (_fileSize == 0) ? 0 : (int)((201 * cursor) / _fileSize / 2);
 
1371
 
 
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);
 
1376
 
 
1377
    if (_searchProgressCounter)
 
1378
        _searchProgressCounter--;
 
1379
}
 
1380
 
 
1381
void Lister::enableSearch(bool enable)
 
1382
{
 
1383
    if (enable) {
 
1384
        _listerLabel->setText(i18n("Search:"));
 
1385
        _searchLineEdit->show();
 
1386
        _searchNextButton->show();
 
1387
        _searchPrevButton->show();
 
1388
        _searchOptions->show();
 
1389
        _searchLineEdit->setFocus();
 
1390
    } else {
 
1391
        _listerLabel->setText(i18n("Lister:"));
 
1392
        _searchLineEdit->hide();
 
1393
        _searchNextButton->hide();
 
1394
        _searchPrevButton->hide();
 
1395
        _searchOptions->hide();
 
1396
    }
 
1397
}
 
1398
 
 
1399
void Lister::searchNext()
 
1400
{
 
1401
    search(true);
 
1402
}
 
1403
 
 
1404
void Lister::searchPrev()
 
1405
{
 
1406
    search(false);
 
1407
}
 
1408
 
 
1409
void Lister::search(bool forward, bool restart)
 
1410
{
 
1411
    _restartFromBeginning = restart;
 
1412
    if (_searchInProgress || _searchLineEdit->text().isEmpty())
 
1413
        return;
 
1414
    if (_searchLineEdit->isHidden())
 
1415
        enableSearch(true);
 
1416
 
 
1417
    _searchPosition = forward ? 0 : _fileSize;
 
1418
    if (_fromCursorAction->isChecked()) {
 
1419
        bool isfirst;
 
1420
        qint64 cursor = _textArea->getCursorPosition(isfirst);
 
1421
        if (cursor != 0 && !forward)
 
1422
            cursor--;
 
1423
        if (_searchLastFailedPosition == -1 || _searchLastFailedPosition != cursor)
 
1424
            _searchPosition = cursor;
 
1425
    }
 
1426
    bool caseSensitive = _caseSensitiveAction->isChecked();
 
1427
    bool matchWholeWord = _matchWholeWordsOnlyAction->isChecked();
 
1428
    bool regExp = _regExpAction->isChecked();
 
1429
    bool hex = _hexAction->isChecked();
 
1430
 
 
1431
    if (hex) {
 
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');
 
1438
 
 
1439
        _searchHexQuery = QByteArray();
 
1440
 
 
1441
        if (hexcontent.length() & 1) {
 
1442
            setColor(false, false);
 
1443
            return;
 
1444
        }
 
1445
 
 
1446
        while (!hexcontent.isEmpty()) {
 
1447
            QString hexData = hexcontent.left(2);
 
1448
            hexcontent = hexcontent.mid(2);
 
1449
            bool ok = true;
 
1450
            int c = hexData.toUInt(&ok, 16);
 
1451
            if (!ok) {
 
1452
                setColor(false, false);
 
1453
                return;
 
1454
            }
 
1455
            _searchHexQuery.push_back((char) c);
 
1456
        }
 
1457
    } else {
 
1458
        _searchQuery.setContent(_searchLineEdit->text(), caseSensitive, matchWholeWord, false, _textArea->codec()->name(), regExp);
 
1459
    }
 
1460
    _searchIsForward = forward;
 
1461
    _searchHexadecimal = hex;
 
1462
 
 
1463
    QTimer::singleShot(0, this, SLOT(slotSearchMore()));
 
1464
    _searchInProgress = true;
 
1465
    _searchProgressCounter = 3;
 
1466
 
 
1467
    enableActions(false);
 
1468
}
 
1469
 
 
1470
void Lister::enableActions(bool state)
 
1471
{
 
1472
    _actionSearch->setEnabled(state);
 
1473
    _actionSearchNext->setEnabled(state);
 
1474
    _actionSearchPrev->setEnabled(state);
 
1475
    _actionJumpToPosition->setEnabled(state);
 
1476
}
 
1477
 
 
1478
void Lister::slotSearchMore()
 
1479
{
 
1480
    if (!_searchInProgress)
 
1481
        return;
 
1482
 
 
1483
    updateProgressBar();
 
1484
    if (!_searchIsForward)
 
1485
        _searchPosition--;
 
1486
 
 
1487
    if (_searchPosition < 0 || _searchPosition >= _fileSize) {
 
1488
        if (_restartFromBeginning)
 
1489
            resetSearchPosition();
 
1490
        else {
 
1491
            searchFailed();
 
1492
            return;
 
1493
        }
 
1494
    }
 
1495
 
 
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) {
 
1503
            searchPos = 0;
 
1504
            _searchPosition = 0;
 
1505
            setPosition = false;
 
1506
        }
 
1507
        qint64 diff = origSearchPos - searchPos;
 
1508
        if (diff < maxCacheSize)
 
1509
            maxCacheSize = diff;
 
1510
    }
 
1511
 
 
1512
    char * cache = cacheRef(searchPos, maxCacheSize);
 
1513
    if (cache == 0 || maxCacheSize == 0) {
 
1514
        searchFailed();
 
1515
        return;
 
1516
    }
 
1517
 
 
1518
    qint64 foundAnchor = -1;
 
1519
    qint64 foundCursor = -1;
 
1520
    int cnt = 0;
 
1521
 
 
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;
 
1531
            } else {
 
1532
                if (_searchPosition > 0)
 
1533
                    _searchPosition += _searchHexQuery.length();
 
1534
            }
 
1535
        }
 
1536
        if (ndx != -1) {
 
1537
            foundAnchor = searchPos + ndx;
 
1538
            foundCursor = foundAnchor + _searchHexQuery.length();
 
1539
        }
 
1540
    } else {
 
1541
        QTextCodec * textCodec = _textArea->codec();
 
1542
        QTextDecoder * decoder = textCodec->makeDecoder();
 
1543
 
 
1544
        int rowStart = 0;
 
1545
 
 
1546
        QString row = "";
 
1547
 
 
1548
        while (cnt < maxCacheSize) {
 
1549
            QString chr = decoder->toUnicode(cache + (cnt++), 1);
 
1550
            if (!chr.isEmpty() || cnt >= maxCacheSize) {
 
1551
                if (chr != "\n")
 
1552
                    row += chr;
 
1553
 
 
1554
                if (chr == "\n" || row.length() >= SEARCH_MAX_ROW_LEN || cnt >= maxCacheSize) {
 
1555
                    if (setPosition) {
 
1556
                        _searchPosition = searchPos + cnt;
 
1557
                        if (!_searchIsForward) {
 
1558
                            _searchPosition ++;
 
1559
                            setPosition = false;
 
1560
                        }
 
1561
                    }
 
1562
 
 
1563
                    if (_searchQuery.checkLine(row, !_searchIsForward)) {
 
1564
                        QByteArray cachedBuffer(cache + rowStart, maxCacheSize - rowStart);
 
1565
 
 
1566
                        QTextStream stream(&cachedBuffer);
 
1567
                        stream.setCodec(textCodec);
 
1568
 
 
1569
                        stream.read(_searchQuery.matchIndex());
 
1570
                        foundAnchor = searchPos + rowStart + stream.pos();
 
1571
 
 
1572
                        stream.read(_searchQuery.matchLength());
 
1573
                        foundCursor = searchPos + rowStart + stream.pos();
 
1574
 
 
1575
                        if (_searchIsForward)
 
1576
                            break;
 
1577
                    }
 
1578
 
 
1579
                    row = "";
 
1580
                    rowStart = cnt;
 
1581
                }
 
1582
            }
 
1583
        }
 
1584
 
 
1585
        delete decoder;
 
1586
    }
 
1587
 
 
1588
    if (foundAnchor != -1 && foundCursor != -1) {
 
1589
        _textArea->setAnchorAndCursor(foundAnchor, foundCursor);
 
1590
        searchSucceeded();
 
1591
        return;
 
1592
    }
 
1593
 
 
1594
    if (_searchIsForward && searchPos + cnt >= _fileSize) {
 
1595
        if (_restartFromBeginning)
 
1596
            resetSearchPosition();
 
1597
        else {
 
1598
            searchFailed();
 
1599
            return;
 
1600
        }
 
1601
    } else if (_searchPosition <= 0 || _searchPosition >= _fileSize) {
 
1602
        if (_restartFromBeginning)
 
1603
            resetSearchPosition();
 
1604
        else {
 
1605
            searchFailed();
 
1606
            return;
 
1607
        }
 
1608
    }
 
1609
 
 
1610
    QTimer::singleShot(0, this, SLOT(slotSearchMore()));
 
1611
}
 
1612
 
 
1613
void Lister::resetSearchPosition()
 
1614
{
 
1615
    _restartFromBeginning = false;
 
1616
    _searchPosition = _searchIsForward ? 0 : _fileSize - 1;
 
1617
}
 
1618
 
 
1619
void Lister::searchSucceeded()
 
1620
{
 
1621
    _searchInProgress = false;
 
1622
    setColor(true, false);
 
1623
    hideProgressBar();
 
1624
    _searchLastFailedPosition = -1;
 
1625
 
 
1626
    enableActions(true);
 
1627
}
 
1628
 
 
1629
void Lister::searchFailed()
 
1630
{
 
1631
    _searchInProgress = false;
 
1632
    setColor(false, false);
 
1633
    hideProgressBar();
 
1634
    bool isfirst;
 
1635
    _searchLastFailedPosition = _textArea->getCursorPosition(isfirst);
 
1636
    if (!_searchIsForward)
 
1637
        _searchLastFailedPosition--;
 
1638
 
 
1639
    enableActions(true);
 
1640
}
 
1641
 
 
1642
void Lister::searchDelete()
 
1643
{
 
1644
    _searchInProgress = false;
 
1645
    setColor(false, true);
 
1646
    hideProgressBar();
 
1647
    _searchLastFailedPosition = -1;
 
1648
 
 
1649
    enableActions(true);
 
1650
}
 
1651
 
 
1652
void Lister::searchTextChanged()
 
1653
{
 
1654
    searchDelete();
 
1655
    if (_fileSize < 0x10000) { // autosearch files less than 64k
 
1656
        if (!_searchLineEdit->text().isEmpty()) {
 
1657
            bool isfirst;
 
1658
            qint64 anchor = _textArea->getCursorAnchor();
 
1659
            qint64 cursor = _textArea->getCursorPosition(isfirst);
 
1660
            if (cursor > anchor && anchor != -1) {
 
1661
                _textArea->setCursorPosition(anchor, true);
 
1662
            }
 
1663
            search(true, true);
 
1664
        }
 
1665
    }
 
1666
}
 
1667
 
 
1668
void Lister::setColor(bool match, bool restore)
 
1669
{
 
1670
    QColor  fore, back;
 
1671
 
 
1672
    if (!restore) {
 
1673
        KConfigGroup gc(krConfig, "Colors");
 
1674
 
 
1675
        QString foreground, background;
 
1676
 
 
1677
        if (match) {
 
1678
            foreground = "Quicksearch Match Foreground";
 
1679
            background = "Quicksearch Match Background";
 
1680
            fore = Qt::black;
 
1681
            back = QColor(192, 255, 192);
 
1682
        } else {
 
1683
            foreground = "Quicksearch Non-match Foreground";
 
1684
            background = "Quicksearch Non-match Background";
 
1685
            fore = Qt::black;
 
1686
            back = QColor(255, 192, 192);
 
1687
        }
 
1688
 
 
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);
 
1693
 
 
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);
 
1698
    } else {
 
1699
        back = _originalBackground;
 
1700
        fore = _originalForeground;
 
1701
    }
 
1702
 
 
1703
    QPalette pal = _searchLineEdit->palette();
 
1704
    pal.setColor(QPalette::Base, back);
 
1705
    pal.setColor(QPalette::Text, fore);
 
1706
    _searchLineEdit->setPalette(pal);
 
1707
}
 
1708
 
 
1709
void Lister::hideProgressBar()
 
1710
{
 
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:"));
 
1719
    }
 
1720
}
 
1721
 
 
1722
void Lister::updateProgressBar()
 
1723
{
 
1724
    if (_searchProgressCounter)
 
1725
        return;
 
1726
 
 
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:"));
 
1735
    }
 
1736
 
 
1737
    qint64 pcnt = (_fileSize == 0) ? 1000 : (2001 * _searchPosition) / _fileSize / 2;
 
1738
    int pctInt = (int)pcnt;
 
1739
    if (_searchProgressBar->value() != pctInt)
 
1740
        _searchProgressBar->setValue(pctInt);
 
1741
}
 
1742
 
 
1743
void Lister::jumpToPosition()
 
1744
{
 
1745
    bool ok = true;
 
1746
    QString res = KInputDialog::getText(i18n("Jump to position"), i18n("Text position:"), "0",
 
1747
                                        &ok, _textArea);
 
1748
    if (!ok)
 
1749
        return;
 
1750
 
 
1751
    res = res.trimmed();
 
1752
    qint64 pos = -1;
 
1753
    if (res.startsWith(QLatin1String("0x"))) {
 
1754
        res = res.mid(2);
 
1755
        bool ok;
 
1756
        qulonglong upos = res.toULongLong(&ok, 16);
 
1757
        if (!ok) {
 
1758
            KMessageBox::error(_textArea, i18n("Invalid number!"), i18n("Jump to position"));
 
1759
            return;
 
1760
        }
 
1761
        pos = (qint64)upos;
 
1762
    } else {
 
1763
        bool ok;
 
1764
        qulonglong upos = res.toULongLong(&ok);
 
1765
        if (!ok) {
 
1766
            KMessageBox::error(_textArea, i18n("Invalid number!"), i18n("Jump to position"));
 
1767
            return;
 
1768
        }
 
1769
        pos = (qint64)upos;
 
1770
    }
 
1771
 
 
1772
    if (pos < 0 || pos > _fileSize) {
 
1773
        KMessageBox::error(_textArea, i18n("Number out of range!"), i18n("Jump to position"));
 
1774
        return;
 
1775
    }
 
1776
 
 
1777
    _textArea->deleteAnchor();
 
1778
    _textArea->setCursorPosition(pos, true);
 
1779
    _textArea->ensureVisibleCursor();
 
1780
}
 
1781
 
 
1782
void Lister::saveAs()
 
1783
{
 
1784
    KUrl url = KFileDialog::getSaveUrl(KUrl(), QString(), _textArea, i18n("Lister"));
 
1785
    if (url.isEmpty())
 
1786
        return;
 
1787
    KUrl sourceUrl;
 
1788
    if (!_downloading)
 
1789
        sourceUrl = KUrl(_filePath);
 
1790
    else
 
1791
        sourceUrl = this->url();
 
1792
 
 
1793
    KUrl::List urlList;
 
1794
    urlList << sourceUrl;
 
1795
 
 
1796
    KIO::Job *job = KIO::copy(urlList, url);
 
1797
    job->setUiDelegate(new KIO::JobUiDelegate());
 
1798
    KIO::getJobTracker()->registerJob(job);
 
1799
    job->ui()->setAutoErrorHandlingEnabled(true);
 
1800
}
 
1801
 
 
1802
void Lister::saveSelected()
 
1803
{
 
1804
    bool isfirst;
 
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..."));
 
1809
        return;
 
1810
    }
 
1811
    if (start > end) {
 
1812
        _savePosition = end;
 
1813
        _saveEnd = start;
 
1814
    } else {
 
1815
        _savePosition = start;
 
1816
        _saveEnd = end;
 
1817
    }
 
1818
 
 
1819
    KUrl url = KFileDialog::getSaveUrl(KUrl(), QString(), _textArea, i18n("Lister"));
 
1820
    if (url.isEmpty())
 
1821
        return;
 
1822
 
 
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 *)));
 
1828
 
 
1829
    saveJob->setUiDelegate(new KIO::JobUiDelegate());
 
1830
    KIO::getJobTracker()->registerJob(saveJob);
 
1831
    saveJob->ui()->setAutoErrorHandlingEnabled(true);
 
1832
 
 
1833
    _actionSaveSelected->setEnabled(false);
 
1834
}
 
1835
 
 
1836
void Lister::slotDataSend(KIO::Job *, QByteArray &array)
 
1837
{
 
1838
    if (_savePosition >= _saveEnd) {
 
1839
        array = QByteArray();
 
1840
        return;
 
1841
    }
 
1842
    qint64 max = _saveEnd - _savePosition;
 
1843
    if (max > 1000)
 
1844
        max = 1000;
 
1845
    int maxBytes = (int)max;
 
1846
    char * cache = cacheRef(_savePosition, maxBytes);
 
1847
    _savePosition += maxBytes;
 
1848
 
 
1849
    array = QByteArray(cache, maxBytes);
 
1850
}
 
1851
 
 
1852
void Lister::slotSendFinished(KJob *)
 
1853
{
 
1854
    _actionSaveSelected->setEnabled(true);
 
1855
}
 
1856
 
 
1857
void Lister::setCharacterSet(QString set)
 
1858
{
 
1859
    _characterSet = set;
 
1860
    _textArea->redrawTextArea(true);
 
1861
}
 
1862
 
 
1863
void Lister::print()
 
1864
{
 
1865
    bool isfirst;
 
1866
    qint64 anchor = _textArea->getCursorAnchor();
 
1867
    qint64 cursor = _textArea->getCursorPosition(isfirst);
 
1868
    bool hasSelection = (anchor != -1 && anchor != cursor);
 
1869
 
 
1870
    QString docName = url().fileName();
 
1871
    QPrinter printer;
 
1872
    printer.setDocName(docName);
 
1873
 
 
1874
    QPointer<QPrintDialog> printDialog = new QPrintDialog(&printer, _textArea);
 
1875
 
 
1876
    if (hasSelection)
 
1877
        printDialog->addEnabledOption(QAbstractPrintDialog::PrintSelection);
 
1878
 
 
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 :
 
1884
                break;
 
1885
            default:
 
1886
                return;
 
1887
            }
 
1888
        }
 
1889
        QPainter painter;
 
1890
        painter.begin(&printer);
 
1891
 
 
1892
        QDate date = QDate::currentDate();
 
1893
        QString dateString = date.toString(Qt::SystemLocaleShortDate);
 
1894
 
 
1895
        QRect pageRect = printer.pageRect();
 
1896
        QRect drawingRect(0, 0, pageRect.width(), pageRect.height());
 
1897
 
 
1898
        QFont normalFont = KGlobalSettings::generalFont();
 
1899
        QFont fixedFont  = KGlobalSettings::fixedFont();
 
1900
 
 
1901
        QFontMetrics fmNormal(normalFont);
 
1902
        int normalFontHeight = fmNormal.height();
 
1903
 
 
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)
 
1910
            fixedFontWidth = 1;
 
1911
 
 
1912
        int effPageSize = drawingRect.height() - normalFontHeight - 1;
 
1913
        int rowsPerPage = effPageSize / fixedFontHeight;
 
1914
        if (rowsPerPage <= 0)
 
1915
            rowsPerPage = 1;
 
1916
        int columnsPerPage = drawingRect.width() / fixedFontWidth;
 
1917
        if (columnsPerPage <= 0)
 
1918
            columnsPerPage = 1;
 
1919
 
 
1920
        bool firstPage = true;
 
1921
 
 
1922
        qint64 startPos = 0;
 
1923
        qint64 endPos = _fileSize;
 
1924
        if (printer.printRange() == QPrinter::Selection) {
 
1925
            if (anchor > cursor)
 
1926
                startPos = cursor, endPos = anchor;
 
1927
            else
 
1928
                startPos = anchor, endPos = cursor;
 
1929
        }
 
1930
 
 
1931
        for (int page = 1;; ++page) {
 
1932
            QStringList rows = readLines(startPos, endPos, columnsPerPage, rowsPerPage);
 
1933
 
 
1934
            bool visible = true;
 
1935
            if (printer.fromPage() && page < printer.fromPage())
 
1936
                visible = false;
 
1937
            if (printer.toPage() && printer.toPage() >= printer.fromPage() && page > printer.toPage())
 
1938
                visible = false;
 
1939
 
 
1940
            if (visible) {
 
1941
                if (!firstPage)
 
1942
                    printer.newPage();
 
1943
                firstPage = false;
 
1944
                // Use the painter to draw on the page.
 
1945
                painter.setFont(normalFont);
 
1946
 
 
1947
                painter.drawText(drawingRect, Qt::AlignLeft, dateString);
 
1948
                painter.drawText(drawingRect, Qt::AlignHCenter, docName);
 
1949
                painter.drawText(drawingRect, Qt::AlignRight, QString("%1").arg(page));
 
1950
 
 
1951
                painter.drawLine(0, normalFontHeight, drawingRect.width(), normalFontHeight);
 
1952
 
 
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;
 
1958
                }
 
1959
            }
 
1960
            if (startPos >= endPos)
 
1961
                break;
 
1962
        }
 
1963
    }
 
1964
 
 
1965
    delete printDialog;
 
1966
}
 
1967
 
 
1968
QStringList Lister::readLines(qint64 &filePos, qint64 endPos, int columns, int lines)
 
1969
{
 
1970
    if (_textArea->hexMode())
 
1971
        return readHexLines(filePos, endPos, columns, lines);
 
1972
    QStringList list;
 
1973
    int maxBytes = columns * lines * MAX_CHAR_LENGTH;
 
1974
    if (maxBytes > (endPos - filePos))
 
1975
        maxBytes = (int)(endPos - filePos);
 
1976
    if (maxBytes <= 0)
 
1977
        return list;
 
1978
    char * cache = cacheRef(filePos, maxBytes);
 
1979
    if (cache == 0 || maxBytes == 0)
 
1980
        return list;
 
1981
 
 
1982
    QTextCodec * textCodec = _textArea->codec();
 
1983
    QTextDecoder * decoder = textCodec->makeDecoder();
 
1984
 
 
1985
    int cnt = 0;
 
1986
    int y = 0;
 
1987
    QString row = "";
 
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'))
 
1993
                chr = QChar(' ');
 
1994
            if (chr == "\n") {
 
1995
                if (!isLastLongLine) {
 
1996
                    list << row;
 
1997
                    row = "";
 
1998
                    y++;
 
1999
                }
 
2000
                isLastLongLine = false;
 
2001
            } else {
 
2002
                isLastLongLine = false;
 
2003
                if (chr == "\t") {
 
2004
                    int tabLength = _textArea->tabWidth() - (row.length() % _textArea->tabWidth());
 
2005
                    if (row.length() + tabLength > columns) {
 
2006
                        list << row;
 
2007
                        row = "";
 
2008
                        y++;
 
2009
                    }
 
2010
                    row += QString(tabLength, QChar(' '));
 
2011
                } else
 
2012
                    row += chr;
 
2013
 
 
2014
                if (row.length() >= columns) {
 
2015
                    list << row;
 
2016
                    row = "";
 
2017
                    y++;
 
2018
                    isLastLongLine = true;
 
2019
                }
 
2020
            }
 
2021
        }
 
2022
    }
 
2023
 
 
2024
    if (y < lines)
 
2025
        list << row;
 
2026
 
 
2027
    filePos += cnt;
 
2028
 
 
2029
    delete decoder;
 
2030
    return list;
 
2031
}
 
2032
 
 
2033
int Lister::hexPositionDigits()
 
2034
{
 
2035
    int positionDigits = 0;
 
2036
    qint64 checker = _fileSize;
 
2037
    while (checker) {
 
2038
        positionDigits++;
 
2039
        checker /= 16;
 
2040
    }
 
2041
    if (positionDigits < 8)
 
2042
        positionDigits = 8;
 
2043
    return positionDigits;
 
2044
}
 
2045
 
 
2046
int Lister::hexBytesPerLine(int columns)
 
2047
{
 
2048
    int positionDigits = hexPositionDigits();
 
2049
    int bytesPerRow = 8;
 
2050
    if (columns >= positionDigits + 5 + 64)
 
2051
        bytesPerRow = 16;
 
2052
    if (columns >= positionDigits + 5 + 128)
 
2053
        bytesPerRow = 32;
 
2054
 
 
2055
    return bytesPerRow;
 
2056
}
 
2057
 
 
2058
QStringList Lister::readHexLines(qint64 &filePos, qint64 endPos, int columns, int lines)
 
2059
{
 
2060
    int positionDigits = hexPositionDigits();
 
2061
    int bytesPerRow = hexBytesPerLine(columns);
 
2062
 
 
2063
    QStringList list;
 
2064
 
 
2065
    qint64 choppedPos = (filePos / bytesPerRow) * bytesPerRow;
 
2066
    int maxBytes = bytesPerRow * lines;
 
2067
    if (maxBytes > (endPos - choppedPos))
 
2068
        maxBytes = (int)(endPos - choppedPos);
 
2069
    if (maxBytes <= 0)
 
2070
        return list;
 
2071
 
 
2072
    char * cache = cacheRef(choppedPos, maxBytes);
 
2073
 
 
2074
    if (cache == 0 || maxBytes == 0)
 
2075
        return list;
 
2076
 
 
2077
    int cnt = 0;
 
2078
    for (int l = 0; l < lines; l++) {
 
2079
        if (filePos >= endPos)
 
2080
            break;
 
2081
        qint64 printPos = (filePos / bytesPerRow) * bytesPerRow;
 
2082
        QString pos;
 
2083
        pos.setNum(printPos, 16);
 
2084
        while (pos.length() < positionDigits)
 
2085
            pos = QString("0") + pos;
 
2086
        pos = QString("0x") + pos;
 
2087
        pos += QString(": ");
 
2088
 
 
2089
        QString charData;
 
2090
 
 
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(" ");
 
2096
            } else {
 
2097
                char c = cache[ cnt ];
 
2098
                int charCode = (int)c;
 
2099
                if (charCode < 0)
 
2100
                    charCode += 256;
 
2101
                QString hex;
 
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)
 
2107
                    c = '.';
 
2108
                charData += QChar(c);
 
2109
            }
 
2110
        }
 
2111
 
 
2112
        pos += QString(" ") + charData;
 
2113
        list << pos;
 
2114
        filePos = printPos + bytesPerRow;
 
2115
    }
 
2116
 
 
2117
    if (filePos > endPos)
 
2118
        filePos = endPos;
 
2119
 
 
2120
    return list;
 
2121
}
 
2122
 
 
2123
int Lister::hexIndexToPosition(int columns, int index)
 
2124
{
 
2125
    int positionDigits = hexPositionDigits();
 
2126
    int bytesPerRow = hexBytesPerLine(columns);
 
2127
 
 
2128
    if (index >= bytesPerRow)
 
2129
        index = bytesPerRow;
 
2130
 
 
2131
    return positionDigits + 4 + (3*index);
 
2132
}
 
2133
 
 
2134
int Lister::hexPositionToIndex(int columns, int position)
 
2135
{
 
2136
    int positionDigits = hexPositionDigits();
 
2137
    int bytesPerRow = hexBytesPerLine(columns);
 
2138
 
 
2139
    position -= 4 + positionDigits;
 
2140
    if (position <= 0)
 
2141
        return 0;
 
2142
 
 
2143
    position /= 3;
 
2144
    if (position >= bytesPerRow)
 
2145
        return bytesPerRow;
 
2146
    return position;
 
2147
}
 
2148
 
 
2149
void Lister::toggleHexMode()
 
2150
{
 
2151
    setHexMode(!_textArea->hexMode());
 
2152
}
 
2153
 
 
2154
void Lister::setHexMode(bool mode)
 
2155
{
 
2156
    if (mode) {
 
2157
        _textArea->setHexMode(true);
 
2158
        _actionHexMode->setText(i18n("Text mode"));
 
2159
    } else {
 
2160
        _textArea->setHexMode(false);
 
2161
        _actionHexMode->setText(i18n("Hex mode"));
 
2162
    }
 
2163
}