00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "Screen.h"
00025
00026
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <unistd.h>
00030 #include <assert.h>
00031 #include <string.h>
00032 #include <ctype.h>
00033
00034
00035 #include <QtCore/QTextStream>
00036 #include <QtCore/QDate>
00037
00038
00039 #include <kdebug.h>
00040
00041
00042 #include "konsole_wcwidth.h"
00043 #include "TerminalCharacterDecoder.h"
00044
00045 using namespace Konsole;
00046
00047
00048
00049 #define BS_CLEARS false
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 #ifndef loc
00061 #define loc(X,Y) ((Y)*columns+(X))
00062 #endif
00063
00064
00065 Character Screen::defaultChar = Character(' ',CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR),CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR),DEFAULT_RENDITION);
00066
00067
00068
00069 Screen::Screen(int l, int c)
00070 : lines(l),
00071 columns(c),
00072 screenLines(new ImageLine[lines+1] ),
00073 _scrolledLines(0),
00074 _droppedLines(0),
00075 hist(new HistoryScrollNone()),
00076 cuX(0), cuY(0),
00077 cu_re(0),
00078 tmargin(0), bmargin(0),
00079 tabstops(0),
00080 sel_begin(0), sel_TL(0), sel_BR(0),
00081 sel_busy(false),
00082 columnmode(false),
00083 ef_fg(CharacterColor()), ef_bg(CharacterColor()), ef_re(0),
00084 sa_cuX(0), sa_cuY(0),
00085 sa_cu_re(0),
00086 lastPos(-1)
00087 {
00088 lineProperties.resize(lines+1);
00089 for (int i=0;i<lines+1;i++)
00090 lineProperties[i]=LINE_DEFAULT;
00091
00092 initTabStops();
00093 clearSelection();
00094 reset();
00095 }
00096
00100 Screen::~Screen()
00101 {
00102 delete[] screenLines;
00103 delete[] tabstops;
00104 delete hist;
00105 }
00106
00107
00108
00109
00110
00111
00112
00113
00114
00125 void Screen::cursorUp(int n)
00126
00127 {
00128 if (n == 0) n = 1;
00129 int stop = cuY < tmargin ? 0 : tmargin;
00130 cuX = qMin(columns-1,cuX);
00131 cuY = qMax(stop,cuY-n);
00132 }
00133
00134 void Screen::cursorDown(int n)
00135
00136 {
00137 if (n == 0) n = 1;
00138 int stop = cuY > bmargin ? lines-1 : bmargin;
00139 cuX = qMin(columns-1,cuX);
00140 cuY = qMin(stop,cuY+n);
00141 }
00142
00143 void Screen::cursorLeft(int n)
00144
00145 {
00146 if (n == 0) n = 1;
00147 cuX = qMin(columns-1,cuX);
00148 cuX = qMax(0,cuX-n);
00149 }
00150
00151 void Screen::cursorRight(int n)
00152
00153 {
00154 if (n == 0) n = 1;
00155 cuX = qMin(columns-1,cuX+n);
00156 }
00157
00158 void Screen::setMargins(int top, int bot)
00159
00160 {
00161 if (top == 0) top = 1;
00162 if (bot == 0) bot = lines;
00163 top = top - 1;
00164 bot = bot - 1;
00165 if ( !( 0 <= top && top < bot && bot < lines ) )
00166 { kDebug()<<" setRegion("<<top<<","<<bot<<") : bad range.";
00167 return;
00168 }
00169 tmargin = top;
00170 bmargin = bot;
00171 cuX = 0;
00172 cuY = getMode(MODE_Origin) ? top : 0;
00173
00174 }
00175
00176 int Screen::topMargin() const
00177 {
00178 return tmargin;
00179 }
00180 int Screen::bottomMargin() const
00181 {
00182 return bmargin;
00183 }
00184
00185 void Screen::index()
00186
00187 {
00188 if (cuY == bmargin)
00189 {
00190 scrollUp(1);
00191 }
00192 else if (cuY < lines-1)
00193 cuY += 1;
00194 }
00195
00196 void Screen::reverseIndex()
00197
00198 {
00199 if (cuY == tmargin)
00200 scrollDown(tmargin,1);
00201 else if (cuY > 0)
00202 cuY -= 1;
00203 }
00204
00205 void Screen::nextLine()
00206
00207 {
00208 toStartOfLine(); index();
00209 }
00210
00211 void Screen::eraseChars(int n)
00212 {
00213 if (n == 0) n = 1;
00214 int p = qMax(0,qMin(cuX+n-1,columns-1));
00215 clearImage(loc(cuX,cuY),loc(p,cuY),' ');
00216 }
00217
00218 void Screen::deleteChars(int n)
00219 {
00220 Q_ASSERT( n >= 0 );
00221
00222
00223 if (n == 0)
00224 n = 1;
00225
00226
00227 if ( cuX >= screenLines[cuY].count() )
00228 return;
00229
00230 if ( cuX+n >= screenLines[cuY].count() )
00231 n = screenLines[cuY].count() - 1 - cuX;
00232
00233 Q_ASSERT( n >= 0 );
00234 Q_ASSERT( cuX+n < screenLines[cuY].count() );
00235
00236 screenLines[cuY].remove(cuX,n);
00237 }
00238
00239 void Screen::insertChars(int n)
00240 {
00241 if (n == 0) n = 1;
00242
00243 if ( screenLines[cuY].size() < cuX )
00244 screenLines[cuY].resize(cuX);
00245
00246 screenLines[cuY].insert(cuX,n,' ');
00247
00248 if ( screenLines[cuY].count() > columns )
00249 screenLines[cuY].resize(columns);
00250 }
00251
00252 void Screen::deleteLines(int n)
00253 {
00254 if (n == 0) n = 1;
00255 scrollUp(cuY,n);
00256 }
00257
00258 void Screen::insertLines(int n)
00259 {
00260 if (n == 0) n = 1;
00261 scrollDown(cuY,n);
00262 }
00263
00264
00265
00266 void Screen::setMode(int m)
00267 {
00268 currParm.mode[m] = true;
00269 switch(m)
00270 {
00271 case MODE_Origin : cuX = 0; cuY = tmargin; break;
00272 }
00273 }
00274
00275 void Screen::resetMode(int m)
00276 {
00277 currParm.mode[m] = false;
00278 switch(m)
00279 {
00280 case MODE_Origin : cuX = 0; cuY = 0; break;
00281 }
00282 }
00283
00284 void Screen::saveMode(int m)
00285 {
00286 saveParm.mode[m] = currParm.mode[m];
00287 }
00288
00289 void Screen::restoreMode(int m)
00290 {
00291 currParm.mode[m] = saveParm.mode[m];
00292 }
00293
00294 bool Screen::getMode(int m) const
00295 {
00296 return currParm.mode[m];
00297 }
00298
00299 void Screen::saveCursor()
00300 {
00301 sa_cuX = cuX;
00302 sa_cuY = cuY;
00303 sa_cu_re = cu_re;
00304 sa_cu_fg = cu_fg;
00305 sa_cu_bg = cu_bg;
00306 }
00307
00308 void Screen::restoreCursor()
00309 {
00310 cuX = qMin(sa_cuX,columns-1);
00311 cuY = qMin(sa_cuY,lines-1);
00312 cu_re = sa_cu_re;
00313 cu_fg = sa_cu_fg;
00314 cu_bg = sa_cu_bg;
00315 effectiveRendition();
00316 }
00317
00318
00319
00320
00321
00322
00323
00324 void Screen::resizeImage(int new_lines, int new_columns)
00325 {
00326 if ((new_lines==lines) && (new_columns==columns)) return;
00327
00328 if (cuY > new_lines-1)
00329 {
00330 bmargin = lines-1;
00331 for (int i = 0; i < cuY-(new_lines-1); i++)
00332 {
00333 addHistLine(); scrollUp(0,1);
00334 }
00335 }
00336
00337
00338
00339 ImageLine* newScreenLines = new ImageLine[new_lines+1];
00340 for (int i=0; i < qMin(lines-1,new_lines+1) ;i++)
00341 newScreenLines[i]=screenLines[i];
00342 for (int i=lines;(i > 0) && (i<new_lines+1);i++)
00343 newScreenLines[i].resize( new_columns );
00344
00345 lineProperties.resize(new_lines+1);
00346 for (int i=lines;(i > 0) && (i<new_lines+1);i++)
00347 lineProperties[i] = LINE_DEFAULT;
00348
00349 clearSelection();
00350
00351 delete[] screenLines;
00352 screenLines = newScreenLines;
00353
00354 lines = new_lines;
00355 columns = new_columns;
00356 cuX = qMin(cuX,columns-1);
00357 cuY = qMin(cuY,lines-1);
00358
00359
00360 tmargin=0;
00361 bmargin=lines-1;
00362 initTabStops();
00363 clearSelection();
00364 }
00365
00366 void Screen::setDefaultMargins()
00367 {
00368 tmargin = 0;
00369 bmargin = lines-1;
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407 void Screen::reverseRendition(Character& p) const
00408 {
00409 CharacterColor f = p.foregroundColor;
00410 CharacterColor b = p.backgroundColor;
00411
00412 p.foregroundColor = b;
00413 p.backgroundColor = f;
00414 }
00415
00416 void Screen::effectiveRendition()
00417
00418 {
00419
00420
00421
00422
00423
00424
00425
00426 ef_re = cu_re;
00427
00428
00429
00430
00431 if (cu_re & RE_REVERSE)
00432 {
00433 ef_fg = cu_bg;
00434 ef_bg = cu_fg;
00435 }
00436 else
00437 {
00438 ef_fg = cu_fg;
00439 ef_bg = cu_bg;
00440 }
00441
00442 if (cu_re & RE_BOLD)
00443 ef_fg.toggleIntensive();
00444 }
00445
00446 void Screen::copyFromHistory(Character* dest, int startLine, int count) const
00447 {
00448 Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= hist->getLines() );
00449
00450 for (int line = startLine; line < startLine + count; line++)
00451 {
00452 const int length = qMin(columns,hist->getLineLen(line));
00453 const int destLineOffset = (line-startLine)*columns;
00454
00455 hist->getCells(line,0,length,dest + destLineOffset);
00456
00457 for (int column = length; column < columns; column++)
00458 dest[destLineOffset+column] = defaultChar;
00459
00460
00461 if (sel_begin !=-1)
00462 {
00463 for (int column = 0; column < columns; column++)
00464 {
00465 if (isSelected(column,line))
00466 {
00467 reverseRendition(dest[destLineOffset + column]);
00468 }
00469 }
00470 }
00471 }
00472 }
00473
00474 void Screen::copyFromScreen(Character* dest , int startLine , int count) const
00475 {
00476 Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= lines );
00477
00478 for (int line = startLine; line < (startLine+count) ; line++)
00479 {
00480 int srcLineStartIndex = line*columns;
00481 int destLineStartIndex = (line-startLine)*columns;
00482
00483 for (int column = 0; column < columns; column++)
00484 {
00485 int srcIndex = srcLineStartIndex + column;
00486 int destIndex = destLineStartIndex + column;
00487
00488 dest[destIndex] = screenLines[srcIndex/columns].value(srcIndex%columns,defaultChar);
00489
00490
00491 if (sel_begin != -1 && isSelected(column,line + hist->getLines()))
00492 reverseRendition(dest[destIndex]);
00493 }
00494
00495 }
00496 }
00497
00498 void Screen::getImage( Character* dest, int size, int startLine, int endLine ) const
00499 {
00500 Q_ASSERT( startLine >= 0 );
00501 Q_ASSERT( endLine >= startLine && endLine < hist->getLines() + lines );
00502
00503 const int mergedLines = endLine - startLine + 1;
00504
00505 Q_ASSERT( size >= mergedLines * columns );
00506
00507 const int linesInHistoryBuffer = qBound(0,hist->getLines()-startLine,mergedLines);
00508 const int linesInScreenBuffer = mergedLines - linesInHistoryBuffer;
00509
00510
00511 if (linesInHistoryBuffer > 0)
00512 copyFromHistory(dest,startLine,linesInHistoryBuffer);
00513
00514
00515 if (linesInScreenBuffer > 0)
00516 copyFromScreen(dest + linesInHistoryBuffer*columns,
00517 startLine + linesInHistoryBuffer - hist->getLines(),
00518 linesInScreenBuffer);
00519
00520
00521 if (getMode(MODE_Screen))
00522 {
00523 for (int i = 0; i < mergedLines*columns; i++)
00524 reverseRendition(dest[i]);
00525 }
00526
00527
00528 int cursorIndex = loc(cuX, cuY + linesInHistoryBuffer);
00529 if(getMode(MODE_Cursor) && cursorIndex < columns*mergedLines)
00530 dest[cursorIndex].rendition |= RE_CURSOR;
00531 }
00532
00533 QVector<LineProperty> Screen::getLineProperties( int startLine , int endLine ) const
00534 {
00535 Q_ASSERT( startLine >= 0 );
00536 Q_ASSERT( endLine >= startLine && endLine < hist->getLines() + lines );
00537
00538 const int mergedLines = endLine-startLine+1;
00539 const int linesInHistory = qBound(0,hist->getLines()-startLine,mergedLines);
00540 const int linesInScreen = mergedLines - linesInHistory;
00541
00542 QVector<LineProperty> result(mergedLines);
00543 int index = 0;
00544
00545
00546 for (int line = startLine; line < startLine + linesInHistory; line++)
00547 {
00548
00549 if (hist->isWrappedLine(line))
00550 {
00551 result[index] = (LineProperty)(result[index] | LINE_WRAPPED);
00552 }
00553 index++;
00554 }
00555
00556
00557 const int firstScreenLine = startLine + linesInHistory - hist->getLines();
00558 for (int line = firstScreenLine; line < firstScreenLine+linesInScreen; line++)
00559 {
00560 result[index]=lineProperties[line];
00561 index++;
00562 }
00563
00564 return result;
00565 }
00566
00567 void Screen::reset(bool clearScreen)
00568 {
00569 setMode(MODE_Wrap ); saveMode(MODE_Wrap );
00570 resetMode(MODE_Origin); saveMode(MODE_Origin);
00571 resetMode(MODE_Insert); saveMode(MODE_Insert);
00572 setMode(MODE_Cursor);
00573 resetMode(MODE_Screen);
00574 resetMode(MODE_NewLine);
00575
00576 tmargin=0;
00577 bmargin=lines-1;
00578
00579 setDefaultRendition();
00580 saveCursor();
00581
00582 if ( clearScreen )
00583 clear();
00584 }
00585
00586 void Screen::clear()
00587 {
00588 clearEntireScreen();
00589 home();
00590 }
00591
00592 void Screen::backspace()
00593 {
00594 cuX = qMin(columns-1,cuX);
00595 cuX = qMax(0,cuX-1);
00596
00597
00598 if (screenLines[cuY].size() < cuX+1)
00599 screenLines[cuY].resize(cuX+1);
00600
00601 if (BS_CLEARS) screenLines[cuY][cuX].character = ' ';
00602 }
00603
00604 void Screen::tab(int n)
00605 {
00606
00607 if (n == 0) n = 1;
00608 while((n > 0) && (cuX < columns-1))
00609 {
00610 cursorRight(1); while((cuX < columns-1) && !tabstops[cuX]) cursorRight(1);
00611 n--;
00612 }
00613 }
00614
00615 void Screen::backtab(int n)
00616 {
00617
00618 if (n == 0) n = 1;
00619 while((n > 0) && (cuX > 0))
00620 {
00621 cursorLeft(1); while((cuX > 0) && !tabstops[cuX]) cursorLeft(1);
00622 n--;
00623 }
00624 }
00625
00626 void Screen::clearTabStops()
00627 {
00628 for (int i = 0; i < columns; i++) tabstops[i] = false;
00629 }
00630
00631 void Screen::changeTabStop(bool set)
00632 {
00633 if (cuX >= columns) return;
00634 tabstops[cuX] = set;
00635 }
00636
00637 void Screen::initTabStops()
00638 {
00639 delete[] tabstops;
00640 tabstops = new bool[columns];
00641
00642
00643
00644
00645 for (int i = 0; i < columns; i++) tabstops[i] = (i%8 == 0 && i != 0);
00646 }
00647
00648 void Screen::newLine()
00649 {
00650 if (getMode(MODE_NewLine)) toStartOfLine();
00651 index();
00652 }
00653
00654 void Screen::checkSelection(int from, int to)
00655 {
00656 if (sel_begin == -1) return;
00657 int scr_TL = loc(0, hist->getLines());
00658
00659 if ( (sel_BR > (from+scr_TL) )&&(sel_TL < (to+scr_TL)) )
00660 {
00661 clearSelection();
00662 }
00663 }
00664
00665 void Screen::displayCharacter(unsigned short c)
00666 {
00667
00668
00669
00670
00671
00672 int w = konsole_wcwidth(c);
00673
00674 if (w <= 0)
00675 return;
00676
00677 if (cuX+w > columns) {
00678 if (getMode(MODE_Wrap)) {
00679 lineProperties[cuY] = (LineProperty)(lineProperties[cuY] | LINE_WRAPPED);
00680 nextLine();
00681 }
00682 else
00683 cuX = columns-w;
00684 }
00685
00686
00687 int size = screenLines[cuY].size();
00688 if (size == 0 && cuY > 0)
00689 {
00690 screenLines[cuY].resize( qMax(screenLines[cuY-1].size() , cuX+w) );
00691 }
00692 else
00693 {
00694 if (size < cuX+w)
00695 {
00696 screenLines[cuY].resize(cuX+w);
00697 }
00698 }
00699
00700 if (getMode(MODE_Insert)) insertChars(w);
00701
00702 lastPos = loc(cuX,cuY);
00703
00704
00705 checkSelection(cuX,cuY);
00706
00707 Character& currentChar = screenLines[cuY][cuX];
00708
00709 currentChar.character = c;
00710 currentChar.foregroundColor = ef_fg;
00711 currentChar.backgroundColor = ef_bg;
00712 currentChar.rendition = ef_re;
00713
00714 int i = 0;
00715 int newCursorX = cuX + w--;
00716 while(w)
00717 {
00718 i++;
00719
00720 if ( screenLines[cuY].size() < cuX + i + 1 )
00721 screenLines[cuY].resize(cuX+i+1);
00722
00723 Character& ch = screenLines[cuY][cuX + i];
00724 ch.character = 0;
00725 ch.foregroundColor = ef_fg;
00726 ch.backgroundColor = ef_bg;
00727 ch.rendition = ef_re;
00728
00729 w--;
00730 }
00731 cuX = newCursorX;
00732 }
00733
00734 void Screen::compose(const QString& )
00735 {
00736 Q_ASSERT( 0 );
00737
00738
00739
00740
00741
00742
00743
00744
00745 }
00746
00747 int Screen::scrolledLines() const
00748 {
00749 return _scrolledLines;
00750 }
00751 int Screen::droppedLines() const
00752 {
00753 return _droppedLines;
00754 }
00755 void Screen::resetDroppedLines()
00756 {
00757 _droppedLines = 0;
00758 }
00759 void Screen::resetScrolledLines()
00760 {
00761 _scrolledLines = 0;
00762 }
00763
00764
00765
00766 void Screen::scrollUp(int n)
00767 {
00768 if (n == 0) n = 1;
00769 if (tmargin == 0) addHistLine();
00770 scrollUp(tmargin, n);
00771 }
00772
00773 QRect Screen::lastScrolledRegion() const
00774 {
00775 return _lastScrolledRegion;
00776 }
00777
00778 void Screen::scrollUp(int from, int n)
00779 {
00780 if (n <= 0 || from + n > bmargin) return;
00781
00782 _scrolledLines -= n;
00783 _lastScrolledRegion = QRect(0,tmargin,columns-1,(bmargin-tmargin));
00784
00785
00786 moveImage(loc(0,from),loc(0,from+n),loc(columns-1,bmargin));
00787 clearImage(loc(0,bmargin-n+1),loc(columns-1,bmargin),' ');
00788 }
00789
00790 void Screen::scrollDown(int n)
00791 {
00792 if (n == 0) n = 1;
00793 scrollDown(tmargin, n);
00794 }
00795
00796 void Screen::scrollDown(int from, int n)
00797 {
00798 _scrolledLines += n;
00799
00800
00801 if (n <= 0) return;
00802 if (from > bmargin) return;
00803 if (from + n > bmargin) n = bmargin - from;
00804 moveImage(loc(0,from+n),loc(0,from),loc(columns-1,bmargin-n));
00805 clearImage(loc(0,from),loc(columns-1,from+n-1),' ');
00806 }
00807
00808 void Screen::setCursorYX(int y, int x)
00809 {
00810 setCursorY(y); setCursorX(x);
00811 }
00812
00813 void Screen::setCursorX(int x)
00814 {
00815 if (x == 0) x = 1;
00816 x -= 1;
00817 cuX = qMax(0,qMin(columns-1, x));
00818 }
00819
00820 void Screen::setCursorY(int y)
00821 {
00822 if (y == 0) y = 1;
00823 y -= 1;
00824 cuY = qMax(0,qMin(lines -1, y + (getMode(MODE_Origin) ? tmargin : 0) ));
00825 }
00826
00827 void Screen::home()
00828 {
00829 cuX = 0;
00830 cuY = 0;
00831 }
00832
00833 void Screen::toStartOfLine()
00834 {
00835 cuX = 0;
00836 }
00837
00838 int Screen::getCursorX() const
00839 {
00840 return cuX;
00841 }
00842
00843 int Screen::getCursorY() const
00844 {
00845 return cuY;
00846 }
00847
00848
00849
00850 void Screen::clearImage(int loca, int loce, char c)
00851 {
00852 int scr_TL=loc(0,hist->getLines());
00853
00854
00855
00856 if ( (sel_BR > (loca+scr_TL) )&&(sel_TL < (loce+scr_TL)) )
00857 {
00858 clearSelection();
00859 }
00860
00861 int topLine = loca/columns;
00862 int bottomLine = loce/columns;
00863
00864 Character clearCh(c,cu_fg,cu_bg,DEFAULT_RENDITION);
00865
00866
00867
00868 bool isDefaultCh = (clearCh == Character());
00869
00870 for (int y=topLine;y<=bottomLine;y++)
00871 {
00872 lineProperties[y] = 0;
00873
00874 int endCol = ( y == bottomLine) ? loce%columns : columns-1;
00875 int startCol = ( y == topLine ) ? loca%columns : 0;
00876
00877 QVector<Character>& line = screenLines[y];
00878
00879 if ( isDefaultCh && endCol == columns-1 )
00880 {
00881 line.resize(startCol);
00882 }
00883 else
00884 {
00885 if (line.size() < endCol + 1)
00886 line.resize(endCol+1);
00887
00888 Character* data = line.data();
00889 for (int i=startCol;i<=endCol;i++)
00890 data[i]=clearCh;
00891 }
00892 }
00893 }
00894
00895 void Screen::moveImage(int dest, int sourceBegin, int sourceEnd)
00896 {
00897 Q_ASSERT( sourceBegin <= sourceEnd );
00898
00899 int lines=(sourceEnd-sourceBegin)/columns;
00900
00901
00902
00903
00904
00905
00906 if (dest < sourceBegin)
00907 {
00908 for (int i=0;i<=lines;i++)
00909 {
00910 screenLines[ (dest/columns)+i ] = screenLines[ (sourceBegin/columns)+i ];
00911 lineProperties[(dest/columns)+i]=lineProperties[(sourceBegin/columns)+i];
00912 }
00913 }
00914 else
00915 {
00916 for (int i=lines;i>=0;i--)
00917 {
00918 screenLines[ (dest/columns)+i ] = screenLines[ (sourceBegin/columns)+i ];
00919 lineProperties[(dest/columns)+i]=lineProperties[(sourceBegin/columns)+i];
00920 }
00921 }
00922
00923 if (lastPos != -1)
00924 {
00925 int diff = dest - sourceBegin;
00926 lastPos += diff;
00927 if ((lastPos < 0) || (lastPos >= (lines*columns)))
00928 lastPos = -1;
00929 }
00930
00931
00932 if (sel_begin != -1)
00933 {
00934 bool beginIsTL = (sel_begin == sel_TL);
00935 int diff = dest - sourceBegin;
00936 int scr_TL=loc(0,hist->getLines());
00937 int srca = sourceBegin+scr_TL;
00938 int srce = sourceEnd+scr_TL;
00939 int desta = srca+diff;
00940 int deste = srce+diff;
00941
00942 if ((sel_TL >= srca) && (sel_TL <= srce))
00943 sel_TL += diff;
00944 else if ((sel_TL >= desta) && (sel_TL <= deste))
00945 sel_BR = -1;
00946
00947 if ((sel_BR >= srca) && (sel_BR <= srce))
00948 sel_BR += diff;
00949 else if ((sel_BR >= desta) && (sel_BR <= deste))
00950 sel_BR = -1;
00951
00952 if (sel_BR < 0)
00953 {
00954 clearSelection();
00955 }
00956 else
00957 {
00958 if (sel_TL < 0)
00959 sel_TL = 0;
00960 }
00961
00962 if (beginIsTL)
00963 sel_begin = sel_TL;
00964 else
00965 sel_begin = sel_BR;
00966 }
00967 }
00968
00969 void Screen::clearToEndOfScreen()
00970 {
00971 clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' ');
00972 }
00973
00974 void Screen::clearToBeginOfScreen()
00975 {
00976 clearImage(loc(0,0),loc(cuX,cuY),' ');
00977 }
00978
00979 void Screen::clearEntireScreen()
00980 {
00981
00982 for (int i = 0; i < (lines-1); i++)
00983 {
00984 addHistLine(); scrollUp(0,1);
00985 }
00986
00987 clearImage(loc(0,0),loc(columns-1,lines-1),' ');
00988 }
00989
00994 void Screen::helpAlign()
00995 {
00996 clearImage(loc(0,0),loc(columns-1,lines-1),'E');
00997 }
00998
00999 void Screen::clearToEndOfLine()
01000 {
01001 clearImage(loc(cuX,cuY),loc(columns-1,cuY),' ');
01002 }
01003
01004 void Screen::clearToBeginOfLine()
01005 {
01006 clearImage(loc(0,cuY),loc(cuX,cuY),' ');
01007 }
01008
01009 void Screen::clearEntireLine()
01010 {
01011 clearImage(loc(0,cuY),loc(columns-1,cuY),' ');
01012 }
01013
01014 void Screen::setRendition(int re)
01015 {
01016 cu_re |= re;
01017 effectiveRendition();
01018 }
01019
01020 void Screen::resetRendition(int re)
01021 {
01022 cu_re &= ~re;
01023 effectiveRendition();
01024 }
01025
01026 void Screen::setDefaultRendition()
01027 {
01028 setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
01029 setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
01030 cu_re = DEFAULT_RENDITION;
01031 effectiveRendition();
01032 }
01033
01034 void Screen::setForeColor(int space, int color)
01035 {
01036 cu_fg = CharacterColor(space, color);
01037
01038 if ( cu_fg.isValid() )
01039 effectiveRendition();
01040 else
01041 setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
01042 }
01043
01044 void Screen::setBackColor(int space, int color)
01045 {
01046 cu_bg = CharacterColor(space, color);
01047
01048 if ( cu_bg.isValid() )
01049 effectiveRendition();
01050 else
01051 setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
01052 }
01053
01054
01055
01056
01057
01058
01059
01060 void Screen::clearSelection()
01061 {
01062 sel_BR = -1;
01063 sel_TL = -1;
01064 sel_begin = -1;
01065 }
01066
01067 void Screen::getSelectionStart(int& column , int& line)
01068 {
01069 if ( sel_TL != -1 )
01070 {
01071 column = sel_TL % columns;
01072 line = sel_TL / columns;
01073 }
01074 else
01075 {
01076 column = cuX + getHistLines();
01077 line = cuY + getHistLines();
01078 }
01079 }
01080 void Screen::getSelectionEnd(int& column , int& line)
01081 {
01082 if ( sel_BR != -1 )
01083 {
01084 column = sel_BR % columns;
01085 line = sel_BR / columns;
01086 }
01087 else
01088 {
01089 column = cuX + getHistLines();
01090 line = cuY + getHistLines();
01091 }
01092 }
01093 void Screen::setSelectionStart(const int x, const int y, const bool mode)
01094 {
01095 sel_begin = loc(x,y);
01096
01097 if (x == columns) sel_begin--;
01098
01099 sel_BR = sel_begin;
01100 sel_TL = sel_begin;
01101 columnmode = mode;
01102 }
01103
01104 void Screen::setSelectionEnd( const int x, const int y)
01105 {
01106 if (sel_begin == -1) return;
01107 int l = loc(x,y);
01108
01109 if (l < sel_begin)
01110 {
01111 sel_TL = l;
01112 sel_BR = sel_begin;
01113 }
01114 else
01115 {
01116
01117 if (x == columns) l--;
01118
01119 sel_TL = sel_begin;
01120 sel_BR = l;
01121 }
01122 }
01123
01124 bool Screen::isSelected( const int x,const int y) const
01125 {
01126 if (columnmode) {
01127 int sel_Left,sel_Right;
01128 if ( sel_TL % columns < sel_BR % columns ) {
01129 sel_Left = sel_TL; sel_Right = sel_BR;
01130 } else {
01131 sel_Left = sel_BR; sel_Right = sel_TL;
01132 }
01133 return ( x >= sel_Left % columns ) && ( x <= sel_Right % columns ) &&
01134 ( y >= sel_TL / columns ) && ( y <= sel_BR / columns );
01135 }
01136 else {
01137 int pos = loc(x,y);
01138 return ( pos >= sel_TL && pos <= sel_BR );
01139 }
01140 }
01141
01142 QString Screen::selectedText(bool preserveLineBreaks)
01143 {
01144 QString result;
01145 QTextStream stream(&result, QIODevice::ReadWrite);
01146
01147 PlainTextDecoder decoder;
01148 decoder.begin(&stream);
01149 writeSelectionToStream(&decoder , preserveLineBreaks);
01150 decoder.end();
01151
01152 return result;
01153 }
01154
01155 bool Screen::isSelectionValid() const
01156 {
01157 return ( sel_TL >= 0 && sel_BR >= 0 );
01158 }
01159
01160 void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder ,
01161 bool preserveLineBreaks)
01162 {
01163
01164 if ( !isSelectionValid() )
01165 return;
01166
01167 int top = sel_TL / columns;
01168 int left = sel_TL % columns;
01169
01170 int bottom = sel_BR / columns;
01171 int right = sel_BR % columns;
01172
01173 Q_ASSERT( top >= 0 && left >= 0 && bottom >= 0 && right >= 0 );
01174
01175 for (int y=top;y<=bottom;y++)
01176 {
01177 int start = 0;
01178 if ( y == top || columnmode ) start = left;
01179
01180 int count = -1;
01181 if ( y == bottom || columnmode ) count = right - start + 1;
01182
01183 const bool appendNewLine = ( y != bottom );
01184 int copied = copyLineToStream( y,
01185 start,
01186 count,
01187 decoder,
01188 appendNewLine,
01189 preserveLineBreaks );
01190
01191
01192
01193
01194
01195
01196 if ( y == bottom &&
01197 copied < count )
01198 {
01199 Character newLineChar('\n');
01200 decoder->decodeLine(&newLineChar,1,0);
01201 }
01202 }
01203 }
01204
01205 int Screen::copyLineToStream(int line ,
01206 int start,
01207 int count,
01208 TerminalCharacterDecoder* decoder,
01209 bool appendNewLine,
01210 bool preserveLineBreaks)
01211 {
01212
01213
01214
01215
01216 static const int MAX_CHARS = 1024;
01217 static Character characterBuffer[MAX_CHARS];
01218
01219 assert( count < MAX_CHARS );
01220
01221 LineProperty currentLineProperties = 0;
01222
01223
01224 if (line < hist->getLines())
01225 {
01226 const int lineLength = hist->getLineLen(line);
01227
01228
01229 start = qMin(start,qMax(0,lineLength-1));
01230
01231
01232
01233
01234 if (count == -1)
01235 {
01236 count = lineLength-start;
01237 }
01238 else
01239 {
01240 count = qMin(start+count,lineLength)-start;
01241 }
01242
01243
01244 assert( start >= 0 );
01245 assert( count >= 0 );
01246 assert( (start+count) <= hist->getLineLen(line) );
01247
01248 hist->getCells(line,start,count,characterBuffer);
01249
01250 if ( hist->isWrappedLine(line) )
01251 currentLineProperties |= LINE_WRAPPED;
01252 }
01253 else
01254 {
01255 if ( count == -1 )
01256 count = columns - start;
01257
01258 assert( count >= 0 );
01259
01260 const int screenLine = line-hist->getLines();
01261
01262 Character* data = screenLines[screenLine].data();
01263 int length = screenLines[screenLine].count();
01264
01265
01266 for (int i = length-1; i >= 0; i--)
01267 if (data[i].character == ' ')
01268 length--;
01269 else
01270 break;
01271
01272
01273 for (int i=start;i < qMin(start+count,length);i++)
01274 {
01275 characterBuffer[i-start] = data[i];
01276 }
01277
01278
01279 count = qBound(0,count,length-start);
01280
01281 Q_ASSERT( screenLine < lineProperties.count() );
01282 currentLineProperties |= lineProperties[screenLine];
01283 }
01284
01285
01286 const bool omitLineBreak = (currentLineProperties & LINE_WRAPPED) ||
01287 !preserveLineBreaks;
01288
01289 if ( !omitLineBreak && appendNewLine && (count+1 < MAX_CHARS) )
01290 {
01291 characterBuffer[count] = '\n';
01292 count++;
01293 }
01294
01295
01296 decoder->decodeLine( (Character*) characterBuffer ,
01297 count, currentLineProperties );
01298
01299 return count;
01300 }
01301
01302 void Screen::writeToStream(TerminalCharacterDecoder* decoder, int from, int to)
01303 {
01304 sel_begin = loc(0,from);
01305 sel_TL = sel_begin;
01306 sel_BR = loc(columns-1,to);
01307 writeSelectionToStream(decoder);
01308 clearSelection();
01309 }
01310
01311 QString Screen::getHistoryLine(int no)
01312 {
01313 sel_begin = loc(0,no);
01314 sel_TL = sel_begin;
01315 sel_BR = loc(columns-1,no);
01316 return selectedText(false);
01317 }
01318
01319 void Screen::addHistLine()
01320 {
01321
01322
01323
01324 if (hasScroll())
01325 {
01326 int oldHistLines = hist->getLines();
01327
01328 hist->addCellsVector(screenLines[0]);
01329 hist->addLine( lineProperties[0] & LINE_WRAPPED );
01330
01331 int newHistLines = hist->getLines();
01332
01333 bool beginIsTL = (sel_begin == sel_TL);
01334
01335
01336
01337 if ( newHistLines == oldHistLines )
01338 _droppedLines++;
01339
01340
01341 if (newHistLines > oldHistLines)
01342 {
01343 if (sel_begin != -1)
01344 {
01345 sel_TL += columns;
01346 sel_BR += columns;
01347 }
01348 }
01349
01350 if (sel_begin != -1)
01351 {
01352
01353 int top_BR = loc(0, 1+newHistLines);
01354
01355 if (sel_TL < top_BR)
01356 sel_TL -= columns;
01357
01358 if (sel_BR < top_BR)
01359 sel_BR -= columns;
01360
01361 if (sel_BR < 0)
01362 {
01363 clearSelection();
01364 }
01365 else
01366 {
01367 if (sel_TL < 0)
01368 sel_TL = 0;
01369 }
01370
01371 if (beginIsTL)
01372 sel_begin = sel_TL;
01373 else
01374 sel_begin = sel_BR;
01375 }
01376 }
01377
01378 }
01379
01380 int Screen::getHistLines()
01381 {
01382 return hist->getLines();
01383 }
01384
01385 void Screen::setScroll(const HistoryType& t , bool copyPreviousScroll)
01386 {
01387 clearSelection();
01388
01389 if ( copyPreviousScroll )
01390 hist = t.scroll(hist);
01391 else
01392 {
01393 HistoryScroll* oldScroll = hist;
01394 hist = t.scroll(0);
01395 delete oldScroll;
01396 }
01397 }
01398
01399 bool Screen::hasScroll()
01400 {
01401 return hist->hasScroll();
01402 }
01403
01404 const HistoryType& Screen::getScroll()
01405 {
01406 return hist->getType();
01407 }
01408
01409 void Screen::setLineProperty(LineProperty property , bool enable)
01410 {
01411 if ( enable )
01412 {
01413 lineProperties[cuY] = (LineProperty)(lineProperties[cuY] | property);
01414 }
01415 else
01416 {
01417 lineProperties[cuY] = (LineProperty)(lineProperties[cuY] & ~property);
01418 }
01419 }
01420 void Screen::fillWithDefaultChar(Character* dest, int count)
01421 {
01422 for (int i=0;i<count;i++)
01423 dest[i] = defaultChar;
01424 }